-
Notifications
You must be signed in to change notification settings - Fork 6
feat: FIR-50249 support transactions in Core #643
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,6 +92,12 @@ public abstract class FireboltConnection extends JdbcBase implements Connection, | |
| // Parameter parser is determined by the version we're running on | ||
| @Getter | ||
| public final ParserVersion parserVersion; | ||
| // Indicates if auto-commit is enabled | ||
| private boolean autoCommit = true; | ||
| // Indicates if the connection is currently in a transaction | ||
| private boolean inTransaction = false; | ||
| // Indicates if a transaction command (commit/rollback) is currently being executed | ||
| private boolean executingTransactionCommand = false; | ||
|
|
||
| protected FireboltConnection(@NonNull String url, | ||
| Properties connectionSettings, | ||
|
|
@@ -220,16 +226,93 @@ private void addStatement(FireboltStatement statement) throws SQLException { | |
| } | ||
| } | ||
|
|
||
| @Override | ||
| public boolean getAutoCommit() throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| @ExcludeFromJacocoGeneratedReport | ||
| @NotImplemented | ||
| public void setAutoCommit(boolean autoCommit) throws SQLException {} | ||
| @Override | ||
| public boolean getAutoCommit() throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
| return autoCommit; | ||
| } | ||
|
|
||
| @Override | ||
| public void setAutoCommit(boolean autoCommit) throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
|
|
||
| if (autoCommit && inTransaction) { | ||
| commit(); | ||
| } | ||
| this.autoCommit = autoCommit; | ||
| } | ||
|
|
||
| @Override | ||
| public int getTransactionIsolation() throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
| return Connection.TRANSACTION_REPEATABLE_READ; | ||
| } | ||
|
|
||
| @Override | ||
| public void setTransactionIsolation(int level) throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
| if (level != Connection.TRANSACTION_REPEATABLE_READ) { | ||
| throw new FireboltSQLFeatureNotSupportedException("Only TRANSACTION_REPEATABLE_READ isolation level is supported"); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void commit() throws SQLException { | ||
| executeTransactionCommand("COMMIT"); | ||
| } | ||
|
|
||
| @Override | ||
| public void rollback() throws SQLException { | ||
| executeTransactionCommand("ROLLBACK"); | ||
| } | ||
|
|
||
| /** | ||
| * Ensures a transaction is started if auto-commit is disabled and no transaction is active. | ||
| * Called automatically before query execution. | ||
| * | ||
| * @throws SQLException if there's an error starting the transaction | ||
| */ | ||
| public void ensureTransactionForQueryExecution() throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
| if (sessionProperties.getTransactionId() == null) { | ||
| inTransaction = false; | ||
| } | ||
|
|
||
| if (executingTransactionCommand || autoCommit) { | ||
| return; | ||
| } | ||
|
|
||
| if (!inTransaction) { | ||
| executingTransactionCommand = true; | ||
| try (Statement statement = createStatement()) { | ||
| statement.execute("BEGIN TRANSACTION"); | ||
| inTransaction = true; | ||
|
Comment on lines
+275
to
+289
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Outside of the scope of this PR, but is this thread-safe? Can there be a case where connection is shared across threads and one of them starts a transaction, but we check before the transaction id is updated and so set the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good one, didn't think of it. To be safe I can move the rollback inside the synchronized block, but I don't think this should happen since only one thread should run the close and it should be after running all queries. Plus I don't think JDBC is assumed to be used with more than one thread and just one connection |
||
| } catch (SQLException ex) { | ||
| throw new FireboltException("Could not start transaction for query execution", ex); | ||
| } finally { | ||
| executingTransactionCommand = false; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void executeTransactionCommand(String sql) throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
| if (autoCommit) { | ||
| throw new FireboltException(String.format("Cannot %s when auto-commit is enabled", sql.toLowerCase())); | ||
| } | ||
| if (!inTransaction) { | ||
| throw new FireboltException("No transaction is currently active"); | ||
| } | ||
| executingTransactionCommand = true; | ||
| try (Statement statement = createStatement()) { | ||
| statement.execute(sql); | ||
| inTransaction = false; | ||
| } catch (SQLException ex) { | ||
| throw new FireboltException(String.format("Could not %s the transaction", sql.toLowerCase()), ex); | ||
| } finally { | ||
| executingTransactionCommand = false; | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isClosed() { | ||
|
|
@@ -266,19 +349,6 @@ public String getEngine() { | |
| return getSessionProperties().getEngine(); | ||
| } | ||
|
|
||
| @Override | ||
| public int getTransactionIsolation() throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
| return Connection.TRANSACTION_NONE; | ||
| } | ||
|
|
||
| @Override | ||
| public void setTransactionIsolation(int level) throws SQLException { | ||
| if (level != Connection.TRANSACTION_NONE) { | ||
| throw new FireboltSQLFeatureNotSupportedException(); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
|
|
@@ -317,6 +387,13 @@ public void close() { | |
| if (isClosed()) { | ||
| return; | ||
| } else { | ||
| if (inTransaction) { | ||
| try { | ||
| rollback(); | ||
| } catch (SQLException e) { | ||
| log.error("Exception encountered while rolling back transaction on close"); | ||
| } | ||
| } | ||
| closed = true; | ||
| } | ||
| } | ||
|
|
@@ -525,20 +602,6 @@ public String getEndpoint() { | |
| return httpConnectionUrl; | ||
| } | ||
|
|
||
| public void ensureTransactionForQueryExecution() throws SQLException {} | ||
|
|
||
| @Override | ||
| @NotImplemented | ||
| public void commit() throws SQLException { | ||
| // no-op as transactions are not supported | ||
| } | ||
|
|
||
| @Override | ||
| @NotImplemented | ||
| public void rollback() throws SQLException { | ||
| // no-op as transactions are not supported | ||
| } | ||
|
|
||
| @Override | ||
| public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { | ||
| validateConnectionIsNotClose(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.