/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.ui.dialogs.sql;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IWorkbenchPartSite;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPEvaluationContext;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.exec.*;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.runtime.jobs.DataSourceJob;
import org.jkiss.dbeaver.model.DBIcon;
import org.jkiss.dbeaver.ui.DBeaverIcons;
import org.jkiss.dbeaver.ui.UIUtils;
import java.util.*;
/**
* Super class for handling dialogs related to
*
* @author Serge Rider
*
*/
public abstract class GenerateMultiSQLDialog<T extends DBSObject> extends GenerateSQLDialog {
private static final String DIALOG_ID = "GenerateMultiSQLDialog";
protected final Collection<T> selectedObjects;
private Table objectsTable;
public GenerateMultiSQLDialog(
IWorkbenchPartSite partSite,
String title,
Collection<T> objects,
boolean meta)
{
this(
partSite,
getContextFromObjects(objects, meta),
title,
objects);
}
public GenerateMultiSQLDialog(
IWorkbenchPartSite partSite,
DBCExecutionContext context,
String title,
Collection<T> objects)
{
super(
partSite,
context,
title,
null);
this.selectedObjects = objects;
}
@Override
protected IDialogSettings getDialogBoundsSettings() {
return UIUtils.getDialogSettings(DIALOG_ID);
}
protected abstract SQLScriptProgressListener<T> getScriptListener();
protected String[] generateSQLScript()
{
List<T> checkedObjects = getCheckedObjects();
List<String> lines = new ArrayList<>();
for (T object : checkedObjects) {
generateObjectCommand(lines, object);
}
return lines.toArray(new String[lines.size()]);
}
public List<T> getCheckedObjects() {
List<T> checkedObjects = new ArrayList<>();
if (objectsTable != null) {
for (TableItem item : objectsTable.getItems()) {
if (item.getChecked()) {
checkedObjects.add((T) item.getData());
}
}
} else {
checkedObjects.addAll(selectedObjects);
}
return checkedObjects;
}
protected void createObjectsSelector(Composite parent) {
if (selectedObjects.size() < 2) {
// Don't need it for a single object
return;
}
UIUtils.createControlLabel(parent, "Tables");
objectsTable = new Table(parent, SWT.BORDER | SWT.CHECK);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.heightHint = 100;
objectsTable.setLayoutData(gd);
for (T table : selectedObjects) {
TableItem item = new TableItem(objectsTable, SWT.NONE);
item.setText(DBUtils.getObjectFullName(table, DBPEvaluationContext.UI));
item.setImage(DBeaverIcons.getImage(DBIcon.TREE_TABLE));
item.setChecked(true);
item.setData(table);
}
objectsTable.addSelectionListener(SQL_CHANGE_LISTENER);
objectsTable.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
boolean hasChecked = !getCheckedObjects().isEmpty();
getButton(IDialogConstants.OK_ID).setEnabled(hasChecked);
getButton(IDialogConstants.DETAILS_ID).setEnabled(hasChecked);
}
});
}
@Override
protected void executeSQL() {
final String jobName = getShell().getText();
final SQLScriptProgressListener<T> scriptListener = getScriptListener();
final List<T> objects = getCheckedObjects();
final Map<T, List<String>> objectsSQL = new LinkedHashMap<>();
for (T object : objects) {
final List<String> lines = new ArrayList<>();
generateObjectCommand(lines, object);
objectsSQL.put(object, lines);
}
final DataSourceJob job = new DataSourceJob(jobName, null, getExecutionContext()) {
public Exception objectProcessingError;
@Override
protected IStatus run(final DBRProgressMonitor monitor)
{
final DataSourceJob curJob = this;
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
scriptListener.beginScriptProcessing(curJob, objects);
}
});
monitor.beginTask(jobName, objects.size());
try (DBCSession session = getExecutionContext().openSession(monitor, DBCExecutionPurpose.UTIL, jobName)) {
for (int i = 0; i < objects.size(); i++) {
if (monitor.isCanceled()) {
break;
}
final int objectNumber = i;
final T object = objects.get(i);
monitor.subTask("Process " + DBUtils.getObjectFullName(object, DBPEvaluationContext.UI));
objectProcessingError = null;
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
scriptListener.beginObjectProcessing(object, objectNumber);
}
});
try {
final List<String> lines = objectsSQL.get(object);
for (String line : lines) {
try (final DBCStatement statement = DBUtils.makeStatement(session, line, false)) {
if (statement.executeStatement()) {
try (DBCResultSet resultSet = statement.openResultSet()) {
// Run in sync because we need result set
DBeaverUI.syncExec(new Runnable() {
@Override
public void run() {
try {
scriptListener.processObjectResults(object, statement, resultSet);
} catch (DBCException e) {
objectProcessingError = e;
}
}
});
}
if (objectProcessingError != null) {
break;
}
} else {
DBeaverUI.syncExec(new Runnable() {
@Override
public void run() {
try {
scriptListener.processObjectResults(object, statement, null);
} catch (DBCException e) {
objectProcessingError = e;
}
}
});
}
}
}
} catch (Exception e) {
objectProcessingError = e;
} finally {
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
scriptListener.endObjectProcessing(object, objectProcessingError);
}
});
}
monitor.worked(1);
}
} finally {
monitor.done();
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
scriptListener.endScriptProcessing();
}
});
}
return Status.OK_STATUS;
}
};
job.setUser(false);
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
if (needsRefreshOnFinish()) {
for (T object : selectedObjects) {
DBUtils.fireObjectRefresh(object);
}
}
}
});
job.schedule();
}
protected boolean needsRefreshOnFinish() {
return false;
}
protected abstract void generateObjectCommand(List<String> sql, T object);
protected static <T extends DBSObject> DBCExecutionContext getContextFromObjects(@NotNull Collection<T> objects, boolean meta) {
Iterator<T> iterator = objects.iterator();
if (iterator.hasNext()) {
T object = iterator.next();
DBPDataSource dataSource = object.getDataSource();
return dataSource == null ? null : dataSource.getDefaultContext(meta);
}
return null;
}
}