Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cb 1084 transactions #2449

Merged
merged 38 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b0f921a
CB-4806 transactions api
yagudin10 Mar 4, 2024
c2e081d
CB-1084 add commit mode plugin
devnaumov Mar 5, 2024
0ebf7e9
CB-1084 rename plugin
devnaumov Mar 5, 2024
a045360
Merge branch 'devel' into CB-1084-transactions
devnaumov Mar 5, 2024
cb42abf
CB-4806 add is auto commit property to web context
yagudin10 Mar 5, 2024
b210c75
CB-1084 add gql queries
devnaumov Mar 6, 2024
a1ed2ad
Merge remote-tracking branch 'origin/devel' into CB-1084-transactions
yagudin10 Mar 6, 2024
fa09481
CB-1084 add loaders
devnaumov Mar 6, 2024
a052b1a
Merge branch 'CB-1084-transactions' of https://github.com/dbeaver/clo…
devnaumov Mar 6, 2024
9ef63b0
CB-4806 transactions for update results
yagudin10 Mar 6, 2024
85c072e
Merge remote-tracking branch 'origin/CB-1084-transactions' into CB-10…
yagudin10 Mar 6, 2024
a8e6696
CB-4806 fix text
yagudin10 Mar 6, 2024
2e32dd6
CB-1084 pass execution context via extensions
devnaumov Mar 7, 2024
86ea375
CB-1084 handle errors
devnaumov Mar 7, 2024
d21fbfd
CB-1084 get connection before the task execution
devnaumov Mar 7, 2024
0069a3d
CB-1084 grab connection from transaction context
devnaumov Mar 7, 2024
ad9dc5c
Merge branch 'devel' into CB-1084-transactions
devnaumov Mar 8, 2024
03ed2f0
CB-1084 support execution context provider for the object viewer
devnaumov Mar 11, 2024
a71c8e5
CB-1084 refresh context manually
devnaumov Mar 11, 2024
6430617
CB-1084 check options panel status
devnaumov Mar 11, 2024
2404c46
CB-1084 move transaction logic to the ConnectionExecutionContext
devnaumov Mar 11, 2024
08c308e
CB-4806 make project id required
yagudin10 Mar 12, 2024
46d3fb0
Merge branch 'devel' into CB-1084-transactions
devnaumov Mar 12, 2024
2f2e35f
CB-1084 make actions naming more unique
devnaumov Mar 12, 2024
d5708f1
CB-1084 remove success flag
devnaumov Mar 12, 2024
c2fc994
CB-1084 add plugin to default product
devnaumov Mar 12, 2024
cbdd9f4
Merge branch 'devel' into CB-1084-transactions
EvgeniaBzzz Mar 13, 2024
97d194c
Merge branch 'devel' into CB-1084-transactions
EvgeniaBzzz Mar 14, 2024
9e1d384
CB-1084 show confirm dialog
devnaumov Mar 14, 2024
687c67a
Merge branch 'devel' into CB-1084-transactions
EvgeniaBzzz Mar 14, 2024
e4ab4f5
CB-1084 always fire disconnect through executor
devnaumov Mar 14, 2024
80423e7
Merge branch 'CB-1084-transactions' of https://github.com/dbeaver/clo…
devnaumov Mar 14, 2024
1c6beab
CB-1084 adjust behaviour
devnaumov Mar 14, 2024
ecfffce
Merge branch 'devel' into CB-1084-transactions
EvgeniaBzzz Mar 15, 2024
0dd614c
CB-1084 add more explicit check
devnaumov Mar 15, 2024
52281f5
Merge branch 'CB-1084-transactions' of https://github.com/dbeaver/clo…
devnaumov Mar 15, 2024
be12770
CB-1084 interrupt disconnect if commit fails
devnaumov Mar 15, 2024
e440e32
Merge branch 'devel' into CB-1084-transactions
EvgeniaBzzz Mar 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type SQLContextInfo {
id: ID!
projectId: ID!
connectionId: ID!
autoCommit: Boolean
defaultCatalog: String
defaultSchema: String

Expand Down Expand Up @@ -401,4 +402,26 @@ extend type Mutation {

asyncSqlRowDataCountResult(taskId: ID!): Int!

@since(version: "24.0.1")
asyncSqlSetAutoCommit(
projectId: ID!,
connectionId: ID!,
contextId: ID!,
autoCommit: Boolean!
): AsyncTaskInfo!

@since(version: "24.0.1")
asyncSqlCommitTransaction(
projectId: ID!,
connectionId: ID!,
contextId: ID!
): AsyncTaskInfo!

@since(version: "24.0.1")
asyncSqlRollbackTransaction(
projectId: ID!,
connectionId: ID!,
contextId: ID!
): AsyncTaskInfo!

}
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,22 @@ String generateGroupByQuery(@NotNull WebSQLContextInfo contextInfo,
@Nullable
@WebAction
Long getRowDataCountResult(@NotNull WebSession webSession, @NotNull String taskId) throws DBWebException;

@WebAction
WebAsyncTaskInfo asyncSqlSetAutoCommit(
@NotNull WebSession webSession,
@NotNull WebSQLContextInfo contextInfo,
boolean autoCommit
) throws DBWebException;

@WebAction
WebAsyncTaskInfo asyncSqlRollbackTransaction(
@NotNull WebSession webSession,
@NotNull WebSQLContextInfo contextInfo
) throws DBWebException;

@WebAction
WebAsyncTaskInfo asyncSqlCommitTransaction(
@NotNull WebSession webSession,
@NotNull WebSQLContextInfo sqlContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,27 @@
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebAction;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.model.WebAsyncTaskInfo;
import io.cloudbeaver.model.session.WebAsyncTaskProcessor;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.model.session.WebSessionProvider;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCExecutionContextDefaults;
import org.jkiss.dbeaver.model.exec.DBExecUtils;
import org.jkiss.dbeaver.model.exec.*;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.qm.QMTransactionState;
import org.jkiss.dbeaver.model.qm.QMUtils;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
import org.jkiss.dbeaver.model.struct.rdb.DBSCatalog;
import org.jkiss.dbeaver.model.struct.rdb.DBSSchema;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -170,4 +177,103 @@ void dispose() {
public WebSession getWebSession() {
return processor.getWebSession();
}


///////////////////////////////////////////////////////
// Transactions

public WebAsyncTaskInfo setAutoCommit(boolean autoCommit) {
DBCExecutionContext context = processor.getExecutionContext();
DBCTransactionManager txnManager = DBUtils.getTransactionManager(context);
WebAsyncTaskProcessor<Boolean> runnable = new WebAsyncTaskProcessor<>() {
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
if (txnManager != null) {
monitor.beginTask("Change connection auto-commit to " + autoCommit, 1);
try {
monitor.subTask("Change context '" + context.getContextName() + "' auto-commit state");
txnManager.setAutoCommit(monitor, autoCommit);
result = true;
} catch (DBException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
}

}
};
return getWebSession().createAndRunAsyncTask("Set auto-commit", runnable);

}

public WebAsyncTaskInfo commitTransaction() {
DBCExecutionContext context = processor.getExecutionContext();
DBCTransactionManager txnManager = DBUtils.getTransactionManager(context);
WebAsyncTaskProcessor<String> runnable = new WebAsyncTaskProcessor<>() {
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
if (txnManager != null) {
QMTransactionState txnInfo = QMUtils.getTransactionState(context);
try (DBCSession session = context.openSession(monitor, DBCExecutionPurpose.UTIL, "Commit transaction")) {
txnManager.commit(session);
} catch (DBCException e) {
throw new InvocationTargetException(e);
}
result = """
Transaction has been committed
Query count: %s
Duration: %s
""".formatted(
txnInfo.getUpdateCount(),
RuntimeUtils.formatExecutionTime(System.currentTimeMillis() - txnInfo.getTransactionStartTime())
);
}
}
};
return getWebSession().createAndRunAsyncTask("Commit transaction", runnable);
}


public WebAsyncTaskInfo rollbackTransaction() {
DBCExecutionContext context = processor.getExecutionContext();
DBCTransactionManager txnManager = DBUtils.getTransactionManager(context);
WebAsyncTaskProcessor<String> runnable = new WebAsyncTaskProcessor<>() {
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
if (txnManager != null) {
QMTransactionState txnInfo = QMUtils.getTransactionState(context);
try (DBCSession session = context.openSession(monitor, DBCExecutionPurpose.UTIL, "Rollback transaction")) {
txnManager.rollback(session, null);
} catch (DBCException e) {
throw new InvocationTargetException(e);
}
result = """
Transaction has been rolled back
Query count: %s
Duration: %s
""".formatted(
txnInfo.getUpdateCount(),
RuntimeUtils.formatExecutionTime(System.currentTimeMillis() - txnInfo.getTransactionStartTime())
);
}
}
};

return getWebSession().createAndRunAsyncTask("Rollback transaction", runnable);
}

@Property
public Boolean isAutoCommit() throws DBWebException {
DBCExecutionContext context = processor.getExecutionContext();
DBCTransactionManager txnManager = DBUtils.getTransactionManager(context);
if (txnManager == null) {
return null;
}
try {
return txnManager.isAutoCommit();
} catch (DBException e) {
throw new DBWebException("Error getting auto-commit parameter from context", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,15 @@ public WebSQLExecuteInfo updateResultsDataBatch(
try (DBCSession session = executionContext.openSession(monitor, DBCExecutionPurpose.USER, "Update data in container")) {
DBCTransactionManager txnManager = DBUtils.getTransactionManager(executionContext);
boolean revertToAutoCommit = false;
if (txnManager != null && txnManager.isSupportsTransactions() && txnManager.isAutoCommit()) {
txnManager.setAutoCommit(monitor, false);
revertToAutoCommit = true;
boolean isAutoCommitEnabled = true;
DBCSavepoint savepoint = null;
if (txnManager != null) {
isAutoCommitEnabled = txnManager.isAutoCommit();
if (txnManager.isSupportsTransactions() && isAutoCommitEnabled) {
txnManager.setAutoCommit(monitor, false);
savepoint = txnManager.setSavepoint(monitor, null);
revertToAutoCommit = true;
}
}
try {
Map<String, Object> options = Collections.emptyMap();
Expand All @@ -375,17 +381,27 @@ public WebSQLExecuteInfo updateResultsDataBatch(
newResultSetRows.add(new WebSQLQueryResultSetRow(rowValues, null));
}

if (txnManager != null && txnManager.isSupportsTransactions()) {
if (txnManager != null && txnManager.isSupportsTransactions() && isAutoCommitEnabled) {
txnManager.commit(session);
}
} catch (Exception e) {
if (txnManager != null && txnManager.isSupportsTransactions()) {
txnManager.rollback(session, null);
txnManager.rollback(session, savepoint);
}
throw new DBCException("Error persisting data changes", e);
} finally {
if (revertToAutoCommit) {
txnManager.setAutoCommit(monitor, true);
if (txnManager != null) {
if (revertToAutoCommit) {
txnManager.setAutoCommit(monitor, true);
}
try {
if (savepoint != null) {
txnManager.releaseSavepoint(monitor, savepoint);
}
} catch (Throwable e) {
// Maybe savepoints not supported
log.debug("Can't release savepoint", e);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,23 @@ public void bindWiring(DBWBindingContext model) throws DBWebException {
getService(env).getRowDataCountResult(
getWebSession(env),
env.getArgument("taskId")
)
);
))
.dataFetcher("asyncSqlSetAutoCommit", env ->
getService(env).asyncSqlSetAutoCommit(
getWebSession(env),
getSQLContext(env),
env.getArgument("autoCommit")
))
.dataFetcher("asyncSqlCommitTransaction", env ->
getService(env).asyncSqlCommitTransaction(
getWebSession(env),
getSQLContext(env)
))
.dataFetcher("asyncSqlRollbackTransaction", env ->
getService(env).asyncSqlRollbackTransaction(
getWebSession(env),
getSQLContext(env)
));
}

@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
import org.jkiss.dbeaver.model.sql.registry.SQLGeneratorConfigurationRegistry;
import org.jkiss.dbeaver.model.sql.registry.SQLGeneratorDescriptor;
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
import org.jkiss.dbeaver.model.struct.DBSEntity;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.model.struct.DBSWrapper;
import org.jkiss.dbeaver.utils.RuntimeUtils;
Expand Down Expand Up @@ -579,4 +578,19 @@ public Long getRowDataCountResult(@NotNull WebSession webSession, @NotNull Strin
return null;
}

@Override
public WebAsyncTaskInfo asyncSqlSetAutoCommit(@NotNull WebSession webSession, @NotNull WebSQLContextInfo contextInfo, boolean autoCommit) throws DBWebException {
return contextInfo.setAutoCommit(autoCommit);
}

@Override
public WebAsyncTaskInfo asyncSqlRollbackTransaction(@NotNull WebSession webSession, @NotNull WebSQLContextInfo contextInfo) throws DBWebException {
return contextInfo.rollbackTransaction();
}

@Override
public WebAsyncTaskInfo asyncSqlCommitTransaction(@NotNull WebSession webSession, @NotNull WebSQLContextInfo contextInfo) {
return contextInfo.commitTransaction();
}

}
Loading
Loading