From 10ee6202652dd09d14359f6c10f5ff1c26e17dd2 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Fri, 9 Jun 2023 13:49:27 +0000 Subject: [PATCH 01/16] feat: add support for Proto Columns to Connection API --- .../ClientSideStatementValueConverters.java | 54 +++++++++++++++++++ .../cloud/spanner/connection/Connection.java | 20 +++++++ .../spanner/connection/ConnectionImpl.java | 33 +++++++++++- .../ConnectionStatementExecutor.java | 4 ++ .../ConnectionStatementExecutorImpl.java | 16 ++++++ .../cloud/spanner/connection/DdlBatch.java | 10 +++- .../cloud/spanner/connection/DdlClient.java | 27 ++++++++-- .../connection/SingleUseTransaction.java | 10 +++- .../spanner/connection/StatementResult.java | 4 +- .../connection/StatementResultImpl.java | 18 +++++++ 10 files changed, 187 insertions(+), 9 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java index a7752ab6671..b8877e49bb4 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner.connection; +import com.google.cloud.ByteArray; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Options.RpcPriority; import com.google.cloud.spanner.SpannerExceptionFactory; @@ -28,6 +29,11 @@ import com.google.protobuf.Duration; import com.google.protobuf.util.Durations; import com.google.spanner.v1.RequestOptions.Priority; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Base64; import java.util.EnumSet; import java.util.HashMap; import java.util.Locale; @@ -494,4 +500,52 @@ public String convert(String value) { return value.substring(7).trim(); } } + + /** Converter for converting strings to byte[] */ + static class ProtoDescriptorsConverter implements ClientSideStatementValueConverter { + + public ProtoDescriptorsConverter(String allowedValues) {} + + @Override + public Class getParameterClass() { + return byte[].class; + } + + @Override + public byte[] convert(String value) { + if (value.length() == 0 || value.equalsIgnoreCase("null")) { + return null; + } + return Base64.getDecoder().decode(value); + } + } + + /** Converter for converting strings that take in file path as input to byte[] */ + static class ProtoDescriptorsFileConverter implements ClientSideStatementValueConverter { + + public ProtoDescriptorsFileConverter(String allowedValues) {} + + @Override + public Class getParameterClass() { + return byte[].class; + } + + @Override + public byte[] convert(String filePath) { + if (filePath != null && filePath.length() > 0) { + try { + File protoDescriptorsFile = new File(filePath); + if (!protoDescriptorsFile.isFile()) { + throw new IOException("File does not exist."); + } + InputStream pdStream = new FileInputStream(protoDescriptorsFile); + return ByteArray.copyFrom(pdStream).toByteArray(); + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, e.getMessage()); + } + } + return null; + } + } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java index d4624bfabbb..e864180420d 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java @@ -42,6 +42,7 @@ import java.util.Iterator; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import javax.annotation.Nonnull; /** * Internal connection API for Google Cloud Spanner. This interface may introduce breaking changes @@ -382,6 +383,25 @@ default String getStatementTag() { throw new UnsupportedOperationException(); } + /** + * Sets the proto descriptors to use for the next DDL statement (single or batch) that will be + * executed. The proto descriptor is automatically cleared after the statement is executed. + * + * @param protoDescriptors The proto descriptors to use with the next DDL statement (single or + * batch) that will be executed on this connection. + */ + default void setProtoDescriptors(@Nonnull byte[] protoDescriptors) { + throw new UnsupportedOperationException(); + } + + /** + * @return The proto descriptor that will be used with the next DDL statement (single or batch) + * that is executed on this connection. + */ + default byte[] getProtoDescriptors() { + throw new UnsupportedOperationException(); + } + /** * @return true if this connection will automatically retry read/write transactions * that abort. This method may only be called when the connection is in read/write diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java index b6e29dbdc0e..565692cd6be 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java @@ -63,6 +63,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import javax.annotation.Nonnull; import org.threeten.bp.Instant; /** Implementation for {@link Connection}, the generic Spanner connection API (not JDBC). */ @@ -85,7 +86,7 @@ private LeakedConnectionException() { } } - private volatile LeakedConnectionException leakedException;; + private volatile LeakedConnectionException leakedException; private final SpannerPool spannerPool; private AbstractStatementParser statementParser; /** @@ -221,6 +222,8 @@ static UnitOfWorkType of(TransactionMode transactionMode) { private String transactionTag; private String statementTag; + private byte[] protoDescriptors; + /** Create a connection and register it in the SpannerPool. */ ConnectionImpl(ConnectionOptions options) { Preconditions.checkNotNull(options); @@ -278,6 +281,7 @@ Spanner getSpanner() { private DdlClient createDdlClient() { return DdlClient.newBuilder() .setDatabaseAdminClient(spanner.getDatabaseAdminClient()) + .setProjectId(options.getProjectId()) .setInstanceId(options.getInstanceId()) .setDatabaseName(options.getDatabaseName()) .build(); @@ -623,6 +627,21 @@ public void setStatementTag(String tag) { this.statementTag = tag; } + @Override + public byte[] getProtoDescriptors() { + ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); + return protoDescriptors; + } + + @Override + public void setProtoDescriptors(@Nonnull byte[] protoDescriptors) { + Preconditions.checkNotNull(protoDescriptors); + ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); + ConnectionPreconditions.checkState( + !isBatchActive(), "Proto descriptors cannot be set when a batch is active"); + this.protoDescriptors = protoDescriptors; + } + /** * Throws an {@link SpannerException} with code {@link ErrorCode#FAILED_PRECONDITION} if the * current state of this connection does not allow changing the setting for retryAbortsInternally. @@ -1379,6 +1398,7 @@ UnitOfWork createNewUnitOfWork() { .setReturnCommitStats(returnCommitStats) .setStatementTimeout(statementTimeout) .withStatementExecutor(statementExecutor) + .setProtoDescriptors(protoDescriptors) .build(); } else { switch (getUnitOfWorkType()) { @@ -1421,6 +1441,7 @@ UnitOfWork createNewUnitOfWork() { .setDatabaseClient(dbClient) .setStatementTimeout(statementTimeout) .withStatementExecutor(statementExecutor) + .setProtoDescriptors(protoDescriptors) .build(); default: } @@ -1444,7 +1465,11 @@ private void popUnitOfWorkFromTransactionStack() { } private ApiFuture executeDdlAsync(CallType callType, ParsedStatement ddl) { - return getCurrentUnitOfWorkOrStartNewUnitOfWork().executeDdlAsync(callType, ddl); + ApiFuture result = + getCurrentUnitOfWorkOrStartNewUnitOfWork().executeDdlAsync(callType, ddl); + // reset proto descriptors after executing a DDL statement + this.protoDescriptors = null; + return result; } @Override @@ -1535,6 +1560,10 @@ public ApiFuture runBatchAsync() { } return ApiFutures.immediateFuture(new long[0]); } finally { + if (isDdlBatchActive()) { + // reset proto descriptors after executing a DDL batch + this.protoDescriptors = null; + } this.batchMode = BatchMode.NONE; setDefaultTransactionOptions(); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java index 718025e1652..a7b6e51c6c2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java @@ -124,5 +124,9 @@ StatementResult statementSetPgSessionCharacteristicsTransactionMode( StatementResult statementShowTransactionIsolationLevel(); + StatementResult statementSetProtoDescriptors(byte[] protoDescriptors); + + StatementResult statementShowProtoDescriptors(); + StatementResult statementExplain(String sql); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java index 4bda03367af..1d42c8a58a0 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java @@ -28,6 +28,7 @@ import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_OPTIMIZER_STATISTICS_PACKAGE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_OPTIMIZER_VERSION; +import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_PROTO_DESCRIPTORS; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_READONLY; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_READ_ONLY_STALENESS; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_RETRY_ABORTS_INTERNALLY; @@ -45,6 +46,7 @@ import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_OPTIMIZER_STATISTICS_PACKAGE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_OPTIMIZER_VERSION; +import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_PROTO_DESCRIPTORS; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_READONLY; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_READ_ONLY_STALENESS; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_READ_TIMESTAMP; @@ -493,6 +495,20 @@ public StatementResult statementShowTransactionIsolationLevel() { return resultSet("transaction_isolation", "serializable", SHOW_TRANSACTION_ISOLATION_LEVEL); } + @Override + public StatementResult statementSetProtoDescriptors(byte[] protoDescriptors) { + getConnection().setProtoDescriptors(protoDescriptors); + return noResult(SET_PROTO_DESCRIPTORS); + } + + @Override + public StatementResult statementShowProtoDescriptors() { + return resultSet( + String.format("%sPROTO_DESCRIPTORS", getNamespace(connection.getDialect())), + getConnection().getProtoDescriptors(), + SHOW_PROTO_DESCRIPTORS); + } + private String processQueryPlan(PlanNode planNode) { StringBuilder planNodeDescription = new StringBuilder(" : { "); com.google.protobuf.Struct metadata = planNode.getMetadata(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java index ebfd2bc4541..91ba90fdb12 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java @@ -58,10 +58,12 @@ class DdlBatch extends AbstractBaseUnitOfWork { private final DatabaseClient dbClient; private final List statements = new ArrayList<>(); private UnitOfWorkState state = UnitOfWorkState.STARTED; + private final byte[] protoDescriptors; static class Builder extends AbstractBaseUnitOfWork.Builder { private DdlClient ddlClient; private DatabaseClient dbClient; + private byte[] protoDescriptors; private Builder() {} @@ -77,6 +79,11 @@ Builder setDatabaseClient(DatabaseClient client) { return this; } + Builder setProtoDescriptors(byte[] protoDescriptors) { + this.protoDescriptors = protoDescriptors; + return this; + } + @Override DdlBatch build() { Preconditions.checkState(ddlClient != null, "No DdlClient specified"); @@ -93,6 +100,7 @@ private DdlBatch(Builder builder) { super(builder); this.ddlClient = builder.ddlClient; this.dbClient = builder.dbClient; + this.protoDescriptors = builder.protoDescriptors; } @Override @@ -239,7 +247,7 @@ public ApiFuture runBatchAsync(CallType callType) { () -> { try { OperationFuture operation = - ddlClient.executeDdl(statements); + ddlClient.executeDdl(statements, protoDescriptors); try { // Wait until the operation has finished. getWithStatementTimeout(operation, RUN_BATCH_STATEMENT); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlClient.java index fedf60d7a91..7bce1ab78cd 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlClient.java @@ -19,6 +19,7 @@ import com.google.api.gax.longrunning.OperationFuture; import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.DatabaseId; import com.google.cloud.spanner.Dialect; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.SpannerExceptionFactory; @@ -35,11 +36,13 @@ */ class DdlClient { private final DatabaseAdminClient dbAdminClient; + private final String projectId; private final String instanceId; private final String databaseName; static class Builder { private DatabaseAdminClient dbAdminClient; + private String projectId; private String instanceId; private String databaseName; @@ -51,6 +54,13 @@ Builder setDatabaseAdminClient(DatabaseAdminClient client) { return this; } + Builder setProjectId(String projectId) { + Preconditions.checkArgument( + !Strings.isNullOrEmpty(projectId), "Empty projectId is not allowed"); + this.projectId = projectId; + return this; + } + Builder setInstanceId(String instanceId) { Preconditions.checkArgument( !Strings.isNullOrEmpty(instanceId), "Empty instanceId is not allowed"); @@ -67,6 +77,7 @@ Builder setDatabaseName(String name) { DdlClient build() { Preconditions.checkState(dbAdminClient != null, "No DatabaseAdminClient specified"); + Preconditions.checkState(!Strings.isNullOrEmpty(projectId), "No ProjectId specified"); Preconditions.checkState(!Strings.isNullOrEmpty(instanceId), "No InstanceId specified"); Preconditions.checkArgument( !Strings.isNullOrEmpty(databaseName), "No database name specified"); @@ -80,6 +91,7 @@ static Builder newBuilder() { private DdlClient(Builder builder) { this.dbAdminClient = builder.dbAdminClient; + this.projectId = builder.projectId; this.instanceId = builder.instanceId; this.databaseName = builder.databaseName; } @@ -92,17 +104,24 @@ OperationFuture executeCreateDatabase( } /** Execute a single DDL statement. */ - OperationFuture executeDdl(String ddl) { - return executeDdl(Collections.singletonList(ddl)); + OperationFuture executeDdl(String ddl, byte[] protoDescriptors) { + return executeDdl(Collections.singletonList(ddl), protoDescriptors); } /** Execute a list of DDL statements as one operation. */ - OperationFuture executeDdl(List statements) { + OperationFuture executeDdl( + List statements, byte[] protoDescriptors) { if (statements.stream().anyMatch(DdlClient::isCreateDatabaseStatement)) { throw SpannerExceptionFactory.newSpannerException( ErrorCode.INVALID_ARGUMENT, "CREATE DATABASE is not supported in a DDL batch"); } - return dbAdminClient.updateDatabaseDdl(instanceId, databaseName, statements, null); + Database.Builder dbBuilder = + dbAdminClient.newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseName)); + if (protoDescriptors != null) { + dbBuilder.setProtoDescriptors(protoDescriptors); + } + Database db = dbBuilder.build(); + return dbAdminClient.updateDatabaseDdl(db, statements, null); } /** Returns true if the statement is a `CREATE DATABASE ...` statement. */ diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java index 0e3dfe02efb..dfac432f4db 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java @@ -73,6 +73,7 @@ class SingleUseTransaction extends AbstractBaseUnitOfWork { private final TimestampBound readOnlyStaleness; private final AutocommitDmlMode autocommitDmlMode; private final boolean returnCommitStats; + private final byte[] protoDescriptors; private volatile SettableApiFuture readTimestamp = null; private volatile TransactionRunner writeTransaction; private boolean used = false; @@ -85,6 +86,7 @@ static class Builder extends AbstractBaseUnitOfWork.Builder executeDdlAsync(CallType callType, final ParsedStatement ddlClient.executeCreateDatabase( ddl.getSqlWithoutComments(), dbClient.getDialect()); } else { - operation = ddlClient.executeDdl(ddl.getSqlWithoutComments()); + operation = ddlClient.executeDdl(ddl.getSqlWithoutComments(), protoDescriptors); } getWithStatementTimeout(operation, ddl); state = UnitOfWorkState.COMMITTED; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java index f4e9237e090..4bd4098e48d 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java @@ -89,7 +89,9 @@ enum ClientSideStatementType { SHOW_TRANSACTION_ISOLATION_LEVEL, SHOW_SAVEPOINT_SUPPORT, SET_SAVEPOINT_SUPPORT, - EXPLAIN + EXPLAIN, + SET_PROTO_DESCRIPTORS, + SHOW_PROTO_DESCRIPTORS } /** diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResultImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResultImpl.java index 58a1f7ae1c0..ee5032463cd 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResultImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResultImpl.java @@ -18,6 +18,7 @@ import static com.google.cloud.spanner.SpannerApiFutures.get; +import com.google.cloud.ByteArray; import com.google.cloud.Timestamp; import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.ResultSets; @@ -147,6 +148,23 @@ static StatementResult resultSet( clientSideStatementType); } + /** + * Convenience method for creating a {@link StatementResult} containing a {@link ResultSet} with + * one BYTES column and one row that is created by a {@link ClientSideStatement}. + */ + static StatementResult resultSet( + String name, byte[] values, ClientSideStatementType clientSideStatementType) { + return of( + ResultSets.forRows( + Type.struct(StructField.of(name, Type.bytes())), + Collections.singletonList( + Struct.newBuilder() + .set(name) + .to(values != null ? ByteArray.copyFrom(values) : null) + .build())), + clientSideStatementType); + } + /** {@link StatementResult} containing no results. */ static StatementResult noResult() { return new StatementResultImpl((ClientSideStatementType) null); From 7feaf106bd34f2218f06a9e634243a09521b9bf5 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Fri, 9 Jun 2023 13:51:03 +0000 Subject: [PATCH 02/16] feat: add client side statement support for proto descriptor --- .../connection/ClientSideStatements.json | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json index 0f58ee951af..8fe70e511b2 100644 --- a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json +++ b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json @@ -474,6 +474,45 @@ "allowedValues": "(TRUE|FALSE)", "converterName": "ClientSideStatementValueConverters$BooleanConverter" } + }, + { + "name": "SET PROTO_DESCRIPTORS = ''", + "executorName": "ClientSideStatementSetExecutor", + "resultType": "NO_RESULT", + "statementType": "SET_PROTO_DESCRIPTORS", + "regex": "(?is)\\A\\s*set\\s+proto_descriptors\\s*(?:=)\\s*(.*)\\z", + "method": "statementSetProtoDescriptors", + "exampleStatements": ["set proto_descriptors='tag1'", "set proto_descriptors='tag2'", "set proto_descriptors=''"], + "setStatement": { + "propertyName": "PROTO_DESCRIPTORS", + "separator": "=", + "allowedValues": "'((\\S+)|())'", + "converterName": "ClientSideStatementValueConverters$ProtoDescriptorsConverter" + } + }, + { + "name": "SHOW VARIABLE PROTO_DESCRIPTORS", + "executorName": "ClientSideStatementNoParamExecutor", + "resultType": "RESULT_SET", + "statementType": "SHOW_PROTO_DESCRIPTORS", + "regex": "(?is)\\A\\s*show\\s+variable\\s+proto_descriptors\\s*\\z", + "method": "statementShowProtoDescriptors", + "exampleStatements": ["show variable proto_descriptors"] + }, + { + "name": "SET PROTO_DESCRIPTORS FILE_PATH = ''", + "executorName": "ClientSideStatementSetExecutor", + "resultType": "NO_RESULT", + "statementType": "SET_PROTO_DESCRIPTORS_FILE_PATH", + "regex": "(?is)\\A\\s*set\\s+proto_descriptors\\s+file_path\\s*(?:=)\\s*(.*)\\z", + "method": "statementSetProtoDescriptors", + "exampleStatements": ["set proto_descriptors file_path='tag1'", "set proto_descriptors='tag2'", "set proto_descriptors=''"], + "setStatement": { + "propertyName": "PROTO_DESCRIPTORS FILE_PATH", + "separator": "=", + "allowedValues": "'((\\S+)|())'", + "converterName": "ClientSideStatementValueConverters$ProtoDescriptorsFileConverter" + } } ] } From 02a31b6a0d49c849f4b0cf496f3751c12329aa6d Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Sat, 10 Jun 2023 07:21:19 +0000 Subject: [PATCH 03/16] feat: update existing unit tests to include proto descriptorss argument --- .../connection/ConnectionImplTest.java | 5 ++- .../spanner/connection/DdlBatchTest.java | 38 ++++++++++--------- .../connection/SingleUseTransactionTest.java | 9 +++-- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java index cd72da4cd3f..a134c4885ed 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyList; import static org.mockito.Mockito.anyString; @@ -213,8 +214,8 @@ private static DdlClient createDefaultMockDdlClient() { UpdateDatabaseDdlMetadata metadata = UpdateDatabaseDdlMetadata.getDefaultInstance(); ApiFuture futureMetadata = ApiFutures.immediateFuture(metadata); when(operation.getMetadata()).thenReturn(futureMetadata); - when(ddlClient.executeDdl(anyString())).thenCallRealMethod(); - when(ddlClient.executeDdl(anyList())).thenReturn(operation); + when(ddlClient.executeDdl(anyString(), isNull())).thenCallRealMethod(); + when(ddlClient.executeDdl(anyList(), isNull())).thenReturn(operation); return ddlClient; } catch (Exception e) { throw new RuntimeException(e); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java index 699ab23f3a4..039bebbfd1e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.anyList; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.argThat; @@ -110,8 +111,8 @@ private DdlClient createDefaultMockDdlClient( ApiFuture metadataFuture = ApiFutures.immediateFuture(metadataBuilder.build()); when(operation.getMetadata()).thenReturn(metadataFuture); - when(ddlClient.executeDdl(anyString())).thenReturn(operation); - when(ddlClient.executeDdl(anyList())).thenReturn(operation); + when(ddlClient.executeDdl(anyString(), isNull())).thenReturn(operation); + when(ddlClient.executeDdl(anyList(), isNull())).thenReturn(operation); return ddlClient; } catch (Exception e) { throw new RuntimeException(e); @@ -273,7 +274,7 @@ public void testGetStateAndIsActive() { DdlClient client = mock(DdlClient.class); SpannerException exception = mock(SpannerException.class); when(exception.getErrorCode()).thenReturn(ErrorCode.FAILED_PRECONDITION); - doThrow(exception).when(client).executeDdl(anyList()); + doThrow(exception).when(client).executeDdl(anyList(), isNull()); batch = createSubject(client); assertThat(batch.getState(), is(UnitOfWorkState.STARTED)); assertThat(batch.isActive(), is(true)); @@ -319,8 +320,8 @@ public void testRunBatch() { DdlBatch batch = createSubject(client); get(batch.runBatchAsync(CallType.SYNC)); assertThat(batch.getState(), is(UnitOfWorkState.RAN)); - verify(client, never()).executeDdl(anyString()); - verify(client, never()).executeDdl(argThat(isEmptyListOfStrings())); + verify(client, never()).executeDdl(anyString(), isNull()); + verify(client, never()).executeDdl(argThat(isEmptyListOfStrings()), isNull()); ParsedStatement statement = mock(ParsedStatement.class); when(statement.getType()).thenReturn(StatementType.DDL); @@ -331,14 +332,14 @@ public void testRunBatch() { batch = createSubject(client); batch.executeDdlAsync(CallType.SYNC, statement); get(batch.runBatchAsync(CallType.SYNC)); - verify(client).executeDdl(argThat(isListOfStringsWithSize(1))); + verify(client).executeDdl(argThat(isListOfStringsWithSize(1)), isNull()); client = createDefaultMockDdlClient(); batch = createSubject(client); batch.executeDdlAsync(CallType.SYNC, statement); batch.executeDdlAsync(CallType.SYNC, statement); get(batch.runBatchAsync(CallType.SYNC)); - verify(client).executeDdl(argThat(isListOfStringsWithSize(2))); + verify(client).executeDdl(argThat(isListOfStringsWithSize(2)), isNull()); assertThat(batch.getState(), is(UnitOfWorkState.RAN)); boolean exception = false; try { @@ -384,7 +385,7 @@ public void testRunBatch() { } assertThat(exception, is(true)); assertThat(batch.getState(), is(UnitOfWorkState.RUN_FAILED)); - verify(client).executeDdl(argThat(isListOfStringsWithSize(2))); + verify(client).executeDdl(argThat(isListOfStringsWithSize(2)), isNull()); } @Test @@ -403,7 +404,8 @@ public void testUpdateCount() throws InterruptedException, ExecutionException { OperationFuture operationFuture = mock(OperationFuture.class); when(operationFuture.get()).thenReturn(null); when(operationFuture.getMetadata()).thenReturn(metadataFuture); - when(client.executeDdl(argThat(isListOfStringsWithSize(2)))).thenReturn(operationFuture); + when(client.executeDdl(argThat(isListOfStringsWithSize(2)), isNull())) + .thenReturn(operationFuture); DdlBatch batch = DdlBatch.newBuilder() .withStatementExecutor(new StatementExecutor()) @@ -441,7 +443,8 @@ public void testFailedUpdateCount() throws InterruptedException, ExecutionExcept new ExecutionException( "ddl statement failed", Status.INVALID_ARGUMENT.asRuntimeException())); when(operationFuture.getMetadata()).thenReturn(metadataFuture); - when(client.executeDdl(argThat(isListOfStringsWithSize(2)))).thenReturn(operationFuture); + when(client.executeDdl(argThat(isListOfStringsWithSize(2)), isNull())) + .thenReturn(operationFuture); DdlBatch batch = DdlBatch.newBuilder() .withStatementExecutor(new StatementExecutor()) @@ -483,7 +486,8 @@ public void testFailedAfterFirstStatement() throws InterruptedException, Executi new ExecutionException( "ddl statement failed", Status.INVALID_ARGUMENT.asRuntimeException())); when(operationFuture.getMetadata()).thenReturn(metadataFuture); - when(client.executeDdl(argThat(isListOfStringsWithSize(2)))).thenReturn(operationFuture); + when(client.executeDdl(argThat(isListOfStringsWithSize(2)), isNull())) + .thenReturn(operationFuture); DdlBatch batch = DdlBatch.newBuilder() .withStatementExecutor(new StatementExecutor()) @@ -514,8 +518,8 @@ public void testAbort() { DdlBatch batch = createSubject(client); batch.abortBatch(); assertThat(batch.getState(), is(UnitOfWorkState.ABORTED)); - verify(client, never()).executeDdl(anyString()); - verify(client, never()).executeDdl(anyList()); + verify(client, never()).executeDdl(anyString(), isNull()); + verify(client, never()).executeDdl(anyList(), isNull()); ParsedStatement statement = mock(ParsedStatement.class); when(statement.getType()).thenReturn(StatementType.DDL); @@ -526,21 +530,21 @@ public void testAbort() { batch = createSubject(client); batch.executeDdlAsync(CallType.SYNC, statement); batch.abortBatch(); - verify(client, never()).executeDdl(anyList()); + verify(client, never()).executeDdl(anyList(), isNull()); client = createDefaultMockDdlClient(); batch = createSubject(client); batch.executeDdlAsync(CallType.SYNC, statement); batch.executeDdlAsync(CallType.SYNC, statement); batch.abortBatch(); - verify(client, never()).executeDdl(anyList()); + verify(client, never()).executeDdl(anyList(), isNull()); client = createDefaultMockDdlClient(); batch = createSubject(client); batch.executeDdlAsync(CallType.SYNC, statement); batch.executeDdlAsync(CallType.SYNC, statement); batch.abortBatch(); - verify(client, never()).executeDdl(anyList()); + verify(client, never()).executeDdl(anyList(), isNull()); boolean exception = false; try { get(batch.runBatchAsync(CallType.SYNC)); @@ -551,7 +555,7 @@ public void testAbort() { exception = true; } assertThat(exception, is(true)); - verify(client, never()).executeDdl(anyList()); + verify(client, never()).executeDdl(anyList(), isNull()); } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java index a96fc59d10f..187a8258f20 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.anyList; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; @@ -299,8 +300,8 @@ private DdlClient createDefaultMockDdlClient() { final OperationFuture operation = mock(OperationFuture.class); when(operation.get()).thenReturn(null); - when(ddlClient.executeDdl(anyString())).thenCallRealMethod(); - when(ddlClient.executeDdl(anyList())).thenReturn(operation); + when(ddlClient.executeDdl(anyString(), isNull())).thenCallRealMethod(); + when(ddlClient.executeDdl(anyList(), isNull())).thenReturn(operation); return ddlClient; } catch (Exception e) { throw new RuntimeException(e); @@ -537,7 +538,7 @@ public void testExecuteDdl() { DdlClient ddlClient = createDefaultMockDdlClient(); SingleUseTransaction subject = createDdlSubject(ddlClient); get(subject.executeDdlAsync(CallType.SYNC, ddl)); - verify(ddlClient).executeDdl(sql); + verify(ddlClient).executeDdl(sql, null); } @Test @@ -729,7 +730,7 @@ public void testMultiUse() { DdlClient ddlClient = createDefaultMockDdlClient(); SingleUseTransaction subject = createDdlSubject(ddlClient); get(subject.executeDdlAsync(CallType.SYNC, ddl)); - verify(ddlClient).executeDdl(sql); + verify(ddlClient).executeDdl(sql, null); try { get(subject.executeDdlAsync(CallType.SYNC, ddl)); fail("missing expected exception"); From 7746e08e60b752b833239dead1c93a3eed4e879f Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 12 Jun 2023 12:07:16 +0000 Subject: [PATCH 04/16] feat: code refactor for client side statements --- .../ClientSideStatementValueConverters.java | 15 ++++++++++++- .../ConnectionStatementExecutorImpl.java | 1 + .../connection/ClientSideStatements.json | 22 +++++++++---------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java index b8877e49bb4..1e94e31dc3b 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java @@ -516,7 +516,11 @@ public byte[] convert(String value) { if (value.length() == 0 || value.equalsIgnoreCase("null")) { return null; } - return Base64.getDecoder().decode(value); + try { + return Base64.getDecoder().decode(value); + } catch (IllegalArgumentException e) { + return null; + } } } @@ -535,9 +539,18 @@ public byte[] convert(String filePath) { if (filePath != null && filePath.length() > 0) { try { File protoDescriptorsFile = new File(filePath); + String fileName = protoDescriptorsFile.getName(); + int dotIndex = fileName.lastIndexOf('.'); + // check if file is a .pb extension file. + if (dotIndex < 0 + || dotIndex > fileName.length() - 1 + || !fileName.substring(dotIndex + 1).equals("pb")) { + return null; + } if (!protoDescriptorsFile.isFile()) { throw new IOException("File does not exist."); } + InputStream pdStream = new FileInputStream(protoDescriptorsFile); return ByteArray.copyFrom(pdStream).toByteArray(); } catch (Exception e) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java index 1d42c8a58a0..49d5ccd008f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java @@ -497,6 +497,7 @@ public StatementResult statementShowTransactionIsolationLevel() { @Override public StatementResult statementSetProtoDescriptors(byte[] protoDescriptors) { + Preconditions.checkNotNull(protoDescriptors); getConnection().setProtoDescriptors(protoDescriptors); return noResult(SET_PROTO_DESCRIPTORS); } diff --git a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json index 8fe70e511b2..e9fb0f84348 100644 --- a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json +++ b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json @@ -482,7 +482,7 @@ "statementType": "SET_PROTO_DESCRIPTORS", "regex": "(?is)\\A\\s*set\\s+proto_descriptors\\s*(?:=)\\s*(.*)\\z", "method": "statementSetProtoDescriptors", - "exampleStatements": ["set proto_descriptors='tag1'", "set proto_descriptors='tag2'", "set proto_descriptors=''"], + "exampleStatements": ["set proto_descriptors='protodescriptorsbase64'"], "setStatement": { "propertyName": "PROTO_DESCRIPTORS", "separator": "=", @@ -490,15 +490,6 @@ "converterName": "ClientSideStatementValueConverters$ProtoDescriptorsConverter" } }, - { - "name": "SHOW VARIABLE PROTO_DESCRIPTORS", - "executorName": "ClientSideStatementNoParamExecutor", - "resultType": "RESULT_SET", - "statementType": "SHOW_PROTO_DESCRIPTORS", - "regex": "(?is)\\A\\s*show\\s+variable\\s+proto_descriptors\\s*\\z", - "method": "statementShowProtoDescriptors", - "exampleStatements": ["show variable proto_descriptors"] - }, { "name": "SET PROTO_DESCRIPTORS FILE_PATH = ''", "executorName": "ClientSideStatementSetExecutor", @@ -506,13 +497,22 @@ "statementType": "SET_PROTO_DESCRIPTORS_FILE_PATH", "regex": "(?is)\\A\\s*set\\s+proto_descriptors\\s+file_path\\s*(?:=)\\s*(.*)\\z", "method": "statementSetProtoDescriptors", - "exampleStatements": ["set proto_descriptors file_path='tag1'", "set proto_descriptors='tag2'", "set proto_descriptors=''"], + "exampleStatements": ["set proto_descriptors file_path='/src/main/resources/descriptors.pb'"], "setStatement": { "propertyName": "PROTO_DESCRIPTORS FILE_PATH", "separator": "=", "allowedValues": "'((\\S+)|())'", "converterName": "ClientSideStatementValueConverters$ProtoDescriptorsFileConverter" } + }, + { + "name": "SHOW VARIABLE PROTO_DESCRIPTORS", + "executorName": "ClientSideStatementNoParamExecutor", + "resultType": "RESULT_SET", + "statementType": "SHOW_PROTO_DESCRIPTORS", + "regex": "(?is)\\A\\s*show\\s+variable\\s+proto_descriptors\\s*\\z", + "method": "statementShowProtoDescriptors", + "exampleStatements": ["show variable proto_descriptors"] } ] } From dcbe1663b61659fc4a213c98a3f43b4d59c426a2 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 12 Jun 2023 12:09:52 +0000 Subject: [PATCH 05/16] feat: add unit tests --- .../connection/ConnectionImplTest.java | 61 +++++++++++++++++ .../ConnectionStatementExecutorTest.java | 12 ++++ .../spanner/connection/DdlBatchTest.java | 47 ++++++++++++- .../spanner/connection/DdlClientTests.java | 49 ++++++++++++-- .../ProtoDescriptorsConverterTest.java | 63 ++++++++++++++++++ .../ProtoDescriptorsFileConverterTest.java | 63 ++++++++++++++++++ .../connection/SingleUseTransactionTest.java | 66 ++++++++++++++++--- .../connection/StatementResultImplTest.java | 19 ++++++ 8 files changed, 363 insertions(+), 17 deletions(-) create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsConverterTest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsFileConverterTest.java diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java index a134c4885ed..6c7d6710533 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java @@ -24,6 +24,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -71,9 +72,11 @@ import com.google.cloud.spanner.connection.StatementResult.ResultType; import com.google.cloud.spanner.connection.UnitOfWork.CallType; import com.google.cloud.spanner.connection.UnitOfWork.UnitOfWorkState; +import com.google.common.io.ByteStreams; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; import com.google.spanner.v1.ResultSetStats; +import java.io.InputStream; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -1611,4 +1614,62 @@ UnitOfWork createNewUnitOfWork() { assertNull(connection.getTransactionTag()); } } + + @Test + public void testProtoDescriptorsAlwaysAllowed() { + ConnectionOptions connectionOptions = mock(ConnectionOptions.class); + when(connectionOptions.isAutocommit()).thenReturn(true); + SpannerPool spannerPool = mock(SpannerPool.class); + DdlClient ddlClient = mock(DdlClient.class); + DatabaseClient dbClient = mock(DatabaseClient.class); + when(dbClient.getDialect()).thenReturn(Dialect.GOOGLE_STANDARD_SQL); + final UnitOfWork unitOfWork = mock(UnitOfWork.class); + when(unitOfWork.executeDdlAsync(any(), any(ParsedStatement.class))) + .thenReturn(ApiFutures.immediateFuture(null)); + when(unitOfWork.executeQueryAsync( + any(), any(ParsedStatement.class), any(AnalyzeMode.class), Mockito.any())) + .thenReturn(ApiFutures.immediateFuture(mock(ResultSet.class))); + try (ConnectionImpl connection = + new ConnectionImpl(connectionOptions, spannerPool, ddlClient, dbClient) { + @Override + UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() { + return unitOfWork; + } + }) { + byte[] protoDescriptors; + try { + InputStream in = + ConnectionImplTest.class + .getClassLoader() + .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + assertNotNull(in); + protoDescriptors = ByteStreams.toByteArray(in); + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + + assertTrue(connection.isAutocommit()); + + assertNull(connection.getProtoDescriptors()); + connection.setProtoDescriptors(protoDescriptors); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + + connection.setAutocommit(false); + + connection.setProtoDescriptors(protoDescriptors); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + + // proto descriptor should reset after executing a DDL statement + connection.setProtoDescriptors(protoDescriptors); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + connection.execute(Statement.of("CREATE PROTO BUNDLE (spanner.examples.music.SingerInfo)")); + assertNull(connection.getProtoDescriptors()); + + // proto descriptor should not reset if the statement is not a DDL statement + connection.setProtoDescriptors(protoDescriptors); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + connection.execute(Statement.of("SELECT FOO FROM BAR")); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + } + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java index bf7822e3285..0553681cf98 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java @@ -252,4 +252,16 @@ public void testStatementSetPgTransactionModeNoOp() { verify(connection, never()).setTransactionMode(TransactionMode.READ_ONLY_TRANSACTION); verify(connection, never()).setTransactionMode(TransactionMode.READ_WRITE_TRANSACTION); } + + @Test + public void testStatementSetProtoDescriptors() { + subject.statementSetProtoDescriptors("protoDescriptor".getBytes()); + verify(connection).setProtoDescriptors("protoDescriptor".getBytes()); + } + + @Test + public void testStatementGetProtoDescriptors() { + subject.statementShowProtoDescriptors(); + verify(connection).getProtoDescriptors(); + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java index 039bebbfd1e..12301d7b15c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java @@ -21,10 +21,12 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyList; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.argThat; @@ -52,9 +54,11 @@ import com.google.cloud.spanner.connection.Connection.InternalMetadataQuery; import com.google.cloud.spanner.connection.UnitOfWork.CallType; import com.google.cloud.spanner.connection.UnitOfWork.UnitOfWorkState; +import com.google.common.io.ByteStreams; import com.google.protobuf.Timestamp; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import io.grpc.Status; +import java.io.InputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -111,8 +115,8 @@ private DdlClient createDefaultMockDdlClient( ApiFuture metadataFuture = ApiFutures.immediateFuture(metadataBuilder.build()); when(operation.getMetadata()).thenReturn(metadataFuture); - when(ddlClient.executeDdl(anyString(), isNull())).thenReturn(operation); - when(ddlClient.executeDdl(anyList(), isNull())).thenReturn(operation); + when(ddlClient.executeDdl(anyString(), any())).thenReturn(operation); + when(ddlClient.executeDdl(anyList(), any())).thenReturn(operation); return ddlClient; } catch (Exception e) { throw new RuntimeException(e); @@ -386,6 +390,45 @@ public void testRunBatch() { assertThat(exception, is(true)); assertThat(batch.getState(), is(UnitOfWorkState.RUN_FAILED)); verify(client).executeDdl(argThat(isListOfStringsWithSize(2)), isNull()); + + // verify when protoDescriptors is null + client = createDefaultMockDdlClient(); + batch = + DdlBatch.newBuilder() + .setDdlClient(client) + .setDatabaseClient(mock(DatabaseClient.class)) + .withStatementExecutor(new StatementExecutor()) + .setProtoDescriptors(null) + .build(); + batch.executeDdlAsync(CallType.SYNC, statement); + batch.executeDdlAsync(CallType.SYNC, statement); + get(batch.runBatchAsync(CallType.SYNC)); + verify(client).executeDdl(argThat(isListOfStringsWithSize(2)), isNull()); + + // verify when protoDescriptors is not null + byte[] protoDescriptors; + try { + InputStream in = + DdlBatchTest.class + .getClassLoader() + .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + assertNotNull(in); + protoDescriptors = ByteStreams.toByteArray(in); + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + client = createDefaultMockDdlClient(); + batch = + DdlBatch.newBuilder() + .setDdlClient(client) + .setDatabaseClient(mock(DatabaseClient.class)) + .withStatementExecutor(new StatementExecutor()) + .setProtoDescriptors(protoDescriptors) + .build(); + batch.executeDdlAsync(CallType.SYNC, statement); + batch.executeDdlAsync(CallType.SYNC, statement); + get(batch.runBatchAsync(CallType.SYNC)); + verify(client).executeDdl(argThat(isListOfStringsWithSize(2)), any(byte[].class)); } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlClientTests.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlClientTests.java index d46e4dca592..c61635fce23 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlClientTests.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlClientTests.java @@ -17,17 +17,25 @@ package com.google.cloud.spanner.connection; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyList; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.isNull; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.SpannerExceptionFactory; +import com.google.common.io.ByteStreams; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; +import java.io.InputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -39,11 +47,13 @@ @RunWith(JUnit4.class) public class DdlClientTests { + private final String projectId = "test-project"; private final String instanceId = "test-instance"; private final String databaseId = "test-database"; private DdlClient createSubject(DatabaseAdminClient client) { return DdlClient.newBuilder() + .setProjectId(projectId) .setInstanceId(instanceId) .setDatabaseName(databaseId) .setDatabaseAdminClient(client) @@ -52,21 +62,48 @@ private DdlClient createSubject(DatabaseAdminClient client) { @Test public void testExecuteDdl() throws InterruptedException, ExecutionException { + byte[] protoDescriptors; + try { + InputStream in = + DdlBatchTest.class + .getClassLoader() + .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + assertNotNull(in); + protoDescriptors = ByteStreams.toByteArray(in); + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + DatabaseAdminClient client = mock(DatabaseAdminClient.class); + Database database = mock(Database.class); + Database.Builder databaseBuilder = mock(Database.Builder.class); @SuppressWarnings("unchecked") OperationFuture operation = mock(OperationFuture.class); + when(operation.get()).thenReturn(null); - when(client.updateDatabaseDdl(eq(instanceId), eq(databaseId), anyList(), isNull())) - .thenReturn(operation); + when(client.newDatabaseBuilder((DatabaseId.of(projectId, instanceId, databaseId)))) + .thenReturn(databaseBuilder); + when(databaseBuilder.setProtoDescriptors(protoDescriptors)).thenReturn(databaseBuilder); + when(databaseBuilder.build()).thenReturn(database); + when(client.updateDatabaseDdl(eq(database), anyList(), isNull())).thenReturn(operation); + DdlClient subject = createSubject(client); String ddl = "CREATE TABLE FOO"; - subject.executeDdl(ddl); - verify(client).updateDatabaseDdl(instanceId, databaseId, Collections.singletonList(ddl), null); + subject.executeDdl(ddl, null); + verify(databaseBuilder, never()).setProtoDescriptors(any(byte[].class)); + verify(client).updateDatabaseDdl(database, Collections.singletonList(ddl), null); subject = createSubject(client); List ddlList = Arrays.asList("CREATE TABLE FOO", "DROP TABLE FOO"); - subject.executeDdl(ddlList); - verify(client).updateDatabaseDdl(instanceId, databaseId, ddlList, null); + subject.executeDdl(ddlList, null); + verify(databaseBuilder, never()).setProtoDescriptors(any(byte[].class)); + verify(client).updateDatabaseDdl(database, ddlList, null); + + subject = createSubject(client); + ddlList = Arrays.asList("CREATE PROTO BUNDLE", "CREATE TABLE FOO"); + subject.executeDdl(ddlList, protoDescriptors); + verify(databaseBuilder).setProtoDescriptors(protoDescriptors); + verify(client).updateDatabaseDdl(database, ddlList, null); } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsConverterTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsConverterTest.java new file mode 100644 index 00000000000..47944ffc88f --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsConverterTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023 Google LLC + * + * 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 com.google.cloud.spanner.connection; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import com.google.cloud.spanner.Dialect; +import com.google.cloud.spanner.SpannerExceptionFactory; +import com.google.cloud.spanner.connection.ClientSideStatementImpl.CompileException; +import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.ProtoDescriptorsConverter; +import com.google.common.io.ByteStreams; +import java.io.InputStream; +import java.util.Base64; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ProtoDescriptorsConverterTest { + @Test + public void testConvert() throws CompileException { + String allowedValues = + ReadOnlyStalenessConverterTest.getAllowedValues( + ProtoDescriptorsConverter.class, Dialect.GOOGLE_STANDARD_SQL); + assertNotNull(allowedValues); + ProtoDescriptorsConverter converter = new ProtoDescriptorsConverter(allowedValues); + + byte[] protoDescriptors; + try { + InputStream in = + ProtoDescriptorsConverterTest.class + .getClassLoader() + .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + assertNotNull(in); + protoDescriptors = ByteStreams.toByteArray(in); + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + + assertNull(converter.convert("")); + assertNull(converter.convert("null")); + assertNull(converter.convert("random string")); + + assertArrayEquals( + converter.convert(Base64.getEncoder().encodeToString(protoDescriptors)), protoDescriptors); + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsFileConverterTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsFileConverterTest.java new file mode 100644 index 00000000000..aa460170911 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsFileConverterTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023 Google LLC + * + * 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 com.google.cloud.spanner.connection; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import com.google.cloud.spanner.Dialect; +import com.google.cloud.spanner.SpannerExceptionFactory; +import com.google.cloud.spanner.connection.ClientSideStatementImpl.CompileException; +import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.ProtoDescriptorsFileConverter; +import com.google.common.io.ByteStreams; +import java.io.InputStream; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ProtoDescriptorsFileConverterTest { + @Test + public void testConvert() throws CompileException { + String allowedValues = + ReadOnlyStalenessConverterTest.getAllowedValues( + ProtoDescriptorsFileConverter.class, Dialect.GOOGLE_STANDARD_SQL); + assertNotNull(allowedValues); + ProtoDescriptorsFileConverter converter = new ProtoDescriptorsFileConverter(allowedValues); + byte[] protoDescriptors; + try { + InputStream in = + ProtoDescriptorsConverterTest.class + .getClassLoader() + .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + assertNotNull(in); + protoDescriptors = ByteStreams.toByteArray(in); + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + + assertNull(converter.convert("")); + assertNull(converter.convert("null")); + assertNull(converter.convert("random string")); + assertNull(converter.convert("/descriptors.txt")); + + assertArrayEquals( + converter.convert("src/test/resources/com/google/cloud/spanner/descriptors.pb"), + protoDescriptors); + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java index 187a8258f20..9bbc613d7cf 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyList; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; @@ -57,8 +57,10 @@ import com.google.cloud.spanner.connection.StatementExecutor.StatementTimeout; import com.google.cloud.spanner.connection.UnitOfWork.CallType; import com.google.common.base.Preconditions; +import com.google.common.io.ByteStreams; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import com.google.spanner.v1.ResultSetStats; +import java.io.InputStream; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; @@ -300,8 +302,8 @@ private DdlClient createDefaultMockDdlClient() { final OperationFuture operation = mock(OperationFuture.class); when(operation.get()).thenReturn(null); - when(ddlClient.executeDdl(anyString(), isNull())).thenCallRealMethod(); - when(ddlClient.executeDdl(anyList(), isNull())).thenReturn(operation); + when(ddlClient.executeDdl(anyString(), any())).thenCallRealMethod(); + when(ddlClient.executeDdl(anyList(), any())).thenReturn(operation); return ddlClient; } catch (Exception e) { throw new RuntimeException(e); @@ -315,7 +317,8 @@ private SingleUseTransaction createSubject() { TimestampBound.strong(), AutocommitDmlMode.TRANSACTIONAL, CommitBehavior.SUCCEED, - 0L); + 0L, + null); } private SingleUseTransaction createSubject(AutocommitDmlMode dmlMode) { @@ -325,7 +328,8 @@ private SingleUseTransaction createSubject(AutocommitDmlMode dmlMode) { TimestampBound.strong(), dmlMode, CommitBehavior.SUCCEED, - 0L); + 0L, + null); } private SingleUseTransaction createSubject(CommitBehavior commitBehavior) { @@ -335,7 +339,8 @@ private SingleUseTransaction createSubject(CommitBehavior commitBehavior) { TimestampBound.strong(), AutocommitDmlMode.TRANSACTIONAL, commitBehavior, - 0L); + 0L, + null); } private SingleUseTransaction createDdlSubject(DdlClient ddlClient) { @@ -345,7 +350,20 @@ private SingleUseTransaction createDdlSubject(DdlClient ddlClient) { TimestampBound.strong(), AutocommitDmlMode.TRANSACTIONAL, CommitBehavior.SUCCEED, - 0L); + 0L, + null); + } + + private SingleUseTransaction createProtoDescriptorsSubject( + DdlClient ddlClient, byte[] protoDescriptors) { + return createSubject( + ddlClient, + false, + TimestampBound.strong(), + AutocommitDmlMode.TRANSACTIONAL, + CommitBehavior.SUCCEED, + 0L, + protoDescriptors); } private SingleUseTransaction createReadOnlySubject(TimestampBound staleness) { @@ -355,7 +373,8 @@ private SingleUseTransaction createReadOnlySubject(TimestampBound staleness) { staleness, AutocommitDmlMode.TRANSACTIONAL, CommitBehavior.SUCCEED, - 0L); + 0L, + null); } private SingleUseTransaction createSubject( @@ -364,7 +383,8 @@ private SingleUseTransaction createSubject( TimestampBound staleness, AutocommitDmlMode dmlMode, final CommitBehavior commitBehavior, - long timeout) { + long timeout, + byte[] protoDescriptors) { DatabaseClient dbClient = mock(DatabaseClient.class); com.google.cloud.spanner.ReadOnlyTransaction singleUse = new SimpleReadOnlyTransaction(staleness); @@ -451,6 +471,7 @@ public TransactionRunner allowNestedTransaction() { .setStatementTimeout( timeout == 0L ? nullTimeout() : timeout(timeout, TimeUnit.MILLISECONDS)) .withStatementExecutor(executor) + .setProtoDescriptors(protoDescriptors) .build(); } @@ -541,6 +562,33 @@ public void testExecuteDdl() { verify(ddlClient).executeDdl(sql, null); } + @Test + public void testExecuteDdlWithProtoDescriptors() { + String sql = "CREATE TABLE FOO"; + ParsedStatement ddl = createParsedDdl(sql); + DdlClient ddlClient = createDefaultMockDdlClient(); + // verify when protoDescriptors value is null + SingleUseTransaction subject = createProtoDescriptorsSubject(ddlClient, null); + get(subject.executeDdlAsync(CallType.SYNC, ddl)); + verify(ddlClient).executeDdl(sql, null); + + // verify when protoDescriptors value is not null + byte[] protoDescriptors; + try { + InputStream in = + SingleUseTransactionTest.class + .getClassLoader() + .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + assertNotNull(in); + protoDescriptors = ByteStreams.toByteArray(in); + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + subject = createProtoDescriptorsSubject(ddlClient, protoDescriptors); + get(subject.executeDdlAsync(CallType.SYNC, ddl)); + verify(ddlClient).executeDdl(sql, protoDescriptors); + } + @Test public void testExecuteCreateDatabase() { String sql = "CREATE DATABASE FOO"; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java index c28d3b75b95..100bcf62aaa 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java @@ -21,9 +21,13 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; +import com.google.cloud.ByteArray; import com.google.cloud.Timestamp; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.ResultSet; @@ -190,4 +194,19 @@ public void testTimestampResultSetGetResultSet() { is(equalTo(Timestamp.ofTimeSecondsAndNanos(10L, 10)))); assertThat(subject.getResultSet().next(), is(false)); } + + @Test + public void testBytesResultSetGetResultSet() { + StatementResult subject = + StatementResultImpl.resultSet( + "foo", "protoDescriptors".getBytes(), ClientSideStatementType.SHOW_PROTO_DESCRIPTORS); + assertEquals(subject.getResultType(), ResultType.RESULT_SET); + assertEquals( + subject.getClientSideStatementType(), ClientSideStatementType.SHOW_PROTO_DESCRIPTORS); + assertNotNull(subject.getResultSet()); + assertTrue(subject.getResultSet().next()); + assertEquals( + subject.getResultSet().getBytes("foo"), ByteArray.copyFrom("protoDescriptors".getBytes())); + assertFalse(subject.getResultSet().next()); + } } From 76fdd7769ab4c75229f119bc84904b7dde219a0d Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 12 Jun 2023 18:19:05 +0000 Subject: [PATCH 06/16] feat: code refactoring for file path client statement --- .../spanner/connection/ConnectionStatementExecutor.java | 2 ++ .../connection/ConnectionStatementExecutorImpl.java | 8 ++++++++ .../google/cloud/spanner/connection/StatementResult.java | 1 + .../cloud/spanner/connection/ClientSideStatements.json | 4 ++-- .../connection/ConnectionStatementExecutorTest.java | 6 ++++++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java index a7b6e51c6c2..91274648dbe 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java @@ -126,6 +126,8 @@ StatementResult statementSetPgSessionCharacteristicsTransactionMode( StatementResult statementSetProtoDescriptors(byte[] protoDescriptors); + StatementResult statementSetProtoDescriptorsFilePath(byte[] protoDescriptors); + StatementResult statementShowProtoDescriptors(); StatementResult statementExplain(String sql); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java index 49d5ccd008f..81f07e71eb6 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java @@ -29,6 +29,7 @@ import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_OPTIMIZER_STATISTICS_PACKAGE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_OPTIMIZER_VERSION; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_PROTO_DESCRIPTORS; +import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_PROTO_DESCRIPTORS_FILE_PATH; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_READONLY; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_READ_ONLY_STALENESS; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_RETRY_ABORTS_INTERNALLY; @@ -502,6 +503,13 @@ public StatementResult statementSetProtoDescriptors(byte[] protoDescriptors) { return noResult(SET_PROTO_DESCRIPTORS); } + @Override + public StatementResult statementSetProtoDescriptorsFilePath(byte[] protoDescriptors) { + Preconditions.checkNotNull(protoDescriptors); + getConnection().setProtoDescriptors(protoDescriptors); + return noResult(SET_PROTO_DESCRIPTORS_FILE_PATH); + } + @Override public StatementResult statementShowProtoDescriptors() { return resultSet( diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java index 4bd4098e48d..3507176b42e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java @@ -91,6 +91,7 @@ enum ClientSideStatementType { SET_SAVEPOINT_SUPPORT, EXPLAIN, SET_PROTO_DESCRIPTORS, + SET_PROTO_DESCRIPTORS_FILE_PATH, SHOW_PROTO_DESCRIPTORS } diff --git a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json index e9fb0f84348..d63b76b449c 100644 --- a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json +++ b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json @@ -496,8 +496,8 @@ "resultType": "NO_RESULT", "statementType": "SET_PROTO_DESCRIPTORS_FILE_PATH", "regex": "(?is)\\A\\s*set\\s+proto_descriptors\\s+file_path\\s*(?:=)\\s*(.*)\\z", - "method": "statementSetProtoDescriptors", - "exampleStatements": ["set proto_descriptors file_path='/src/main/resources/descriptors.pb'"], + "method": "statementSetProtoDescriptorsFilePath", + "exampleStatements": ["set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'"], "setStatement": { "propertyName": "PROTO_DESCRIPTORS FILE_PATH", "separator": "=", diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java index 0553681cf98..89f3614a6a1 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java @@ -259,6 +259,12 @@ public void testStatementSetProtoDescriptors() { verify(connection).setProtoDescriptors("protoDescriptor".getBytes()); } + @Test + public void testStatementSetProtoDescriptorsFilePath() { + subject.statementSetProtoDescriptorsFilePath("protoDescriptor".getBytes()); + verify(connection).setProtoDescriptors("protoDescriptor".getBytes()); + } + @Test public void testStatementGetProtoDescriptors() { subject.statementShowProtoDescriptors(); From 33044c49e34c60eae2456941d6243c6856a85ae2 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 12 Jun 2023 18:21:06 +0000 Subject: [PATCH 07/16] test: add integration test for DDL --- .../cloud/spanner/connection/ITDdlTest.sql | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITDdlTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITDdlTest.sql index 2dea0423151..75fc742b13b 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITDdlTest.sql +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITDdlTest.sql @@ -187,3 +187,42 @@ RUN BATCH; START BATCH DDL; ABORT BATCH; + +NEW_CONNECTION; +-- Set proto descriptors using relative path to the descriptors.pb file. This gets applied for next DDL statement +SET PROTO_DESCRIPTORS FILE_PATH = 'src/test/resources/com/google/cloud/spanner/descriptors.pb'; +-- Check if Proto descriptors is set +@EXPECT RESULT_SET 'PROTO_DESCRIPTORS' +SHOW VARIABLE PROTO_DESCRIPTORS; + +CREATE PROTO BUNDLE (spanner.examples.music.Genre); +-- Check if Proto descriptors is reset to null +@EXPECT RESULT_SET 'PROTO_DESCRIPTORS',null +SHOW VARIABLE PROTO_DESCRIPTORS; + +-- Set Proto Descriptor as base64 string. This gets applied to all statements in next DDL batch +SET PROTO_DESCRIPTORS = 'CvgBCgxzaW5nZXIucHJvdG8SFnNwYW5uZXIuZXhhbXBsZXMubXVzaWMinwEKClNpbmdlckluZm8SGwoJc2luZ2VyX2lkGAEgASgDUghzaW5nZXJJZBIdCgpiaXJ0aF9kYXRlGAIgASgJUgliaXJ0aERhdGUSIAoLbmF0aW9uYWxpdHkYAyABKAlSC25hdGlvbmFsaXR5EjMKBWdlbnJlGAQgASgOMh0uc3Bhbm5lci5leGFtcGxlcy5tdXNpYy5HZW5yZVIFZ2VucmUqLgoFR2VucmUSBwoDUE9QEAASCAoESkFaWhABEggKBEZPTEsQAhIICgRST0NLEAM='; + +@EXPECT RESULT_SET 'PROTO_DESCRIPTORS' +SHOW VARIABLE PROTO_DESCRIPTORS; + +START BATCH DDL; +ALTER PROTO BUNDLE INSERT (spanner.examples.music.SingerInfo); +CREATE TABLE Singers ( + SingerId INT64 NOT NULL, + FirstName STRING(1024), + LastName STRING(1024), + SingerInfo spanner.examples.music.SingerInfo, + SingerGenre spanner.examples.music.Genre +) PRIMARY KEY (SingerId); +-- Run the batch +RUN BATCH; + +-- Check if Proto descriptors is reset to null +@EXPECT RESULT_SET 'PROTO_DESCRIPTORS',null +SHOW VARIABLE PROTO_DESCRIPTORS; +-- Check that the table is created +@EXPECT RESULT_SET +SELECT COUNT(*) AS ACTUAL, 1 AS EXPECTED +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_NAME='Singers'; From ad0873ab1edc7f2a6fb5adcec4cc289c33bc68f3 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 13 Jun 2023 06:07:36 +0000 Subject: [PATCH 08/16] fix: comment refactoring --- .../spanner/connection/ClientSideStatementValueConverters.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java index 1e94e31dc3b..52a7fc44ff1 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java @@ -501,7 +501,7 @@ public String convert(String value) { } } - /** Converter for converting strings to byte[] */ + /** Converter for converting Base64 encoded string to byte[] */ static class ProtoDescriptorsConverter implements ClientSideStatementValueConverter { public ProtoDescriptorsConverter(String allowedValues) {} From a5f16979c6a782d31717da303875244021e88f9c Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 13 Jun 2023 18:15:10 +0000 Subject: [PATCH 09/16] feat: move proto descriptor file read logic to ConnectionImpl file to fix autogenerated client side statement tests --- .../ClientSideStatementValueConverters.java | 40 ++++------------ .../spanner/connection/ConnectionImpl.java | 46 +++++++++++++++++-- .../ConnectionStatementExecutor.java | 2 +- .../ConnectionStatementExecutorImpl.java | 6 +-- .../connection/ClientSideStatements.json | 2 +- .../ConnectionStatementExecutorTest.java | 5 +- .../ProtoDescriptorsFileConverterTest.java | 25 ++-------- 7 files changed, 63 insertions(+), 63 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java index 52a7fc44ff1..f59aefa8dce 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java @@ -16,7 +16,6 @@ package com.google.cloud.spanner.connection; -import com.google.cloud.ByteArray; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Options.RpcPriority; import com.google.cloud.spanner.SpannerExceptionFactory; @@ -29,10 +28,6 @@ import com.google.protobuf.Duration; import com.google.protobuf.util.Durations; import com.google.spanner.v1.RequestOptions.Priority; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; import java.util.Base64; import java.util.EnumSet; import java.util.HashMap; @@ -524,41 +519,22 @@ public byte[] convert(String value) { } } - /** Converter for converting strings that take in file path as input to byte[] */ - static class ProtoDescriptorsFileConverter implements ClientSideStatementValueConverter { + /** Converter for converting String that take in file path as input to String */ + static class ProtoDescriptorsFileConverter implements ClientSideStatementValueConverter { public ProtoDescriptorsFileConverter(String allowedValues) {} @Override - public Class getParameterClass() { - return byte[].class; + public Class getParameterClass() { + return String.class; } @Override - public byte[] convert(String filePath) { - if (filePath != null && filePath.length() > 0) { - try { - File protoDescriptorsFile = new File(filePath); - String fileName = protoDescriptorsFile.getName(); - int dotIndex = fileName.lastIndexOf('.'); - // check if file is a .pb extension file. - if (dotIndex < 0 - || dotIndex > fileName.length() - 1 - || !fileName.substring(dotIndex + 1).equals("pb")) { - return null; - } - if (!protoDescriptorsFile.isFile()) { - throw new IOException("File does not exist."); - } - - InputStream pdStream = new FileInputStream(protoDescriptorsFile); - return ByteArray.copyFrom(pdStream).toByteArray(); - } catch (Exception e) { - throw SpannerExceptionFactory.newSpannerException( - ErrorCode.INVALID_ARGUMENT, e.getMessage()); - } + public String convert(String filePath) { + if (filePath == null || filePath.length() == 0) { + return null; } - return null; + return filePath; } } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java index 565692cd6be..c8223c26dc0 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java @@ -21,6 +21,7 @@ import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; +import com.google.cloud.ByteArray; import com.google.cloud.Timestamp; import com.google.cloud.spanner.AsyncResultSet; import com.google.cloud.spanner.CommitResponse; @@ -51,6 +52,10 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; import com.google.spanner.v1.ResultSetStats; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -223,6 +228,7 @@ static UnitOfWorkType of(TransactionMode transactionMode) { private String statementTag; private byte[] protoDescriptors; + private String protoDescriptorsFilePath; /** Create a connection and register it in the SpannerPool. */ ConnectionImpl(ConnectionOptions options) { @@ -630,7 +636,32 @@ public void setStatementTag(String tag) { @Override public byte[] getProtoDescriptors() { ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); - return protoDescriptors; + if (this.protoDescriptorsFilePath != null) { + // Read from file if filepath is valid + try { + File protoDescriptorsFile = new File(this.protoDescriptorsFilePath); + String fileName = protoDescriptorsFile.getName(); + int dotIndex = fileName.lastIndexOf('.'); + // check if the file is a .pb extension file. + if (dotIndex < 0 + || dotIndex > fileName.length() - 1 + || !fileName.substring(dotIndex + 1).equals("pb")) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, "Proto descriptor file should be a .pb extension file"); + } + if (!protoDescriptorsFile.isFile()) { + throw new IOException("File does not exist."); + } + + InputStream pdStream = new FileInputStream(protoDescriptorsFile); + this.protoDescriptors = ByteArray.copyFrom(pdStream).toByteArray(); + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, e.getMessage()); + } + this.protoDescriptorsFilePath = null; + } + return this.protoDescriptors; } @Override @@ -640,6 +671,15 @@ public void setProtoDescriptors(@Nonnull byte[] protoDescriptors) { ConnectionPreconditions.checkState( !isBatchActive(), "Proto descriptors cannot be set when a batch is active"); this.protoDescriptors = protoDescriptors; + this.protoDescriptorsFilePath = null; + } + + void setProtoDescriptorsFilePath(@Nonnull String protoDescriptorsFilePath) { + Preconditions.checkNotNull(protoDescriptorsFilePath); + ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); + ConnectionPreconditions.checkState( + !isBatchActive(), "Proto descriptors cannot be set when a batch is active"); + this.protoDescriptorsFilePath = protoDescriptorsFilePath; } /** @@ -1398,7 +1438,7 @@ UnitOfWork createNewUnitOfWork() { .setReturnCommitStats(returnCommitStats) .setStatementTimeout(statementTimeout) .withStatementExecutor(statementExecutor) - .setProtoDescriptors(protoDescriptors) + .setProtoDescriptors(getProtoDescriptors()) .build(); } else { switch (getUnitOfWorkType()) { @@ -1441,7 +1481,7 @@ UnitOfWork createNewUnitOfWork() { .setDatabaseClient(dbClient) .setStatementTimeout(statementTimeout) .withStatementExecutor(statementExecutor) - .setProtoDescriptors(protoDescriptors) + .setProtoDescriptors(getProtoDescriptors()) .build(); default: } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java index 91274648dbe..84494a56dff 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java @@ -126,7 +126,7 @@ StatementResult statementSetPgSessionCharacteristicsTransactionMode( StatementResult statementSetProtoDescriptors(byte[] protoDescriptors); - StatementResult statementSetProtoDescriptorsFilePath(byte[] protoDescriptors); + StatementResult statementSetProtoDescriptorsFilePath(String filePath); StatementResult statementShowProtoDescriptors(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java index 81f07e71eb6..73bcec14815 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java @@ -504,9 +504,9 @@ public StatementResult statementSetProtoDescriptors(byte[] protoDescriptors) { } @Override - public StatementResult statementSetProtoDescriptorsFilePath(byte[] protoDescriptors) { - Preconditions.checkNotNull(protoDescriptors); - getConnection().setProtoDescriptors(protoDescriptors); + public StatementResult statementSetProtoDescriptorsFilePath(String filePath) { + Preconditions.checkNotNull(filePath); + getConnection().setProtoDescriptorsFilePath(filePath); return noResult(SET_PROTO_DESCRIPTORS_FILE_PATH); } diff --git a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json index d63b76b449c..9c9acb1f3bf 100644 --- a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json +++ b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json @@ -499,7 +499,7 @@ "method": "statementSetProtoDescriptorsFilePath", "exampleStatements": ["set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'"], "setStatement": { - "propertyName": "PROTO_DESCRIPTORS FILE_PATH", + "propertyName": "PROTO_DESCRIPTORS\\s+FILE_PATH", "separator": "=", "allowedValues": "'((\\S+)|())'", "converterName": "ClientSideStatementValueConverters$ProtoDescriptorsFileConverter" diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java index 89f3614a6a1..90505e839fd 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java @@ -261,8 +261,9 @@ public void testStatementSetProtoDescriptors() { @Test public void testStatementSetProtoDescriptorsFilePath() { - subject.statementSetProtoDescriptorsFilePath("protoDescriptor".getBytes()); - verify(connection).setProtoDescriptors("protoDescriptor".getBytes()); + String filePath = "com/google/cloud/spanner/descriptors.pb"; + subject.statementSetProtoDescriptorsFilePath(filePath); + verify(connection).setProtoDescriptorsFilePath(filePath); } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsFileConverterTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsFileConverterTest.java index aa460170911..67428327057 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsFileConverterTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsFileConverterTest.java @@ -16,16 +16,13 @@ package com.google.cloud.spanner.connection; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import com.google.cloud.spanner.Dialect; -import com.google.cloud.spanner.SpannerExceptionFactory; import com.google.cloud.spanner.connection.ClientSideStatementImpl.CompileException; import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.ProtoDescriptorsFileConverter; -import com.google.common.io.ByteStreams; -import java.io.InputStream; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -39,25 +36,11 @@ public void testConvert() throws CompileException { ProtoDescriptorsFileConverter.class, Dialect.GOOGLE_STANDARD_SQL); assertNotNull(allowedValues); ProtoDescriptorsFileConverter converter = new ProtoDescriptorsFileConverter(allowedValues); - byte[] protoDescriptors; - try { - InputStream in = - ProtoDescriptorsConverterTest.class - .getClassLoader() - .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); - assertNotNull(in); - protoDescriptors = ByteStreams.toByteArray(in); - } catch (Exception e) { - throw SpannerExceptionFactory.newSpannerException(e); - } assertNull(converter.convert("")); - assertNull(converter.convert("null")); - assertNull(converter.convert("random string")); - assertNull(converter.convert("/descriptors.txt")); + assertNull(converter.convert(null)); - assertArrayEquals( - converter.convert("src/test/resources/com/google/cloud/spanner/descriptors.pb"), - protoDescriptors); + String filePath = "com/google/cloud/spanner/descriptors.pb"; + assertEquals(converter.convert(filePath), filePath); } } From e8fed61c38fccbe397f3e8c557b90d61af47d05b Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 13 Jun 2023 18:27:15 +0000 Subject: [PATCH 10/16] feat: add autogenerated test for new proto columns client side statements --- .../connection/ClientSideStatementsTest.sql | 596 ++++++++++++++++++ 1 file changed, 596 insertions(+) diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ClientSideStatementsTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ClientSideStatementsTest.sql index 914244a02a8..dd81bb6e25a 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ClientSideStatementsTest.sql +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ClientSideStatementsTest.sql @@ -17701,3 +17701,599 @@ set delay_transaction_start_until_first_write = false/-; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT set delay_transaction_start_until_first_write =/-false; +NEW_CONNECTION; +set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +SET PROTO_DESCRIPTORS='PROTODESCRIPTORSBASE64'; +NEW_CONNECTION; +set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; + set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; + set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; + + + +set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +set proto_descriptors='protodescriptorsbase64' ; +NEW_CONNECTION; +set proto_descriptors='protodescriptorsbase64' ; +NEW_CONNECTION; +set proto_descriptors='protodescriptorsbase64' + +; +NEW_CONNECTION; +set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +set +proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors='protodescriptorsbase64'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-proto_descriptors='protodescriptorsbase64'; +NEW_CONNECTION; +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +SET PROTO_DESCRIPTORS FILE_PATH='SRC/TEST/RESOURCES/COM/GOOGLE/CLOUD/SPANNER/DESCRIPTORS.PB'; +NEW_CONNECTION; +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; + set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; + set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; + + + +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' ; +NEW_CONNECTION; +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' ; +NEW_CONNECTION; +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' + +; +NEW_CONNECTION; +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +set +proto_descriptors +file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors%file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors&file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors$file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors@file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors!file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors*file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors(file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors)file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors-file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors+file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors-#file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors/file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors\file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors?file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors-/file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors/#file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set proto_descriptors/-file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +NEW_CONNECTION; +show variable proto_descriptors; +NEW_CONNECTION; +SHOW VARIABLE PROTO_DESCRIPTORS; +NEW_CONNECTION; +show variable proto_descriptors; +NEW_CONNECTION; + show variable proto_descriptors; +NEW_CONNECTION; + show variable proto_descriptors; +NEW_CONNECTION; + + + +show variable proto_descriptors; +NEW_CONNECTION; +show variable proto_descriptors ; +NEW_CONNECTION; +show variable proto_descriptors ; +NEW_CONNECTION; +show variable proto_descriptors + +; +NEW_CONNECTION; +show variable proto_descriptors; +NEW_CONNECTION; +show variable proto_descriptors; +NEW_CONNECTION; +show +variable +proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors%; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable%proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable_proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors&; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable&proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors$; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable$proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors@; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable@proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors!; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable!proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors*; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable*proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors(; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable(proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors); +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable)proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors+; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable+proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors-#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-#proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors\; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable\proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors?; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable?proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors-/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-/proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors/#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/#proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-show variable proto_descriptors; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors/-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/-proto_descriptors; From b15dd754bbe6ee9506dda2e5742ee21563a8108c Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Wed, 14 Jun 2023 11:29:05 +0000 Subject: [PATCH 11/16] feat: add unit tests to verify proto descriptor set via filepath --- .../connection/ConnectionImplTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java index 6c7d6710533..bc2e62c7244 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java @@ -1670,6 +1670,30 @@ UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() { assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); connection.execute(Statement.of("SELECT FOO FROM BAR")); assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + + // test proto descriptor file path as input + connection.setProtoDescriptorsFilePath( + "src/test/resources/com/google/cloud/spanner/descriptors.pb"); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + connection.execute(Statement.of("CREATE PROTO BUNDLE (spanner.examples.music.SingerInfo)")); + assertNull(connection.getProtoDescriptors()); + + // proto descriptor set through file path should overwrite the proto descriptor set from + // byte[] + connection.setProtoDescriptors("protoDescriptors".getBytes()); + connection.setProtoDescriptorsFilePath( + "src/test/resources/com/google/cloud/spanner/descriptors.pb"); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + connection.execute(Statement.of("CREATE PROTO BUNDLE (spanner.examples.music.SingerInfo)")); + assertNull(connection.getProtoDescriptors()); + + // proto descriptor set through byte[] should overwrite the proto descriptor from file path + connection.setProtoDescriptorsFilePath( + "src/test/resources/com/google/cloud/spanner/descriptors.pb"); + connection.setProtoDescriptors("protoDescriptors".getBytes()); + assertArrayEquals("protoDescriptors".getBytes(), connection.getProtoDescriptors()); + connection.execute(Statement.of("CREATE PROTO BUNDLE (spanner.examples.music.SingerInfo)")); + assertNull(connection.getProtoDescriptors()); } } } From 0c9f4f6a340136395210b5c2ae5b30b89cfb1fb4 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Thu, 15 Jun 2023 12:01:31 +0000 Subject: [PATCH 12/16] feat: add review comments --- .../ClientSideStatementValueConverters.java | 5 ++-- .../spanner/connection/ConnectionImpl.java | 23 ++++++++++++----- .../connection/ConnectionImplTest.java | 25 ++++++++++++++----- .../ProtoDescriptorsConverterTest.java | 1 + 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java index f59aefa8dce..b8ed22b3f3a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java @@ -25,6 +25,7 @@ import com.google.cloud.spanner.connection.PgTransactionMode.IsolationLevel; import com.google.common.base.Function; import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.protobuf.Duration; import com.google.protobuf.util.Durations; import com.google.spanner.v1.RequestOptions.Priority; @@ -508,7 +509,7 @@ public Class getParameterClass() { @Override public byte[] convert(String value) { - if (value.length() == 0 || value.equalsIgnoreCase("null")) { + if (value == null || value.length() == 0 || value.equalsIgnoreCase("null")) { return null; } try { @@ -531,7 +532,7 @@ public Class getParameterClass() { @Override public String convert(String filePath) { - if (filePath == null || filePath.length() == 0) { + if (Strings.isNullOrEmpty(filePath)) { return null; } return filePath; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java index c8223c26dc0..9d19baf3b6a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java @@ -54,7 +54,6 @@ import com.google.spanner.v1.ResultSetStats; import java.io.File; import java.io.FileInputStream; -import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; @@ -636,7 +635,7 @@ public void setStatementTag(String tag) { @Override public byte[] getProtoDescriptors() { ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); - if (this.protoDescriptorsFilePath != null) { + if (this.protoDescriptors == null && this.protoDescriptorsFilePath != null) { // Read from file if filepath is valid try { File protoDescriptorsFile = new File(this.protoDescriptorsFilePath); @@ -650,16 +649,20 @@ public byte[] getProtoDescriptors() { ErrorCode.INVALID_ARGUMENT, "Proto descriptor file should be a .pb extension file"); } if (!protoDescriptorsFile.isFile()) { - throw new IOException("File does not exist."); + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, + String.format( + "File %s is not a valid proto descriptors file", this.protoDescriptorsFilePath)); } InputStream pdStream = new FileInputStream(protoDescriptorsFile); this.protoDescriptors = ByteArray.copyFrom(pdStream).toByteArray(); - } catch (Exception e) { + } catch (SpannerException exception) { + throw exception; + } catch (Exception exception) { throw SpannerExceptionFactory.newSpannerException( - ErrorCode.INVALID_ARGUMENT, e.getMessage()); + ErrorCode.INVALID_ARGUMENT, exception.getMessage()); } - this.protoDescriptorsFilePath = null; } return this.protoDescriptors; } @@ -680,6 +683,12 @@ void setProtoDescriptorsFilePath(@Nonnull String protoDescriptorsFilePath) { ConnectionPreconditions.checkState( !isBatchActive(), "Proto descriptors cannot be set when a batch is active"); this.protoDescriptorsFilePath = protoDescriptorsFilePath; + this.protoDescriptors = null; + } + + String getProtoDescriptorsFilePath() { + ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); + return this.protoDescriptorsFilePath; } /** @@ -1509,6 +1518,7 @@ private ApiFuture executeDdlAsync(CallType callType, ParsedStatement ddl) getCurrentUnitOfWorkOrStartNewUnitOfWork().executeDdlAsync(callType, ddl); // reset proto descriptors after executing a DDL statement this.protoDescriptors = null; + this.protoDescriptorsFilePath = null; return result; } @@ -1603,6 +1613,7 @@ public ApiFuture runBatchAsync() { if (isDdlBatchActive()) { // reset proto descriptors after executing a DDL batch this.protoDescriptors = null; + this.protoDescriptorsFilePath = null; } this.batchMode = BatchMode.NONE; setDefaultTransactionOptions(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java index bc2e62c7244..c0951bb8cad 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java @@ -1624,6 +1624,8 @@ public void testProtoDescriptorsAlwaysAllowed() { DatabaseClient dbClient = mock(DatabaseClient.class); when(dbClient.getDialect()).thenReturn(Dialect.GOOGLE_STANDARD_SQL); final UnitOfWork unitOfWork = mock(UnitOfWork.class); + final String protoDescriptorsFilePath = + "src/test/resources/com/google/cloud/spanner/descriptors.pb"; when(unitOfWork.executeDdlAsync(any(), any(ParsedStatement.class))) .thenReturn(ApiFutures.immediateFuture(null)); when(unitOfWork.executeQueryAsync( @@ -1671,9 +1673,22 @@ UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() { connection.execute(Statement.of("SELECT FOO FROM BAR")); assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + // proto descriptor file path should reset after executing a DDL statement + connection.setProtoDescriptorsFilePath(protoDescriptorsFilePath); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + connection.execute(Statement.of("CREATE PROTO BUNDLE (spanner.examples.music.SingerInfo)")); + assertNull(connection.getProtoDescriptors()); + assertNull(connection.getProtoDescriptorsFilePath()); + + // proto descriptor file path should not reset if the statement is not a DDL statement + connection.setProtoDescriptorsFilePath(protoDescriptorsFilePath); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + connection.execute(Statement.of("SELECT FOO FROM BAR")); + assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); + assertEquals(protoDescriptorsFilePath, connection.getProtoDescriptorsFilePath()); + // test proto descriptor file path as input - connection.setProtoDescriptorsFilePath( - "src/test/resources/com/google/cloud/spanner/descriptors.pb"); + connection.setProtoDescriptorsFilePath(protoDescriptorsFilePath); assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); connection.execute(Statement.of("CREATE PROTO BUNDLE (spanner.examples.music.SingerInfo)")); assertNull(connection.getProtoDescriptors()); @@ -1681,15 +1696,13 @@ UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() { // proto descriptor set through file path should overwrite the proto descriptor set from // byte[] connection.setProtoDescriptors("protoDescriptors".getBytes()); - connection.setProtoDescriptorsFilePath( - "src/test/resources/com/google/cloud/spanner/descriptors.pb"); + connection.setProtoDescriptorsFilePath(protoDescriptorsFilePath); assertArrayEquals(protoDescriptors, connection.getProtoDescriptors()); connection.execute(Statement.of("CREATE PROTO BUNDLE (spanner.examples.music.SingerInfo)")); assertNull(connection.getProtoDescriptors()); // proto descriptor set through byte[] should overwrite the proto descriptor from file path - connection.setProtoDescriptorsFilePath( - "src/test/resources/com/google/cloud/spanner/descriptors.pb"); + connection.setProtoDescriptorsFilePath(protoDescriptorsFilePath); connection.setProtoDescriptors("protoDescriptors".getBytes()); assertArrayEquals("protoDescriptors".getBytes(), connection.getProtoDescriptors()); connection.execute(Statement.of("CREATE PROTO BUNDLE (spanner.examples.music.SingerInfo)")); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsConverterTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsConverterTest.java index 47944ffc88f..b2041d1a332 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsConverterTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ProtoDescriptorsConverterTest.java @@ -55,6 +55,7 @@ public void testConvert() throws CompileException { assertNull(converter.convert("")); assertNull(converter.convert("null")); + assertNull(converter.convert(null)); assertNull(converter.convert("random string")); assertArrayEquals( From f97b2495ba3f70652f375aa0faf44a47053e991c Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Thu, 15 Jun 2023 12:31:42 +0000 Subject: [PATCH 13/16] feat: add client side statement to show proto descriptors file path --- .../ConnectionStatementExecutor.java | 2 + .../ConnectionStatementExecutorImpl.java | 9 + .../spanner/connection/StatementResult.java | 3 +- .../connection/ClientSideStatements.json | 17 +- .../ConnectionStatementExecutorTest.java | 6 + .../connection/StatementResultImplTest.java | 12 + .../connection/ClientSideStatementsTest.sql | 336 ++++++++++++++---- .../cloud/spanner/connection/ITDdlTest.sql | 8 +- 8 files changed, 316 insertions(+), 77 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java index 84494a56dff..40350dfef7a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java @@ -130,5 +130,7 @@ StatementResult statementSetPgSessionCharacteristicsTransactionMode( StatementResult statementShowProtoDescriptors(); + StatementResult statementShowProtoDescriptorsFilePath(); + StatementResult statementExplain(String sql); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java index 73bcec14815..d3854027d9e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java @@ -48,6 +48,7 @@ import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_OPTIMIZER_STATISTICS_PACKAGE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_OPTIMIZER_VERSION; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_PROTO_DESCRIPTORS; +import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_PROTO_DESCRIPTORS_FILE_PATH; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_READONLY; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_READ_ONLY_STALENESS; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_READ_TIMESTAMP; @@ -518,6 +519,14 @@ public StatementResult statementShowProtoDescriptors() { SHOW_PROTO_DESCRIPTORS); } + @Override + public StatementResult statementShowProtoDescriptorsFilePath() { + return resultSet( + String.format("%sPROTO_DESCRIPTORS_FILE_PATH", getNamespace(connection.getDialect())), + getConnection().getProtoDescriptorsFilePath(), + SHOW_PROTO_DESCRIPTORS_FILE_PATH); + } + private String processQueryPlan(PlanNode planNode) { StringBuilder planNodeDescription = new StringBuilder(" : { "); com.google.protobuf.Struct metadata = planNode.getMetadata(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java index 3507176b42e..cc09f62dbea 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java @@ -92,7 +92,8 @@ enum ClientSideStatementType { EXPLAIN, SET_PROTO_DESCRIPTORS, SET_PROTO_DESCRIPTORS_FILE_PATH, - SHOW_PROTO_DESCRIPTORS + SHOW_PROTO_DESCRIPTORS, + SHOW_PROTO_DESCRIPTORS_FILE_PATH } /** diff --git a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json index 9c9acb1f3bf..f726b8181c7 100644 --- a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json +++ b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json @@ -491,15 +491,15 @@ } }, { - "name": "SET PROTO_DESCRIPTORS FILE_PATH = ''", + "name": "SET PROTO_DESCRIPTORS_FILE_PATH = ''", "executorName": "ClientSideStatementSetExecutor", "resultType": "NO_RESULT", "statementType": "SET_PROTO_DESCRIPTORS_FILE_PATH", - "regex": "(?is)\\A\\s*set\\s+proto_descriptors\\s+file_path\\s*(?:=)\\s*(.*)\\z", + "regex": "(?is)\\A\\s*set\\s+proto_descriptors_file_path\\s*(?:=)\\s*(.*)\\z", "method": "statementSetProtoDescriptorsFilePath", - "exampleStatements": ["set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'"], + "exampleStatements": ["set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'"], "setStatement": { - "propertyName": "PROTO_DESCRIPTORS\\s+FILE_PATH", + "propertyName": "PROTO_DESCRIPTORS_FILE_PATH", "separator": "=", "allowedValues": "'((\\S+)|())'", "converterName": "ClientSideStatementValueConverters$ProtoDescriptorsFileConverter" @@ -513,6 +513,15 @@ "regex": "(?is)\\A\\s*show\\s+variable\\s+proto_descriptors\\s*\\z", "method": "statementShowProtoDescriptors", "exampleStatements": ["show variable proto_descriptors"] + }, + { + "name": "SHOW VARIABLE PROTO_DESCRIPTORS_FILE_PATH", + "executorName": "ClientSideStatementNoParamExecutor", + "resultType": "RESULT_SET", + "statementType": "SHOW_PROTO_DESCRIPTORS_FILE_PATH", + "regex": "(?is)\\A\\s*show\\s+variable\\s+proto_descriptors_file_path\\s*\\z", + "method": "statementShowProtoDescriptorsFilePath", + "exampleStatements": ["show variable proto_descriptors_file_path"] } ] } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java index 90505e839fd..3e883c377fe 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorTest.java @@ -271,4 +271,10 @@ public void testStatementGetProtoDescriptors() { subject.statementShowProtoDescriptors(); verify(connection).getProtoDescriptors(); } + + @Test + public void testStatementGetProtoDescriptorsFilePath() { + subject.statementShowProtoDescriptorsFilePath(); + verify(connection).getProtoDescriptorsFilePath(); + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java index 100bcf62aaa..0a55ff2c420 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java @@ -158,6 +158,18 @@ public void testStringResultSetGetResultSet() { assertThat(subject.getResultSet().next(), is(true)); assertThat(subject.getResultSet().getString("foo"), is(equalTo("bar"))); assertThat(subject.getResultSet().next(), is(false)); + + subject = + StatementResultImpl.resultSet( + "path", "descriptors.pb", ClientSideStatementType.SHOW_PROTO_DESCRIPTORS_FILE_PATH); + assertThat(subject.getResultType(), is(equalTo(ResultType.RESULT_SET))); + assertThat( + subject.getClientSideStatementType(), + is(equalTo(ClientSideStatementType.SHOW_PROTO_DESCRIPTORS_FILE_PATH))); + assertThat(subject.getResultSet(), is(notNullValue())); + assertThat(subject.getResultSet().next(), is(true)); + assertThat(subject.getResultSet().getString("path"), is(equalTo("descriptors.pb"))); + assertThat(subject.getResultSet().next(), is(false)); } @Test diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ClientSideStatementsTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ClientSideStatementsTest.sql index dd81bb6e25a..b18a41b3202 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ClientSideStatementsTest.sql +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ClientSideStatementsTest.sql @@ -17900,204 +17900,203 @@ NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT set/-proto_descriptors='protodescriptorsbase64'; NEW_CONNECTION; -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; -SET PROTO_DESCRIPTORS FILE_PATH='SRC/TEST/RESOURCES/COM/GOOGLE/CLOUD/SPANNER/DESCRIPTORS.PB'; +SET PROTO_DESCRIPTORS_FILE_PATH='SRC/TEST/RESOURCES/COM/GOOGLE/CLOUD/SPANNER/DESCRIPTORS.PB'; NEW_CONNECTION; -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; - set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; + set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; - set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; + set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' ; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' ; NEW_CONNECTION; -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' ; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' ; NEW_CONNECTION; -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' ; NEW_CONNECTION; -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; set -proto_descriptors -file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -foo set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +foo set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' bar; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb' bar; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -%set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +%set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'%; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'%; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors%file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set%proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -_set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +_set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'_; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'_; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set_proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -&set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +&set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'&; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'&; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors&file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set&proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -$set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +$set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'$; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'$; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors$file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set$proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -@set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +@set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'@; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'@; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors@file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set@proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -!set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +!set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'!; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'!; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors!file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set!proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -*set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +*set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'*; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'*; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors*file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set*proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -(set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +(set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'(; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'(; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors(file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set(proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -)set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +)set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'); +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'); NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors)file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set)proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT --set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +-set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors-file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set-proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -+set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; ++set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'+; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'+; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors+file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set+proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT --#set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +-#set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-#; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-#; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors-#file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set-#proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -/set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +/set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors/file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set/proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -\set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +\set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'\; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'\; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors\file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set\proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -?set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +?set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'?; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'?; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors?file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set?proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT --/set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +-/set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-/; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'-/; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors-/file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set-/proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -/#set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +/#set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/#; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/#; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors/#file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set/#proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -/-set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +/-set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/-; +set proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'/-; NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT -set proto_descriptors/-file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; +set/-proto_descriptors_file_path='src/test/resources/com/google/cloud/spanner/descriptors.pb'; NEW_CONNECTION; show variable proto_descriptors; NEW_CONNECTION; @@ -18297,3 +18296,202 @@ show variable proto_descriptors/-; NEW_CONNECTION; @EXPECT EXCEPTION UNIMPLEMENTED show variable/-proto_descriptors; +NEW_CONNECTION; +show variable proto_descriptors_file_path; +NEW_CONNECTION; +SHOW VARIABLE PROTO_DESCRIPTORS_FILE_PATH; +NEW_CONNECTION; +show variable proto_descriptors_file_path; +NEW_CONNECTION; + show variable proto_descriptors_file_path; +NEW_CONNECTION; + show variable proto_descriptors_file_path; +NEW_CONNECTION; + + + +show variable proto_descriptors_file_path; +NEW_CONNECTION; +show variable proto_descriptors_file_path ; +NEW_CONNECTION; +show variable proto_descriptors_file_path ; +NEW_CONNECTION; +show variable proto_descriptors_file_path + +; +NEW_CONNECTION; +show variable proto_descriptors_file_path; +NEW_CONNECTION; +show variable proto_descriptors_file_path; +NEW_CONNECTION; +show +variable +proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path%; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable%proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path_; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable_proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path&; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable&proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path$; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable$proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path@; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable@proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path!; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable!proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path*; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable*proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path(; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable(proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path); +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable)proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path+; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable+proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path-#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-#proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path\; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable\proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path?; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable?proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path-/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-/proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path/#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/#proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-show variable proto_descriptors_file_path; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable proto_descriptors_file_path/-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/-proto_descriptors_file_path; diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITDdlTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITDdlTest.sql index 75fc742b13b..8d81cef0d0f 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITDdlTest.sql +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITDdlTest.sql @@ -190,15 +190,17 @@ ABORT BATCH; NEW_CONNECTION; -- Set proto descriptors using relative path to the descriptors.pb file. This gets applied for next DDL statement -SET PROTO_DESCRIPTORS FILE_PATH = 'src/test/resources/com/google/cloud/spanner/descriptors.pb'; +SET PROTO_DESCRIPTORS_FILE_PATH = 'src/test/resources/com/google/cloud/spanner/descriptors.pb'; -- Check if Proto descriptors is set -@EXPECT RESULT_SET 'PROTO_DESCRIPTORS' -SHOW VARIABLE PROTO_DESCRIPTORS; +@EXPECT RESULT_SET 'PROTO_DESCRIPTORS_FILE_PATH' +SHOW VARIABLE PROTO_DESCRIPTORS_FILE_PATH; CREATE PROTO BUNDLE (spanner.examples.music.Genre); -- Check if Proto descriptors is reset to null @EXPECT RESULT_SET 'PROTO_DESCRIPTORS',null SHOW VARIABLE PROTO_DESCRIPTORS; +@EXPECT RESULT_SET 'PROTO_DESCRIPTORS_FILE_PATH',null +SHOW VARIABLE PROTO_DESCRIPTORS_FILE_PATH; -- Set Proto Descriptor as base64 string. This gets applied to all statements in next DDL batch SET PROTO_DESCRIPTORS = 'CvgBCgxzaW5nZXIucHJvdG8SFnNwYW5uZXIuZXhhbXBsZXMubXVzaWMinwEKClNpbmdlckluZm8SGwoJc2luZ2VyX2lkGAEgASgDUghzaW5nZXJJZBIdCgpiaXJ0aF9kYXRlGAIgASgJUgliaXJ0aERhdGUSIAoLbmF0aW9uYWxpdHkYAyABKAlSC25hdGlvbmFsaXR5EjMKBWdlbnJlGAQgASgOMh0uc3Bhbm5lci5leGFtcGxlcy5tdXNpYy5HZW5yZVIFZ2VucmUqLgoFR2VucmUSBwoDUE9QEAASCAoESkFaWhABEggKBEZPTEsQAhIICgRST0NLEAM='; From a42761b515729d2ebf703054505605b3db6dd3b7 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Thu, 15 Jun 2023 13:19:07 +0000 Subject: [PATCH 14/16] fix: remove proto descriptors file extension validation --- .../cloud/spanner/connection/ConnectionImpl.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java index 9d19baf3b6a..d5f1c7ecf3b 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java @@ -639,22 +639,12 @@ public byte[] getProtoDescriptors() { // Read from file if filepath is valid try { File protoDescriptorsFile = new File(this.protoDescriptorsFilePath); - String fileName = protoDescriptorsFile.getName(); - int dotIndex = fileName.lastIndexOf('.'); - // check if the file is a .pb extension file. - if (dotIndex < 0 - || dotIndex > fileName.length() - 1 - || !fileName.substring(dotIndex + 1).equals("pb")) { - throw SpannerExceptionFactory.newSpannerException( - ErrorCode.INVALID_ARGUMENT, "Proto descriptor file should be a .pb extension file"); - } if (!protoDescriptorsFile.isFile()) { throw SpannerExceptionFactory.newSpannerException( ErrorCode.INVALID_ARGUMENT, String.format( "File %s is not a valid proto descriptors file", this.protoDescriptorsFilePath)); } - InputStream pdStream = new FileInputStream(protoDescriptorsFile); this.protoDescriptors = ByteArray.copyFrom(pdStream).toByteArray(); } catch (SpannerException exception) { From 865fc0c7cfbfa4e69b78ce372e2cba8f42f3805c Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Thu, 15 Jun 2023 13:49:04 +0000 Subject: [PATCH 15/16] feat: comment refactor --- .../com/google/cloud/spanner/connection/ConnectionImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java index d5f1c7ecf3b..35ab5fdeda8 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java @@ -671,7 +671,7 @@ void setProtoDescriptorsFilePath(@Nonnull String protoDescriptorsFilePath) { Preconditions.checkNotNull(protoDescriptorsFilePath); ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); ConnectionPreconditions.checkState( - !isBatchActive(), "Proto descriptors cannot be set when a batch is active"); + !isBatchActive(), "Proto descriptors file path cannot be set when a batch is active"); this.protoDescriptorsFilePath = protoDescriptorsFilePath; this.protoDescriptors = null; } From f1e3f3ac067181013706501fb3821d3993c7fa1c Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Fri, 23 Jun 2023 05:47:08 +0000 Subject: [PATCH 16/16] feat: address review comments --- .../com/google/cloud/spanner/connection/ConnectionImpl.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java index 35ab5fdeda8..1d4c6bb4d7a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java @@ -647,11 +647,8 @@ public byte[] getProtoDescriptors() { } InputStream pdStream = new FileInputStream(protoDescriptorsFile); this.protoDescriptors = ByteArray.copyFrom(pdStream).toByteArray(); - } catch (SpannerException exception) { - throw exception; } catch (Exception exception) { - throw SpannerExceptionFactory.newSpannerException( - ErrorCode.INVALID_ARGUMENT, exception.getMessage()); + throw SpannerExceptionFactory.newSpannerException(exception); } } return this.protoDescriptors;