提交 be62fc82 编写于 作者: S serge-rider

#2201 Auto-recover after SQL execute


Former-commit-id: 0d5bb1fb
上级 527b3823
......@@ -62,6 +62,7 @@ import org.jkiss.dbeaver.ui.dialogs.exec.ExecutionQueueErrorResponse;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
......@@ -377,98 +378,16 @@ public class SQLQueryJob extends DataSourceJob
}
startTime = System.currentTimeMillis();
DBCExecutionSource source = new AbstractExecutionSource(dataContainer, executionContext, partSite.getPart(), sqlQuery);
final DBCStatement dbcStatement = DBUtils.makeStatement(
source,
session,
DBCStatementType.SCRIPT,
sqlQuery,
rsOffset, rsMaxRows);
curStatement = dbcStatement;
int statementTimeout = getDataSourceContainer().getPreferenceStore().getInt(DBeaverPreferences.STATEMENT_TIMEOUT);
if (statementTimeout > 0) {
try {
dbcStatement.setStatementTimeout(statementTimeout);
} catch (Throwable e) {
log.debug("Can't set statement timeout:" + e.getMessage());
}
}
// Execute statement
try {
session.getProgressMonitor().subTask("Execute query");
boolean hasResultSet = dbcStatement.executeStatement();
curResult.setHasResultSet(hasResultSet);
statistics.addExecuteTime(System.currentTimeMillis() - startTime);
statistics.addStatementsCount();
long updateCount = -1;
while (hasResultSet || resultSetNumber == 0 || updateCount >= 0) {
// Fetch data only if we have to fetch all results or if it is rs requested
if (fetchResultSetNumber < 0 || fetchResultSetNumber == resultSetNumber) {
if (hasResultSet && fetchResultSets) {
DBCResultSet resultSet = dbcStatement.openResultSet();
if (resultSet == null) {
// Kind of bug in the driver. It says it has resultset but returns null
break;
} else {
DBDDataReceiver dataReceiver = resultsConsumer.getDataReceiver(sqlQuery, resultSetNumber);
if (dataReceiver != null) {
hasResultSet = fetchQueryData(session, resultSet, curResult, dataReceiver, true);
}
}
}
}
if (!hasResultSet) {
try {
updateCount = dbcStatement.getUpdateRowCount();
if (updateCount >= 0) {
curResult.setUpdateCount(updateCount);
statistics.addRowsUpdated(updateCount);
}
} catch (DBCException e) {
// In some cases we can't read update count
// This is bad but we can live with it
// Just print a warning
log.warn("Can't obtain update count", e);
}
}
if (hasResultSet && fetchResultSets) {
resultSetNumber++;
fetchResultSetNumber = resultSetNumber;
}
if (!hasResultSet && updateCount < 0) {
// Nothing else to fetch
break;
}
if (dataSource.getInfo().supportsMultipleResults()) {
try {
hasResultSet = dbcStatement.nextResults();
} catch (DBCException e) {
log.error(e);
// #2792: Check this twice. Some drivers (e.g. Sybase jConnect)
// throw error on n'th result fetch - but it still can keep fetching next results
hasResultSet = dbcStatement.nextResults();
}
updateCount = hasResultSet ? -1 : 0;
} else {
break;
}
}
}
finally {
SQLQuery execStatement = sqlQuery;
long execStartTime = startTime;
DBUtils.tryExecuteRecover(session, session.getDataSource(), param -> {
try {
curResult.addWarnings(dbcStatement.getStatementWarnings());
executeStatement(session, execStatement, execStartTime, curResult);
} catch (Throwable e) {
log.warn("Can't read execution warnings", e);
throw new InvocationTargetException(e);
}
//monitor.subTask("Close query");
if (!keepStatementOpen()) {
closeStatement();
}
}
});
}
catch (Throwable ex) {
if (!(ex instanceof DBException)) {
......@@ -498,6 +417,101 @@ public class SQLQueryJob extends DataSourceJob
return true;
}
private void executeStatement(@NotNull DBCSession session, SQLQuery sqlQuery, long startTime, SQLQueryResult curResult) throws DBCException {
DBCExecutionSource source = new AbstractExecutionSource(dataContainer, session.getExecutionContext(), partSite.getPart(), sqlQuery);
final DBCStatement dbcStatement = DBUtils.makeStatement(
source,
session,
DBCStatementType.SCRIPT,
sqlQuery,
rsOffset, rsMaxRows);
curStatement = dbcStatement;
int statementTimeout = getDataSourceContainer().getPreferenceStore().getInt(DBeaverPreferences.STATEMENT_TIMEOUT);
if (statementTimeout > 0) {
try {
dbcStatement.setStatementTimeout(statementTimeout);
} catch (Throwable e) {
log.debug("Can't set statement timeout:" + e.getMessage());
}
}
// Execute statement
try {
session.getProgressMonitor().subTask("Execute query");
boolean hasResultSet = dbcStatement.executeStatement();
curResult.setHasResultSet(hasResultSet);
statistics.addExecuteTime(System.currentTimeMillis() - startTime);
statistics.addStatementsCount();
long updateCount = -1;
while (hasResultSet || resultSetNumber == 0 || updateCount >= 0) {
// Fetch data only if we have to fetch all results or if it is rs requested
if (fetchResultSetNumber < 0 || fetchResultSetNumber == resultSetNumber) {
if (hasResultSet && fetchResultSets) {
DBCResultSet resultSet = dbcStatement.openResultSet();
if (resultSet == null) {
// Kind of bug in the driver. It says it has resultset but returns null
break;
} else {
DBDDataReceiver dataReceiver = resultsConsumer.getDataReceiver(sqlQuery, resultSetNumber);
if (dataReceiver != null) {
hasResultSet = fetchQueryData(session, resultSet, curResult, dataReceiver, true);
}
}
}
}
if (!hasResultSet) {
try {
updateCount = dbcStatement.getUpdateRowCount();
if (updateCount >= 0) {
curResult.setUpdateCount(updateCount);
statistics.addRowsUpdated(updateCount);
}
} catch (DBCException e) {
// In some cases we can't read update count
// This is bad but we can live with it
// Just print a warning
log.warn("Can't obtain update count", e);
}
}
if (hasResultSet && fetchResultSets) {
resultSetNumber++;
fetchResultSetNumber = resultSetNumber;
}
if (!hasResultSet && updateCount < 0) {
// Nothing else to fetch
break;
}
if (session.getDataSource().getInfo().supportsMultipleResults()) {
try {
hasResultSet = dbcStatement.nextResults();
} catch (DBCException e) {
log.error(e);
// #2792: Check this twice. Some drivers (e.g. Sybase jConnect)
// throw error on n'th result fetch - but it still can keep fetching next results
hasResultSet = dbcStatement.nextResults();
}
updateCount = hasResultSet ? -1 : 0;
} else {
break;
}
}
}
finally {
try {
curResult.addWarnings(dbcStatement.getStatementWarnings());
} catch (Throwable e) {
log.warn("Can't read execution warnings", e);
}
//monitor.subTask("Close query");
if (!keepStatementOpen()) {
closeStatement();
}
}
}
private boolean executeControlCommand(SQLControlCommand command) throws DBException {
if (command.isEmptyCommand()) {
return true;
......
......@@ -113,7 +113,7 @@ public final class ModelPreferences
private static void initializeDefaultPreferences(DBPPreferenceStore store) {
// Common
PrefUtils.setDefaultPreferenceValue(store, QUERY_ROLLBACK_ON_ERROR, false);
PrefUtils.setDefaultPreferenceValue(store, EXECUTE_RECOVER_ENABLED, true);
PrefUtils.setDefaultPreferenceValue(store, EXECUTE_RECOVER_ENABLED, false);
PrefUtils.setDefaultPreferenceValue(store, EXECUTE_RECOVER_RETRY_COUNT, 1);
// SQL execution
......
......@@ -29,7 +29,8 @@ import org.jkiss.dbeaver.model.exec.*;
import org.jkiss.dbeaver.model.impl.data.DefaultValueHandler;
import org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
import org.jkiss.dbeaver.model.runtime.DBRRunnableParametrized;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.model.sql.*;
import org.jkiss.dbeaver.model.struct.*;
import org.jkiss.dbeaver.model.struct.rdb.*;
......@@ -1468,7 +1469,11 @@ public final class DBUtils {
return list;
}
public static boolean tryExecuteRecover(@NotNull DBRProgressMonitor monitor, @NotNull DBPDataSource dataSource, @NotNull DBRRunnableWithProgress runnable) throws DBException {
/**
* @param param DBRProgressProgress monitor or DBCSession
*
*/
public static <T> boolean tryExecuteRecover(@NotNull T param, @NotNull DBPDataSource dataSource, @NotNull DBRRunnableParametrized<T> runnable) throws DBException {
int tryCount = 1;
boolean recoverEnabled = dataSource.getContainer().getPreferenceStore().getBoolean(ModelPreferences.EXECUTE_RECOVER_ENABLED);
if (recoverEnabled) {
......@@ -1477,7 +1482,7 @@ public final class DBUtils {
Throwable lastError = null;
for (int i = 0; i < tryCount; i++) {
try {
runnable.run(monitor);
runnable.run(param);
lastError = null;
break;
} catch (InvocationTargetException e) {
......@@ -1487,6 +1492,14 @@ public final class DBUtils {
break;
}
log.debug("Invalidate datasource '" + dataSource.getContainer().getName() + "' connections...");
DBRProgressMonitor monitor;
if (param instanceof DBRProgressMonitor) {
monitor = (DBRProgressMonitor) param;
} else if (param instanceof DBCSession) {
monitor = ((DBCSession) param).getProgressMonitor();
} else {
monitor = new VoidProgressMonitor();
}
InvalidateJob.invalidateDataSource(monitor, dataSource, false);
if (i < tryCount - 1) {
log.error("Operation failed. Retry count remains = " + (tryCount - i - 1), lastError);
......@@ -1501,4 +1514,5 @@ public final class DBUtils {
}
return true;
}
}
/*
* 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.model.runtime;
import java.lang.reflect.InvocationTargetException;
/**
* Runnable with parameter
*/
public interface DBRRunnableParametrized<T> {
void run(T param)
throws InvocationTargetException, InterruptedException;
}
\ No newline at end of file
......@@ -17,15 +17,11 @@
package org.jkiss.dbeaver.model.runtime;
import java.lang.reflect.InvocationTargetException;
/**
* Database progress monitor.
* Similar to IProgressMonitor but with DBP specific features
*/
public interface DBRRunnableWithProgress {
public interface DBRRunnableWithProgress extends DBRRunnableParametrized<DBRProgressMonitor> {
void run(DBRProgressMonitor monitor)
throws InvocationTargetException, InterruptedException;
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册