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

feat: call java_client:execute from executeUpdate #896

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner-bom</artifactId>
<version>6.25.5</version>
<version>6.26.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down Expand Up @@ -114,6 +114,7 @@
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner</artifactId>
<version>6.26.0</version>
</dependency>
<!-- TODO: Remove grpc-alts from here once it has been removed as a runtime dependency from java-spanner -->
<dependency>
Expand Down Expand Up @@ -155,6 +156,7 @@
<dependency>
<groupId>com.google.api.grpc</groupId>
<artifactId>proto-google-cloud-spanner-v1</artifactId>
<version>6.26.0</version>
</dependency>

<!-- Test dependencies -->
Expand All @@ -163,6 +165,7 @@
<artifactId>google-cloud-spanner</artifactId>
<type>test-jar</type>
<scope>test</scope>
<version>6.26.0</version>
</dependency>
<dependency>
<groupId>com.google.truth</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/** Base class for Cloud Spanner JDBC {@link Statement}s */
Expand Down Expand Up @@ -228,13 +229,10 @@ int executeUpdate(com.google.cloud.spanner.Statement statement) throws SQLExcept
* @throws SQLException if a database error occurs
*/
long executeLargeUpdate(com.google.cloud.spanner.Statement statement) throws SQLException {
StatementTimeout originalTimeout = setTemporaryStatementTimeout();
try {
return connection.getSpannerConnection().executeUpdate(statement);
return getConnection().getSpannerConnection().executeUpdate(statement);
} catch (SpannerException e) {
throw JdbcSqlExceptionFactory.of(e);
} finally {
resetStatementTimeout(originalTimeout);
throw JdbcSqlExceptionFactory.of(e.getMessage(), Code.forNumber(e.getCode()));
}
}

Expand Down
17 changes: 5 additions & 12 deletions src/main/java/com/google/cloud/spanner/jdbc/JdbcStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/** Implementation of {@link java.sql.Statement} for Google Cloud Spanner. */
class JdbcStatement extends AbstractJdbcStatement {
Expand Down Expand Up @@ -83,18 +84,10 @@ public int executeUpdate(String sql) throws SQLException {
public long executeLargeUpdate(String sql) throws SQLException {
checkClosed();
Statement statement = Statement.of(sql);
StatementResult result = execute(statement);
switch (result.getResultType()) {
case RESULT_SET:
throw JdbcSqlExceptionFactory.of(
"The statement is not an update or DDL statement", Code.INVALID_ARGUMENT);
case UPDATE_COUNT:
return result.getUpdateCount();
case NO_RESULT:
return 0L;
default:
throw JdbcSqlExceptionFactory.of(
"unknown result: " + result.getResultType(), Code.FAILED_PRECONDITION);
try {
return getConnection().getSpannerConnection().executeUpdate(statement);
} catch (SpannerException e) {
throw JdbcSqlExceptionFactory.of(e.getMessage(), Code.forNumber(e.getCode()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.google.protobuf.ListValue;
import com.google.protobuf.Value;
import com.google.spanner.v1.ResultSetMetadata;
import com.google.spanner.v1.ResultSetStats;
import com.google.spanner.v1.StructType;
import com.google.spanner.v1.StructType.Field;
import com.google.spanner.v1.Type;
Expand All @@ -49,8 +50,10 @@
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -93,10 +96,15 @@ public void retryFinished(
.build())
.setMetadata(SELECT1_METADATA)
.build();
private static final int UPDATE_COUNT = 1;
private static final com.google.spanner.v1.ResultSet UPDATE1_RESULTSET =
com.google.spanner.v1.ResultSet.newBuilder()
.setStats(ResultSetStats.newBuilder().setRowCountExact(UPDATE_COUNT))
.setMetadata(ResultSetMetadata.getDefaultInstance().toBuilder().setRowType(StructType.getDefaultInstance()))
.build();
private static final Statement SELECT_RANDOM = Statement.of("SELECT * FROM RANDOM");
private static final Statement UPDATE_STATEMENT =
Statement.of("UPDATE FOO SET BAR=1 WHERE BAZ=2");
private static final int UPDATE_COUNT = 1;

private static MockSpannerServiceImpl mockSpanner;
private static Server server;
Expand All @@ -116,7 +124,7 @@ public static void startStaticServer() throws IOException {
mockSpanner = new MockSpannerServiceImpl();
mockSpanner.setAbortProbability(0.0D); // We don't want any unpredictable aborted transactions.
mockSpanner.putStatementResult(StatementResult.query(SELECT1, SELECT1_RESULTSET));
mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT));
mockSpanner.putStatementResult(StatementResult.query(UPDATE_STATEMENT, UPDATE1_RESULTSET));
MockInstanceAdminImpl mockInstanceAdmin = new MockInstanceAdminImpl();
MockDatabaseAdminImpl mockDatabaseAdmin = new MockDatabaseAdminImpl();
InetSocketAddress address = new InetSocketAddress("localhost", 0);
Expand All @@ -129,6 +137,12 @@ public static void startStaticServer() throws IOException {
.start();
}

@Before
public void setupMockSpannerResults() {
mockSpanner.putStatementResult(StatementResult.query(SELECT1, SELECT1_RESULTSET));
mockSpanner.putStatementResult(StatementResult.query(UPDATE_STATEMENT, UPDATE1_RESULTSET));
}

@AfterClass
public static void stopServer() throws Exception {
SpannerPool.closeSpannerPool();
Expand Down Expand Up @@ -192,6 +206,8 @@ public void testTransactionalUpdateAborted() throws SQLException {
public void testAutocommitBatchUpdateAborted() throws SQLException {
try (java.sql.Connection connection = createConnection()) {
mockSpanner.abortNextStatement();
mockSpanner.putStatementResult(
MockSpannerServiceImpl.StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT));
try (java.sql.Statement statement = connection.createStatement()) {
statement.addBatch(UPDATE_STATEMENT.getSql());
statement.addBatch(UPDATE_STATEMENT.getSql());
Expand All @@ -206,6 +222,8 @@ public void testTransactionalBatchUpdateAborted() throws SQLException {
try (java.sql.Connection connection = createConnection()) {
connection.setAutoCommit(false);
mockSpanner.abortNextStatement();
mockSpanner.putStatementResult(
MockSpannerServiceImpl.StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT));
try (java.sql.Statement statement = connection.createStatement()) {
statement.addBatch(UPDATE_STATEMENT.getSql());
statement.addBatch(UPDATE_STATEMENT.getSql());
Expand Down Expand Up @@ -317,7 +335,7 @@ public void testTransactionalUpdateWithErrorOnRetryAndNotOnOriginal() throws SQL
try (java.sql.Connection connection = createConnection()) {
connection.setAutoCommit(false);
// Set a normal response to the update statement.
mockSpanner.putStatementResult(StatementResult.update(Statement.of(sql), 1L));
mockSpanner.putStatementResult(StatementResult.query(Statement.of(sql), UPDATE1_RESULTSET));
connection.createStatement().executeUpdate(sql);
// Set an error as response for the same update statement that will be used during the retry.
// This will cause the retry to fail.
Expand All @@ -332,7 +350,7 @@ public void testTransactionalUpdateWithErrorOnRetryAndNotOnOriginal() throws SQL
assertThat(retryAbortsInternally).isTrue();
assertThat(e.getDatabaseErrorDuringRetry().getErrorCode())
.isEqualTo(ErrorCode.INVALID_ARGUMENT);
assertThat(e.getDatabaseErrorDuringRetry().getMessage()).endsWith("test");
assertThat(e.getDatabaseErrorDuringRetry().getMessage()).contains("test");
} catch (JdbcAbortedException e) {
assertThat(retryAbortsInternally).isFalse();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,26 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;

import com.google.cloud.spanner.MockSpannerServiceImpl;
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
import com.google.cloud.spanner.admin.database.v1.MockDatabaseAdminImpl;
import com.google.cloud.spanner.admin.instance.v1.MockInstanceAdminImpl;
import com.google.cloud.spanner.connection.AbstractMockServerTest;
import com.google.common.util.concurrent.AbstractFuture;
import com.google.longrunning.GetOperationRequest;
import com.google.longrunning.Operation;
import com.google.longrunning.OperationsGrpc.OperationsImplBase;
import com.google.protobuf.Any;
import com.google.protobuf.Empty;
import com.google.spanner.v1.BatchCreateSessionsRequest;
import com.google.spanner.v1.ResultSetMetadata;
import com.google.spanner.v1.ResultSetStats;
import com.google.spanner.v1.StructType;
import io.grpc.internal.LogExceptionRunnable;
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.CountDownLatch;
Expand All @@ -30,7 +48,9 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -61,6 +81,16 @@ public void testMinSessions() throws InterruptedException, TimeoutException, SQL
}

public static class ConnectionMaxSessionsTest extends AbstractMockServerTest {
private static final com.google.spanner.v1.ResultSet UPDATE1_RESULTSET =
com.google.spanner.v1.ResultSet.newBuilder()
.setStats(ResultSetStats.newBuilder().setRowCountExact(1))
.setMetadata(ResultSetMetadata.getDefaultInstance().toBuilder().setRowType(StructType.getDefaultInstance()))
.build();

@BeforeClass
public static void setMockSpanner() {
mockSpanner.putStatementResult(StatementResult.query(INSERT_STATEMENT, UPDATE1_RESULTSET));
}

@AfterClass
public static void reset() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.google.protobuf.Value;
import com.google.rpc.Code;
import com.google.spanner.v1.ResultSetMetadata;
import com.google.spanner.v1.ResultSetStats;
import com.google.spanner.v1.StructType;
import com.google.spanner.v1.StructType.Field;
import com.google.spanner.v1.Type;
Expand All @@ -47,6 +48,7 @@
import java.sql.SQLException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -75,6 +77,11 @@ public class JdbcGrpcErrorTest {
.build())
.setMetadata(SELECT1_METADATA)
.build();
private static final com.google.spanner.v1.ResultSet UPDATE1_RESULTSET =
com.google.spanner.v1.ResultSet.newBuilder()
.setStats(ResultSetStats.newBuilder().setRowCountExact(1))
.setMetadata(ResultSetMetadata.getDefaultInstance().toBuilder().setRowType(StructType.getDefaultInstance()))
.build();
private static final Statement UPDATE_STATEMENT =
Statement.of("UPDATE FOO SET BAR=1 WHERE BAZ=2");
private static final int UPDATE_COUNT = 1;
Expand Down Expand Up @@ -119,6 +126,16 @@ public static void stopServer() throws Exception {
server.awaitTermination();
}

@Before
public void setupMockSpannerResults() {
mockSpanner.putStatementResult(StatementResult.query(SELECT1, SELECT1_RESULTSET));
mockSpanner.putStatementResult(StatementResult.query(UPDATE_STATEMENT, UPDATE1_RESULTSET));
mockSpanner.putStatementResult(
StatementResult.exception(
INVALID_UPDATE_STATEMENT,
Status.NOT_FOUND.withDescription("Unknown table name").asRuntimeException()));
}

@After
public void reset() {
// Close Spanner pool to prevent reusage of the same Spanner instance (and thereby the same
Expand Down Expand Up @@ -171,6 +188,8 @@ public void autocommitBeginPDMLTransaction() {
SimulatedExecutionTime.ofException(serverException));
try (java.sql.Connection connection = createConnection()) {
connection.createStatement().execute("SET AUTOCOMMIT_DML_MODE='PARTITIONED_NON_ATOMIC'");
mockSpanner.putStatementResult(
MockSpannerServiceImpl.StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT));
connection.createStatement().executeUpdate(UPDATE_STATEMENT.getSql());
fail("missing expected exception");
} catch (SQLException e) {
Expand Down Expand Up @@ -209,7 +228,7 @@ public void readOnlyBeginTransaction() {

@Test
public void autocommitExecuteSql() {
mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofException(serverException));
mockSpanner.setExecuteStreamingSqlExecutionTime(SimulatedExecutionTime.ofException(serverException));
try (java.sql.Connection connection = createConnection()) {
connection.createStatement().executeUpdate(UPDATE_STATEMENT.getSql());
fail("missing expected exception");
Expand All @@ -233,13 +252,14 @@ public void autocommitPDMLExecuteSql() throws SQLException {
connection.createStatement().executeUpdate(UPDATE_STATEMENT.getSql());
fail("missing expected exception");
} catch (SQLException e) {
System.out.println(e.getMessage());
assertThat(testExceptionMatcher.matches(e)).isTrue();
}
}

@Test
public void transactionalExecuteSql() {
mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofException(serverException));
mockSpanner.setExecuteStreamingSqlExecutionTime(SimulatedExecutionTime.ofException(serverException));
try (java.sql.Connection connection = createConnection()) {
connection.setAutoCommit(false);
connection.createStatement().executeUpdate(UPDATE_STATEMENT.getSql());
Expand Down Expand Up @@ -284,6 +304,7 @@ public void transactionalExecuteBatchDml() throws SQLException {

@Test
public void autocommitCommit() {
mockSpanner.putStatementResult(StatementResult.query(UPDATE_STATEMENT, UPDATE1_RESULTSET));
mockSpanner.setCommitExecutionTime(SimulatedExecutionTime.ofException(serverException));
try (java.sql.Connection connection = createConnection()) {
connection.createStatement().executeUpdate(UPDATE_STATEMENT.getSql());
Expand Down Expand Up @@ -325,6 +346,7 @@ public void autocommitRollback() {

@Test
public void transactionalRollback() throws SQLException {
mockSpanner.putStatementResult(StatementResult.query(UPDATE_STATEMENT, UPDATE1_RESULTSET));
// Rollback exceptions are ignored by the client library and not propagated to the JDBC driver.
// This method will therefore not throw any errors.
mockSpanner.setRollbackExecutionTime(SimulatedExecutionTime.ofException(serverException));
Expand Down