Skip to content

Allow enabling autoCommit without an active transaction #3477

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

Merged
merged 3 commits into from
Jul 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ message TransactionalRequest {
InsertRequest insertRequest = 2;
CommitRequest commitRequest = 3;
RollbackRequest rollbackRequest = 4;
EnableAutoCommitRequest enableAutoCommitRequest = 5;
}
}

Expand All @@ -130,7 +131,10 @@ message TransactionalResponse {
InsertResponse insertResponse = 2;
CommitResponse commitResponse = 3;
RollbackResponse rollbackResponse = 4;

google.protobuf.Any errorResponse = 5;

EnableAutoCommitResponse enableAutoCommitResponse = 6;
}
}

Expand Down Expand Up @@ -162,6 +166,12 @@ message RollbackRequest {
message RollbackResponse {
}

message EnableAutoCommitRequest {
}

message EnableAutoCommitResponse {
}

message DatabaseMetaDataRequest {}
message DatabaseMetaDataResponse {
string url = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.apple.foundationdb.relational.jdbc.grpc.GrpcSQLExceptionUtil;
import com.apple.foundationdb.relational.jdbc.grpc.v1.CommitRequest;
import com.apple.foundationdb.relational.jdbc.grpc.v1.DatabaseMetaDataRequest;
import com.apple.foundationdb.relational.jdbc.grpc.v1.EnableAutoCommitRequest;
import com.apple.foundationdb.relational.jdbc.grpc.v1.InsertRequest;
import com.apple.foundationdb.relational.jdbc.grpc.v1.InsertResponse;
import com.apple.foundationdb.relational.jdbc.grpc.v1.JDBCServiceGrpc;
Expand Down Expand Up @@ -345,7 +346,23 @@ public void setAutoCommit(boolean autoCommit) throws SQLException {
this.autoCommit = false;
} else {
// commit any remaining work
commit();
try {
TransactionalRequest.Builder transactionRequest = TransactionalRequest.newBuilder()
.setEnableAutoCommitRequest(EnableAutoCommitRequest.newBuilder().build());
// wait here for response
final TransactionalResponse response = serverConnection.sendRequest(transactionRequest.build());
checkForResponseError(response);
if (!response.hasEnableAutoCommitResponse()) {
throw new JdbcConnectionException("Wrong kind of response received, expected EnableAutoCommitResponse");
}
} catch (StatusRuntimeException statusRuntimeException) {
final SQLException sqlException = toSQLException(statusRuntimeException);
if (sqlException != null) {
throw sqlException;
} else {
throw statusRuntimeException;
}
}
this.autoCommit = true;
serverConnection.close();
serverConnection = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void tearDown() throws Exception {
* Run a test with the default (auto-commit on) for sanity.
*/
@Test
void autoCommitOn() throws SQLException, IOException {
void autoCommitOn() throws SQLException {
try (RelationalConnection connection = DriverManager.getConnection(getTestDbUri()).unwrap(RelationalConnection.class)) {
try (RelationalStatement statement = connection.createStatement()) {
insertOneRow(statement);
Expand All @@ -80,6 +80,69 @@ void autoCommitOn() throws SQLException, IOException {
}
}

@Test
void autoCommitWithNoTransactionInBetween() throws SQLException {
try (RelationalConnection connection = DriverManager.getConnection(getTestDbUri()).unwrap(RelationalConnection.class)) {
connection.setAutoCommit(false);
connection.setAutoCommit(true);
}
}

@Test
void autoCommitStayOn() throws SQLException {
try (RelationalConnection connection = DriverManager.getConnection(getTestDbUri()).unwrap(RelationalConnection.class)) {
connection.setAutoCommit(true);
}
}

@Test
void autoCommitStayOff() throws SQLException {
try (RelationalConnection connection = DriverManager.getConnection(getTestDbUri()).unwrap(RelationalConnection.class)) {
connection.setAutoCommit(false);
connection.setAutoCommit(false);
}
}

@Test
void commitEnableAutoCommit() throws SQLException {
try (RelationalConnection connection = DriverManager.getConnection(getTestDbUri()).unwrap(RelationalConnection.class)) {
connection.setAutoCommit(false);

try (RelationalStatement statement = connection.createStatement()) {
insertOneRow(statement);
}
connection.commit();
connection.setAutoCommit(true);
try (RelationalStatement statement = connection.createStatement()) {
insertOneRow(statement, 101);
}
try (RelationalStatement statement = connection.createStatement()) {
RelationalResultSet resultSet = statement.executeQuery("SELECT * FROM test_table");
assertNextResult(resultSet, 100, "one hundred");
assertNextResult(resultSet, 101, "one hundred");
assertNoNextResult(resultSet);
}
}
}

@Test
void rollbackThenEnableAutoCommit() throws SQLException {
try (RelationalConnection connection = DriverManager.getConnection(getTestDbUri()).unwrap(RelationalConnection.class)) {
connection.setAutoCommit(false);

try (RelationalStatement statement = connection.createStatement()) {
insertOneRow(statement);
}
connection.rollback();
connection.setAutoCommit(true);
try (RelationalStatement statement = connection.createStatement()) {
RelationalResultSet resultSet = statement.executeQuery("SELECT * FROM test_table");
assertNoNextResult(resultSet);
assertNoNextResult(resultSet);
}
}
}

/**
* Run a test with commit and then read.
*/
Expand Down Expand Up @@ -148,7 +211,7 @@ void revertToAutoCommitOn() throws Exception {

try (RelationalStatement statement = connection.createStatement()) {
insertOneRow(statement);
connection.setAutoCommit(true);
connection.setAutoCommit(true); // this should commit

RelationalResultSet resultSet = statement.executeQuery("SELECT * FROM test_table");
assertNextResult(resultSet, 100, "one hundred");
Expand Down Expand Up @@ -323,8 +386,12 @@ protected String getHostPort() {
}

private static void insertOneRow(final RelationalStatement statement) throws SQLException {
insertOneRow(statement, 100);
}

private static void insertOneRow(final RelationalStatement statement, int restNo) throws SQLException {
RelationalStruct insert = JDBCRelationalStruct.newBuilder()
.addLong("REST_NO", 100)
.addLong("REST_NO", restNo)
.addString("NAME", "one hundred")
.build();
int res = statement.executeInsert("TEST_TABLE", insert);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ public void transactionalRollback(TransactionalToken token) throws SQLException
token.getConnection().rollback();
}

public void enableAutoCommit(TransactionalToken token) throws SQLException {
assertValidToken(token);
token.getConnection().setAutoCommit(true);
}

public void transactionalClose(TransactionalToken token) throws SQLException {
if (token != null && !token.expired()) {
token.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.apple.foundationdb.relational.jdbc.TypeConversion;
import com.apple.foundationdb.relational.jdbc.grpc.GrpcSQLExceptionUtil;
import com.apple.foundationdb.relational.jdbc.grpc.v1.CommitResponse;
import com.apple.foundationdb.relational.jdbc.grpc.v1.EnableAutoCommitResponse;
import com.apple.foundationdb.relational.jdbc.grpc.v1.InsertRequest;
import com.apple.foundationdb.relational.jdbc.grpc.v1.InsertResponse;
import com.apple.foundationdb.relational.jdbc.grpc.v1.RollbackResponse;
Expand Down Expand Up @@ -110,8 +111,16 @@ public void onNext(final TransactionalRequest transactionRequest) {
logger.info("Handling rollback request");
frl.transactionalRollback(transactionalToken);
responseBuilder.setRollbackResponse(RollbackResponse.newBuilder().build());
} else if (transactionRequest.hasEnableAutoCommitRequest()) {
logger.info("Enabling autoCommit");
// we don't actually call setAutoCommit(false) until an operation happens, so if there is no token
// there's no connection that needs updating
if (transactionalToken != null) {
frl.enableAutoCommit(transactionalToken);
}
responseBuilder.setEnableAutoCommitResponse(EnableAutoCommitResponse.newBuilder().build());
} else {
throw new IllegalArgumentException("Unknown transactional request type in" + transactionRequest);
throw new IllegalArgumentException("Unknown transactional request type: " + transactionRequest);
}
responseObserver.onNext(responseBuilder.build());
} catch (SQLException e) {
Expand Down