diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index b16f5212010..9a71e7679c2 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -14,6 +14,7 @@ branchProtectionRules: - units (8) - units (11) - 'Kokoro - Test: Integration' + - 'Kokoro - Test: Integration with Multiplexed Sessions' - cla/google - checkstyle - compile (8) diff --git a/.github/workflows/unmanaged_dependency_check.yaml b/.github/workflows/unmanaged_dependency_check.yaml index 1d7e28014c4..f6594602a26 100644 --- a/.github/workflows/unmanaged_dependency_check.yaml +++ b/.github/workflows/unmanaged_dependency_check.yaml @@ -17,6 +17,6 @@ jobs: # repository .kokoro/build.sh - name: Unmanaged dependency check - uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.29.0 + uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.30.0 with: bom-path: google-cloud-spanner-bom/pom.xml diff --git a/.kokoro/presubmit/graalvm-native-17.cfg b/.kokoro/presubmit/graalvm-native-17.cfg index 326361c6b5e..b20ec8ff352 100644 --- a/.kokoro/presubmit/graalvm-native-17.cfg +++ b/.kokoro/presubmit/graalvm-native-17.cfg @@ -3,7 +3,7 @@ # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.29.0" + value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.30.0" } env_vars: { diff --git a/.kokoro/presubmit/graalvm-native.cfg b/.kokoro/presubmit/graalvm-native.cfg index 1b1d4c4bfe3..aad0db97859 100644 --- a/.kokoro/presubmit/graalvm-native.cfg +++ b/.kokoro/presubmit/graalvm-native.cfg @@ -3,7 +3,7 @@ # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.29.0" + value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.30.0" } env_vars: { diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f3fc6d1395..a878fe0500f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## [6.66.0](https://github.com/googleapis/java-spanner/compare/v6.65.1...v6.66.0) (2024-05-03) + + +### Features + +* Allow DDL with autocommit=false ([#3057](https://github.com/googleapis/java-spanner/issues/3057)) ([22833ac](https://github.com/googleapis/java-spanner/commit/22833acf9f073271ce0ee10f2b496f3a1d39566a)) +* Include stack trace of checked out sessions in exception ([#3092](https://github.com/googleapis/java-spanner/issues/3092)) ([ba6a0f6](https://github.com/googleapis/java-spanner/commit/ba6a0f644b6caa4d2f3aa130c6061341b70957dd)) + + +### Bug Fixes + +* Multiplexed session metrics were not included in refactor move ([#3088](https://github.com/googleapis/java-spanner/issues/3088)) ([f3589c4](https://github.com/googleapis/java-spanner/commit/f3589c430b0e84933a91008bb306c26089788357)) + + +### Dependencies + +* Update dependency com.google.cloud:sdk-platform-java-config to v3.30.0 ([#3082](https://github.com/googleapis/java-spanner/issues/3082)) ([ddfc98e](https://github.com/googleapis/java-spanner/commit/ddfc98e240fb47ef51075ba4461bf9a98aa25ce0)) + ## [6.65.1](https://github.com/googleapis/java-spanner/compare/v6.65.0...v6.65.1) (2024-04-30) diff --git a/README.md b/README.md index 2f904b1c112..5333b8b4bda 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ If you are using Maven without the BOM, add this to your dependencies: com.google.cloud google-cloud-spanner - 6.65.0 + 6.65.1 ``` @@ -50,20 +50,20 @@ If you are using Maven without the BOM, add this to your dependencies: If you are using Gradle 5.x or later, add this to your dependencies: ```Groovy -implementation platform('com.google.cloud:libraries-bom:26.37.0') +implementation platform('com.google.cloud:libraries-bom:26.38.0') implementation 'com.google.cloud:google-cloud-spanner' ``` If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-spanner:6.65.0' +implementation 'com.google.cloud:google-cloud-spanner:6.65.1' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.65.0" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.65.1" ``` @@ -651,7 +651,7 @@ Java is a registered trademark of Oracle and/or its affiliates. [kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java11.html [stability-image]: https://img.shields.io/badge/stability-stable-green [maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-spanner.svg -[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.65.0 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.65.1 [authentication]: https://github.com/googleapis/google-cloud-java#authentication [auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes [predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index cd672b3fc54..bcd6137641f 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -24,7 +24,7 @@ com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 @@ -92,7 +92,7 @@ com.google.cloud google-cloud-spanner - 6.63.0 + 6.65.1 commons-cli diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index b3778261e43..f73943c2924 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,12 +3,12 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 6.65.1 + 6.66.0 pom com.google.cloud sdk-platform-java-config - 3.29.0 + 3.30.0 Google Cloud Spanner BOM @@ -53,43 +53,43 @@ com.google.cloud google-cloud-spanner - 6.65.1 + 6.66.0 com.google.cloud google-cloud-spanner test-jar - 6.65.1 + 6.66.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.65.1 + 6.66.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.65.1 + 6.66.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.65.1 + 6.66.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.65.1 + 6.66.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.65.1 + 6.66.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.65.1 + 6.66.0 diff --git a/google-cloud-spanner-executor/pom.xml b/google-cloud-spanner-executor/pom.xml index eb3d34a63d8..21239775cee 100644 --- a/google-cloud-spanner-executor/pom.xml +++ b/google-cloud-spanner-executor/pom.xml @@ -5,14 +5,14 @@ 4.0.0 com.google.cloud google-cloud-spanner-executor - 6.65.1 + 6.66.0 jar Google Cloud Spanner Executor com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index 5fea47fe9a8..92dcab6e2ce 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -656,5 +656,17 @@ com/google/cloud/spanner/connection/Connection com.google.cloud.spanner.Spanner getSpanner() + + + + 7012 + com/google/cloud/spanner/connection/Connection + void setDdlInTransactionMode(com.google.cloud.spanner.connection.DdlInTransactionMode) + + + 7012 + com/google/cloud/spanner/connection/Connection + com.google.cloud.spanner.connection.DdlInTransactionMode getDdlInTransactionMode() + diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 2c0480522f8..12f15f1eb31 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 6.65.1 + 6.66.0 jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 google-cloud-spanner diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractMultiplexedSessionDatabaseClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractMultiplexedSessionDatabaseClient.java new file mode 100644 index 00000000000..92035a18418 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractMultiplexedSessionDatabaseClient.java @@ -0,0 +1,96 @@ +/* + * Copyright 2024 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; + +import com.google.api.gax.rpc.ServerStream; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.Options.TransactionOption; +import com.google.cloud.spanner.Options.UpdateOption; +import com.google.spanner.v1.BatchWriteResponse; + +/** + * Base class for the Multiplexed Session {@link DatabaseClient} implementation. Throws {@link + * UnsupportedOperationException} for all methods that are currently not supported for multiplexed + * sessions. The concrete implementation implements the methods that are supported with multiplexed + * sessions. + */ +abstract class AbstractMultiplexedSessionDatabaseClient implements DatabaseClient { + + @Override + public Dialect getDialect() { + throw new UnsupportedOperationException(); + } + + @Override + public String getDatabaseRole() { + throw new UnsupportedOperationException(); + } + + @Override + public Timestamp write(Iterable mutations) throws SpannerException { + throw new UnsupportedOperationException(); + } + + @Override + public CommitResponse writeWithOptions(Iterable mutations, TransactionOption... options) + throws SpannerException { + throw new UnsupportedOperationException(); + } + + @Override + public Timestamp writeAtLeastOnce(Iterable mutations) throws SpannerException { + throw new UnsupportedOperationException(); + } + + @Override + public CommitResponse writeAtLeastOnceWithOptions( + Iterable mutations, TransactionOption... options) throws SpannerException { + throw new UnsupportedOperationException(); + } + + @Override + public ServerStream batchWriteAtLeastOnce( + Iterable mutationGroups, TransactionOption... options) + throws SpannerException { + throw new UnsupportedOperationException(); + } + + @Override + public TransactionRunner readWriteTransaction(TransactionOption... options) { + throw new UnsupportedOperationException(); + } + + @Override + public TransactionManager transactionManager(TransactionOption... options) { + throw new UnsupportedOperationException(); + } + + @Override + public AsyncRunner runAsync(TransactionOption... options) { + throw new UnsupportedOperationException(); + } + + @Override + public AsyncTransactionManager transactionManagerAsync(TransactionOption... options) { + throw new UnsupportedOperationException(); + } + + @Override + public long executePartitionedUpdate(Statement stmt, UpdateOption... options) { + throw new UnsupportedOperationException(); + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java index 18a1cc3692c..4d17ba4e1b7 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java @@ -809,6 +809,7 @@ public final void invalidate() { @Override public void close() { + session.onTransactionDone(); span.end(); synchronized (lock) { isClosed = true; @@ -844,11 +845,14 @@ public void onTransactionMetadata(Transaction transaction, boolean shouldInclude @Override public SpannerException onError(SpannerException e, boolean withBeginTransaction) { + this.session.onError(e); return e; } @Override - public void onDone(boolean withBeginTransaction) {} + public void onDone(boolean withBeginTransaction) { + this.session.onReadDone(); + } private ResultSet readInternal( String table, diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java index c89cce9a79e..b2d6b19a528 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java @@ -21,7 +21,6 @@ import com.google.cloud.spanner.Options.TransactionOption; import com.google.cloud.spanner.Options.UpdateOption; import com.google.cloud.spanner.SessionPool.PooledSessionFuture; -import com.google.cloud.spanner.SessionPool.SessionFutureWrapper; import com.google.cloud.spanner.SpannerImpl.ClosedException; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; @@ -36,15 +35,26 @@ class DatabaseClientImpl implements DatabaseClient { private final TraceWrapper tracer; @VisibleForTesting final String clientId; @VisibleForTesting final SessionPool pool; + @VisibleForTesting final MultiplexedSessionDatabaseClient multiplexedSessionDatabaseClient; @VisibleForTesting DatabaseClientImpl(SessionPool pool, TraceWrapper tracer) { - this("", pool, tracer); + this("", pool, /* multiplexedSessionDatabaseClient = */ null, tracer); } + @VisibleForTesting DatabaseClientImpl(String clientId, SessionPool pool, TraceWrapper tracer) { + this(clientId, pool, /* multiplexedSessionDatabaseClient = */ null, tracer); + } + + DatabaseClientImpl( + String clientId, + SessionPool pool, + @Nullable MultiplexedSessionDatabaseClient multiplexedSessionDatabaseClient, + TraceWrapper tracer) { this.clientId = clientId; this.pool = pool; + this.multiplexedSessionDatabaseClient = multiplexedSessionDatabaseClient; this.tracer = tracer; } @@ -54,7 +64,11 @@ PooledSessionFuture getSession() { } @VisibleForTesting - SessionFutureWrapper getMultiplexedSession() { + DatabaseClient getMultiplexedSession() { + if (this.multiplexedSessionDatabaseClient != null + && this.multiplexedSessionDatabaseClient.isMultiplexedSessionsSupported()) { + return this.multiplexedSessionDatabaseClient; + } return pool.getMultiplexedSessionWithFallback(); } @@ -270,7 +284,18 @@ private T runWithSessionRetry(Function callable) { } } + boolean isValid() { + return pool.isValid() + && (multiplexedSessionDatabaseClient == null + || multiplexedSessionDatabaseClient.isValid() + || !multiplexedSessionDatabaseClient.isMultiplexedSessionsSupported()); + } + ListenableFuture closeAsync(ClosedException closedException) { + if (this.multiplexedSessionDatabaseClient != null) { + // This method is non-blocking. + this.multiplexedSessionDatabaseClient.close(); + } return pool.closeAsync(closedException); } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DelayedMultiplexedSessionTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DelayedMultiplexedSessionTransaction.java new file mode 100644 index 00000000000..928927d49a0 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DelayedMultiplexedSessionTransaction.java @@ -0,0 +1,122 @@ +/* + * Copyright 2024 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; + +import static com.google.cloud.spanner.SessionImpl.NO_CHANNEL_HINT; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.cloud.spanner.DelayedReadContext.DelayedReadOnlyTransaction; +import com.google.cloud.spanner.MultiplexedSessionDatabaseClient.MultiplexedSessionTransaction; +import com.google.common.util.concurrent.MoreExecutors; + +/** + * Represents a delayed execution of a transaction on a multiplexed session. The execution is + * delayed because the multiplexed session is not yet ready. This class is only used during client + * creation before the multiplexed session has been created. The use of this class while the + * multiplexed session is still being created ensures that the creation of a {@link DatabaseClient} + * is non-blocking. + */ +class DelayedMultiplexedSessionTransaction extends AbstractMultiplexedSessionDatabaseClient { + + private final MultiplexedSessionDatabaseClient client; + + private final ISpan span; + + private final ApiFuture sessionFuture; + + DelayedMultiplexedSessionTransaction( + MultiplexedSessionDatabaseClient client, + ISpan span, + ApiFuture sessionFuture) { + this.client = client; + this.span = span; + this.sessionFuture = sessionFuture; + } + + @Override + public ReadContext singleUse() { + return new DelayedReadContext<>( + ApiFutures.transform( + this.sessionFuture, + sessionReference -> + new MultiplexedSessionTransaction( + client, span, sessionReference, NO_CHANNEL_HINT, true) + .singleUse(), + MoreExecutors.directExecutor())); + } + + @Override + public ReadContext singleUse(TimestampBound bound) { + return new DelayedReadContext<>( + ApiFutures.transform( + this.sessionFuture, + sessionReference -> + new MultiplexedSessionTransaction( + client, span, sessionReference, NO_CHANNEL_HINT, true) + .singleUse(bound), + MoreExecutors.directExecutor())); + } + + @Override + public ReadOnlyTransaction singleUseReadOnlyTransaction() { + return new DelayedReadOnlyTransaction( + ApiFutures.transform( + this.sessionFuture, + sessionReference -> + new MultiplexedSessionTransaction( + client, span, sessionReference, NO_CHANNEL_HINT, true) + .singleUseReadOnlyTransaction(), + MoreExecutors.directExecutor())); + } + + @Override + public ReadOnlyTransaction singleUseReadOnlyTransaction(TimestampBound bound) { + return new DelayedReadOnlyTransaction( + ApiFutures.transform( + this.sessionFuture, + sessionReference -> + new MultiplexedSessionTransaction( + client, span, sessionReference, NO_CHANNEL_HINT, true) + .singleUseReadOnlyTransaction(bound), + MoreExecutors.directExecutor())); + } + + @Override + public ReadOnlyTransaction readOnlyTransaction() { + return new DelayedReadOnlyTransaction( + ApiFutures.transform( + this.sessionFuture, + sessionReference -> + new MultiplexedSessionTransaction( + client, span, sessionReference, NO_CHANNEL_HINT, false) + .readOnlyTransaction(), + MoreExecutors.directExecutor())); + } + + @Override + public ReadOnlyTransaction readOnlyTransaction(TimestampBound bound) { + return new DelayedReadOnlyTransaction( + ApiFutures.transform( + this.sessionFuture, + sessionReference -> + new MultiplexedSessionTransaction( + client, span, sessionReference, NO_CHANNEL_HINT, false) + .readOnlyTransaction(bound), + MoreExecutors.directExecutor())); + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DelayedReadContext.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DelayedReadContext.java new file mode 100644 index 00000000000..752c41cdea3 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DelayedReadContext.java @@ -0,0 +1,157 @@ +/* + * Copyright 2024 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; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.Options.QueryOption; +import com.google.cloud.spanner.Options.ReadOption; +import com.google.common.base.Suppliers; +import com.google.common.util.concurrent.MoreExecutors; +import java.util.concurrent.ExecutionException; +import javax.annotation.Nullable; + +/** + * Represents a {@link ReadContext} using a multiplexed session that is not yet ready. The execution + * will be delayed until the multiplexed session has been created and is ready. This class is only + * used during the startup of the client and the multiplexed session has not yet been created. This + * ensures that the creation of {@link DatabaseClient} is non-blocking. + */ +class DelayedReadContext implements ReadContext { + + private final ApiFuture readContextFuture; + + DelayedReadContext(ApiFuture readContextFuture) { + this.readContextFuture = readContextFuture; + } + + T getReadContext() { + try { + return this.readContextFuture.get(); + } catch (ExecutionException executionException) { + throw SpannerExceptionFactory.asSpannerException(executionException.getCause()); + } catch (InterruptedException interruptedException) { + throw SpannerExceptionFactory.propagateInterrupt(interruptedException); + } + } + + @Override + public ResultSet read( + String table, KeySet keys, Iterable columns, ReadOption... options) { + return new ForwardingResultSet( + Suppliers.memoize(() -> getReadContext().read(table, keys, columns, options))); + } + + @Override + public AsyncResultSet readAsync( + String table, KeySet keys, Iterable columns, ReadOption... options) { + return new ForwardingAsyncResultSet( + Suppliers.memoize(() -> getReadContext().readAsync(table, keys, columns, options))); + } + + @Override + public ResultSet readUsingIndex( + String table, String index, KeySet keys, Iterable columns, ReadOption... options) { + return new ForwardingResultSet( + Suppliers.memoize( + () -> getReadContext().readUsingIndex(table, index, keys, columns, options))); + } + + @Override + public AsyncResultSet readUsingIndexAsync( + String table, String index, KeySet keys, Iterable columns, ReadOption... options) { + return new ForwardingAsyncResultSet( + Suppliers.memoize( + () -> getReadContext().readUsingIndexAsync(table, index, keys, columns, options))); + } + + @Nullable + @Override + public Struct readRow(String table, Key key, Iterable columns) { + // This is allowed to be blocking. + return getReadContext().readRow(table, key, columns); + } + + @Override + public ApiFuture readRowAsync(String table, Key key, Iterable columns) { + return ApiFutures.transformAsync( + this.readContextFuture, + readContext -> readContext.readRowAsync(table, key, columns), + MoreExecutors.directExecutor()); + } + + @Nullable + @Override + public Struct readRowUsingIndex(String table, String index, Key key, Iterable columns) { + // This is allowed to be blocking. + return getReadContext().readRowUsingIndex(table, index, key, columns); + } + + @Override + public ApiFuture readRowUsingIndexAsync( + String table, String index, Key key, Iterable columns) { + return ApiFutures.transformAsync( + this.readContextFuture, + readContext -> readContext.readRowUsingIndexAsync(table, index, key, columns), + MoreExecutors.directExecutor()); + } + + @Override + public ResultSet executeQuery(Statement statement, QueryOption... options) { + return new ForwardingResultSet( + Suppliers.memoize(() -> getReadContext().executeQuery(statement, options))); + } + + @Override + public AsyncResultSet executeQueryAsync(Statement statement, QueryOption... options) { + return new ForwardingAsyncResultSet( + Suppliers.memoize(() -> getReadContext().executeQueryAsync(statement, options))); + } + + @Override + public ResultSet analyzeQuery(Statement statement, QueryAnalyzeMode queryMode) { + return new ForwardingResultSet( + Suppliers.memoize(() -> getReadContext().analyzeQuery(statement, queryMode))); + } + + @Override + public void close() { + try { + this.readContextFuture.get().close(); + } catch (Throwable ignore) { + // Ignore any errors during close, as this error has already propagated to the user through + // other means. + } + } + + /** + * Represents a {@link ReadContext} using a multiplexed session that is not yet ready. The + * execution will be delayed until the multiplexed session has been created and is ready. + */ + static class DelayedReadOnlyTransaction extends DelayedReadContext + implements ReadOnlyTransaction { + DelayedReadOnlyTransaction(ApiFuture readContextFuture) { + super(readContextFuture); + } + + @Override + public Timestamp getReadTimestamp() { + return getReadContext().getReadTimestamp(); + } + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingAsyncResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingAsyncResultSet.java index e94590bd092..a0197cb7b8d 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingAsyncResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingAsyncResultSet.java @@ -19,46 +19,54 @@ import com.google.api.core.ApiFuture; import com.google.common.base.Function; import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; import java.util.List; import java.util.concurrent.Executor; /** Forwarding implementation of {@link AsyncResultSet} that forwards all calls to a delegate. */ public class ForwardingAsyncResultSet extends ForwardingResultSet implements AsyncResultSet { - final AsyncResultSet delegate; public ForwardingAsyncResultSet(AsyncResultSet delegate) { super(Preconditions.checkNotNull(delegate)); - this.delegate = delegate; + } + + ForwardingAsyncResultSet(Supplier delegateSupplier) { + super(Preconditions.checkNotNull(delegateSupplier)); + } + + @Override + AsyncResultSet getDelegate() { + return (AsyncResultSet) super.getDelegate(); } @Override public CursorState tryNext() throws SpannerException { - return delegate.tryNext(); + return getDelegate().tryNext(); } @Override public ApiFuture setCallback(Executor exec, ReadyCallback cb) { - return delegate.setCallback(exec, cb); + return getDelegate().setCallback(exec, cb); } @Override public void cancel() { - delegate.cancel(); + getDelegate().cancel(); } @Override public void resume() { - delegate.resume(); + getDelegate().resume(); } @Override public ApiFuture> toListAsync( Function transformer, Executor executor) { - return delegate.toListAsync(transformer, executor); + return getDelegate().toListAsync(transformer, executor); } @Override public List toList(Function transformer) throws SpannerException { - return delegate.toList(transformer); + return getDelegate().toList(transformer); } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java index 18ecbeceb0f..babbb310a45 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java @@ -25,14 +25,14 @@ /** Forwarding implementation of ResultSet that forwards all calls to a delegate. */ public class ForwardingResultSet extends ForwardingStructReader implements ProtobufResultSet { - private Supplier delegate; + private Supplier delegate; public ForwardingResultSet(ResultSet delegate) { super(delegate); this.delegate = Suppliers.ofInstance(Preconditions.checkNotNull(delegate)); } - public ForwardingResultSet(Supplier supplier) { + public ForwardingResultSet(Supplier supplier) { super(supplier); this.delegate = supplier; } @@ -50,6 +50,10 @@ void replaceDelegate(ResultSet newDelegate) { this.delegate = Suppliers.ofInstance(Preconditions.checkNotNull(newDelegate)); } + ResultSet getDelegate() { + return delegate.get(); + } + @Override public boolean next() throws SpannerException { return delegate.get().next(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/GrpcResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/GrpcResultSet.java index 37a4792ad87..7b61901a60e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/GrpcResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/GrpcResultSet.java @@ -90,6 +90,8 @@ public boolean next() throws SpannerException { boolean hasNext = currRow.consumeRow(iterator); if (!hasNext) { statistics = iterator.getStats(); + // Close the ResultSet when there is no more data. + close(); } return hasNext; } catch (Throwable t) { @@ -113,9 +115,14 @@ public ResultSetMetadata getMetadata() { @Override public void close() { + synchronized (this) { + if (closed) { + return; + } + closed = true; + } listener.onDone(iterator.isWithBeginTransaction()); iterator.close("ResultSet closed"); - closed = true; } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClient.java new file mode 100644 index 00000000000..e742481be2c --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClient.java @@ -0,0 +1,458 @@ +/* + * Copyright 2024 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; + +import static com.google.cloud.spanner.SessionImpl.NO_CHANNEL_HINT; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.cloud.spanner.SessionClient.SessionConsumer; +import com.google.cloud.spanner.SpannerException.ResourceNotFoundException; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.util.BitSet; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +/** + * {@link DatabaseClient} implementation that uses a single multiplexed session to execute + * transactions. + */ +final class MultiplexedSessionDatabaseClient extends AbstractMultiplexedSessionDatabaseClient { + + /** + * Represents a single transaction on a multiplexed session. This can be both a single-use or + * multi-use transaction, and both read/write or read-only transaction. This can be compared to a + * 'checked out session' of a pool, except as multiplexed sessions support multiple parallel + * transactions, we do not need to actually check out and exclusively reserve a single session for + * a transaction. This class therefore only contains context information about the current + * transaction, such as the current span, and a reference to the multiplexed session that is used + * for the transaction. + */ + static class MultiplexedSessionTransaction extends SessionImpl { + private final MultiplexedSessionDatabaseClient client; + + private final boolean singleUse; + + private final int singleUseChannelHint; + + private boolean done; + + MultiplexedSessionTransaction( + MultiplexedSessionDatabaseClient client, + ISpan span, + SessionReference sessionReference, + int singleUseChannelHint, + boolean singleUse) { + super(client.sessionClient.getSpanner(), sessionReference, singleUseChannelHint); + this.client = client; + this.singleUse = singleUse; + this.singleUseChannelHint = singleUseChannelHint; + this.client.numSessionsAcquired.incrementAndGet(); + setCurrentSpan(span); + } + + @Override + void onError(SpannerException spannerException) { + if (this.client.resourceNotFoundException.get() == null + && (spannerException instanceof DatabaseNotFoundException + || spannerException instanceof InstanceNotFoundException + || spannerException instanceof SessionNotFoundException)) { + // This could in theory set this field more than once, but we don't want to bother with + // synchronizing, as it does not really matter exactly which error is set. + this.client.resourceNotFoundException.set((ResourceNotFoundException) spannerException); + } + } + + @Override + void onReadDone() { + // This method is called whenever a ResultSet that was returned by this transaction is closed. + // Close the active transaction if this is a single-use transaction. This ensures that the + // active span is ended. + if (this.singleUse && getActiveTransaction() != null) { + getActiveTransaction().close(); + setActive(null); + if (this.singleUseChannelHint != NO_CHANNEL_HINT) { + this.client.channelUsage.clear(this.singleUseChannelHint); + } + this.client.numCurrentSingleUseTransactions.decrementAndGet(); + } + } + + @Override + void onTransactionDone() { + boolean markedDone = false; + synchronized (this) { + if (!this.done) { + this.done = true; + markedDone = true; + } + } + if (markedDone) { + client.numSessionsReleased.incrementAndGet(); + } + } + + @Override + public void close() { + // no-op, we don't want to delete the multiplexed session. + } + } + + /** + * Keeps track of which channels have been 'given' to single-use transactions for a given Spanner + * instance. + */ + private static final Map CHANNEL_USAGE = new HashMap<>(); + + private final BitSet channelUsage; + + private final int numChannels; + + /** + * The number of single-use read-only transactions currently running on this multiplexed session. + */ + private final AtomicInteger numCurrentSingleUseTransactions = new AtomicInteger(); + + private boolean isClosed; + + /** The duration before we try to replace the multiplexed session. The default is 7 days. */ + private final Duration sessionExpirationDuration; + + private final SessionClient sessionClient; + + private final TraceWrapper tracer; + + /** The current multiplexed session that is used by this client. */ + private final AtomicReference> multiplexedSessionReference; + + /** The expiration date/time of the current multiplexed session. */ + private final AtomicReference expirationDate; + + /** + * The maintainer runs every 10 minutes to check whether the multiplexed session should be + * refreshed. + */ + private final MultiplexedSessionMaintainer maintainer; + + /** + * If a {@link DatabaseNotFoundException} or {@link InstanceNotFoundException} is returned by the + * server, then we set this field to mark the client as invalid. + */ + private final AtomicReference resourceNotFoundException = + new AtomicReference<>(); + + private final AtomicLong numSessionsAcquired = new AtomicLong(); + + private final AtomicLong numSessionsReleased = new AtomicLong(); + + /** + * This flag is set to true if the server return UNIMPLEMENTED when we try to create a multiplexed + * session. TODO: Remove once this is guaranteed to be available. + */ + private final AtomicBoolean unimplemented = new AtomicBoolean(false); + + MultiplexedSessionDatabaseClient(SessionClient sessionClient) { + this(sessionClient, Clock.systemUTC()); + } + + @VisibleForTesting + MultiplexedSessionDatabaseClient(SessionClient sessionClient, Clock clock) { + this.numChannels = sessionClient.getSpanner().getOptions().getNumChannels(); + synchronized (CHANNEL_USAGE) { + CHANNEL_USAGE.putIfAbsent(sessionClient.getSpanner(), new BitSet(numChannels)); + this.channelUsage = CHANNEL_USAGE.get(sessionClient.getSpanner()); + } + this.sessionExpirationDuration = + Duration.ofMillis( + sessionClient + .getSpanner() + .getOptions() + .getSessionPoolOptions() + .getMultiplexedSessionMaintenanceDuration() + .toMillis()); + // Initialize the expiration date to the current time + 7 days to avoid unnecessary null checks. + // The time difference with the actual creation is small enough that it does not matter. + this.expirationDate = new AtomicReference<>(Instant.now().plus(this.sessionExpirationDuration)); + this.sessionClient = sessionClient; + this.maintainer = new MultiplexedSessionMaintainer(clock); + this.tracer = sessionClient.getSpanner().getTracer(); + final SettableApiFuture initialSessionReferenceFuture = + SettableApiFuture.create(); + this.multiplexedSessionReference = new AtomicReference<>(initialSessionReferenceFuture); + this.sessionClient.asyncCreateMultiplexedSession( + new SessionConsumer() { + @Override + public void onSessionReady(SessionImpl session) { + initialSessionReferenceFuture.set(session.getSessionReference()); + // only start the maintainer if we actually managed to create a session in the first + // place. + maintainer.start(); + } + + @Override + public void onSessionCreateFailure(Throwable t, int createFailureForSessionCount) { + // Mark multiplexes sessions as unimplemented and fall back to regular sessions if + // UNIMPLEMENTED is returned. + maybeMarkUnimplemented(t); + initialSessionReferenceFuture.setException(t); + } + }); + maybeWaitForSessionCreation( + sessionClient.getSpanner().getOptions().getSessionPoolOptions(), + initialSessionReferenceFuture); + } + + private static void maybeWaitForSessionCreation( + SessionPoolOptions sessionPoolOptions, ApiFuture future) { + org.threeten.bp.Duration waitDuration = sessionPoolOptions.getWaitForMinSessions(); + if (waitDuration != null && !waitDuration.isZero()) { + long timeoutMillis = waitDuration.toMillis(); + try { + future.get(timeoutMillis, TimeUnit.MILLISECONDS); + } catch (ExecutionException executionException) { + throw SpannerExceptionFactory.asSpannerException(executionException.getCause()); + } catch (InterruptedException interruptedException) { + throw SpannerExceptionFactory.propagateInterrupt(interruptedException); + } catch (TimeoutException timeoutException) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.DEADLINE_EXCEEDED, + "Timed out after waiting " + timeoutMillis + "ms for multiplexed session creation"); + } + } + } + + private void maybeMarkUnimplemented(Throwable t) { + SpannerException spannerException = SpannerExceptionFactory.asSpannerException(t); + if (spannerException.getErrorCode() == ErrorCode.UNIMPLEMENTED) { + unimplemented.set(true); + } + } + + boolean isValid() { + return resourceNotFoundException.get() == null; + } + + AtomicLong getNumSessionsAcquired() { + return this.numSessionsAcquired; + } + + AtomicLong getNumSessionsReleased() { + return this.numSessionsReleased; + } + + boolean isMultiplexedSessionsSupported() { + return !this.unimplemented.get(); + } + + void close() { + synchronized (this) { + if (!this.isClosed) { + this.isClosed = true; + this.maintainer.stop(); + } + } + } + + @VisibleForTesting + MultiplexedSessionMaintainer getMaintainer() { + return this.maintainer; + } + + @VisibleForTesting + SessionReference getCurrentSessionReference() { + try { + return this.multiplexedSessionReference.get().get(); + } catch (ExecutionException executionException) { + throw SpannerExceptionFactory.asSpannerException(executionException.getCause()); + } catch (InterruptedException interruptedException) { + throw SpannerExceptionFactory.propagateInterrupt(interruptedException); + } + } + + /** + * Returns true if the multiplexed session has been created. This client can be used before the + * session has been created, and will in that case use a delayed transaction that contains a + * future reference to the multiplexed session. The delayed transaction will block at the first + * actual statement that is being executed (e.g. the first query that is sent to Spanner). + */ + private boolean isMultiplexedSessionCreated() { + return multiplexedSessionReference.get().isDone(); + } + + private DatabaseClient createMultiplexedSessionTransaction(boolean singleUse) { + Preconditions.checkState(!isClosed, "This client has been closed"); + return isMultiplexedSessionCreated() + ? createDirectMultiplexedSessionTransaction(singleUse) + : createDelayedMultiplexSessionTransaction(); + } + + private MultiplexedSessionTransaction createDirectMultiplexedSessionTransaction( + boolean singleUse) { + try { + return new MultiplexedSessionTransaction( + this, + tracer.getCurrentSpan(), + // Getting the result of the SettableApiFuture that contains the multiplexed session will + // also automatically propagate any error that happened during the creation of the + // session, such as for example a DatabaseNotFound exception. We therefore do not need + // any special handling of such errors. + multiplexedSessionReference.get().get(), + singleUse ? getSingleUseChannelHint() : NO_CHANNEL_HINT, + singleUse); + } catch (ExecutionException executionException) { + throw SpannerExceptionFactory.asSpannerException(executionException.getCause()); + } catch (InterruptedException interruptedException) { + throw SpannerExceptionFactory.propagateInterrupt(interruptedException); + } + } + + private DelayedMultiplexedSessionTransaction createDelayedMultiplexSessionTransaction() { + return new DelayedMultiplexedSessionTransaction( + this, tracer.getCurrentSpan(), multiplexedSessionReference.get()); + } + + private int getSingleUseChannelHint() { + if (this.numCurrentSingleUseTransactions.incrementAndGet() > this.numChannels) { + return NO_CHANNEL_HINT; + } + synchronized (this.channelUsage) { + // Get the first unused channel. + int channel = this.channelUsage.nextClearBit(/* fromIndex = */ 0); + // BitSet returns an index larger than its original size if all the bits are set. + // This then means that all channels have already been assigned to single-use transactions, + // and that we should not use a specific channel, but rather pick a random one. + if (channel == this.numChannels) { + return NO_CHANNEL_HINT; + } + this.channelUsage.set(channel); + return channel; + } + } + + @Override + public ReadContext singleUse() { + return createMultiplexedSessionTransaction(true).singleUse(); + } + + @Override + public ReadContext singleUse(TimestampBound bound) { + return createMultiplexedSessionTransaction(true).singleUse(bound); + } + + @Override + public ReadOnlyTransaction singleUseReadOnlyTransaction() { + return createMultiplexedSessionTransaction(true).singleUseReadOnlyTransaction(); + } + + @Override + public ReadOnlyTransaction singleUseReadOnlyTransaction(TimestampBound bound) { + return createMultiplexedSessionTransaction(true).singleUseReadOnlyTransaction(bound); + } + + @Override + public ReadOnlyTransaction readOnlyTransaction() { + return createMultiplexedSessionTransaction(false).readOnlyTransaction(); + } + + @Override + public ReadOnlyTransaction readOnlyTransaction(TimestampBound bound) { + return createMultiplexedSessionTransaction(false).readOnlyTransaction(bound); + } + + /** + * It is enough with one executor to maintain the multiplexed sessions in all the clients, as they + * do not need to be updated often, and the maintenance task is light. + */ + private static final ScheduledExecutorService MAINTAINER_SERVICE = + Executors.newScheduledThreadPool( + /* corePoolSize = */ 0, + ThreadFactoryUtil.createVirtualOrPlatformDaemonThreadFactory( + "multiplexed-session-maintainer", /* tryVirtual = */ false)); + + final class MultiplexedSessionMaintainer { + private final Clock clock; + + private ScheduledFuture scheduledFuture; + + MultiplexedSessionMaintainer(Clock clock) { + this.clock = clock; + } + + void start() { + // Schedule the maintainer to run once every ten minutes (by default). + long loopFrequencyMillis = + MultiplexedSessionDatabaseClient.this + .sessionClient + .getSpanner() + .getOptions() + .getSessionPoolOptions() + .getMultiplexedSessionMaintenanceLoopFrequency() + .toMillis(); + this.scheduledFuture = + MAINTAINER_SERVICE.scheduleAtFixedRate( + this::maintain, loopFrequencyMillis, loopFrequencyMillis, TimeUnit.MILLISECONDS); + } + + void stop() { + if (this.scheduledFuture != null) { + this.scheduledFuture.cancel(false); + } + } + + void maintain() { + if (clock.instant().isAfter(expirationDate.get())) { + sessionClient.asyncCreateMultiplexedSession( + new SessionConsumer() { + @Override + public void onSessionReady(SessionImpl session) { + multiplexedSessionReference.set( + ApiFutures.immediateFuture(session.getSessionReference())); + expirationDate.set( + clock + .instant() + .plus(MultiplexedSessionDatabaseClient.this.sessionExpirationDuration)); + } + + @Override + public void onSessionCreateFailure(Throwable t, int createFailureForSessionCount) { + // ignore any errors during re-creation of the multiplexed session. This means that + // we continue to use the session that has passed its expiration date for now, and + // that a new attempt at creating a new session will be done in 10 minutes from now. + // The only exception to this rule is if the server returns UNIMPLEMENTED. In that + // case we invalidate the client and fall back to regular sessions. + maybeMarkUnimplemented(t); + } + }); + } + } + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDmlTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDmlTransaction.java index d498bb232a1..949265ea28a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDmlTransaction.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDmlTransaction.java @@ -142,6 +142,10 @@ public void invalidate() { @Override public void setSpan(ISpan span) {} + /** No-op method needed to implement SessionTransaction interface. */ + @Override + public void close() {} + private Duration tryUpdateTimeout(final Duration timeout, final Stopwatch stopwatch) { final Duration remainingTimeout = timeout.minus(stopwatch.elapsed(TimeUnit.MILLISECONDS), ChronoUnit.MILLIS); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java index 8d7dcb34756..ab985cebf45 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner; +import static com.google.cloud.spanner.SessionClient.optionMap; import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException; import com.google.api.core.ApiFuture; @@ -27,6 +28,7 @@ import com.google.cloud.spanner.AbstractReadContext.SingleUseReadOnlyTransaction; import com.google.cloud.spanner.Options.TransactionOption; import com.google.cloud.spanner.Options.UpdateOption; +import com.google.cloud.spanner.SessionClient.SessionOption; import com.google.cloud.spanner.TransactionRunnerImpl.TransactionContextImpl; import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.common.base.Ticker; @@ -92,19 +94,38 @@ interface SessionTransaction { /** Registers the current span on the transaction. */ void setSpan(ISpan span); + + /** Closes the transaction. */ + void close(); } + static final int NO_CHANNEL_HINT = -1; + private final SpannerImpl spanner; private final SessionReference sessionReference; private SessionTransaction activeTransaction; private ISpan currentSpan; private final Clock clock; + private final Map options; SessionImpl(SpannerImpl spanner, SessionReference sessionReference) { + this(spanner, sessionReference, NO_CHANNEL_HINT); + } + + SessionImpl(SpannerImpl spanner, SessionReference sessionReference, int channelHint) { this.spanner = spanner; this.tracer = spanner.getTracer(); this.sessionReference = sessionReference; this.clock = spanner.getOptions().getSessionPoolOptions().getPoolMaintainerClock(); + this.options = createOptions(sessionReference, channelHint); + } + + static Map createOptions( + SessionReference sessionReference, int channelHint) { + if (channelHint == NO_CHANNEL_HINT) { + return sessionReference.getOptions(); + } + return optionMap(SessionOption.channelHint(channelHint)); } @Override @@ -113,7 +134,7 @@ public String getName() { } Map getOptions() { - return sessionReference.getOptions(); + return options; } void setCurrentSpan(ISpan span) { @@ -440,6 +461,10 @@ TransactionContextImpl newTransaction(Options options) { .build(); } + SessionTransaction getActiveTransaction() { + return this.activeTransaction; + } + T setActive(@Nullable T ctx) { throwIfTransactionsPending(); // multiplexed sessions support running concurrent transactions @@ -455,6 +480,12 @@ T setActive(@Nullable T ctx) { return ctx; } + void onError(SpannerException spannerException) {} + + void onReadDone() {} + + void onTransactionDone() {} + TraceWrapper getTracer() { return tracer; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java index 587e7763eee..f36da57a816 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java @@ -68,7 +68,6 @@ import com.google.common.base.Function; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; -import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ForwardingListenableFuture; import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; @@ -88,6 +87,8 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.metrics.Meter; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; @@ -144,7 +145,7 @@ void maybeWaitOnMinSessions() { "Timed out after waiting " + timeoutMillis + "ms for session pool creation"); } - if (options.getUseMultiplexedSession() + if (useMultiplexedSessions() && !waitOnMultiplexedSessionsLatch.await(timeoutNanos, TimeUnit.NANOSECONDS)) { final long timeoutMillis = options.getWaitForMinSessions().toMillis(); throw SpannerExceptionFactory.newSpannerException( @@ -156,7 +157,8 @@ void maybeWaitOnMinSessions() { } } - private abstract static class CachedResultSetSupplier implements Supplier { + private abstract static class CachedResultSetSupplier + implements com.google.common.base.Supplier { private ResultSet cached; @@ -577,6 +579,7 @@ public PooledSessionFuture replaceSession( numSessionsInUse--; numSessionsReleased++; checkedOutSessions.remove(session); + markedCheckedOutSessions.remove(session); } session.leakedException = null; invalidateSession(session.get()); @@ -1333,6 +1336,9 @@ void clearLeakedException() { private void markCheckedOut() { if (options.isTrackStackTraceOfSessionCheckout()) { this.leakedException = new LeakedSessionException(); + synchronized (SessionPool.this.lock) { + SessionPool.this.markedCheckedOutSessions.add(this); + } } } @@ -1526,6 +1532,7 @@ public ApiFuture asyncClose() { synchronized (lock) { leakedException = null; checkedOutSessions.remove(this); + markedCheckedOutSessions.remove(this); } } return ApiFutures.immediateFuture(Empty.getDefaultInstance()); @@ -1835,7 +1842,7 @@ interface CachedSession extends Session { class PooledSession implements CachedSession { - @VisibleForTesting SessionImpl delegate; + @VisibleForTesting final SessionImpl delegate; private volatile SpannerException lastException; private volatile boolean allowReplacing = true; @@ -1872,7 +1879,7 @@ class PooledSession implements CachedSession { private SessionState state; private PooledSession(SessionImpl delegate) { - this.delegate = delegate; + this.delegate = Preconditions.checkNotNull(delegate); this.state = SessionState.AVAILABLE; // initialise the lastUseTime field for each session. @@ -2265,7 +2272,6 @@ public String getName() { @Override public void close() { synchronized (lock) { - numMultiplexedSessionsReleased++; if (lastException != null && isDatabaseOrInstanceNotFound(lastException)) { SessionPool.this.resourceNotFoundException = MoreObjects.firstNonNull( @@ -2348,7 +2354,8 @@ private PooledSession pollUninterruptiblyWithTimeout( "Timed out after waiting " + acquireSessionTimeout.toMillis() + "ms for acquiring session. To mitigate error SessionPoolOptions#setAcquireSessionTimeout(Duration) to set a higher timeout" - + " or increase the number of sessions in the session pool."); + + " or increase the number of sessions in the session pool.\n" + + createCheckedOutSessionsStackTraces()); if (waiter.setException(exception)) { // Only throw the exception if setting it on the waiter was successful. The // waiter.setException(..) method returns false if some other thread in the meantime @@ -2648,7 +2655,7 @@ private void removeLongRunningSessions( void maintainMultiplexedSession(Instant currentTime) { try { - if (options.getUseMultiplexedSession()) { + if (useMultiplexedSessions()) { if (currentMultiplexedSessionReference.get().isDone()) { SessionReference sessionReference = getMultiplexedSessionInstance(); if (sessionReference != null @@ -2771,15 +2778,9 @@ enum Position { @GuardedBy("lock") private long numSessionsAcquired = 0; - @GuardedBy("lock") - private long numMultiplexedSessionsAcquired = 0; - @GuardedBy("lock") private long numSessionsReleased = 0; - @GuardedBy("lock") - private long numMultiplexedSessionsReleased = 0; - @GuardedBy("lock") private long numIdleSessionsRemoved = 0; @@ -2801,6 +2802,9 @@ enum Position { @VisibleForTesting final Set checkedOutSessions = new HashSet<>(); + @GuardedBy("lock") + private final Set markedCheckedOutSessions = new HashSet<>(); + private final SessionConsumer sessionConsumer = new SessionConsumerImpl(); private final MultiplexedSessionInitializationConsumer multiplexedSessionInitializationConsumer = @@ -2830,7 +2834,9 @@ static SessionPool createPool( SessionClient sessionClient, TraceWrapper tracer, List labelValues, - Attributes attributes) { + Attributes attributes, + AtomicLong numMultiplexedSessionsAcquired, + AtomicLong numMultiplexedSessionsReleased) { final SessionPoolOptions sessionPoolOptions = spannerOptions.getSessionPoolOptions(); // A clock instance is passed in {@code SessionPoolOptions} in order to allow mocking via tests. @@ -2846,7 +2852,9 @@ static SessionPool createPool( tracer, labelValues, spannerOptions.getOpenTelemetry(), - attributes); + attributes, + numMultiplexedSessionsAcquired, + numMultiplexedSessionsReleased); } static SessionPool createPool( @@ -2884,7 +2892,9 @@ static SessionPool createPool( tracer, SPANNER_DEFAULT_LABEL_VALUES, openTelemetry, - null); + null, + new AtomicLong(), + new AtomicLong()); } static SessionPool createPool( @@ -2898,7 +2908,9 @@ static SessionPool createPool( TraceWrapper tracer, List labelValues, OpenTelemetry openTelemetry, - Attributes attributes) { + Attributes attributes, + AtomicLong numMultiplexedSessionsAcquired, + AtomicLong numMultiplexedSessionsReleased) { SessionPool pool = new SessionPool( poolOptions, @@ -2912,7 +2924,9 @@ static SessionPool createPool( tracer, labelValues, openTelemetry, - attributes); + attributes, + numMultiplexedSessionsAcquired, + numMultiplexedSessionsReleased); pool.initPool(); return pool; } @@ -2929,7 +2943,9 @@ private SessionPool( TraceWrapper tracer, List labelValues, OpenTelemetry openTelemetry, - Attributes attributes) { + Attributes attributes, + AtomicLong numMultiplexedSessionsAcquired, + AtomicLong numMultiplexedSessionsReleased) { this.options = options; this.databaseRole = databaseRole; this.executorFactory = executorFactory; @@ -2940,13 +2956,24 @@ private SessionPool( this.initialReleasePosition = initialReleasePosition; this.poolMaintainer = new PoolMaintainer(); this.tracer = tracer; - this.initOpenCensusMetricsCollection(metricRegistry, labelValues); - this.initOpenTelemetryMetricsCollection(openTelemetry, attributes); + this.initOpenCensusMetricsCollection( + metricRegistry, + labelValues, + numMultiplexedSessionsAcquired, + numMultiplexedSessionsReleased); + this.initOpenTelemetryMetricsCollection( + openTelemetry, attributes, numMultiplexedSessionsAcquired, numMultiplexedSessionsReleased); this.waitOnMinSessionsLatch = options.getMinSessions() > 0 ? new CountDownLatch(1) : new CountDownLatch(0); this.waitOnMultiplexedSessionsLatch = new CountDownLatch(1); } + // TODO: Remove once all code for multiplexed sessions has been removed from the pool. + private boolean useMultiplexedSessions() { + // Multiplexed sessions have moved to MultiplexedSessionDatabaseClient + return false; + } + /** * @return the {@link Dialect} of the underlying database. This method will block until the * dialect is available. It will potentially execute one or two RPCs to get the dialect if @@ -2996,6 +3023,13 @@ int getNumberOfSessionsInUse() { } } + @VisibleForTesting + int getMaxSessionsInUse() { + synchronized (lock) { + return maxSessionsInUse; + } + } + @VisibleForTesting double getRatioOfSessionsInUse() { synchronized (lock) { @@ -3071,7 +3105,7 @@ private void initPool() { if (options.getMinSessions() > 0) { createSessions(options.getMinSessions(), true); } - if (options.getUseMultiplexedSession()) { + if (useMultiplexedSessions()) { maybeCreateMultiplexedSession(multiplexedSessionInitializationConsumer); } } @@ -3137,10 +3171,10 @@ boolean isValid() { /** * Returns a multiplexed session. The method fallbacks to a regular session if {@link - * SessionPoolOptions#useMultiplexedSession} is not set. + * SessionPoolOptions#getUseMultiplexedSession} is not set. */ SessionFutureWrapper getMultiplexedSessionWithFallback() throws SpannerException { - if (options.getUseMultiplexedSession()) { + if (useMultiplexedSessions()) { ISpan span = tracer.getCurrentSpan(); try { return getWrappedMultiplexedSessionFuture(span); @@ -3244,30 +3278,60 @@ private void incrementNumSessionsInUse(boolean isMultiplexed) { maxSessionsInUse = numSessionsInUse; } numSessionsAcquired++; - } else { - numMultiplexedSessionsAcquired++; } } } private void maybeCreateSession() { ISpan span = tracer.getCurrentSpan(); + boolean throwResourceExhaustedException = false; synchronized (lock) { if (numWaiters() >= numSessionsBeingCreated) { if (canCreateSession()) { span.addAnnotation("Creating sessions"); createSessions(getAllowedCreateSessions(options.getIncStep()), false); } else if (options.isFailIfPoolExhausted()) { - span.addAnnotation("Pool exhausted. Failing"); - // throw specific exception - throw newSpannerException( - ErrorCode.RESOURCE_EXHAUSTED, - "No session available in the pool. Maximum number of sessions in the pool can be" - + " overridden by invoking SessionPoolOptions#Builder#setMaxSessions. Client can be made to block" - + " rather than fail by setting SessionPoolOptions#Builder#setBlockIfPoolExhausted."); + throwResourceExhaustedException = true; } } } + if (!throwResourceExhaustedException) { + return; + } + span.addAnnotation("Pool exhausted. Failing"); + + String message = + "No session available in the pool. Maximum number of sessions in the pool can be" + + " overridden by invoking SessionPoolOptions#Builder#setMaxSessions. Client can be made to block" + + " rather than fail by setting SessionPoolOptions#Builder#setBlockIfPoolExhausted.\n" + + createCheckedOutSessionsStackTraces(); + throw newSpannerException(ErrorCode.RESOURCE_EXHAUSTED, message); + } + + private StringBuilder createCheckedOutSessionsStackTraces() { + List currentlyCheckedOutSessions; + synchronized (lock) { + currentlyCheckedOutSessions = new ArrayList<>(this.markedCheckedOutSessions); + } + + // Create the error message without holding the lock, as we are potentially looping through a + // large set, and analyzing a large number of stack traces. + StringBuilder stackTraces = + new StringBuilder( + "There are currently " + + currentlyCheckedOutSessions.size() + + " sessions checked out:\n\n"); + if (options.isTrackStackTraceOfSessionCheckout()) { + for (PooledSessionFuture session : currentlyCheckedOutSessions) { + if (session.leakedException != null) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + session.leakedException.printStackTrace(printWriter); + stackTraces.append(writer).append("\n\n"); + } + } + } + return stackTraces; } private void releaseSession(Tuple sessionWithPosition) { @@ -3752,6 +3816,10 @@ public void onSessionReady(SessionImpl session) { public void onSessionCreateFailure(Throwable t, int createFailureForSessionCount) { synchronized (lock) { numSessionsBeingCreated -= createFailureForSessionCount; + if (numSessionsBeingCreated == 0) { + // Don't continue to block if no more sessions are being created. + waitOnMinSessionsLatch.countDown(); + } if (isClosed()) { decrementPendingClosures(createFailureForSessionCount); } @@ -3765,7 +3833,10 @@ public void onSessionCreateFailure(Throwable t, int createFailureForSessionCount * exporter, it allows users to monitor client behavior. */ private void initOpenCensusMetricsCollection( - MetricRegistry metricRegistry, List labelValues) { + MetricRegistry metricRegistry, + List labelValues, + AtomicLong numMultiplexedSessionsAcquired, + AtomicLong numMultiplexedSessionsReleased) { if (!SpannerOptions.isEnabledOpenCensusMetrics()) { return; } @@ -3850,18 +3921,14 @@ private void initOpenCensusMetricsCollection( labelValuesWithRegularSessions, this, sessionPool -> sessionPool.numSessionsAcquired); numAcquiredSessionsMetric.removeTimeSeries(labelValuesWithMultiplexedSessions); numAcquiredSessionsMetric.createTimeSeries( - labelValuesWithMultiplexedSessions, - this, - sessionPool -> sessionPool.numMultiplexedSessionsAcquired); + labelValuesWithMultiplexedSessions, this, unused -> numMultiplexedSessionsAcquired.get()); numReleasedSessionsMetric.removeTimeSeries(labelValuesWithRegularSessions); numReleasedSessionsMetric.createTimeSeries( labelValuesWithRegularSessions, this, sessionPool -> sessionPool.numSessionsReleased); numReleasedSessionsMetric.removeTimeSeries(labelValuesWithMultiplexedSessions); numReleasedSessionsMetric.createTimeSeries( - labelValuesWithMultiplexedSessions, - this, - sessionPool -> sessionPool.numMultiplexedSessionsReleased); + labelValuesWithMultiplexedSessions, this, unused -> numMultiplexedSessionsReleased.get()); List labelValuesWithBeingPreparedType = new ArrayList<>(labelValues); labelValuesWithBeingPreparedType.add(NUM_SESSIONS_BEING_PREPARED); @@ -3899,7 +3966,10 @@ private void initOpenCensusMetricsCollection( * an exporter, it allows users to monitor client behavior. */ private void initOpenTelemetryMetricsCollection( - OpenTelemetry openTelemetry, Attributes attributes) { + OpenTelemetry openTelemetry, + Attributes attributes, + AtomicLong numMultiplexedSessionsAcquired, + AtomicLong numMultiplexedSessionsReleased) { if (openTelemetry == null || !SpannerOptions.isEnabledOpenTelemetryMetrics()) { return; } @@ -3971,7 +4041,8 @@ private void initOpenTelemetryMetricsCollection( .buildWithCallback( measurement -> { measurement.record(this.numSessionsAcquired, attributesRegularSession); - measurement.record(this.numMultiplexedSessionsAcquired, attributesMultiplexedSession); + measurement.record( + numMultiplexedSessionsAcquired.get(), attributesMultiplexedSession); }); meter @@ -3981,7 +4052,8 @@ private void initOpenTelemetryMetricsCollection( .buildWithCallback( measurement -> { measurement.record(this.numSessionsReleased, attributesRegularSession); - measurement.record(this.numMultiplexedSessionsReleased, attributesMultiplexedSession); + measurement.record( + numMultiplexedSessionsReleased.get(), attributesMultiplexedSession); }); } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java index 4a048af52c0..382bef1b5a2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java @@ -49,6 +49,7 @@ public class SessionPoolOptions { private final ActionOnExhaustion actionOnExhaustion; private final long loopFrequency; + private final java.time.Duration multiplexedSessionMaintenanceLoopFrequency; private final int keepAliveIntervalMinutes; private final Duration removeInactiveSessionAfter; private final ActionOnSessionNotFound actionOnSessionNotFound; @@ -72,6 +73,10 @@ public class SessionPoolOptions { private final Clock poolMaintainerClock; private final boolean useMultiplexedSession; + + private final boolean useRandomChannelHint; + + // TODO: Change to use java.time.Duration. private final Duration multiplexedSessionMaintenanceDuration; private SessionPoolOptions(Builder builder) { @@ -89,6 +94,8 @@ private SessionPoolOptions(Builder builder) { this.trackStackTraceOfSessionCheckout = builder.trackStackTraceOfSessionCheckout; this.initialWaitForSessionTimeoutMillis = builder.initialWaitForSessionTimeoutMillis; this.loopFrequency = builder.loopFrequency; + this.multiplexedSessionMaintenanceLoopFrequency = + builder.multiplexedSessionMaintenanceLoopFrequency; this.keepAliveIntervalMinutes = builder.keepAliveIntervalMinutes; this.removeInactiveSessionAfter = builder.removeInactiveSessionAfter; this.autoDetectDialect = builder.autoDetectDialect; @@ -98,7 +105,12 @@ private SessionPoolOptions(Builder builder) { this.randomizePositionQPSThreshold = builder.randomizePositionQPSThreshold; this.inactiveTransactionRemovalOptions = builder.inactiveTransactionRemovalOptions; this.poolMaintainerClock = builder.poolMaintainerClock; - this.useMultiplexedSession = builder.useMultiplexedSession; + // TODO: Remove when multiplexed sessions are guaranteed to be supported. + this.useMultiplexedSession = + builder.useMultiplexedSession + && !Boolean.parseBoolean( + System.getenv("GOOGLE_CLOUD_SPANNER_FORCE_DISABLE_MULTIPLEXED_SESSIONS")); + this.useRandomChannelHint = builder.useRandomChannelHint; this.multiplexedSessionMaintenanceDuration = builder.multiplexedSessionMaintenanceDuration; } @@ -121,6 +133,9 @@ public boolean equals(Object o) { && Objects.equals( this.initialWaitForSessionTimeoutMillis, other.initialWaitForSessionTimeoutMillis) && Objects.equals(this.loopFrequency, other.loopFrequency) + && Objects.equals( + this.multiplexedSessionMaintenanceLoopFrequency, + other.multiplexedSessionMaintenanceLoopFrequency) && Objects.equals(this.keepAliveIntervalMinutes, other.keepAliveIntervalMinutes) && Objects.equals(this.removeInactiveSessionAfter, other.removeInactiveSessionAfter) && Objects.equals(this.autoDetectDialect, other.autoDetectDialect) @@ -132,6 +147,7 @@ public boolean equals(Object o) { this.inactiveTransactionRemovalOptions, other.inactiveTransactionRemovalOptions) && Objects.equals(this.poolMaintainerClock, other.poolMaintainerClock) && Objects.equals(this.useMultiplexedSession, other.useMultiplexedSession) + && Objects.equals(this.useRandomChannelHint, other.useRandomChannelHint) && Objects.equals( this.multiplexedSessionMaintenanceDuration, other.multiplexedSessionMaintenanceDuration); @@ -151,6 +167,7 @@ public int hashCode() { this.trackStackTraceOfSessionCheckout, this.initialWaitForSessionTimeoutMillis, this.loopFrequency, + this.multiplexedSessionMaintenanceLoopFrequency, this.keepAliveIntervalMinutes, this.removeInactiveSessionAfter, this.autoDetectDialect, @@ -161,6 +178,7 @@ public int hashCode() { this.inactiveTransactionRemovalOptions, this.poolMaintainerClock, this.useMultiplexedSession, + this.useRandomChannelHint, this.multiplexedSessionMaintenanceDuration); } @@ -204,6 +222,10 @@ long getLoopFrequency() { return loopFrequency; } + java.time.Duration getMultiplexedSessionMaintenanceLoopFrequency() { + return this.multiplexedSessionMaintenanceLoopFrequency; + } + public int getKeepAliveIntervalMinutes() { return keepAliveIntervalMinutes; } @@ -290,6 +312,10 @@ public boolean getUseMultiplexedSession() { return useMultiplexedSession; } + boolean isUseRandomChannelHint() { + return useRandomChannelHint; + } + Duration getMultiplexedSessionMaintenanceDuration() { return multiplexedSessionMaintenanceDuration; } @@ -476,6 +502,8 @@ public static class Builder { private InactiveTransactionRemovalOptions inactiveTransactionRemovalOptions = InactiveTransactionRemovalOptions.newBuilder().build(); private long loopFrequency = 10 * 1000L; + private java.time.Duration multiplexedSessionMaintenanceLoopFrequency = + java.time.Duration.ofMinutes(10); private int keepAliveIntervalMinutes = 30; private Duration removeInactiveSessionAfter = Duration.ofMinutes(55L); private boolean autoDetectDialect = false; @@ -492,6 +520,8 @@ public static class Builder { private boolean useMultiplexedSession = getUseMultiplexedSessionFromEnvVariable(); + private boolean useRandomChannelHint; + private Duration multiplexedSessionMaintenanceDuration = Duration.ofDays(7); private Clock poolMaintainerClock = Clock.INSTANCE; @@ -535,6 +565,8 @@ private Builder(SessionPoolOptions options) { this.actionOnSessionLeak = options.actionOnSessionLeak; this.trackStackTraceOfSessionCheckout = options.trackStackTraceOfSessionCheckout; this.loopFrequency = options.loopFrequency; + this.multiplexedSessionMaintenanceLoopFrequency = + options.multiplexedSessionMaintenanceLoopFrequency; this.keepAliveIntervalMinutes = options.keepAliveIntervalMinutes; this.removeInactiveSessionAfter = options.removeInactiveSessionAfter; this.autoDetectDialect = options.autoDetectDialect; @@ -599,6 +631,11 @@ Builder setLoopFrequency(long loopFrequency) { return this; } + Builder setMultiplexedSessionMaintenanceLoopFrequency(java.time.Duration frequency) { + this.multiplexedSessionMaintenanceLoopFrequency = frequency; + return this; + } + Builder setInactiveTransactionRemovalOptions( InactiveTransactionRemovalOptions inactiveTransactionRemovalOptions) { this.inactiveTransactionRemovalOptions = inactiveTransactionRemovalOptions; @@ -723,6 +760,11 @@ Builder setUseMultiplexedSession(boolean useMultiplexedSession) { return this; } + Builder setUseRandomChannelHint(boolean useRandomChannelHint) { + this.useRandomChannelHint = useRandomChannelHint; + return this; + } + @VisibleForTesting Builder setMultiplexedSessionMaintenanceDuration( Duration multiplexedSessionMaintenanceDuration) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java index 69c8be9a706..86b5de01c69 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java @@ -50,6 +50,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; @@ -247,7 +248,7 @@ public DatabaseClient getDatabaseClient(DatabaseId db) { synchronized (this) { checkClosed(); String clientId = null; - if (dbClients.containsKey(db) && !dbClients.get(db).pool.isValid()) { + if (dbClients.containsKey(db) && !dbClients.get(db).isValid()) { // Close the invalidated client and remove it. dbClients.get(db).closeAsync(new ClosedException()); clientId = dbClients.get(db).clientId; @@ -271,15 +272,32 @@ public DatabaseClient getDatabaseClient(DatabaseId db) { attributesBuilder.put("database", db.getDatabase()); attributesBuilder.put("instance_id", db.getInstanceId().getName()); + boolean useMultiplexedSession = + getOptions().getSessionPoolOptions().getUseMultiplexedSession(); + MultiplexedSessionDatabaseClient multiplexedSessionDatabaseClient = + useMultiplexedSession + ? new MultiplexedSessionDatabaseClient(SpannerImpl.this.getSessionClient(db)) + : null; + AtomicLong numMultiplexedSessionsAcquired = + useMultiplexedSession + ? multiplexedSessionDatabaseClient.getNumSessionsAcquired() + : new AtomicLong(); + AtomicLong numMultiplexedSessionsReleased = + useMultiplexedSession + ? multiplexedSessionDatabaseClient.getNumSessionsReleased() + : new AtomicLong(); SessionPool pool = SessionPool.createPool( getOptions(), SpannerImpl.this.getSessionClient(db), this.tracer, labelValues, - attributesBuilder.build()); + attributesBuilder.build(), + numMultiplexedSessionsAcquired, + numMultiplexedSessionsReleased); pool.maybeWaitOnMinSessions(); - DatabaseClientImpl dbClient = createDatabaseClient(clientId, pool); + DatabaseClientImpl dbClient = + createDatabaseClient(clientId, pool, multiplexedSessionDatabaseClient); dbClients.put(db, dbClient); return dbClient; } @@ -287,8 +305,11 @@ public DatabaseClient getDatabaseClient(DatabaseId db) { } @VisibleForTesting - DatabaseClientImpl createDatabaseClient(String clientId, SessionPool pool) { - return new DatabaseClientImpl(clientId, pool, tracer); + DatabaseClientImpl createDatabaseClient( + String clientId, + SessionPool pool, + @Nullable MultiplexedSessionDatabaseClient multiplexedSessionClient) { + return new DatabaseClientImpl(clientId, pool, multiplexedSessionClient, tracer); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java index 2d7cf812121..4deeeb92af8 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java @@ -155,12 +155,12 @@ public ApiFuture setCallback(Executor exec, ReadyCallback cb) { @Override public void addListener(Runnable listener) { - ((ListenableAsyncResultSet) this.delegate).addListener(listener); + ((ListenableAsyncResultSet) getDelegate()).addListener(listener); } @Override public void removeListener(Runnable listener) { - ((ListenableAsyncResultSet) this.delegate).removeListener(listener); + ((ListenableAsyncResultSet) getDelegate()).removeListener(listener); } } @@ -601,6 +601,8 @@ String getTransactionTag() { @Override public SpannerException onError(SpannerException e, boolean withBeginTransaction) { + e = super.onError(e, withBeginTransaction); + // If the statement that caused an error was the statement that included a BeginTransaction // option, we simulate an aborted transaction to force a retry of the entire transaction. This // will cause the retry to execute an explicit BeginTransaction RPC and then the actual @@ -1118,4 +1120,7 @@ public CommitResponse getCommitResponse() { public void invalidate() { isValid = false; } + + @Override + public void close() {} } 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 c0859b57903..e1a4415ea49 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 @@ -773,6 +773,12 @@ default boolean isDelayTransactionStartUntilFirstWrite() { /** Sets how savepoints should be supported on this connection. */ void setSavepointSupport(SavepointSupport savepointSupport); + /** Returns the current {@link DdlInTransactionMode} for this connection. */ + DdlInTransactionMode getDdlInTransactionMode(); + + /** Sets how the connection should behave if a DDL statement is executed during a transaction. */ + void setDdlInTransactionMode(DdlInTransactionMode ddlInTransactionMode); + /** * Creates a savepoint with the given name. * 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 d0cb7169793..70e789eb580 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 @@ -243,6 +243,7 @@ static UnitOfWorkType of(TransactionMode transactionMode) { private QueryOptions queryOptions = QueryOptions.getDefaultInstance(); private RpcPriority rpcPriority = null; private SavepointSupport savepointSupport = SavepointSupport.FAIL_AFTER_ROLLBACK; + private DdlInTransactionMode ddlInTransactionMode; private String transactionTag; private String statementTag; @@ -271,6 +272,7 @@ static UnitOfWorkType of(TransactionMode transactionMode) { this.autocommit = options.isAutocommit(); this.queryOptions = this.queryOptions.toBuilder().mergeFrom(options.getQueryOptions()).build(); this.rpcPriority = options.getRPCPriority(); + this.ddlInTransactionMode = options.getDdlInTransactionMode(); this.returnCommitStats = options.isReturnCommitStats(); this.delayTransactionStartUntilFirstWrite = options.isDelayTransactionStartUntilFirstWrite(); this.dataBoostEnabled = options.isDataBoostEnabled(); @@ -296,6 +298,7 @@ static UnitOfWorkType of(TransactionMode transactionMode) { new StatementExecutor(options.isUseVirtualThreads(), Collections.emptyList()); this.spannerPool = Preconditions.checkNotNull(spannerPool); this.options = Preconditions.checkNotNull(options); + this.ddlInTransactionMode = options.getDdlInTransactionMode(); this.spanner = spannerPool.getSpanner(options, this); this.ddlClient = Preconditions.checkNotNull(ddlClient); this.dbClient = Preconditions.checkNotNull(dbClient); @@ -571,6 +574,21 @@ public RpcPriority getRPCPriority() { return this.rpcPriority; } + @Override + public DdlInTransactionMode getDdlInTransactionMode() { + return this.ddlInTransactionMode; + } + + @Override + public void setDdlInTransactionMode(DdlInTransactionMode ddlInTransactionMode) { + ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); + ConnectionPreconditions.checkState( + !isBatchActive(), "Cannot set DdlInTransactionMode while in a batch"); + ConnectionPreconditions.checkState( + !isTransactionStarted(), "Cannot set DdlInTransactionMode while a transaction is active"); + this.ddlInTransactionMode = Preconditions.checkNotNull(ddlInTransactionMode); + } + @Override public void setStatementTimeout(long timeout, TimeUnit unit) { Preconditions.checkArgument(timeout > 0L, "Zero or negative timeout values are not allowed"); @@ -1639,7 +1657,16 @@ private ApiFuture internalExecuteBatchUpdateAsync( } private UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() { - return getCurrentUnitOfWorkOrStartNewUnitOfWork(false); + return getCurrentUnitOfWorkOrStartNewUnitOfWork(StatementType.UNKNOWN, false); + } + + @VisibleForTesting + UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork(boolean isInternalMetadataQuery) { + return getCurrentUnitOfWorkOrStartNewUnitOfWork(StatementType.UNKNOWN, isInternalMetadataQuery); + } + + private UnitOfWork getOrStartDdlUnitOfWork() { + return getCurrentUnitOfWorkOrStartNewUnitOfWork(StatementType.DDL, false); } /** @@ -1647,20 +1674,38 @@ private UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() { * current transaction settings of the connection and returns that. */ @VisibleForTesting - UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork(boolean isInternalMetadataQuery) { + UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork( + StatementType statementType, boolean isInternalMetadataQuery) { if (isInternalMetadataQuery) { // Just return a temporary single-use transaction. - return createNewUnitOfWork(true); + return createNewUnitOfWork(/* isInternalMetadataQuery = */ true, /* forceSingleUse = */ true); } + maybeAutoCommitCurrentTransaction(statementType); if (this.currentUnitOfWork == null || !this.currentUnitOfWork.isActive()) { - this.currentUnitOfWork = createNewUnitOfWork(false); + this.currentUnitOfWork = + createNewUnitOfWork( + /* isInternalMetadataQuery = */ false, + /* forceSingleUse = */ statementType == StatementType.DDL + && this.ddlInTransactionMode != DdlInTransactionMode.FAIL + && !this.transactionBeginMarked); } return this.currentUnitOfWork; } + void maybeAutoCommitCurrentTransaction(StatementType statementType) { + if (this.currentUnitOfWork instanceof ReadWriteTransaction + && this.currentUnitOfWork.isActive() + && statementType == StatementType.DDL + && this.ddlInTransactionMode == DdlInTransactionMode.AUTO_COMMIT_TRANSACTION) { + commit(); + } + } + @VisibleForTesting - UnitOfWork createNewUnitOfWork(boolean isInternalMetadataQuery) { - if (isInternalMetadataQuery || (isAutocommit() && !isInTransaction() && !isInBatch())) { + UnitOfWork createNewUnitOfWork(boolean isInternalMetadataQuery, boolean forceSingleUse) { + if (isInternalMetadataQuery + || (isAutocommit() && !isInTransaction() && !isInBatch()) + || forceSingleUse) { return SingleUseTransaction.newBuilder() .setInternalMetadataQuery(isInternalMetadataQuery) .setDdlClient(ddlClient) @@ -1741,7 +1786,7 @@ private void popUnitOfWorkFromTransactionStack() { } private ApiFuture executeDdlAsync(CallType callType, ParsedStatement ddl) { - return getCurrentUnitOfWorkOrStartNewUnitOfWork().executeDdlAsync(callType, ddl); + return getOrStartDdlUnitOfWork().executeDdlAsync(callType, ddl); } @Override @@ -1788,15 +1833,23 @@ public void startBatchDdl() { ConnectionPreconditions.checkState( !isReadOnly(), "Cannot start a DDL batch when the connection is in read-only mode"); ConnectionPreconditions.checkState( - !isTransactionStarted(), "Cannot start a DDL batch while a transaction is active"); + !isTransactionStarted() + || getDdlInTransactionMode() == DdlInTransactionMode.AUTO_COMMIT_TRANSACTION, + "Cannot start a DDL batch while a transaction is active"); ConnectionPreconditions.checkState( !(isAutocommit() && isInTransaction()), "Cannot start a DDL batch while in a temporary transaction"); ConnectionPreconditions.checkState( !transactionBeginMarked, "Cannot start a DDL batch when a transaction has begun"); + ConnectionPreconditions.checkState( + isAutocommit() || getDdlInTransactionMode() != DdlInTransactionMode.FAIL, + "Cannot start a DDL batch when autocommit=false and ddlInTransactionMode=FAIL"); + + maybeAutoCommitCurrentTransaction(StatementType.DDL); this.batchMode = BatchMode.DDL; this.unitOfWorkType = UnitOfWorkType.DDL_BATCH; - this.currentUnitOfWork = createNewUnitOfWork(false); + this.currentUnitOfWork = + createNewUnitOfWork(/* isInternalMetadataQuery = */ false, /* forceSingleUse = */ false); } @Override @@ -1814,7 +1867,8 @@ public void startBatchDml() { // Then create the DML batch. this.batchMode = BatchMode.DML; this.unitOfWorkType = UnitOfWorkType.DML_BATCH; - this.currentUnitOfWork = createNewUnitOfWork(false); + this.currentUnitOfWork = + createNewUnitOfWork(/* isInternalMetadataQuery = */ false, /* forceSingleUse = */ false); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java index f79a764a94c..59c30789afb 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java @@ -183,6 +183,8 @@ public String[] getValidValues() { private static final String DEFAULT_OPTIMIZER_VERSION = ""; private static final String DEFAULT_OPTIMIZER_STATISTICS_PACKAGE = ""; private static final RpcPriority DEFAULT_RPC_PRIORITY = null; + private static final DdlInTransactionMode DEFAULT_DDL_IN_TRANSACTION_MODE = + DdlInTransactionMode.ALLOW_IN_EMPTY_TRANSACTION; private static final boolean DEFAULT_RETURN_COMMIT_STATS = false; private static final boolean DEFAULT_LENIENT = false; private static final boolean DEFAULT_ROUTE_TO_LEADER = true; @@ -253,6 +255,8 @@ public String[] getValidValues() { public static final String LENIENT_PROPERTY_NAME = "lenient"; /** Name of the 'rpcPriority' connection property. */ public static final String RPC_PRIORITY_NAME = "rpcPriority"; + + public static final String DDL_IN_TRANSACTION_MODE_PROPERTY_NAME = "ddlInTransactionMode"; /** Dialect to use for a connection. */ private static final String DIALECT_PROPERTY_NAME = "dialect"; /** Name of the 'databaseRole' connection property. */ @@ -374,6 +378,11 @@ private static String generateGuardedConnectionPropertyError( ConnectionProperty.createStringProperty( RPC_PRIORITY_NAME, "Sets the priority for all RPC invocations from this connection (HIGH/MEDIUM/LOW). The default is HIGH."), + ConnectionProperty.createStringProperty( + DDL_IN_TRANSACTION_MODE_PROPERTY_NAME, + "Sets the behavior of a connection when a DDL statement is executed in a read/write transaction. The default is " + + DEFAULT_DDL_IN_TRANSACTION_MODE + + "."), ConnectionProperty.createStringProperty( DIALECT_PROPERTY_NAME, "Sets the dialect to use for new databases that are created by this connection."), @@ -697,6 +706,7 @@ public static Builder newBuilder() { private final boolean autoConfigEmulator; private final Dialect dialect; private final RpcPriority rpcPriority; + private final DdlInTransactionMode ddlInTransactionMode; private final boolean delayTransactionStartUntilFirstWrite; private final boolean trackSessionLeaks; private final boolean trackConnectionLeaks; @@ -757,6 +767,7 @@ private ConnectionOptions(Builder builder) { determineHost( matcher, parseEndpoint(this.uri), autoConfigEmulator, usePlainText, System.getenv()); this.rpcPriority = parseRPCPriority(this.uri); + this.ddlInTransactionMode = parseDdlInTransactionMode(this.uri); this.delayTransactionStartUntilFirstWrite = parseDelayTransactionStartUntilFirstWrite(this.uri); this.trackSessionLeaks = parseTrackSessionLeaks(this.uri); this.trackConnectionLeaks = parseTrackConnectionLeaks(this.uri); @@ -1195,6 +1206,14 @@ static RpcPriority parseRPCPriority(String uri) { return value != null ? RpcPriority.valueOf(value) : DEFAULT_RPC_PRIORITY; } + @VisibleForTesting + static DdlInTransactionMode parseDdlInTransactionMode(String uri) { + String value = parseUriProperty(uri, DDL_IN_TRANSACTION_MODE_PROPERTY_NAME); + return value != null + ? DdlInTransactionMode.valueOf(value.toUpperCase()) + : DEFAULT_DDL_IN_TRANSACTION_MODE; + } + @VisibleForTesting static String parseUriProperty(String uri, String property) { Pattern pattern = Pattern.compile(String.format("(?is)(?:;|\\?)%s=(.*?)(?:;|$)", property)); @@ -1466,6 +1485,10 @@ RpcPriority getRPCPriority() { return rpcPriority; } + DdlInTransactionMode getDdlInTransactionMode() { + return this.ddlInTransactionMode; + } + /** * Whether connections created by this {@link ConnectionOptions} should delay the actual start of * a read/write transaction until the first write operation. diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlInTransactionMode.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlInTransactionMode.java new file mode 100644 index 00000000000..16645e929cb --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlInTransactionMode.java @@ -0,0 +1,35 @@ +/* + * Copyright 2024 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; + +/** Enum used for setting the behavior of DDL in read/write transactions. */ +public enum DdlInTransactionMode { + /** All DDL statements in a read/write transaction fail. */ + FAIL, + /** + * DDL statements in an empty transaction are allowed. That is; if the connection is in + * AutoCommit=false mode and no other statement has been executed, then executing a DDL statement + * or a DDL batch is allowed. + */ + ALLOW_IN_EMPTY_TRANSACTION, + /** + * DDL statements automatically cause the current transaction to be committed and the DDL + * statement is subsequently executed without a transaction. This is equal to how MySQL and Oracle + * behave. + */ + AUTO_COMMIT_TRANSACTION; +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementExecutor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementExecutor.java index f3c93c6dd1c..a126bd8ff37 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementExecutor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementExecutor.java @@ -28,6 +28,7 @@ import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.Duration; +import io.opentelemetry.context.Context; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; @@ -147,13 +148,16 @@ org.threeten.bp.Duration asDuration() { /** Creates an {@link ExecutorService} for a {@link StatementExecutor}. */ private static ListeningExecutorService createExecutorService(boolean useVirtualThreads) { return MoreExecutors.listeningDecorator( - new ThreadPoolExecutor( - 1, - 1, - 0L, - TimeUnit.MILLISECONDS, - new LinkedBlockingQueue<>(), - useVirtualThreads ? DEFAULT_VIRTUAL_THREAD_FACTORY : DEFAULT_DAEMON_THREAD_FACTORY)); + Context.taskWrapping( + new ThreadPoolExecutor( + 1, + 1, + 0L, + TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), + useVirtualThreads + ? DEFAULT_VIRTUAL_THREAD_FACTORY + : DEFAULT_DAEMON_THREAD_FACTORY))); } private final ListeningExecutorService executor; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncRunnerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncRunnerTest.java index 07f7967c2aa..a209ff07112 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncRunnerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncRunnerTest.java @@ -261,12 +261,11 @@ public void asyncRunnerWaitsUntilAsyncUpdateHasFinished() throws Exception { executor); res.get(); if (isMultiplexedSessionsEnabled()) { + // The mock server could have received a CreateSession request for a multiplexed session, but + // it could also be that that request has not yet reached the server. assertThat(mockSpanner.getRequestTypes()) - .containsExactly( - CreateSessionRequest.class, - BatchCreateSessionsRequest.class, - ExecuteSqlRequest.class, - CommitRequest.class); + .containsAtLeast( + BatchCreateSessionsRequest.class, ExecuteSqlRequest.class, CommitRequest.class); } else { assertThat(mockSpanner.getRequestTypes()) .containsExactly( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java index 09d14cee3bf..e96ea3a6a4b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java @@ -898,49 +898,29 @@ public void asyncTransactionManagerBatchUpdateAbortedWithoutGettingResult() thro } } assertThat(attempt.get()).isEqualTo(2); - Iterable> requests = mockSpanner.getRequestTypes(); + List> requests = mockSpanner.getRequestTypes(); + // Remove the CreateSession requests for multiplexed sessions, as those are not relevant for + // this test. + requests.removeIf(request -> request == CreateSessionRequest.class); int size = Iterables.size(requests); assertThat(size).isIn(Range.closed(5, 6)); - if (isMultiplexedSessionsEnabled()) { - if (size == 6) { - assertThat(requests) - .containsExactly( - CreateSessionRequest.class, - BatchCreateSessionsRequest.class, - ExecuteBatchDmlRequest.class, - BeginTransactionRequest.class, - ExecuteBatchDmlRequest.class, - CommitRequest.class); - } else { - assertThat(requests) - .containsExactly( - CreateSessionRequest.class, - BatchCreateSessionsRequest.class, - ExecuteBatchDmlRequest.class, - CommitRequest.class, - BeginTransactionRequest.class, - ExecuteBatchDmlRequest.class, - CommitRequest.class); - } + if (size == 5) { + assertThat(requests) + .containsExactly( + BatchCreateSessionsRequest.class, + ExecuteBatchDmlRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); } else { - if (size == 5) { - assertThat(requests) - .containsExactly( - BatchCreateSessionsRequest.class, - ExecuteBatchDmlRequest.class, - BeginTransactionRequest.class, - ExecuteBatchDmlRequest.class, - CommitRequest.class); - } else { - assertThat(requests) - .containsExactly( - BatchCreateSessionsRequest.class, - ExecuteBatchDmlRequest.class, - CommitRequest.class, - BeginTransactionRequest.class, - ExecuteBatchDmlRequest.class, - CommitRequest.class); - } + assertThat(requests) + .containsExactly( + BatchCreateSessionsRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ChannelUsageTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ChannelUsageTest.java index 4b1d3361cc6..30e06719181 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ChannelUsageTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ChannelUsageTest.java @@ -18,12 +18,11 @@ import static io.grpc.Grpc.TRANSPORT_ATTR_REMOTE_ADDR; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import com.google.cloud.NoCredentials; import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ListValue; @@ -43,16 +42,13 @@ import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; import java.io.IOException; import java.net.InetSocketAddress; -import java.util.ArrayList; +import java.time.Duration; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.junit.After; @@ -223,7 +219,7 @@ public void testCreatesNumChannels() { try (Spanner spanner = createSpannerOptions().getService()) { assumeFalse( "GRPC-GCP is currently not supported with multiplexed sessions", - isMultiplexedSessionsEnabled(spanner)); + isMultiplexedSessionsEnabled(spanner) && enableGcpPool); DatabaseClient client = spanner.getDatabaseClient(DatabaseId.of("p", "i", "d")); try (ResultSet resultSet = client.singleUse().executeQuery(SELECT1)) { while (resultSet.next()) {} @@ -233,34 +229,38 @@ public void testCreatesNumChannels() { } @Test - public void testUsesAllChannels() throws InterruptedException, ExecutionException { + public void testUsesAllChannels() throws InterruptedException { + final int multiplier = 2; try (Spanner spanner = createSpannerOptions().getService()) { assumeFalse( "GRPC-GCP is currently not supported with multiplexed sessions", isMultiplexedSessionsEnabled(spanner)); DatabaseClient client = spanner.getDatabaseClient(DatabaseId.of("p", "i", "d")); ListeningExecutorService executor = - MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(numChannels * 2)); - CountDownLatch latch = new CountDownLatch(numChannels * 2); - List> futures = new ArrayList<>(numChannels * 2); - for (int run = 0; run < numChannels * 2; run++) { - futures.add( - executor.submit( - () -> { - try (ReadOnlyTransaction transaction = client.readOnlyTransaction()) { - try (ResultSet resultSet = transaction.executeQuery(SELECT1)) { - while (resultSet.next()) {} - latch.countDown(); - try { - return latch.await(10L, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw SpannerExceptionFactory.asSpannerException(e); - } - } - } - })); + MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(numChannels * multiplier)); + CountDownLatch latch = new CountDownLatch(numChannels * multiplier); + for (int run = 0; run < numChannels * multiplier; run++) { + executor.submit( + () -> { + // Use a multi-use read-only transaction to make sure we keep a session in use for + // a longer period of time. + try (ReadOnlyTransaction transaction = client.readOnlyTransaction()) { + try (ResultSet resultSet = transaction.executeQuery(SELECT1)) { + while (resultSet.next()) {} + } + latch.countDown(); + // Wait here until we now that all threads have reached this point and have a + // session in use. + latch.await(); + try (ResultSet resultSet = transaction.executeQuery(SELECT1)) { + while (resultSet.next()) {} + } + } + return true; + }); } - assertEquals(numChannels * 2, Futures.allAsList(futures).get().size()); + executor.shutdown(); + assertTrue(executor.awaitTermination(Duration.ofSeconds(10L))); } assertEquals(numChannels, executeSqlLocalIps.size()); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java index 2a0c9c77c36..41da46a56a8 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java @@ -79,6 +79,7 @@ import com.google.spanner.v1.BatchWriteResponse; import com.google.spanner.v1.BeginTransactionRequest; import com.google.spanner.v1.CommitRequest; +import com.google.spanner.v1.CreateSessionRequest; import com.google.spanner.v1.DeleteSessionRequest; import com.google.spanner.v1.DirectedReadOptions; import com.google.spanner.v1.DirectedReadOptions.IncludeReplicas; @@ -3005,43 +3006,72 @@ public void testDatabaseOrInstanceDoesNotExistOnInitialization() throws Exceptio @Test public void testDatabaseOrInstanceDoesNotExistOnCreate() { - StatusRuntimeException[] exceptions = - new StatusRuntimeException[] { - SpannerExceptionFactoryTest.newStatusResourceNotFoundException( - "Database", SpannerExceptionFactory.DATABASE_RESOURCE_TYPE, DATABASE_NAME), - SpannerExceptionFactoryTest.newStatusResourceNotFoundException( - "Instance", SpannerExceptionFactory.INSTANCE_RESOURCE_TYPE, INSTANCE_NAME) - }; - for (StatusRuntimeException exception : exceptions) { - mockSpanner.setCreateSessionExecutionTime( - SimulatedExecutionTime.ofStickyException(exception)); - mockSpanner.setBatchCreateSessionsExecutionTime( - SimulatedExecutionTime.ofStickyException(exception)); - // Ensure there are no sessions in the pool by default. - try (Spanner spanner = - SpannerOptions.newBuilder() - .setProjectId(TEST_PROJECT) - .setChannelProvider(channelProvider) - .setCredentials(NoCredentials.getInstance()) - .setSessionPoolOption(SessionPoolOptions.newBuilder().setMinSessions(0).build()) - .build() - .getService()) { - DatabaseClientImpl dbClient = - (DatabaseClientImpl) - spanner.getDatabaseClient( - DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); - // The create session failure should propagate to the client and not retry. - try (ResultSet rs = dbClient.singleUse().executeQuery(SELECT1)) { - assertThrows(ResourceNotFoundException.class, rs::next); - // The server should only receive one BatchCreateSessions request. - assertThat(mockSpanner.getRequests()).hasSize(1); + for (Duration waitForMinSessions : ImmutableList.of(Duration.ZERO, Duration.ofSeconds(5L))) { + StatusRuntimeException[] exceptions = + new StatusRuntimeException[] { + SpannerExceptionFactoryTest.newStatusResourceNotFoundException( + "Database", SpannerExceptionFactory.DATABASE_RESOURCE_TYPE, DATABASE_NAME), + SpannerExceptionFactoryTest.newStatusResourceNotFoundException( + "Instance", SpannerExceptionFactory.INSTANCE_RESOURCE_TYPE, INSTANCE_NAME) + }; + for (StatusRuntimeException exception : exceptions) { + mockSpanner.setCreateSessionExecutionTime( + SimulatedExecutionTime.ofStickyException(exception)); + mockSpanner.setBatchCreateSessionsExecutionTime( + SimulatedExecutionTime.ofStickyException(exception)); + // Ensure there are no sessions in the pool by default. + try (Spanner spanner = + SpannerOptions.newBuilder() + .setProjectId(TEST_PROJECT) + .setChannelProvider(channelProvider) + .setCredentials(NoCredentials.getInstance()) + .setSessionPoolOption( + SessionPoolOptions.newBuilder() + .setMinSessions(0) + .setWaitForMinSessions(waitForMinSessions) + .build()) + .build() + .getService()) { + boolean useMultiplexedSession = + spanner.getOptions().getSessionPoolOptions().getUseMultiplexedSession(); + DatabaseId databaseId = DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE); + if (useMultiplexedSession && !waitForMinSessions.isZero()) { + assertThrows( + ResourceNotFoundException.class, () -> spanner.getDatabaseClient(databaseId)); + } else { + // Freeze the server until we try to execute ResultSet#next() to prevent the creation of + // a multiplexed session to finish before we try to use it. + mockSpanner.freeze(); + DatabaseClientImpl dbClient = + (DatabaseClientImpl) spanner.getDatabaseClient(databaseId); + // The CreateSession / BatchCreateSessions failure should propagate to the client and + // not retry. + try (ResultSet rs = dbClient.singleUse().executeQuery(SELECT1)) { + mockSpanner.unfreeze(); + assertThrows(ResourceNotFoundException.class, rs::next); + // The server should only receive one BatchCreateSessions request. + assertThat(mockSpanner.getRequests()).hasSize(1); + } + assertThrows( + ResourceNotFoundException.class, + () -> + dbClient + .readWriteTransaction() + .run(transaction -> transaction.executeUpdate(UPDATE_STATEMENT))); + // No additional requests should have been sent by the client. + // Note that in case of the use of multiplexed sessions, then we have 2 requests: + // 1. BatchCreateSessions for the session pool. + // 2. CreateSession for the multiplexed session. + assertThat(mockSpanner.getRequests()) + .hasSize( + spanner.getOptions().getSessionPoolOptions().getUseMultiplexedSession() + ? 2 + : 1); + } } - assertThrows(ResourceNotFoundException.class, dbClient::readWriteTransaction); - // No additional requests should have been sent by the client. - assertThat(mockSpanner.getRequests()).hasSize(1); + mockSpanner.reset(); + mockSpanner.removeAllExecutionTimes(); } - mockSpanner.reset(); - mockSpanner.removeAllExecutionTimes(); } } @@ -3146,8 +3176,16 @@ public void testDatabaseOrInstanceIsDeletedAndThenRecreated() throws Exception { // receive any new requests. mockSpanner.reset(); // All subsequent calls should fail with a DatabaseNotFoundException. - assertThrows( - ResourceNotFoundException.class, () -> dbClient.singleUse().executeQuery(SELECT1)); + + if (!spanner.getOptions().getSessionPoolOptions().getUseMultiplexedSession()) { + // We only verify this for read-only transactions if we are not using multiplexed + // sessions. For multiplexed sessions, we don't need any special handling, as deleting the + // database will also invalidate the multiplexed session, and trying to continue to use it + // will continue to return an error. + assertThrows( + ResourceNotFoundException.class, () -> dbClient.singleUse().executeQuery(SELECT1)); + } + assertThrows( ResourceNotFoundException.class, () -> dbClient.readWriteTransaction().run(transaction -> null)); @@ -3204,10 +3242,17 @@ public void testGetInvalidatedClientMultipleTimes() { assertThrows( ResourceNotFoundException.class, () -> dbClient.singleUse().executeQuery(SELECT1).next()); - // The server should only receive one BatchCreateSessions request for each run as we - // have set MinSessions=0. - assertThat(mockSpanner.getRequests()).hasSize(run + 1); - assertThat(dbClient.pool.isValid()).isFalse(); + if (spanner.getOptions().getSessionPoolOptions().getUseMultiplexedSession()) { + // We should only receive 1 CreateSession request. The query should never be executed, + // as the session creation fails before it gets to executing a query. + assertEquals(1, mockSpanner.countRequestsOfType(CreateSessionRequest.class)); + assertEquals(0, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class)); + } else { + // The server should only receive one BatchCreateSessions request for each run as we + // have set MinSessions=0. + assertThat(mockSpanner.getRequests()).hasSize(run + 1); + assertThat(dbClient.pool.isValid()).isFalse(); + } } } } @@ -3653,29 +3698,53 @@ public void testClientIdReusedOnDatabaseNotFound() { @Test public void testBatchCreateSessionsPermissionDenied() { - mockSpanner.setBatchCreateSessionsExecutionTime( - SimulatedExecutionTime.ofStickyException( - Status.PERMISSION_DENIED.withDescription("Not permitted").asRuntimeException())); - mockSpanner.setCreateSessionExecutionTime( - SimulatedExecutionTime.ofStickyException( - Status.PERMISSION_DENIED.withDescription("Not permitted").asRuntimeException())); - try (Spanner spanner = - SpannerOptions.newBuilder() - .setProjectId("my-project") - .setChannelProvider(channelProvider) - .setCredentials(NoCredentials.getInstance()) - .build() - .getService()) { - DatabaseId databaseId = DatabaseId.of("my-project", "my-instance", "my-database"); - DatabaseClient client = spanner.getDatabaseClient(databaseId); - // The following call is non-blocking and will not generate an exception. - ResultSet rs = client.singleUse().executeQuery(SELECT1); - // Actually trying to get any results will cause an exception. - SpannerException e = assertThrows(SpannerException.class, rs::next); - assertEquals(ErrorCode.PERMISSION_DENIED, e.getErrorCode()); - } finally { - mockSpanner.setBatchCreateSessionsExecutionTime(SimulatedExecutionTime.none()); - mockSpanner.setCreateSessionExecutionTime(SimulatedExecutionTime.none()); + for (Duration waitForMinSessions : ImmutableList.of(Duration.ZERO, Duration.ofSeconds(5L))) { + mockSpanner.setBatchCreateSessionsExecutionTime( + SimulatedExecutionTime.ofStickyException( + Status.PERMISSION_DENIED.withDescription("Not permitted").asRuntimeException())); + mockSpanner.setCreateSessionExecutionTime( + SimulatedExecutionTime.ofStickyException( + Status.PERMISSION_DENIED.withDescription("Not permitted").asRuntimeException())); + if (waitForMinSessions.isZero()) { + mockSpanner.freeze(); + } + try (Spanner spanner = + SpannerOptions.newBuilder() + .setProjectId("my-project") + .setChannelProvider(channelProvider) + .setCredentials(NoCredentials.getInstance()) + .setSessionPoolOption( + SessionPoolOptions.newBuilder().setWaitForMinSessions(waitForMinSessions).build()) + .build() + .getService()) { + DatabaseId databaseId = DatabaseId.of("my-project", "my-instance", "my-database"); + SpannerException spannerException; + if (waitForMinSessions.isZero()) { + // The following call is non-blocking and will not generate an exception. + DatabaseClient client = spanner.getDatabaseClient(databaseId); + ResultSet resultSet = client.singleUse().executeQuery(SELECT1); + mockSpanner.unfreeze(); + // Actually trying to get any results will cause an exception. + spannerException = assertThrows(SpannerException.class, resultSet::next); + } else { + // This is blocking when we should wait for min sessions, and will therefore fail. + if (spanner.getOptions().getSessionPoolOptions().getUseMultiplexedSession()) { + spannerException = + assertThrows(SpannerException.class, () -> spanner.getDatabaseClient(databaseId)); + } else { + // TODO: Fix the session pool implementation for waiting for min sessions, so this also + // propagates the error directly when session creation fails. + DatabaseClient client = spanner.getDatabaseClient(databaseId); + spannerException = + assertThrows( + SpannerException.class, () -> client.singleUse().executeQuery(SELECT1).next()); + } + } + assertEquals(ErrorCode.PERMISSION_DENIED, spannerException.getErrorCode()); + } finally { + mockSpanner.setBatchCreateSessionsExecutionTime(SimulatedExecutionTime.none()); + mockSpanner.setCreateSessionExecutionTime(SimulatedExecutionTime.none()); + } } } @@ -3790,12 +3859,14 @@ public void testCreateSessionsFailure_shouldNotPropagateToCloseMethod() { // Simulate session creation failures on the backend. mockSpanner.setCreateSessionExecutionTime( SimulatedExecutionTime.ofStickyException(Status.RESOURCE_EXHAUSTED.asRuntimeException())); + // This will not cause any failure as getting a session from the pool is guaranteed to be + // non-blocking, and any exceptions will be delayed until actual query execution. + mockSpanner.freeze(); DatabaseClient client = spannerWithEmptySessionPool.getDatabaseClient( DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); - // This will not cause any failure as getting a session from the pool is guaranteed to be - // non-blocking, and any exceptions will be delayed until actual query execution. try (ResultSet rs = client.singleUse().executeQuery(SELECT1)) { + mockSpanner.unfreeze(); SpannerException e = assertThrows(SpannerException.class, rs::next); assertThat(e.getErrorCode()).isEqualTo(ErrorCode.RESOURCE_EXHAUSTED); } @@ -4989,6 +5060,62 @@ public void testRetryOnResourceExhausted() { } } + @Test + public void testSessionPoolExhaustedError_containsStackTraces() { + try (Spanner spanner = + SpannerOptions.newBuilder() + .setProjectId(TEST_PROJECT) + .setChannelProvider(channelProvider) + .setCredentials(NoCredentials.getInstance()) + .setSessionPoolOption( + SessionPoolOptions.newBuilder() + .setFailIfPoolExhausted() + .setMinSessions(2) + .setMaxSessions(4) + .setWaitForMinSessions(Duration.ofSeconds(10L)) + .build()) + .build() + .getService()) { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + List transactions = new ArrayList<>(); + // Deliberately leak 4 sessions. + for (int i = 0; i < 4; i++) { + // Get a transaction manager without doing anything with it. This will reserve a session + // from + // the pool, but not increase the number of sessions marked as in use. + transactions.add(client.transactionManager()); + } + // Trying to get yet another transaction will fail. + // NOTE: This fails directly, because we have set the setFailIfPoolExhausted() option. + SpannerException spannerException = + assertThrows(SpannerException.class, client::transactionManager); + assertEquals(ErrorCode.RESOURCE_EXHAUSTED, spannerException.getErrorCode()); + assertTrue( + spannerException.getMessage(), + spannerException.getMessage().contains("There are currently 4 sessions checked out:")); + assertTrue( + spannerException.getMessage(), + spannerException.getMessage().contains("Session was checked out from the pool at")); + + SessionPool pool = ((DatabaseClientImpl) client).pool; + // Verify that there are no sessions in the pool. + assertEquals(0, pool.getNumberOfSessionsInPool()); + // Verify that the sessions have not (yet) been marked as in use. + assertEquals(0, pool.getNumberOfSessionsInUse()); + assertEquals(0, pool.getMaxSessionsInUse()); + // Verify that we have 4 sessions in the pool. + assertEquals(4, pool.getTotalSessionsPlusNumSessionsBeingCreated()); + + // Release the sessions back into the pool. + for (TransactionManager transaction : transactions) { + transaction.close(); + } + // Closing the transactions should return the sessions to the pool. + assertEquals(4, pool.getNumberOfSessionsInPool()); + } + } + static void assertAsString(String expected, ResultSet resultSet, int col) { assertEquals(expected, resultSet.getValue(col).getAsString()); assertEquals(ImmutableList.of(expected), resultSet.getValue(col).getAsStringList()); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestWithClosedSessionsEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestWithClosedSessionsEnv.java index 69004a4913b..b71771ae2ca 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestWithClosedSessionsEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestWithClosedSessionsEnv.java @@ -46,7 +46,8 @@ private static class SpannerWithClosedSessionsImpl extends SpannerImpl { } @Override - DatabaseClientImpl createDatabaseClient(String clientId, SessionPool pool) { + DatabaseClientImpl createDatabaseClient( + String clientId, SessionPool pool, MultiplexedSessionDatabaseClient ignore) { return new DatabaseClientWithClosedSessionImpl(clientId, pool, tracer); } } @@ -89,7 +90,7 @@ PooledSessionFuture getSession() { @Override SessionFutureWrapper getMultiplexedSession() { - SessionFutureWrapper session = super.getMultiplexedSession(); + SessionFutureWrapper session = (SessionFutureWrapper) super.getMultiplexedSession(); if (invalidateNextSession) { session.get().get().getDelegate().close(); session.get().get().setAllowReplacing(false); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/JavaVersionUtil.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/JavaVersionUtil.java index acca12118c2..99f7a993234 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/JavaVersionUtil.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/JavaVersionUtil.java @@ -16,20 +16,13 @@ package com.google.cloud.spanner; +import com.google.gson.internal.JavaVersion; + /** Util class for getting the Java version the tests are executed on. */ public class JavaVersionUtil { /** Returns the major Java version (e.g. 8, 11, 17) */ public static int getJavaMajorVersion() { - String version = System.getProperty("java.version"); - if (version.startsWith("1.")) { - version = version.substring(2, 3); - } else { - int dot = version.indexOf("."); - if (dot != -1) { - version = version.substring(0, dot); - } - } - return Integer.parseInt(version); + return JavaVersion.getMajorJavaVersion(); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java index 07e8bdae1bc..54b992b69ff 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java @@ -2162,7 +2162,7 @@ public List getRequestsOfType(Class type) { return result; } - public Iterable> getRequestTypes() { + public List> getRequestTypes() { List> res = new LinkedList<>(); for (AbstractMessage m : this.requests) { res.add(m.getClass()); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClientMockServerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClientMockServerTest.java new file mode 100644 index 00000000000..bf4a02a10c5 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClientMockServerTest.java @@ -0,0 +1,321 @@ +/* + * Copyright 2024 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.NoCredentials; +import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime; +import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; +import com.google.cloud.spanner.connection.RandomResultSetGenerator; +import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableList; +import com.google.spanner.v1.ExecuteSqlRequest; +import com.google.spanner.v1.Session; +import io.grpc.Status; +import java.time.Duration; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class MultiplexedSessionDatabaseClientMockServerTest extends AbstractMockServerTest { + private static final Statement STATEMENT = Statement.of("select * from random"); + + @BeforeClass + public static void setupResults() { + mockSpanner.putStatementResults( + StatementResult.query(STATEMENT, new RandomResultSetGenerator(1).generate())); + } + + @Before + public void createSpannerInstance() { + spanner = + SpannerOptions.newBuilder() + .setProjectId("test-project") + .setChannelProvider(channelProvider) + .setCredentials(NoCredentials.getInstance()) + .setSessionPoolOption( + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(true) + // Set the maintainer to loop once every 1ms + .setMultiplexedSessionMaintenanceLoopFrequency(Duration.ofMillis(1L)) + // Set multiplexed sessions to be replaced once every 1ms + .setMultiplexedSessionMaintenanceDuration(org.threeten.bp.Duration.ofMillis(1L)) + .setFailOnSessionLeak() + .build()) + .build() + .getService(); + } + + @Test + public void testMultiUseReadOnlyTransactionUsesSameSession() { + // Execute two queries using the same transaction. Both queries should use the same + // session, also when the maintainer has executed in the meantime. + DatabaseClientImpl client = + (DatabaseClientImpl) spanner.getDatabaseClient(DatabaseId.of("p", "i", "d")); + try (ReadOnlyTransaction transaction = client.readOnlyTransaction()) { + try (ResultSet resultSet = transaction.executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + + // Wait until the maintainer has replaced the current session. + waitForSessionToBeReplaced(client); + + try (ResultSet resultSet = transaction.executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + } + List requests = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class); + assertEquals(2, requests.size()); + assertEquals(requests.get(0).getSession(), requests.get(1).getSession()); + + assertNotNull(client.multiplexedSessionDatabaseClient); + assertEquals(1L, client.multiplexedSessionDatabaseClient.getNumSessionsAcquired().get()); + assertEquals(1L, client.multiplexedSessionDatabaseClient.getNumSessionsReleased().get()); + } + + @Test + public void testNewTransactionUsesNewSession() { + // Execute a single-use read-only transactions, then wait for the maintainer to replace the + // current session, and then run another single-use read-only transaction. The two transactions + // should use two different sessions. + DatabaseClientImpl client = + (DatabaseClientImpl) spanner.getDatabaseClient(DatabaseId.of("p", "i", "d")); + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + + // Wait until the maintainer has replaced the current session. + waitForSessionToBeReplaced(client); + + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + + List requests = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class); + assertEquals(2, requests.size()); + assertNotEquals(requests.get(0).getSession(), requests.get(1).getSession()); + + assertNotNull(client.multiplexedSessionDatabaseClient); + assertEquals(2L, client.multiplexedSessionDatabaseClient.getNumSessionsAcquired().get()); + assertEquals(2L, client.multiplexedSessionDatabaseClient.getNumSessionsReleased().get()); + } + + @Test + public void testMaintainerMaintainsMultipleClients() { + // Verify that the single-threaded shared executor that is used by the multiplexed client + // maintains and replaces sessions from multiple clients. + DatabaseClientImpl client1 = + (DatabaseClientImpl) + spanner.getDatabaseClient(DatabaseId.of("p", "i", "d" + UUID.randomUUID())); + DatabaseClientImpl client2 = + (DatabaseClientImpl) + spanner.getDatabaseClient(DatabaseId.of("p", "i", "d" + UUID.randomUUID())); + + for (DatabaseClientImpl client : ImmutableList.of(client1, client2)) { + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + // Wait until the maintainer has replaced the current session. + waitForSessionToBeReplaced(client); + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + } + + List requests = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class); + assertEquals(4, requests.size()); + // Put all session IDs in a Set to verify that they were all different. + Set sessionIds = + requests.stream().map(ExecuteSqlRequest::getSession).collect(Collectors.toSet()); + assertEquals(4, sessionIds.size()); + + for (DatabaseClientImpl client : ImmutableList.of(client1, client2)) { + assertNotNull(client.multiplexedSessionDatabaseClient); + assertEquals(2L, client.multiplexedSessionDatabaseClient.getNumSessionsAcquired().get()); + assertEquals(2L, client.multiplexedSessionDatabaseClient.getNumSessionsReleased().get()); + } + } + + @Test + public void testUnimplementedErrorOnCreation_fallsBackToRegularSessions() { + mockSpanner.setCreateSessionExecutionTime( + SimulatedExecutionTime.ofException( + Status.UNIMPLEMENTED + .withDescription("Multiplexed sessions are not implemented") + .asRuntimeException())); + DatabaseClientImpl client = + (DatabaseClientImpl) spanner.getDatabaseClient(DatabaseId.of("p", "i", "d")); + // Get the current session reference. This will block until the CreateSession RPC has failed. + assertNotNull(client.multiplexedSessionDatabaseClient); + SpannerException spannerException = + assertThrows( + SpannerException.class, + client.multiplexedSessionDatabaseClient::getCurrentSessionReference); + assertEquals(ErrorCode.UNIMPLEMENTED, spannerException.getErrorCode()); + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + // Verify that we received one ExecuteSqlRequest, and that it used a regular session. + assertEquals(1, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class)); + List requests = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class); + + Session session = mockSpanner.getSession(requests.get(0).getSession()); + assertNotNull(session); + assertFalse(session.getMultiplexed()); + + assertNotNull(client.multiplexedSessionDatabaseClient); + assertEquals(0L, client.multiplexedSessionDatabaseClient.getNumSessionsAcquired().get()); + assertEquals(0L, client.multiplexedSessionDatabaseClient.getNumSessionsReleased().get()); + } + + @Test + public void + testUnimplementedErrorOnCreation_firstReceivesError_secondFallsBackToRegularSessions() { + mockSpanner.setCreateSessionExecutionTime( + SimulatedExecutionTime.ofException( + Status.UNIMPLEMENTED + .withDescription("Multiplexed sessions are not implemented") + .asRuntimeException())); + // Freeze the mock server to ensure that the CreateSession RPC does not return an error or any + // other result just yet. + mockSpanner.freeze(); + // Get a database client using multiplexed sessions. The CreateSession RPC will be blocked as + // long as the mock server is frozen. + DatabaseClientImpl client = + (DatabaseClientImpl) spanner.getDatabaseClient(DatabaseId.of("p", "i", "d")); + // Try to execute a query. This is all non-blocking until the call to ResultSet#next(). + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + // Unfreeze the mock server to get the error from the backend. This query will then fail. + mockSpanner.unfreeze(); + SpannerException spannerException = assertThrows(SpannerException.class, resultSet::next); + assertEquals(ErrorCode.UNIMPLEMENTED, spannerException.getErrorCode()); + } + // The next query will fall back to regular sessions and succeed. + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + // Verify that we received one ExecuteSqlRequest, and that it used a regular session. + assertEquals(1, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class)); + List requests = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class); + + Session session = mockSpanner.getSession(requests.get(0).getSession()); + assertNotNull(session); + assertFalse(session.getMultiplexed()); + + assertNotNull(client.multiplexedSessionDatabaseClient); + assertEquals(0L, client.multiplexedSessionDatabaseClient.getNumSessionsAcquired().get()); + assertEquals(0L, client.multiplexedSessionDatabaseClient.getNumSessionsReleased().get()); + } + + @Test + public void testMaintainerInvalidatesMultiplexedSessionClientIfUnimplemented() { + DatabaseClientImpl client = + (DatabaseClientImpl) spanner.getDatabaseClient(DatabaseId.of("p", "i", "d")); + // The first query should succeed. + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + // Now ensure that CreateSession returns UNIMPLEMENTED. This error should be recognized by the + // maintainer and invalidate the MultiplexedSessionDatabaseClient. New queries will fall back to + // regular sessions. + mockSpanner.setCreateSessionExecutionTime( + SimulatedExecutionTime.ofException( + Status.UNIMPLEMENTED + .withDescription("Multiplexed sessions are not implemented") + .asRuntimeException())); + // Wait until the client sees that MultiplexedSessions are not supported. + assertNotNull(client.multiplexedSessionDatabaseClient); + Stopwatch stopwatch = Stopwatch.createStarted(); + while (client.multiplexedSessionDatabaseClient.isMultiplexedSessionsSupported() + && stopwatch.elapsed().compareTo(Duration.ofSeconds(5)) < 0) { + Thread.yield(); + } + // Queries should fall back to regular sessions. + try (ResultSet resultSet = client.singleUse().executeQuery(STATEMENT)) { + //noinspection StatementWithEmptyBody + while (resultSet.next()) { + // ignore + } + } + // Verify that we received two ExecuteSqlRequests, and that the first one used a multiplexed + // session, and that the second used a regular session. + assertEquals(2, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class)); + List requests = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class); + + Session session1 = mockSpanner.getSession(requests.get(0).getSession()); + assertNotNull(session1); + assertTrue(session1.getMultiplexed()); + + Session session2 = mockSpanner.getSession(requests.get(1).getSession()); + assertNotNull(session2); + assertFalse(session2.getMultiplexed()); + + assertNotNull(client.multiplexedSessionDatabaseClient); + assertEquals(1L, client.multiplexedSessionDatabaseClient.getNumSessionsAcquired().get()); + assertEquals(1L, client.multiplexedSessionDatabaseClient.getNumSessionsReleased().get()); + } + + private void waitForSessionToBeReplaced(DatabaseClientImpl client) { + assertNotNull(client.multiplexedSessionDatabaseClient); + SessionReference sessionReference = + client.multiplexedSessionDatabaseClient.getCurrentSessionReference(); + while (sessionReference + == client.multiplexedSessionDatabaseClient.getCurrentSessionReference()) { + Thread.yield(); + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClientTest.java new file mode 100644 index 00000000000..d7d9b7395ed --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionDatabaseClientTest.java @@ -0,0 +1,153 @@ +/* + * Copyright 2024 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.cloud.spanner.SessionClient.SessionConsumer; +import java.lang.reflect.Field; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.stubbing.Answer; + +@RunWith(JUnit4.class) +public class MultiplexedSessionDatabaseClientTest { + + @Test + public void testMaintainer() { + // This fails for the native builds due to the extensive use of reflection. + assumeTrue(isJava8()); + + Instant now = Instant.now(); + Clock clock = mock(Clock.class); + when(clock.instant()).thenReturn(now); + SessionClient sessionClient = mock(SessionClient.class); + SpannerImpl spanner = mock(SpannerImpl.class); + SpannerOptions spannerOptions = mock(SpannerOptions.class); + SessionPoolOptions sessionPoolOptions = mock(SessionPoolOptions.class); + when(sessionClient.getSpanner()).thenReturn(spanner); + when(spanner.getOptions()).thenReturn(spannerOptions); + when(spannerOptions.getSessionPoolOptions()).thenReturn(sessionPoolOptions); + when(sessionPoolOptions.getMultiplexedSessionMaintenanceDuration()) + .thenReturn(org.threeten.bp.Duration.ofDays(7)); + when(sessionPoolOptions.getMultiplexedSessionMaintenanceLoopFrequency()) + .thenReturn(Duration.ofMinutes(10)); + + SessionImpl session1 = mock(SessionImpl.class); + SessionReference sessionReference1 = mock(SessionReference.class); + when(session1.getSessionReference()).thenReturn(sessionReference1); + + SessionImpl session2 = mock(SessionImpl.class); + SessionReference sessionReference2 = mock(SessionReference.class); + when(session2.getSessionReference()).thenReturn(sessionReference2); + + doAnswer( + (Answer) + invocationOnMock -> { + SessionConsumer consumer = invocationOnMock.getArgument(0); + // Return session1 the first time it is called. + consumer.onSessionReady(session1); + return null; + }) + .doAnswer( + (Answer) + invocationOnMock -> { + SessionConsumer consumer = invocationOnMock.getArgument(0); + // Return session2 the second time that it is called. + consumer.onSessionReady(session2); + return null; + }) + .when(sessionClient) + .asyncCreateMultiplexedSession(any(SessionConsumer.class)); + + // Create a client. This should get session1. + MultiplexedSessionDatabaseClient client = + new MultiplexedSessionDatabaseClient(sessionClient, clock); + + // Make sure that the client uses the initial session that is created. + assertEquals(client.getCurrentSessionReference(), session1.getSessionReference()); + + // Run the maintainer without advancing the clock. We should still get the same session. + client.getMaintainer().maintain(); + assertEquals(client.getCurrentSessionReference(), session1.getSessionReference()); + + // Advance the clock by 1 day. We should still get the same session. + when(clock.instant()).thenReturn(now.plus(Duration.ofDays(1))); + client.getMaintainer().maintain(); + assertEquals(client.getCurrentSessionReference(), session1.getSessionReference()); + + // Advance the clock by 8 days. We should now get a new session. + when(clock.instant()).thenReturn(now.plus(Duration.ofDays(8))); + client.getMaintainer().maintain(); + assertEquals(client.getCurrentSessionReference(), session2.getSessionReference()); + } + + @Test + public void testForceDisableEnvVar() throws Exception { + assumeTrue(isJava8() && !isWindows()); + assumeFalse( + System.getenv().containsKey("GOOGLE_CLOUD_SPANNER_FORCE_DISABLE_MULTIPLEXED_SESSIONS")); + + // Assert that the mux sessions setting is respected by default. + assertTrue( + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(true) + .build() + .getUseMultiplexedSession()); + + Class classOfMap = System.getenv().getClass(); + Field field = classOfMap.getDeclaredField("m"); + field.setAccessible(true); + Map writeableEnvironmentVariables = + (Map) field.get(System.getenv()); + + try { + writeableEnvironmentVariables.put( + "GOOGLE_CLOUD_SPANNER_FORCE_DISABLE_MULTIPLEXED_SESSIONS", "true"); + // Assert that the env var overrides the mux sessions setting. + assertFalse( + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(true) + .build() + .getUseMultiplexedSession()); + } finally { + writeableEnvironmentVariables.remove( + "GOOGLE_CLOUD_SPANNER_FORCE_DISABLE_MULTIPLEXED_SESSIONS"); + } + } + + private boolean isJava8() { + return JavaVersionUtil.getJavaMajorVersion() == 8; + } + + private boolean isWindows() { + return System.getProperty("os.name").toLowerCase().contains("windows"); + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionMaintainerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionMaintainerTest.java index 457004a18fb..f596183507e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionMaintainerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionMaintainerTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -41,8 +42,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; -import org.junit.Assume; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -62,6 +63,11 @@ public class MultiplexedSessionMaintainerTest extends BaseSessionPoolTest { private FakeClock clock = new FakeClock(); private List multiplexedSessionsRemoved = new ArrayList<>(); + @BeforeClass + public static void checkUsesMultiplexedSessionPool() { + assumeTrue("Only run if the maintainer in the session pool is used", false); + } + @Before public void setUp() { initMocks(this); @@ -81,7 +87,7 @@ public void setUp() { .setPoolMaintainerClock(clock) .build(); when(spannerOptions.getSessionPoolOptions()).thenReturn(options); - Assume.assumeTrue(options.getUseMultiplexedSession()); + assumeTrue(options.getUseMultiplexedSession()); multiplexedSessionsRemoved.clear(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionPoolTest.java index 5e96e519fc7..ed9926dea88 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MultiplexedSessionPoolTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.times; @@ -36,8 +37,8 @@ import io.opentelemetry.api.OpenTelemetry; import java.io.PrintWriter; import java.io.StringWriter; -import org.junit.Assume; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mock; import org.threeten.bp.Duration; @@ -66,6 +67,11 @@ private SessionPool createPool() { OpenTelemetry.noop()); } + @BeforeClass + public static void checkUsesMultiplexedSessionPool() { + assumeTrue("Only run if the maintainer in the session pool is used", false); + } + @Before public void setUp() { initMocks(this); @@ -83,7 +89,7 @@ public void setUp() { .setUseMultiplexedSession(true) .build(); when(spannerOptions.getSessionPoolOptions()).thenReturn(options); - Assume.assumeTrue(options.getUseMultiplexedSession()); + assumeTrue(options.getUseMultiplexedSession()); } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetrySpanTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetrySpanTest.java index 8a4859fa132..a351231f0e7 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetrySpanTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetrySpanTest.java @@ -22,6 +22,7 @@ import com.google.api.gax.grpc.testing.LocalChannelProvider; import com.google.cloud.NoCredentials; import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; +import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import com.google.protobuf.ListValue; import com.google.spanner.v1.ResultSetMetadata; @@ -231,7 +232,7 @@ public void setUp() throws Exception { .setSessionPoolOption( SessionPoolOptions.newBuilder() .setMinSessions(2) - .setWaitForMinSessions(Duration.ofSeconds(5)) + .setWaitForMinSessions(Duration.ofSeconds(10)) .build()); spanner = builder.build().getService(); @@ -250,9 +251,7 @@ public void tearDown() { @Test public void singleUse() { List expectedReadOnlyTransactionSingleUseEvents = - isMultiplexedSessionsEnabled() - ? ImmutableList.of("Using Session") - : ImmutableList.of("Acquiring session", "Acquired session", "Using Session"); + getExpectedReadOnlyTransactionSingleUseEvents(); List expectedReadOnlyTransactionSpans = isMultiplexedSessionsEnabled() ? ImmutableList.of( @@ -266,7 +265,8 @@ public void singleUse() { "CloudSpannerOperation.ExecuteStreamingQuery", "CloudSpannerOperation.BatchCreateSessions", "CloudSpanner.ReadOnlyTransaction"); - int expectedReadOnlyTransactionSingleUseEventsCount = isMultiplexedSessionsEnabled() ? 1 : 3; + int expectedReadOnlyTransactionSingleUseEventsCount = + expectedReadOnlyTransactionSingleUseEvents.size(); try (ResultSet rs = client.singleUse().executeQuery(SELECT1)) { while (rs.next()) { @@ -322,6 +322,17 @@ public void singleUse() { verifySpans(actualSpanItems, expectedReadOnlyTransactionSpans); } + private List getExpectedReadOnlyTransactionSingleUseEvents() { + List expectedReadOnlyTransactionSingleUseEvents; + if (isMultiplexedSessionsEnabled()) { + expectedReadOnlyTransactionSingleUseEvents = ImmutableList.of(); + } else { + expectedReadOnlyTransactionSingleUseEvents = + ImmutableList.of("Acquiring session", "Acquired session", "Using Session"); + } + return expectedReadOnlyTransactionSingleUseEvents; + } + @Test public void multiUse() { List expectedReadOnlyTransactionSpans = @@ -337,17 +348,21 @@ public void multiUse() { "CloudSpannerOperation.ExecuteStreamingQuery", "CloudSpannerOperation.BatchCreateSessions", "CloudSpanner.ReadOnlyTransaction"); - List expectedReadOnlyTransactionMultiUseEvents = - isMultiplexedSessionsEnabled() - ? ImmutableList.of("Using Session", "Creating Transaction", "Transaction Creation Done") - : ImmutableList.of( - "Acquiring session", - "Acquired session", - "Using Session", - "Creating Transaction", - "Transaction Creation Done"); - - int expectedReadOnlyTransactionMultiUseEventsCount = isMultiplexedSessionsEnabled() ? 3 : 5; + List expectedReadOnlyTransactionMultiUseEvents; + if (isMultiplexedSessionsEnabled()) { + expectedReadOnlyTransactionMultiUseEvents = + ImmutableList.of("Creating Transaction", "Transaction Creation Done"); + } else { + expectedReadOnlyTransactionMultiUseEvents = + ImmutableList.of( + "Acquiring session", + "Acquired session", + "Using Session", + "Creating Transaction", + "Transaction Creation Done"); + } + int expectedReadOnlyTransactionMultiUseEventsCount = + expectedReadOnlyTransactionMultiUseEvents.size(); try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { try (ResultSet rs = tx.executeQuery(SELECT1)) { @@ -537,7 +552,8 @@ public void transactionRunnerWithFailedAndBeginTransaction() { "CloudSpannerOperation.Commit", "CloudSpannerOperation.BatchCreateSessions", "CloudSpanner.ReadWriteTransaction"); - Long updateCount = + assertEquals( + Long.valueOf(1L), client .readWriteTransaction() .run( @@ -552,7 +568,16 @@ public void transactionRunnerWithFailedAndBeginTransaction() { () -> transaction.executeUpdate(INVALID_UPDATE_STATEMENT)); assertEquals(ErrorCode.INVALID_ARGUMENT, e.getErrorCode()); return transaction.executeUpdate(UPDATE_STATEMENT); - }); + })); + // Wait for all spans to finish. Failing to do so can cause the test to miss the + // BatchCreateSessions span, as that span is executed asynchronously in the SessionClient, and + // the SessionClient returns the session to the pool before the span has finished fully. + Stopwatch stopwatch = Stopwatch.createStarted(); + while (spanExporter.getFinishedSpanItems().size() + < expectedReadWriteTransactionWithCommitAndBeginTransactionSpans.size() + && stopwatch.elapsed().compareTo(java.time.Duration.ofMillis(1000)) < 0) { + Thread.yield(); + } List actualSpanItems = new ArrayList<>(); spanExporter diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java index 13dd8500b76..dbef7ce29f6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java @@ -184,17 +184,19 @@ public void pointReadNotFound() throws Exception { } @Test - public void invalidDatabase() throws Exception { + public void invalidDatabase() { mockSpanner.setCreateSessionExecutionTime( SimulatedExecutionTime.stickyDatabaseNotFoundException("invalid-database")); mockSpanner.setBatchCreateSessionsExecutionTime( SimulatedExecutionTime.stickyDatabaseNotFoundException("invalid-database")); + mockSpanner.freeze(); DatabaseClient invalidClient = spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, "invalid-database")); ApiFuture row = invalidClient .singleUse(TimestampBound.strong()) .readRowAsync(READ_TABLE_NAME, Key.of("k99"), READ_COLUMN_NAMES); + mockSpanner.unfreeze(); assertThrows(DatabaseNotFoundException.class, () -> get(row)); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java index 75580c25124..ab7eb80cf90 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java @@ -117,6 +117,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -192,7 +193,9 @@ private SessionPool createPool( tracer, labelValues, OpenTelemetry.noop(), - null); + null, + new AtomicLong(), + new AtomicLong()); } private SessionPool createPool( @@ -212,7 +215,9 @@ private SessionPool createPool( tracer, labelValues, openTelemetry, - attributes); + attributes, + new AtomicLong(), + new AtomicLong()); } @BeforeClass diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java index 9a13731b0f7..fdfe4871680 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java @@ -281,6 +281,21 @@ public void singleUse() { // Just consume the result set. } } + verifySingleUseSpans(); + } + + @Test + public void singleUseWithoutTryWithResources() { + // NOTE: This is bad practice. Always use try-with-resources. This test is only here to verify + // that our safeguards work. + ResultSet rs = client.singleUse().executeQuery(SELECT1); + while (rs.next()) { + // Just consume the result set. + } + verifySingleUseSpans(); + } + + private void verifySingleUseSpans() { // OpenTelemetry spans should be 0 as OpenCensus is default enabled. assertEquals(openTelemetrySpanExporter.getFinishedSpanItems().size(), 0); @@ -307,7 +322,6 @@ public void singleUse() { "Request for 2 sessions returned 2 sessions", "Request for 1 multiplexed session returned 1 session", "Creating 2 sessions", - "Using Session", "Starting/Resuming stream"); if (spanner.getOptions().getSessionPoolOptions().getUseMultiplexedSession()) { verifyAnnotations( @@ -324,6 +338,61 @@ public void singleUse() { } } + @Test + public void singleUseWithError() { + Statement invalidStatement = Statement.of("select * from foo"); + mockSpanner.putStatementResults( + StatementResult.exception(invalidStatement, Status.INVALID_ARGUMENT.asRuntimeException())); + + SpannerException spannerException = + assertThrows( + SpannerException.class, + () -> client.singleUse().executeQuery(INVALID_UPDATE_STATEMENT).next()); + assertEquals(ErrorCode.INVALID_ARGUMENT, spannerException.getErrorCode()); + + // OpenTelemetry spans should be 0 as OpenCensus is default enabled. + assertEquals(openTelemetrySpanExporter.getFinishedSpanItems().size(), 0); + + // OpenCensus spans and events verification + Map spans = failOnOverkillTraceComponent.getSpans(); + assertThat(spans).containsEntry("CloudSpanner.ReadOnlyTransaction", true); + assertThat(spans).containsEntry("CloudSpannerOperation.BatchCreateSessions", true); + assertThat(spans).containsEntry("CloudSpannerOperation.BatchCreateSessionsRequest", true); + assertThat(spans).containsEntry("CloudSpannerOperation.ExecuteStreamingQuery", true); + + List expectedAnnotations = + ImmutableList.of( + "Requesting 2 sessions", + "Request for 2 sessions returned 2 sessions", + "Creating 2 sessions", + "Acquiring session", + "Acquired session", + "Using Session", + "Starting/Resuming stream", + "Stream broken. Not safe to retry"); + List expectedAnnotationsForMultiplexedSession = + ImmutableList.of( + "Requesting 2 sessions", + "Request for 2 sessions returned 2 sessions", + "Request for 1 multiplexed session returned 1 session", + "Creating 2 sessions", + "Starting/Resuming stream", + "Stream broken. Not safe to retry"); + if (spanner.getOptions().getSessionPoolOptions().getUseMultiplexedSession()) { + verifyAnnotations( + failOnOverkillTraceComponent.getAnnotations().stream() + .distinct() + .collect(Collectors.toList()), + expectedAnnotationsForMultiplexedSession); + } else { + verifyAnnotations( + failOnOverkillTraceComponent.getAnnotations().stream() + .distinct() + .collect(Collectors.toList()), + expectedAnnotations); + } + } + @Test public void multiUse() { try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { @@ -357,7 +426,6 @@ public void multiUse() { "Request for 2 sessions returned 2 sessions", "Request for 1 multiplexed session returned 1 session", "Creating 2 sessions", - "Using Session", "Starting/Resuming stream", "Creating Transaction", "Transaction Creation Done"); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java index 8c5b9be5e07..90d76c6a2bb 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java @@ -284,7 +284,8 @@ public void singleUseResourceExhausted_retryable() { @Test public void singleUseNonRetryableError() { - mockSpanner.addException(FAILED_PRECONDITION); + mockSpanner.setExecuteStreamingSqlExecutionTime( + SimulatedExecutionTime.ofException(FAILED_PRECONDITION)); try (ResultSet rs = client.singleUse().executeQuery(SELECT1AND2)) { SpannerException e = assertThrows(SpannerException.class, () -> rs.next()); assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); @@ -294,7 +295,8 @@ public void singleUseNonRetryableError() { @Test public void singleUseNonRetryableErrorOnNext() { try (ResultSet rs = client.singleUse().executeQuery(SELECT1AND2)) { - mockSpanner.addException(FAILED_PRECONDITION); + mockSpanner.setExecuteStreamingSqlExecutionTime( + SimulatedExecutionTime.ofException(FAILED_PRECONDITION)); SpannerException e = assertThrows(SpannerException.class, () -> rs.next()); assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); } @@ -302,7 +304,8 @@ public void singleUseNonRetryableErrorOnNext() { @Test public void singleUseInternal() { - mockSpanner.addException(new IllegalArgumentException()); + mockSpanner.setExecuteStreamingSqlExecutionTime( + SimulatedExecutionTime.ofException(new IllegalArgumentException())); try (ResultSet rs = client.singleUse().executeQuery(SELECT1AND2)) { SpannerException e = assertThrows(SpannerException.class, () -> rs.next()); assertEquals(ErrorCode.INTERNAL, e.getErrorCode()); 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 015927440d5..7b57e3f9014 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 @@ -1751,7 +1751,7 @@ public void testTransactionTagNotAllowedAfterTransactionStarted() { new ConnectionImpl( connectionOptions, spannerPool, ddlClient, dbClient, mock(BatchClient.class)) { @Override - UnitOfWork createNewUnitOfWork(boolean isInternalMetadataQuery) { + UnitOfWork createNewUnitOfWork(boolean isInternalMetadataQuery, boolean forceSingleUse) { return unitOfWork; } }) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTransactionalReadWriteTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTransactionalReadWriteTest.java index aac7497d074..ba47421287a 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTransactionalReadWriteTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTransactionalReadWriteTest.java @@ -151,7 +151,8 @@ boolean isGetCommitTimestampAllowed() { boolean isExecuteAllowed(StatementType type) { return type == StatementType.CLIENT_SIDE || type == StatementType.QUERY - || type == StatementType.UPDATE; + || type == StatementType.UPDATE + || type == StatementType.DDL; } @Override @@ -765,7 +766,8 @@ boolean isGetCommitTimestampAllowed() { boolean isExecuteAllowed(StatementType type) { return type == StatementType.CLIENT_SIDE || type == StatementType.QUERY - || type == StatementType.UPDATE; + || type == StatementType.UPDATE + || type == StatementType.DDL; } @Override @@ -920,7 +922,8 @@ boolean isGetCommitTimestampAllowed() { boolean isExecuteAllowed(StatementType type) { return type == StatementType.CLIENT_SIDE || type == StatementType.QUERY - || type == StatementType.UPDATE; + || type == StatementType.UPDATE + || type == StatementType.DDL; } @Override @@ -1074,7 +1077,8 @@ boolean isGetCommitTimestampAllowed() { boolean isExecuteAllowed(StatementType type) { return type == StatementType.CLIENT_SIDE || type == StatementType.QUERY - || type == StatementType.UPDATE; + || type == StatementType.UPDATE + || type == StatementType.DDL; } @Override @@ -1378,7 +1382,8 @@ boolean isGetCommitTimestampAllowed() { boolean isExecuteAllowed(StatementType type) { return type == StatementType.CLIENT_SIDE || type == StatementType.QUERY - || type == StatementType.UPDATE; + || type == StatementType.UPDATE + || type == StatementType.DDL; } @Override @@ -1829,7 +1834,8 @@ boolean isGetCommitTimestampAllowed() { boolean isExecuteAllowed(StatementType type) { return type == StatementType.CLIENT_SIDE || type == StatementType.QUERY - || type == StatementType.UPDATE; + || type == StatementType.UPDATE + || type == StatementType.DDL; } @Override @@ -1979,7 +1985,8 @@ boolean isGetCommitTimestampAllowed() { boolean isExecuteAllowed(StatementType type) { return type == StatementType.CLIENT_SIDE || type == StatementType.QUERY - || type == StatementType.UPDATE; + || type == StatementType.UPDATE + || type == StatementType.DDL; } @Override diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionTest.java index d88882fc4c2..c52be0e4d09 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionTest.java @@ -290,7 +290,10 @@ public void testMaxSessions() assertThat(count1.isDone()).isTrue(); assertThat(count2.isDone()).isTrue(); if (isMultiplexedSessionsEnabled(connection1.getSpanner())) { - assertThat(mockSpanner.numSessionsCreated()).isEqualTo(2); + // We don't use the multiplexed session, so we don't know whether the server had time to + // create it or not. That means that we have between 1 and 2 sessions on the server. + assertThat(mockSpanner.numSessionsCreated()).isAtLeast(1); + assertThat(mockSpanner.numSessionsCreated()).isAtMost(2); } else { assertThat(mockSpanner.numSessionsCreated()).isEqualTo(1); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlTest.java index 0b9b2bdd8dd..44a2f4d9ff7 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlTest.java @@ -17,7 +17,10 @@ package com.google.cloud.spanner.connection; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import com.google.cloud.spanner.ErrorCode; +import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.connection.StatementResult.ResultType; import com.google.longrunning.Operation; @@ -25,6 +28,7 @@ import com.google.protobuf.Empty; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlRequest; +import com.google.spanner.v1.CommitRequest; import java.util.List; import java.util.stream.Collectors; import org.junit.After; @@ -106,4 +110,124 @@ public void testBatchedAnalyzeStatement() { assertEquals("create table foo (id int64) primary key (id)", requests.get(0).getStatements(0)); assertEquals("analyze", requests.get(0).getStatements(1)); } + + @Test + public void testDdlAtStartOfTransaction() { + Statement statement = Statement.of("create table foo (id int64) primary key (id)"); + for (DdlInTransactionMode mode : DdlInTransactionMode.values()) { + mockDatabaseAdmin.getRequests().clear(); + if (mode != DdlInTransactionMode.FAIL) { + addUpdateDdlResponse(); + } + + try (Connection connection = createConnection()) { + connection.setAutocommit(false); + connection.setDdlInTransactionMode(mode); + + if (mode == DdlInTransactionMode.FAIL) { + SpannerException exception = + assertThrows(SpannerException.class, () -> connection.execute(statement)); + assertEquals(ErrorCode.FAILED_PRECONDITION, exception.getErrorCode()); + } else { + assertEquals(ResultType.NO_RESULT, connection.execute(statement).getResultType()); + assertEquals(1, mockDatabaseAdmin.getRequests().size()); + } + } + } + } + + @Test + public void testDdlBatchAtStartOfTransaction() { + for (DdlInTransactionMode mode : DdlInTransactionMode.values()) { + mockDatabaseAdmin.getRequests().clear(); + if (mode != DdlInTransactionMode.FAIL) { + addUpdateDdlResponse(); + } + + try (Connection connection = createConnection()) { + connection.setAutocommit(false); + connection.setDdlInTransactionMode(mode); + + if (mode == DdlInTransactionMode.FAIL) { + SpannerException exception = + assertThrows( + SpannerException.class, + () -> connection.execute(Statement.of("start batch ddl"))); + assertEquals(ErrorCode.FAILED_PRECONDITION, exception.getErrorCode()); + } else { + connection.execute(Statement.of("start batch ddl")); + connection.execute(Statement.of("create table foo")); + connection.execute(Statement.of("alter table bar")); + connection.execute(Statement.of("run batch")); + assertEquals(1, mockDatabaseAdmin.getRequests().size()); + UpdateDatabaseDdlRequest request = + (UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(0); + assertEquals(2, request.getStatementsCount()); + } + } + } + } + + @Test + public void testDdlInTransaction() { + Statement statement = Statement.of("create table foo (id int64) primary key (id)"); + for (DdlInTransactionMode mode : DdlInTransactionMode.values()) { + mockDatabaseAdmin.getRequests().clear(); + if (mode == DdlInTransactionMode.AUTO_COMMIT_TRANSACTION) { + addUpdateDdlResponse(); + } + + try (Connection connection = createConnection()) { + connection.setAutocommit(false); + connection.setDdlInTransactionMode(mode); + + connection.execute(INSERT_STATEMENT); + + if (mode != DdlInTransactionMode.AUTO_COMMIT_TRANSACTION) { + SpannerException exception = + assertThrows(SpannerException.class, () -> connection.execute(statement)); + assertEquals(ErrorCode.FAILED_PRECONDITION, exception.getErrorCode()); + } else { + assertEquals(ResultType.NO_RESULT, connection.execute(statement).getResultType()); + assertEquals(1, mockDatabaseAdmin.getRequests().size()); + assertEquals(1, mockSpanner.countRequestsOfType(CommitRequest.class)); + } + } + } + } + + @Test + public void testDdlBatchInTransaction() { + for (DdlInTransactionMode mode : DdlInTransactionMode.values()) { + mockDatabaseAdmin.getRequests().clear(); + if (mode == DdlInTransactionMode.AUTO_COMMIT_TRANSACTION) { + addUpdateDdlResponse(); + } + + try (Connection connection = createConnection()) { + connection.setAutocommit(false); + connection.setDdlInTransactionMode(mode); + + connection.execute(INSERT_STATEMENT); + + if (mode != DdlInTransactionMode.AUTO_COMMIT_TRANSACTION) { + SpannerException exception = + assertThrows( + SpannerException.class, + () -> connection.execute(Statement.of("start batch ddl"))); + assertEquals(ErrorCode.FAILED_PRECONDITION, exception.getErrorCode()); + } else { + connection.execute(Statement.of("start batch ddl")); + connection.execute(Statement.of("create table foo")); + connection.execute(Statement.of("alter table bar")); + connection.execute(Statement.of("run batch")); + assertEquals(1, mockDatabaseAdmin.getRequests().size()); + UpdateDatabaseDdlRequest request = + (UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(0); + assertEquals(2, request.getStatementsCount()); + assertEquals(1, mockSpanner.countRequestsOfType(CommitRequest.class)); + } + } + } + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java index ab45eb67179..f9230b8836b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java @@ -36,7 +36,9 @@ import com.google.cloud.spanner.Mutation; import com.google.cloud.spanner.ParallelIntegrationTest; import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.SessionNotFoundException; import com.google.cloud.spanner.SpannerException; +import com.google.cloud.spanner.SpannerException.ResourceNotFoundException; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.TransactionContext; import com.google.cloud.spanner.TransactionRunner.TransactionCallable; @@ -89,9 +91,10 @@ public void databaseDeletedTest() throws Exception { .setMaxElapsedTimeMillis(65000) .setMaxIntervalMillis(5000) .build(); - DatabaseNotFoundException notFoundException = null; - long millis = 0L; + ResourceNotFoundException notFoundException = null; + long millis; while ((millis = backoff.nextBackOffMillis()) != ExponentialBackOff.STOP) { + //noinspection BusyWait Thread.sleep(millis); // Queries to this database should eventually return DatabaseNotFoundExceptions. try (ResultSet rs = client.singleUse().executeQuery(Statement.of("SELECT 1"))) { @@ -115,13 +118,40 @@ public void databaseDeletedTest() throws Exception { Collections.emptyList()); Database newDb = op.get(); - // Queries using the same DatabaseClient should still return DatabaseNotFoundExceptions. - try (ResultSet rs = client.singleUse().executeQuery(Statement.of("SELECT 1"))) { - rs.next(); - fail("Missing expected DatabaseNotFoundException"); - } catch (DatabaseNotFoundException e) { - // This is what we expect. + // Now try to query using the old session and verify that we also now (eventually) get a + // 'Database not found' error. + backoff = + new ExponentialBackOff.Builder() + .setInitialIntervalMillis(1000) + .setMaxElapsedTimeMillis(65000) + .setMaxIntervalMillis(5000) + .build(); + + notFoundException = null; + while ((millis = backoff.nextBackOffMillis()) != ExponentialBackOff.STOP) { + //noinspection BusyWait + Thread.sleep(millis); + // Queries to this database should eventually return DatabaseNotFoundExceptions. + try (ResultSet rs = client.singleUse().executeQuery(Statement.of("SELECT 1"))) { + rs.next(); + } catch (DatabaseNotFoundException databaseNotFoundException) { + // This is what we expect. + notFoundException = databaseNotFoundException; + break; + } catch (SessionNotFoundException sessionNotFoundException) { + if (isUsingEmulator()) { + // This is expected on the emulator, as the emulator does not see a difference between two + // different databases with the same name. The original session from the first database is + // however not present on the newly created database, which is why we get a + // SessionNotFoundException. + notFoundException = sessionNotFoundException; + break; + } else { + throw sessionNotFoundException; + } + } } + assertThat(notFoundException).isNotNull(); // Now get a new DatabaseClient for the database. This should now result in a valid // DatabaseClient. 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 b8183a6c944..30aed342903 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 @@ -2727,6 +2727,205 @@ NEW_CONNECTION; @EXPECT EXCEPTION UNIMPLEMENTED show variable/-return_commit_stats; NEW_CONNECTION; +show variable max_commit_delay; +NEW_CONNECTION; +SHOW VARIABLE MAX_COMMIT_DELAY; +NEW_CONNECTION; +show variable max_commit_delay; +NEW_CONNECTION; + show variable max_commit_delay; +NEW_CONNECTION; + show variable max_commit_delay; +NEW_CONNECTION; + + + +show variable max_commit_delay; +NEW_CONNECTION; +show variable max_commit_delay ; +NEW_CONNECTION; +show variable max_commit_delay ; +NEW_CONNECTION; +show variable max_commit_delay + +; +NEW_CONNECTION; +show variable max_commit_delay; +NEW_CONNECTION; +show variable max_commit_delay; +NEW_CONNECTION; +show +variable +max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay%; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable%max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay_; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable_max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay&; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable&max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay$; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable$max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay@; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable@max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay!; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable!max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay*; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable*max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay(; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable(max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay); +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable)max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay+; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable+max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay-#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-#max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay\; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable\max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay?; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable?max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay-/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-/max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay/#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/#max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-show variable max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable max_commit_delay/-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/-max_commit_delay; +NEW_CONNECTION; update foo set bar=1; show variable commit_response; NEW_CONNECTION; @@ -15371,6 +15570,996 @@ NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT set return_commit_stats =/-false; NEW_CONNECTION; +set max_commit_delay=null; +NEW_CONNECTION; +SET MAX_COMMIT_DELAY=NULL; +NEW_CONNECTION; +set max_commit_delay=null; +NEW_CONNECTION; + set max_commit_delay=null; +NEW_CONNECTION; + set max_commit_delay=null; +NEW_CONNECTION; + + + +set max_commit_delay=null; +NEW_CONNECTION; +set max_commit_delay=null ; +NEW_CONNECTION; +set max_commit_delay=null ; +NEW_CONNECTION; +set max_commit_delay=null + +; +NEW_CONNECTION; +set max_commit_delay=null; +NEW_CONNECTION; +set max_commit_delay=null; +NEW_CONNECTION; +set +max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay=null/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-max_commit_delay=null; +NEW_CONNECTION; +set max_commit_delay='1s'; +NEW_CONNECTION; +SET MAX_COMMIT_DELAY='1S'; +NEW_CONNECTION; +set max_commit_delay='1s'; +NEW_CONNECTION; + set max_commit_delay='1s'; +NEW_CONNECTION; + set max_commit_delay='1s'; +NEW_CONNECTION; + + + +set max_commit_delay='1s'; +NEW_CONNECTION; +set max_commit_delay='1s' ; +NEW_CONNECTION; +set max_commit_delay='1s' ; +NEW_CONNECTION; +set max_commit_delay='1s' + +; +NEW_CONNECTION; +set max_commit_delay='1s'; +NEW_CONNECTION; +set max_commit_delay='1s'; +NEW_CONNECTION; +set +max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='1s'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-max_commit_delay='1s'; +NEW_CONNECTION; +set max_commit_delay='100ms'; +NEW_CONNECTION; +SET MAX_COMMIT_DELAY='100MS'; +NEW_CONNECTION; +set max_commit_delay='100ms'; +NEW_CONNECTION; + set max_commit_delay='100ms'; +NEW_CONNECTION; + set max_commit_delay='100ms'; +NEW_CONNECTION; + + + +set max_commit_delay='100ms'; +NEW_CONNECTION; +set max_commit_delay='100ms' ; +NEW_CONNECTION; +set max_commit_delay='100ms' ; +NEW_CONNECTION; +set max_commit_delay='100ms' + +; +NEW_CONNECTION; +set max_commit_delay='100ms'; +NEW_CONNECTION; +set max_commit_delay='100ms'; +NEW_CONNECTION; +set +max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='100ms'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-max_commit_delay='100ms'; +NEW_CONNECTION; +set max_commit_delay='10000us'; +NEW_CONNECTION; +SET MAX_COMMIT_DELAY='10000US'; +NEW_CONNECTION; +set max_commit_delay='10000us'; +NEW_CONNECTION; + set max_commit_delay='10000us'; +NEW_CONNECTION; + set max_commit_delay='10000us'; +NEW_CONNECTION; + + + +set max_commit_delay='10000us'; +NEW_CONNECTION; +set max_commit_delay='10000us' ; +NEW_CONNECTION; +set max_commit_delay='10000us' ; +NEW_CONNECTION; +set max_commit_delay='10000us' + +; +NEW_CONNECTION; +set max_commit_delay='10000us'; +NEW_CONNECTION; +set max_commit_delay='10000us'; +NEW_CONNECTION; +set +max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set max_commit_delay='10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='10000us'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-max_commit_delay='10000us'; +NEW_CONNECTION; +set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +SET MAX_COMMIT_DELAY='9223372036854775807NS'; +NEW_CONNECTION; +set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; + set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; + set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; + + + +set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +set max_commit_delay='9223372036854775807ns' ; +NEW_CONNECTION; +set max_commit_delay='9223372036854775807ns' ; +NEW_CONNECTION; +set max_commit_delay='9223372036854775807ns' + +; +NEW_CONNECTION; +set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +set +max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set max_commit_delay='9223372036854775807ns'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-max_commit_delay='9223372036854775807ns'; +NEW_CONNECTION; set statement_tag='tag1'; NEW_CONNECTION; SET STATEMENT_TAG='TAG1'; diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ConnectionImplGeneratedSqlScriptTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ConnectionImplGeneratedSqlScriptTest.sql index bde12f6662e..84275c3d5c3 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ConnectionImplGeneratedSqlScriptTest.sql +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ConnectionImplGeneratedSqlScriptTest.sql @@ -160,15 +160,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:15.740000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:15.740000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:32.894000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:32.894000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:15.740000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:32.894000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -510,15 +510,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; SET READ_ONLY_STALENESS='EXACT_STALENESS 10s'; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:16.217000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:16.217000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.008000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.008000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; SET READ_ONLY_STALENESS='EXACT_STALENESS 10s'; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:16.217000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.008000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -950,8 +950,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; ROLLBACK; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:16.608000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:16.608000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.111000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.111000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -961,7 +961,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; ROLLBACK; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:16.608000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.111000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -1462,8 +1462,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:17.090000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:17.090000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.217000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.217000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -1473,7 +1473,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:17.090000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.217000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -1876,15 +1876,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:17.518000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:17.518000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.318000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.318000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:17.518000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.318000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -2243,14 +2243,14 @@ SET AUTOCOMMIT=FALSE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:17.918000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.388000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:17.918000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.388000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -2600,13 +2600,13 @@ SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:18.303000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.472000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:18.303000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.472000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -2910,14 +2910,14 @@ SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:18.684000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:18.684000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.543000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.543000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:18.684000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.543000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -3114,7 +3114,6 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; COMMIT; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET READONLY=FALSE; @@ -3246,15 +3245,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:19.116000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:19.116000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.630000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.630000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:19.116000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.630000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -3486,7 +3485,6 @@ SET AUTOCOMMIT=FALSE; START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); RUN BATCH; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET READONLY=FALSE; @@ -3664,8 +3662,8 @@ SET AUTOCOMMIT=FALSE; START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); RUN BATCH; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:19.521000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:19.521000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.713000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.713000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -3674,7 +3672,7 @@ START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); RUN BATCH; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:19.521000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.713000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4083,14 +4081,14 @@ SET AUTOCOMMIT=FALSE; START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:19.953000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.778000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:19.953000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.778000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4440,13 +4438,13 @@ SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:20.274000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.833000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:20.274000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.833000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4679,7 +4677,6 @@ SET TRANSACTION READ ONLY; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET READONLY=FALSE; @@ -4880,8 +4877,8 @@ SET TRANSACTION READ ONLY; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:20.662000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:20.662000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.892000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.892000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -4891,7 +4888,7 @@ SET TRANSACTION READ ONLY; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:20.662000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.892000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5291,15 +5288,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET TRANSACTION READ ONLY; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:21.051000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:21.051000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.959000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.959000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET TRANSACTION READ ONLY; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:21.051000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.959000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5513,7 +5510,6 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET READ_ONLY_STALENESS='EXACT_STALENESS 10s'; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET READONLY=FALSE; @@ -5645,15 +5641,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET READ_ONLY_STALENESS='EXACT_STALENESS 10s'; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:21.343000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:21.343000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.012000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.012000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET READ_ONLY_STALENESS='EXACT_STALENESS 10s'; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:21.343000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.012000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5892,7 +5888,6 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; ROLLBACK; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET READONLY=FALSE; @@ -6093,8 +6088,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; ROLLBACK; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:21.630000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:21.630000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.073000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.073000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -6104,7 +6099,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; ROLLBACK; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:21.630000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.073000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -6412,7 +6407,6 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET READONLY=FALSE; @@ -6613,8 +6607,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:22.181000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:22.181000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.152000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.152000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -6624,7 +6618,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:22.181000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.152000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7029,15 +7023,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:22.566000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:22.566000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.223000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.223000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:22.566000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.223000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7400,14 +7394,14 @@ SET AUTOCOMMIT=FALSE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:22.853000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.285000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:22.853000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.285000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7762,13 +7756,13 @@ SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:23.261000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.350000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:23.261000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.350000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7973,7 +7967,6 @@ UPDATE foo SET bar=1; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET READONLY=FALSE; @@ -8082,14 +8075,14 @@ SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:23.615000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:23.615000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.415000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.415000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:23.615000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.415000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -8399,13 +8392,13 @@ SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:23.894000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.468000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:23.894000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.468000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -8760,8 +8753,8 @@ SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SET TRANSACTION READ ONLY; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:24.167000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:24.167000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.517000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.517000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -8769,7 +8762,7 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SET TRANSACTION READ ONLY; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:24.167000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.517000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -9204,8 +9197,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; UPDATE foo SET bar=1; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:24.502000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:24.502000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.575000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.575000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -9213,8 +9206,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; UPDATE foo SET bar=1; COMMIT; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:24.502000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:24.502000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.575000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.575000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -9600,15 +9593,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:24.834000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:24.834000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.641000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.641000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:24.834000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.641000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -9959,15 +9952,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:25.130000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:25.130000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.691000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.691000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:25.130000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:25.130000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.691000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.691000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -10327,15 +10320,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; UPDATE foo SET bar=1; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:25.446000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:25.446000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.768000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.768000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; UPDATE foo SET bar=1; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:25.446000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:25.446000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.768000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.768000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -10725,16 +10718,16 @@ SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:25.758000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:25.758000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.829000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.829000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:25.758000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:25.758000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.829000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.829000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -11117,15 +11110,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:26.062000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:26.062000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.886000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.886000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:26.062000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:26.062000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.886000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.886000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -11455,14 +11448,14 @@ SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:26.366000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:26.366000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.946000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.946000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:26.366000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:26.366000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.946000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.946000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -11785,15 +11778,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; SET READ_ONLY_STALENESS='MAX_STALENESS 10s'; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:26.618000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:26.618000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.999000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.999000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; SET READ_ONLY_STALENESS='MAX_STALENESS 10s'; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:26.618000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:26.618000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.999000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.999000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -12200,8 +12193,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:26.883000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:26.883000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.050000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.050000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -12209,8 +12202,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:26.883000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:26.883000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.050000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.050000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -12593,15 +12586,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:27.234000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:27.234000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.106000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.106000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:27.234000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.106000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; @@ -12939,15 +12932,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:27.524000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:27.524000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.157000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.157000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:27.524000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:27.524000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.157000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.157000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -13294,15 +13287,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:27.818000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:27.818000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.213000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.213000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:27.818000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:27.818000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.213000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.213000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -13619,14 +13612,14 @@ SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:28.091000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:28.091000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.269000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.269000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:28.091000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:28.091000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.269000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.269000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITTransactionModeTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITTransactionModeTest.sql index 7bb0f80943a..e2253d3cda0 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITTransactionModeTest.sql +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/ITTransactionModeTest.sql @@ -33,6 +33,8 @@ NEW_CONNECTION; SHOW VARIABLE AUTOCOMMIT; @EXPECT RESULT_SET 'READONLY',false SHOW VARIABLE READONLY; +@EXPECT RESULT_SET 'C',1 +SELECT 1 AS C; @EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE FOO (ID INT64 NOT NULL, NAME STRING(100) PRIMARY KEY (ID); diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ClientSideStatementsTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ClientSideStatementsTest.sql index e8843ab6aa7..5ffa722385d 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ClientSideStatementsTest.sql +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ClientSideStatementsTest.sql @@ -5443,6 +5443,403 @@ NEW_CONNECTION; @EXPECT EXCEPTION UNIMPLEMENTED show variable/-spanner.return_commit_stats; NEW_CONNECTION; +show spanner.max_commit_delay; +NEW_CONNECTION; +SHOW SPANNER.MAX_COMMIT_DELAY; +NEW_CONNECTION; +show spanner.max_commit_delay; +NEW_CONNECTION; + show spanner.max_commit_delay; +NEW_CONNECTION; + show spanner.max_commit_delay; +NEW_CONNECTION; + + + +show spanner.max_commit_delay; +NEW_CONNECTION; +show spanner.max_commit_delay ; +NEW_CONNECTION; +show spanner.max_commit_delay ; +NEW_CONNECTION; +show spanner.max_commit_delay + +; +NEW_CONNECTION; +show spanner.max_commit_delay; +NEW_CONNECTION; +show spanner.max_commit_delay; +NEW_CONNECTION; +show +spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show%spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show_spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show&spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show$spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show@spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show!spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show*spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show(spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show)spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show-spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show+spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show-#spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show/spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show\spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show?spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show-/spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show/#spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-show spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.max_commit_delay/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show/-spanner.max_commit_delay; +NEW_CONNECTION; +show variable spanner.max_commit_delay; +NEW_CONNECTION; +SHOW VARIABLE SPANNER.MAX_COMMIT_DELAY; +NEW_CONNECTION; +show variable spanner.max_commit_delay; +NEW_CONNECTION; + show variable spanner.max_commit_delay; +NEW_CONNECTION; + show variable spanner.max_commit_delay; +NEW_CONNECTION; + + + +show variable spanner.max_commit_delay; +NEW_CONNECTION; +show variable spanner.max_commit_delay ; +NEW_CONNECTION; +show variable spanner.max_commit_delay ; +NEW_CONNECTION; +show variable spanner.max_commit_delay + +; +NEW_CONNECTION; +show variable spanner.max_commit_delay; +NEW_CONNECTION; +show variable spanner.max_commit_delay; +NEW_CONNECTION; +show +variable +spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay%; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable%spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay_; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable_spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay&; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable&spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay$; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable$spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay@; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable@spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay!; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable!spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay*; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable*spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay(; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable(spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay); +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable)spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay+; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable+spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay-#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-#spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay\; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable\spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay?; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable?spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay-/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-/spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay/#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/#spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-show variable spanner.max_commit_delay; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.max_commit_delay/-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/-spanner.max_commit_delay; +NEW_CONNECTION; update foo set bar=1; show spanner.commit_response; NEW_CONNECTION; @@ -66128,6 +66525,1000 @@ NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT set spanner.return_commit_stats to/-false; NEW_CONNECTION; +set spanner.max_commit_delay=null; +NEW_CONNECTION; +SET SPANNER.MAX_COMMIT_DELAY=NULL; +NEW_CONNECTION; +set spanner.max_commit_delay=null; +NEW_CONNECTION; + set spanner.max_commit_delay=null; +NEW_CONNECTION; + set spanner.max_commit_delay=null; +NEW_CONNECTION; + + + +set spanner.max_commit_delay=null; +NEW_CONNECTION; +set spanner.max_commit_delay=null ; +NEW_CONNECTION; +set spanner.max_commit_delay=null ; +NEW_CONNECTION; +set spanner.max_commit_delay=null + +; +NEW_CONNECTION; +set spanner.max_commit_delay=null; +NEW_CONNECTION; +set spanner.max_commit_delay=null; +NEW_CONNECTION; +set +spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.max_commit_delay=null; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay=null/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-spanner.max_commit_delay=null; +NEW_CONNECTION; +set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +SET SPANNER.MAX_COMMIT_DELAY='1S'; +NEW_CONNECTION; +set spanner.max_commit_delay='1s'; +NEW_CONNECTION; + set spanner.max_commit_delay='1s'; +NEW_CONNECTION; + set spanner.max_commit_delay='1s'; +NEW_CONNECTION; + + + +set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +set spanner.max_commit_delay='1s' ; +NEW_CONNECTION; +set spanner.max_commit_delay='1s' ; +NEW_CONNECTION; +set spanner.max_commit_delay='1s' + +; +NEW_CONNECTION; +set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +set +spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.max_commit_delay='1s'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='1s'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-spanner.max_commit_delay='1s'; +NEW_CONNECTION; +set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +SET SPANNER.MAX_COMMIT_DELAY='100MS'; +NEW_CONNECTION; +set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; + set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; + set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; + + + +set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +set spanner.max_commit_delay='100ms' ; +NEW_CONNECTION; +set spanner.max_commit_delay='100ms' ; +NEW_CONNECTION; +set spanner.max_commit_delay='100ms' + +; +NEW_CONNECTION; +set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +set +spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set%spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set_spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set&spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set$spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set@spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set!spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set*spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set(spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set)spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set+spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-#spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set\spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set?spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set-/spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/#spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay='100ms'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set/-spanner.max_commit_delay='100ms'; +NEW_CONNECTION; +set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +SET SPANNER.MAX_COMMIT_DELAY TO '10000US'; +NEW_CONNECTION; +set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; + set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; + set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; + + + +set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +set spanner.max_commit_delay to '10000us' ; +NEW_CONNECTION; +set spanner.max_commit_delay to '10000us' ; +NEW_CONNECTION; +set spanner.max_commit_delay to '10000us' + +; +NEW_CONNECTION; +set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +set +spanner.max_commit_delay +to +'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to%'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to_'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to&'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to$'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to@'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to!'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to*'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to('10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to)'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to-'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to+'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to-#'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to/'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to\'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to?'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to-/'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to/#'10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.max_commit_delay to '10000us'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to '10000us'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay to/-'10000us'; +NEW_CONNECTION; +set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +SET SPANNER.MAX_COMMIT_DELAY TO '9223372036854775807NS'; +NEW_CONNECTION; +set spanner.max_commit_delay to '9223372036854775807ns'; +NEW_CONNECTION; + set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; + set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; + + + +set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +set spanner.max_commit_delay TO '9223372036854775807ns' ; +NEW_CONNECTION; +set spanner.max_commit_delay TO '9223372036854775807ns' ; +NEW_CONNECTION; +set spanner.max_commit_delay TO '9223372036854775807ns' + +; +NEW_CONNECTION; +set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +set +spanner.max_commit_delay +TO +'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO%'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO_'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO&'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO$'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO@'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO!'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO*'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO('9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO)'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO-'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO+'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO-#'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO/'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO\'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO?'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO-/'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO/#'9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.max_commit_delay TO '9223372036854775807ns'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO '9223372036854775807ns'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.max_commit_delay TO/-'9223372036854775807ns'; +NEW_CONNECTION; set spanner.statement_tag='tag1'; NEW_CONNECTION; SET SPANNER.STATEMENT_TAG='TAG1'; @@ -67322,6 +68713,206 @@ NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT set spanner.statement_tag to/-''; NEW_CONNECTION; +set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +SET SPANNER.STATEMENT_TAG TO 'TEST_TAG'; +NEW_CONNECTION; +set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; + set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; + set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; + + + +set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +set spanner.statement_tag to 'test_tag' ; +NEW_CONNECTION; +set spanner.statement_tag to 'test_tag' ; +NEW_CONNECTION; +set spanner.statement_tag to 'test_tag' + +; +NEW_CONNECTION; +set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +set +spanner.statement_tag +to +'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag' bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to%'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to_'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to&'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to$'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to@'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to!'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to*'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to('test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to)'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to-'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to+'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to-#'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to/'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to\'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to?'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to-/'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to/#'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.statement_tag to 'test_tag'; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to 'test_tag'/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.statement_tag to/-'test_tag'; +NEW_CONNECTION; set autocommit = false; set spanner.transaction_tag='tag1'; NEW_CONNECTION; @@ -68924,6 +70515,274 @@ set autocommit = false; @EXPECT EXCEPTION INVALID_ARGUMENT set spanner.transaction_tag to/-''; NEW_CONNECTION; +set autocommit = false; +set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +SET SPANNER.TRANSACTION_TAG TO 'TEST_TAG'; +NEW_CONNECTION; +set autocommit = false; +set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; + set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; + set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; + + + +set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +set spanner.transaction_tag to 'test_tag' ; +NEW_CONNECTION; +set autocommit = false; +set spanner.transaction_tag to 'test_tag' ; +NEW_CONNECTION; +set autocommit = false; +set spanner.transaction_tag to 'test_tag' + +; +NEW_CONNECTION; +set autocommit = false; +set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +set +spanner.transaction_tag +to +'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag' bar; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'%; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to%'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'_; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to_'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'&; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to&'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'$; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to$'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'@; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to@'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'!; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to!'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'*; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to*'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'(; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to('test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'); +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to)'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'-; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to-'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'+; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to+'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'-#; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to-#'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'/; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to/'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'\; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to\'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'?; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to?'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'-/; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to-/'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'/#; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to/#'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.transaction_tag to 'test_tag'; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to 'test_tag'/-; +NEW_CONNECTION; +set autocommit = false; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.transaction_tag to/-'test_tag'; +NEW_CONNECTION; set spanner.rpc_priority='HIGH'; NEW_CONNECTION; SET SPANNER.RPC_PRIORITY='HIGH'; diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ConnectionImplGeneratedSqlScriptTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ConnectionImplGeneratedSqlScriptTest.sql index c64d2b6ce13..e35ae5f3c3c 100644 --- a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ConnectionImplGeneratedSqlScriptTest.sql +++ b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ConnectionImplGeneratedSqlScriptTest.sql @@ -160,15 +160,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:16.008000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:16.008000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:32.957000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:32.957000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:16.008000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:32.957000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -510,15 +510,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; SET SPANNER.READ_ONLY_STALENESS='EXACT_STALENESS 10s'; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:16.391000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:16.391000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.060000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.060000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; SET SPANNER.READ_ONLY_STALENESS='EXACT_STALENESS 10s'; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:16.391000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.060000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -950,8 +950,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; ROLLBACK; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:16.882000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:16.882000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.165000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.165000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -961,7 +961,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; ROLLBACK; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:16.882000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.165000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -1462,8 +1462,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:17.326000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:17.326000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.275000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.275000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -1473,7 +1473,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:17.326000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.275000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -1876,15 +1876,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:17.672000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:17.672000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.351000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.351000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:17.672000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.351000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -2243,14 +2243,14 @@ SET AUTOCOMMIT=FALSE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:18.117000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.428000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:18.117000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.428000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -2600,13 +2600,13 @@ SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:18.509000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.509000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:18.509000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.509000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -2910,14 +2910,14 @@ SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:18.834000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:18.834000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.575000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.575000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:18.834000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.575000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -3114,7 +3114,6 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; COMMIT; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -3246,15 +3245,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:19.286000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:19.286000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.662000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.662000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:19.286000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.662000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -3486,7 +3485,6 @@ SET AUTOCOMMIT=FALSE; START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); RUN BATCH; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -3664,8 +3662,8 @@ SET AUTOCOMMIT=FALSE; START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); RUN BATCH; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:19.688000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:19.688000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.747000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.747000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -3674,7 +3672,7 @@ START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); RUN BATCH; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:19.688000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.747000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4083,14 +4081,14 @@ SET AUTOCOMMIT=FALSE; START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:20.139000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.806000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; START BATCH DDL; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:20.139000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.806000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4440,13 +4438,13 @@ SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:20.445000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.861000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:20.445000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.861000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4679,7 +4677,6 @@ SET TRANSACTION READ ONLY; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -4880,8 +4877,8 @@ SET TRANSACTION READ ONLY; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:20.850000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:20.850000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.927000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.927000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -4891,7 +4888,7 @@ SET TRANSACTION READ ONLY; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:20.850000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.927000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5291,15 +5288,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET TRANSACTION READ ONLY; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:21.197000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:21.197000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:33.985000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:33.985000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET TRANSACTION READ ONLY; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:21.197000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:33.985000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5513,7 +5510,6 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET SPANNER.READ_ONLY_STALENESS='EXACT_STALENESS 10s'; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -5645,15 +5641,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET SPANNER.READ_ONLY_STALENESS='EXACT_STALENESS 10s'; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:21.478000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:21.478000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.041000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.041000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET SPANNER.READ_ONLY_STALENESS='EXACT_STALENESS 10s'; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:21.478000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.041000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5892,7 +5888,6 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; ROLLBACK; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -6093,8 +6088,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; ROLLBACK; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:21.844000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:21.844000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.108000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.108000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -6104,7 +6099,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; ROLLBACK; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:21.844000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.108000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -6412,7 +6407,6 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -6613,8 +6607,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:22.407000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:22.407000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.191000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.191000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -6624,7 +6618,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:22.407000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.191000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7029,15 +7023,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:22.697000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:22.697000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.254000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.254000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:22.697000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.254000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7400,14 +7394,14 @@ SET AUTOCOMMIT=FALSE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:23.054000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.318000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:23.054000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.318000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7762,13 +7756,13 @@ SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:23.432000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.384000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:23.432000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.384000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7973,7 +7967,6 @@ UPDATE foo SET bar=1; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; -@EXPECT EXCEPTION FAILED_PRECONDITION CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -8082,14 +8075,14 @@ SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:23.761000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:23.761000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.443000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.443000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:23.761000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.443000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -8399,13 +8392,13 @@ SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:24.025000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.492000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:24.025000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.492000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -8760,8 +8753,8 @@ SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SET TRANSACTION READ ONLY; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:24.320000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:24.320000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.542000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.542000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -8769,7 +8762,7 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SET TRANSACTION READ ONLY; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:24.320000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.542000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -9204,8 +9197,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; UPDATE foo SET bar=1; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:24.676000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:24.676000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.611000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.611000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -9213,8 +9206,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; UPDATE foo SET bar=1; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:24.676000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:24.676000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.611000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.611000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -9600,15 +9593,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:24.973000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:24.973000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.665000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.665000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:24.973000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.665000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -9959,15 +9952,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:25.308000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:25.308000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.719000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.719000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id); -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:25.308000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:25.308000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.719000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.719000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -10327,15 +10320,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; UPDATE foo SET bar=1; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:25.588000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:25.588000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.800000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.800000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; UPDATE foo SET bar=1; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:25.588000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:25.588000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.800000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.800000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -10725,16 +10718,16 @@ SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:25.921000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:25.921000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.857000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.857000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:25.921000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:25.921000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.857000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.857000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -11117,15 +11110,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:26.199000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:26.199000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.918000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.918000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:26.199000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:26.199000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.918000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.918000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -11455,14 +11448,14 @@ SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:26.495000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:26.495000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:34.974000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:34.974000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:26.495000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:26.495000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:34.974000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:34.974000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -11785,15 +11778,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; SET SPANNER.READ_ONLY_STALENESS='MAX_STALENESS 10s'; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:26.744000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:26.744000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.024000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.024000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; SET SPANNER.READ_ONLY_STALENESS='MAX_STALENESS 10s'; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:26.744000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:26.744000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.024000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.024000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -12200,8 +12193,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:27.080000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:27.080000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.080000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.080000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -12209,8 +12202,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:27.080000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:27.080000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.080000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.080000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -12593,15 +12586,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:27.369000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:27.369000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.129000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.129000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:27.369000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.129000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; @@ -12939,15 +12932,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:27.669000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:27.669000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.184000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.184000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:27.669000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:27.669000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.184000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.184000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -13294,15 +13287,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:27.959000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:27.959000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.242000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.242000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:27.959000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:27.959000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.242000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.242000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -13619,14 +13612,14 @@ SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-03-26T15:31:28.213000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-03-26T15:31:28.213000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-04-22T15:43:35.293000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-04-22T15:43:35.293000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-03-26T15:31:28.213000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-03-26T15:31:28.213000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-04-22T15:43:35.293000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-04-22T15:43:35.293000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 5e57f9fbb96..c2dabff690d 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.65.1 + 6.66.0 grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index d1511ecde81..1d37e0a7ecc 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.65.1 + 6.66.0 grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/grpc-google-cloud-spanner-executor-v1/pom.xml b/grpc-google-cloud-spanner-executor-v1/pom.xml index 19bed8f9e7e..02b9b9a4cf3 100644 --- a/grpc-google-cloud-spanner-executor-v1/pom.xml +++ b/grpc-google-cloud-spanner-executor-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-executor-v1 - 6.65.1 + 6.66.0 grpc-google-cloud-spanner-executor-v1 GRPC library for google-cloud-spanner com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index a1ffaec8604..416ec81e640 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.65.1 + 6.66.0 grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/pom.xml b/pom.xml index 09d67fc0da3..380dd7a5a33 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 6.65.1 + 6.66.0 Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -14,7 +14,7 @@ com.google.cloud sdk-platform-java-config - 3.29.0 + 3.30.0 @@ -61,47 +61,47 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.65.1 + 6.66.0 com.google.api.grpc proto-google-cloud-spanner-executor-v1 - 6.65.1 + 6.66.0 com.google.api.grpc grpc-google-cloud-spanner-executor-v1 - 6.65.1 + 6.66.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.65.1 + 6.66.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.65.1 + 6.66.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.65.1 + 6.66.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.65.1 + 6.66.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.65.1 + 6.66.0 com.google.cloud google-cloud-spanner - 6.65.1 + 6.66.0 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index bc81f7897c9..703d3a48917 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.65.1 + 6.66.0 proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 5f99c4cbd10..234537b46d0 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.65.1 + 6.66.0 proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/proto-google-cloud-spanner-executor-v1/pom.xml b/proto-google-cloud-spanner-executor-v1/pom.xml index dcddc4fd462..ad9fe73b971 100644 --- a/proto-google-cloud-spanner-executor-v1/pom.xml +++ b/proto-google-cloud-spanner-executor-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-executor-v1 - 6.65.1 + 6.66.0 proto-google-cloud-spanner-executor-v1 Proto library for google-cloud-spanner com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 8403789f397..14c9f9b5ad3 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.65.1 + 6.66.0 proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.65.1 + 6.66.0 diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 0765c5285f7..bc846dfdc77 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -33,7 +33,7 @@ com.google.cloud google-cloud-spanner - 6.65.0 + 6.65.1 diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 71d2979a0b7..6ffc3d57db9 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -32,7 +32,7 @@ com.google.cloud google-cloud-spanner - 6.65.1 + 6.66.0 diff --git a/versions.txt b/versions.txt index f7fe285588e..0f6c4274453 100644 --- a/versions.txt +++ b/versions.txt @@ -1,13 +1,13 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:6.65.1:6.65.1 -proto-google-cloud-spanner-v1:6.65.1:6.65.1 -proto-google-cloud-spanner-admin-database-v1:6.65.1:6.65.1 -grpc-google-cloud-spanner-v1:6.65.1:6.65.1 -grpc-google-cloud-spanner-admin-instance-v1:6.65.1:6.65.1 -grpc-google-cloud-spanner-admin-database-v1:6.65.1:6.65.1 -google-cloud-spanner:6.65.1:6.65.1 -google-cloud-spanner-executor:6.65.1:6.65.1 -proto-google-cloud-spanner-executor-v1:6.65.1:6.65.1 -grpc-google-cloud-spanner-executor-v1:6.65.1:6.65.1 +proto-google-cloud-spanner-admin-instance-v1:6.66.0:6.66.0 +proto-google-cloud-spanner-v1:6.66.0:6.66.0 +proto-google-cloud-spanner-admin-database-v1:6.66.0:6.66.0 +grpc-google-cloud-spanner-v1:6.66.0:6.66.0 +grpc-google-cloud-spanner-admin-instance-v1:6.66.0:6.66.0 +grpc-google-cloud-spanner-admin-database-v1:6.66.0:6.66.0 +google-cloud-spanner:6.66.0:6.66.0 +google-cloud-spanner-executor:6.66.0:6.66.0 +proto-google-cloud-spanner-executor-v1:6.66.0:6.66.0 +grpc-google-cloud-spanner-executor-v1:6.66.0:6.66.0