diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0e38c416770..7eca4c6d5f0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -52,7 +52,7 @@ jobs: - run: .kokoro/build.sh env: JOB_TYPE: test - GOOGLE_CLOUD_SPANNER_ENABLE_MULTIPLEXED_SESSIONS: true + GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true units-java8: # Building using Java 17 and run the tests with Java 8 runtime name: "units (8)" @@ -91,7 +91,7 @@ jobs: - run: .kokoro/build.sh env: JOB_TYPE: test - GOOGLE_CLOUD_SPANNER_ENABLE_MULTIPLEXED_SESSIONS: true + GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true windows: runs-on: windows-latest steps: diff --git a/.github/workflows/integration-tests-against-emulator-with-multiplexed-session.yaml b/.github/workflows/integration-tests-against-emulator-with-multiplexed-session.yaml index 741fecb089d..bd7dfef3972 100644 --- a/.github/workflows/integration-tests-against-emulator-with-multiplexed-session.yaml +++ b/.github/workflows/integration-tests-against-emulator-with-multiplexed-session.yaml @@ -39,4 +39,4 @@ jobs: env: JOB_TYPE: test SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_SPANNER_ENABLE_MULTIPLEXED_SESSIONS: true + GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true diff --git a/.kokoro/presubmit/integration-multiplexed-sessions-enabled.cfg b/.kokoro/presubmit/integration-multiplexed-sessions-enabled.cfg index 0acb1a445b0..771405de422 100644 --- a/.kokoro/presubmit/integration-multiplexed-sessions-enabled.cfg +++ b/.kokoro/presubmit/integration-multiplexed-sessions-enabled.cfg @@ -33,6 +33,6 @@ env_vars: { } env_vars: { - key: "GOOGLE_CLOUD_SPANNER_ENABLE_MULTIPLEXED_SESSIONS" + key: "GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS" value: "true" -} \ No newline at end of file +} diff --git a/.readme-partials.yaml b/.readme-partials.yaml index 0da4b073838..09b3632d24f 100644 --- a/.readme-partials.yaml +++ b/.readme-partials.yaml @@ -153,8 +153,9 @@ custom_content: | #### OpenTelemetry SQL Statement Tracing The OpenTelemetry traces that are generated by the Java client include any request and transaction - tags that have been set. The traces can also include the SQL statements that are executed. Enable - this with the `enableExtendedTracing` option: + tags that have been set. The traces can also include the SQL statements that are executed and the + name of the thread that executes the statement. Enable this with the `enableExtendedTracing` + option: ``` SpannerOptions options = SpannerOptions.newBuilder() diff --git a/CHANGELOG.md b/CHANGELOG.md index 12289f4cfc2..e996cccc5a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [6.71.0](https://github.com/googleapis/java-spanner/compare/v6.70.0...v6.71.0) (2024-07-03) + + +### Features + +* Include thread name in traces ([#3173](https://github.com/googleapis/java-spanner/issues/3173)) ([92b1e07](https://github.com/googleapis/java-spanner/commit/92b1e079e6093bc4a2e7b458c1bbe0f62a0fada9)) +* Support multiplexed sessions for RO transactions ([#3141](https://github.com/googleapis/java-spanner/issues/3141)) ([2b8e9ed](https://github.com/googleapis/java-spanner/commit/2b8e9ededc1ea1a5e8d4f90083f2cf862fcc198a)) + ## [6.70.0](https://github.com/googleapis/java-spanner/compare/v6.69.0...v6.70.0) (2024-06-27) diff --git a/README.md b/README.md index 81c0d3bdbbc..979d8832013 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,13 @@ 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.69.0' +implementation 'com.google.cloud:google-cloud-spanner:6.70.0' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.69.0" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.70.0" ``` @@ -259,8 +259,9 @@ Spanner spanner = options.getService(); #### OpenTelemetry SQL Statement Tracing The OpenTelemetry traces that are generated by the Java client include any request and transaction -tags that have been set. The traces can also include the SQL statements that are executed. Enable -this with the `enableExtendedTracing` option: +tags that have been set. The traces can also include the SQL statements that are executed and the +name of the thread that executes the statement. Enable this with the `enableExtendedTracing` +option: ``` SpannerOptions options = SpannerOptions.newBuilder() @@ -687,7 +688,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.69.0 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.70.0 [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 7db591eff7d..7244dd6eb6b 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -24,7 +24,7 @@ com.google.cloud google-cloud-spanner-parent - 6.70.0 + 6.71.0 diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 5fc0a2e120c..48bbd634f53 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 6.70.0 + 6.71.0 pom com.google.cloud @@ -53,43 +53,43 @@ com.google.cloud google-cloud-spanner - 6.70.0 + 6.71.0 com.google.cloud google-cloud-spanner test-jar - 6.70.0 + 6.71.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.70.0 + 6.71.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.70.0 + 6.71.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.70.0 + 6.71.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.70.0 + 6.71.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.70.0 + 6.71.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.70.0 + 6.71.0 diff --git a/google-cloud-spanner-executor/pom.xml b/google-cloud-spanner-executor/pom.xml index b8d6385dccd..63ef3b9cecf 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.70.0 + 6.71.0 jar Google Cloud Spanner Executor com.google.cloud google-cloud-spanner-parent - 6.70.0 + 6.71.0 diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index d7ce1c4f947..9433fcba5ad 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -732,4 +732,16 @@ com/google/cloud/spanner/connection/Connection void reset() + + + + 7012 + com/google/cloud/spanner/connection/Connection + void setKeepTransactionAlive(boolean) + + + 7012 + com/google/cloud/spanner/connection/Connection + boolean isKeepTransactionAlive() + diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index f6b22bc818a..e56fdb154a6 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.70.0 + 6.71.0 jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 6.70.0 + 6.71.0 google-cloud-spanner @@ -255,6 +255,24 @@ io.opentelemetry opentelemetry-context + + io.opentelemetry + opentelemetry-sdk-common + + + io.opentelemetry + opentelemetry-sdk-metrics + + + com.google.cloud + google-cloud-monitoring + 3.38.0 + + + com.google.api.grpc + proto-google-cloud-monitoring-v3 + 3.38.0 + com.google.auth google-auth-library-oauth2-http @@ -415,16 +433,6 @@ opentelemetry-sdk test - - io.opentelemetry - opentelemetry-sdk-common - test - - - io.opentelemetry - opentelemetry-sdk-metrics - test - io.opentelemetry opentelemetry-sdk-trace diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsConstant.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsConstant.java new file mode 100644 index 00000000000..179eafcf53c --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsConstant.java @@ -0,0 +1,82 @@ +/* + * 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.common.collect.ImmutableSet; +import io.opentelemetry.api.common.AttributeKey; +import java.util.Set; +import java.util.stream.Collectors; + +public class BuiltInMetricsConstant { + + public static final String METER_NAME = "spanner.googleapis.com/internal/client"; + + public static final String GAX_METER_NAME = "gax-java"; + + static final String OPERATION_LATENCIES_NAME = "operation_latencies"; + static final String ATTEMPT_LATENCIES_NAME = "attempt_latencies"; + static final String OPERATION_LATENCY_NAME = "operation_latency"; + static final String ATTEMPT_LATENCY_NAME = "attempt_latency"; + static final String OPERATION_COUNT_NAME = "operation_count"; + static final String ATTEMPT_COUNT_NAME = "attempt_count"; + + public static final Set SPANNER_METRICS = + ImmutableSet.of( + OPERATION_LATENCIES_NAME, + ATTEMPT_LATENCIES_NAME, + OPERATION_COUNT_NAME, + ATTEMPT_COUNT_NAME) + .stream() + .map(m -> METER_NAME + '/' + m) + .collect(Collectors.toSet()); + + public static final String SPANNER_RESOURCE_TYPE = "spanner_instance_client"; + + public static final AttributeKey PROJECT_ID_KEY = AttributeKey.stringKey("project_id"); + public static final AttributeKey INSTANCE_ID_KEY = AttributeKey.stringKey("instance_id"); + public static final AttributeKey LOCATION_ID_KEY = AttributeKey.stringKey("location"); + public static final AttributeKey INSTANCE_CONFIG_ID_KEY = + AttributeKey.stringKey("instance_config"); + + // These metric labels will be promoted to the spanner monitored resource fields + public static final Set> SPANNER_PROMOTED_RESOURCE_LABELS = + ImmutableSet.of(PROJECT_ID_KEY, INSTANCE_ID_KEY, INSTANCE_CONFIG_ID_KEY, LOCATION_ID_KEY); + + public static final AttributeKey DATABASE_KEY = AttributeKey.stringKey("database"); + public static final AttributeKey CLIENT_UID_KEY = AttributeKey.stringKey("client_uid"); + public static final AttributeKey CLIENT_NAME_KEY = AttributeKey.stringKey("client_name"); + public static final AttributeKey METHOD_KEY = AttributeKey.stringKey("method"); + public static final AttributeKey STATUS_KEY = AttributeKey.stringKey("status"); + public static final AttributeKey DIRECT_PATH_ENABLED_KEY = + AttributeKey.stringKey("directpath_enabled"); + public static final AttributeKey DIRECT_PATH_USED_KEY = + AttributeKey.stringKey("directpath_used"); + + public static final Set COMMON_ATTRIBUTES = + ImmutableSet.of( + PROJECT_ID_KEY, + INSTANCE_ID_KEY, + LOCATION_ID_KEY, + INSTANCE_CONFIG_ID_KEY, + CLIENT_UID_KEY, + METHOD_KEY, + STATUS_KEY, + DATABASE_KEY, + CLIENT_NAME_KEY, + DIRECT_PATH_ENABLED_KEY, + DIRECT_PATH_USED_KEY); +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/OpenTelemetryContextKeys.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/OpenTelemetryContextKeys.java new file mode 100644 index 00000000000..e5fbedb7c37 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/OpenTelemetryContextKeys.java @@ -0,0 +1,30 @@ +/* + * 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.InternalApi; +import io.opentelemetry.context.ContextKey; + +/** + * Keys for OpenTelemetry context variables that are used by the Spanner client library. Only + * intended for internal use. + */ +@InternalApi +public class OpenTelemetryContextKeys { + @InternalApi + public static final ContextKey THREAD_NAME_KEY = ContextKey.named("thread.name"); +} 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 0088dbf3c9f..2a065c8b2ce 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 @@ -16,7 +16,6 @@ package com.google.cloud.spanner; -import com.google.api.core.BetaApi; import com.google.api.core.InternalApi; import com.google.cloud.spanner.SessionPool.Position; import com.google.common.annotations.VisibleForTesting; @@ -103,11 +102,12 @@ private SessionPoolOptions(Builder builder) { this.randomizePositionQPSThreshold = builder.randomizePositionQPSThreshold; this.inactiveTransactionRemovalOptions = builder.inactiveTransactionRemovalOptions; this.poolMaintainerClock = builder.poolMaintainerClock; - // TODO: Remove when multiplexed sessions are guaranteed to be supported. + // useMultiplexedSession priority => Environment var > private setter > client default + Boolean useMultiplexedSessionFromEnvVariable = getUseMultiplexedSessionFromEnvVariable(); this.useMultiplexedSession = - builder.useMultiplexedSession - && !Boolean.parseBoolean( - System.getenv("GOOGLE_CLOUD_SPANNER_FORCE_DISABLE_MULTIPLEXED_SESSIONS")); + (useMultiplexedSessionFromEnvVariable != null) + ? useMultiplexedSessionFromEnvVariable + : builder.useMultiplexedSession; this.multiplexedSessionMaintenanceDuration = builder.multiplexedSessionMaintenanceDuration; } @@ -307,6 +307,22 @@ public boolean getUseMultiplexedSession() { return useMultiplexedSession; } + private static Boolean getUseMultiplexedSessionFromEnvVariable() { + String useMultiplexedSessionFromEnvVariable = + System.getenv("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS"); + if (useMultiplexedSessionFromEnvVariable != null + && useMultiplexedSessionFromEnvVariable.length() > 0) { + if ("true".equalsIgnoreCase(useMultiplexedSessionFromEnvVariable) + || "false".equalsIgnoreCase(useMultiplexedSessionFromEnvVariable)) { + return Boolean.parseBoolean(useMultiplexedSessionFromEnvVariable); + } else { + throw new IllegalArgumentException( + "GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS should be either true or false."); + } + } + return null; + } + Duration getMultiplexedSessionMaintenanceDuration() { return multiplexedSessionMaintenanceDuration; } @@ -509,7 +525,9 @@ public static class Builder { */ private long randomizePositionQPSThreshold = 0L; - private boolean useMultiplexedSession = getUseMultiplexedSessionFromEnvVariable(); + // This field controls the default behavior of session management in Java client. + // Set useMultiplexedSession to true to make multiplexed session the default. + private boolean useMultiplexedSession = false; private Duration multiplexedSessionMaintenanceDuration = Duration.ofDays(7); private Clock poolMaintainerClock = Clock.INSTANCE; @@ -527,18 +545,6 @@ private static Position getReleaseToPositionFromSystemProperty() { return Position.FIRST; } - /** - * This environment is only added to support internal spanner testing. Support for it can be - * removed in the future. Use {@link SessionPoolOptions#useMultiplexedSession} instead to use - * multiplexed sessions. - */ - @InternalApi - @BetaApi - private static boolean getUseMultiplexedSessionFromEnvVariable() { - return Boolean.parseBoolean( - System.getenv("GOOGLE_CLOUD_SPANNER_ENABLE_MULTIPLEXED_SESSIONS")); - } - public Builder() {} private Builder(SessionPoolOptions options) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporter.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporter.java new file mode 100644 index 00000000000..51dc890902c --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporter.java @@ -0,0 +1,236 @@ +/* + * 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.BuiltInMetricsConstant.SPANNER_METRICS; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutureCallback; +import com.google.api.core.ApiFutures; +import com.google.api.gax.core.CredentialsProvider; +import com.google.api.gax.core.FixedCredentialsProvider; +import com.google.api.gax.core.NoCredentialsProvider; +import com.google.api.gax.rpc.PermissionDeniedException; +import com.google.auth.Credentials; +import com.google.cloud.monitoring.v3.MetricServiceClient; +import com.google.cloud.monitoring.v3.MetricServiceSettings; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; +import com.google.common.collect.Iterables; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.monitoring.v3.CreateTimeSeriesRequest; +import com.google.monitoring.v3.ProjectName; +import com.google.monitoring.v3.TimeSeries; +import com.google.protobuf.Empty; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +import org.threeten.bp.Duration; + +/** + * Spanner Cloud Monitoring OpenTelemetry Exporter. + * + *

The exporter will look for all spanner owned metrics under spanner.googleapis.com + * instrumentation scope and upload it via the Google Cloud Monitoring API. + */ +class SpannerCloudMonitoringExporter implements MetricExporter { + + private static final Logger logger = + Logger.getLogger(SpannerCloudMonitoringExporter.class.getName()); + + // This system property can be used to override the monitoring endpoint + // to a different environment. It's meant for internal testing only. + private static final String MONITORING_ENDPOINT = + MoreObjects.firstNonNull( + System.getProperty("spanner.test-monitoring-endpoint"), + MetricServiceSettings.getDefaultEndpoint()); + + // This the quota limit from Cloud Monitoring. More details in + // https://cloud.google.com/monitoring/quotas#custom_metrics_quotas. + private static final int EXPORT_BATCH_SIZE_LIMIT = 200; + private final AtomicBoolean spannerExportFailureLogged = new AtomicBoolean(false); + private CompletableResultCode lastExportCode; + private final MetricServiceClient client; + private final String spannerProjectId; + + static SpannerCloudMonitoringExporter create(String projectId, @Nullable Credentials credentials) + throws IOException { + MetricServiceSettings.Builder settingsBuilder = MetricServiceSettings.newBuilder(); + CredentialsProvider credentialsProvider; + if (credentials == null) { + credentialsProvider = NoCredentialsProvider.create(); + } else { + credentialsProvider = FixedCredentialsProvider.create(credentials); + } + settingsBuilder.setCredentialsProvider(credentialsProvider); + settingsBuilder.setEndpoint(MONITORING_ENDPOINT); + + org.threeten.bp.Duration timeout = Duration.ofMinutes(1); + // TODO: createServiceTimeSeries needs special handling if the request failed. Leaving + // it as not retried for now. + settingsBuilder.createServiceTimeSeriesSettings().setSimpleTimeoutNoRetries(timeout); + + return new SpannerCloudMonitoringExporter( + projectId, MetricServiceClient.create(settingsBuilder.build())); + } + + @VisibleForTesting + SpannerCloudMonitoringExporter(String projectId, MetricServiceClient client) { + this.client = client; + this.spannerProjectId = projectId; + } + + @Override + public CompletableResultCode export(Collection collection) { + if (client.isShutdown()) { + logger.log(Level.WARNING, "Exporter is shut down"); + return CompletableResultCode.ofFailure(); + } + + this.lastExportCode = exportSpannerClientMetrics(collection); + return lastExportCode; + } + + /** Export client built in metrics */ + private CompletableResultCode exportSpannerClientMetrics(Collection collection) { + // Filter spanner metrics + List spannerMetricData = + collection.stream() + .filter(md -> SPANNER_METRICS.contains(md.getName())) + .collect(Collectors.toList()); + + // Skips exporting if there's none + if (spannerMetricData.isEmpty()) { + return CompletableResultCode.ofSuccess(); + } + + // Verifies metrics project id is the same as the spanner project id set on this client + if (!spannerMetricData.stream() + .flatMap(metricData -> metricData.getData().getPoints().stream()) + .allMatch( + pd -> spannerProjectId.equals(SpannerCloudMonitoringExporterUtils.getProjectId(pd)))) { + logger.log(Level.WARNING, "Metric data has a different projectId. Skipping export."); + return CompletableResultCode.ofFailure(); + } + + List spannerTimeSeries; + try { + spannerTimeSeries = + SpannerCloudMonitoringExporterUtils.convertToSpannerTimeSeries(spannerMetricData); + } catch (Throwable e) { + logger.log( + Level.WARNING, + "Failed to convert spanner metric data to cloud monitoring timeseries.", + e); + return CompletableResultCode.ofFailure(); + } + + ProjectName projectName = ProjectName.of(spannerProjectId); + + ApiFuture> futureList = exportTimeSeriesInBatch(projectName, spannerTimeSeries); + + CompletableResultCode spannerExportCode = new CompletableResultCode(); + ApiFutures.addCallback( + futureList, + new ApiFutureCallback>() { + @Override + public void onFailure(Throwable throwable) { + if (spannerExportFailureLogged.compareAndSet(false, true)) { + String msg = "createServiceTimeSeries request failed for spanner metrics."; + if (throwable instanceof PermissionDeniedException) { + // TODO: Add the link of public documentation when available in the log message. + msg += + String.format( + " Need monitoring metric writer permission on project=%s.", + projectName.getProject()); + } + logger.log(Level.WARNING, msg, throwable); + } + spannerExportCode.fail(); + } + + @Override + public void onSuccess(List empty) { + // When an export succeeded reset the export failure flag to false so if there's a + // transient failure it'll be logged. + spannerExportFailureLogged.set(false); + spannerExportCode.succeed(); + } + }, + MoreExecutors.directExecutor()); + + return spannerExportCode; + } + + private ApiFuture> exportTimeSeriesInBatch( + ProjectName projectName, List timeSeries) { + List> batchResults = new ArrayList<>(); + + for (List batch : Iterables.partition(timeSeries, EXPORT_BATCH_SIZE_LIMIT)) { + CreateTimeSeriesRequest req = + CreateTimeSeriesRequest.newBuilder() + .setName(projectName.toString()) + .addAllTimeSeries(batch) + .build(); + batchResults.add(this.client.createServiceTimeSeriesCallable().futureCall(req)); + } + + return ApiFutures.allAsList(batchResults); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + if (client.isShutdown()) { + logger.log(Level.WARNING, "shutdown is called multiple times"); + return CompletableResultCode.ofSuccess(); + } + CompletableResultCode shutdownResult = new CompletableResultCode(); + try { + client.shutdown(); + shutdownResult.succeed(); + } catch (Throwable e) { + logger.log(Level.WARNING, "failed to shutdown the monitoring client", e); + shutdownResult.fail(); + } + return shutdownResult; + } + + /** + * For Google Cloud Monitoring always return CUMULATIVE to keep track of the cumulative value of a + * metric over time. + */ + @Override + public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { + return AggregationTemporality.CUMULATIVE; + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterUtils.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterUtils.java new file mode 100644 index 00000000000..a6d1e29d587 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterUtils.java @@ -0,0 +1,211 @@ +/* + * 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.api.MetricDescriptor.MetricKind.CUMULATIVE; +import static com.google.api.MetricDescriptor.MetricKind.GAUGE; +import static com.google.api.MetricDescriptor.MetricKind.UNRECOGNIZED; +import static com.google.api.MetricDescriptor.ValueType.DISTRIBUTION; +import static com.google.api.MetricDescriptor.ValueType.DOUBLE; +import static com.google.api.MetricDescriptor.ValueType.INT64; +import static com.google.cloud.spanner.BuiltInMetricsConstant.GAX_METER_NAME; +import static com.google.cloud.spanner.BuiltInMetricsConstant.PROJECT_ID_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.SPANNER_PROMOTED_RESOURCE_LABELS; +import static com.google.cloud.spanner.BuiltInMetricsConstant.SPANNER_RESOURCE_TYPE; + +import com.google.api.Distribution; +import com.google.api.Distribution.BucketOptions; +import com.google.api.Distribution.BucketOptions.Explicit; +import com.google.api.Metric; +import com.google.api.MetricDescriptor.MetricKind; +import com.google.api.MetricDescriptor.ValueType; +import com.google.api.MonitoredResource; +import com.google.monitoring.v3.Point; +import com.google.monitoring.v3.TimeInterval; +import com.google.monitoring.v3.TimeSeries; +import com.google.monitoring.v3.TypedValue; +import com.google.protobuf.util.Timestamps; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.DoublePointData; +import io.opentelemetry.sdk.metrics.data.HistogramData; +import io.opentelemetry.sdk.metrics.data.HistogramPointData; +import io.opentelemetry.sdk.metrics.data.LongPointData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.data.MetricDataType; +import io.opentelemetry.sdk.metrics.data.PointData; +import io.opentelemetry.sdk.metrics.data.SumData; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +class SpannerCloudMonitoringExporterUtils { + + private static final Logger logger = + Logger.getLogger(SpannerCloudMonitoringExporterUtils.class.getName()); + + private SpannerCloudMonitoringExporterUtils() {} + + static String getProjectId(PointData pointData) { + return pointData.getAttributes().get(PROJECT_ID_KEY); + } + + static List convertToSpannerTimeSeries(List collection) { + List allTimeSeries = new ArrayList<>(); + + for (MetricData metricData : collection) { + // Get common metrics data from GAX library + if (!metricData.getInstrumentationScopeInfo().getName().equals(GAX_METER_NAME)) { + // Filter out metric data for instruments that are not part of the spanner metrics list + continue; + } + metricData.getData().getPoints().stream() + .map(pointData -> convertPointToSpannerTimeSeries(metricData, pointData)) + .forEach(allTimeSeries::add); + } + + return allTimeSeries; + } + + private static TimeSeries convertPointToSpannerTimeSeries( + MetricData metricData, PointData pointData) { + TimeSeries.Builder builder = + TimeSeries.newBuilder() + .setMetricKind(convertMetricKind(metricData)) + .setValueType(convertValueType(metricData.getType())); + Metric.Builder metricBuilder = Metric.newBuilder().setType(metricData.getName()); + + Attributes attributes = pointData.getAttributes(); + MonitoredResource.Builder monitoredResourceBuilder = + MonitoredResource.newBuilder().setType(SPANNER_RESOURCE_TYPE); + + for (AttributeKey key : attributes.asMap().keySet()) { + if (SPANNER_PROMOTED_RESOURCE_LABELS.contains(key)) { + monitoredResourceBuilder.putLabels(key.getKey(), String.valueOf(attributes.get(key))); + } else { + metricBuilder.putLabels(key.getKey(), String.valueOf(attributes.get(key))); + } + } + + builder.setResource(monitoredResourceBuilder.build()); + builder.setMetric(metricBuilder.build()); + + TimeInterval timeInterval = + TimeInterval.newBuilder() + .setStartTime(Timestamps.fromNanos(pointData.getStartEpochNanos())) + .setEndTime(Timestamps.fromNanos(pointData.getEpochNanos())) + .build(); + + builder.addPoints(createPoint(metricData.getType(), pointData, timeInterval)); + + return builder.build(); + } + + private static MetricKind convertMetricKind(MetricData metricData) { + switch (metricData.getType()) { + case HISTOGRAM: + case EXPONENTIAL_HISTOGRAM: + return convertHistogramType(metricData.getHistogramData()); + case LONG_GAUGE: + case DOUBLE_GAUGE: + return GAUGE; + case LONG_SUM: + return convertSumDataType(metricData.getLongSumData()); + case DOUBLE_SUM: + return convertSumDataType(metricData.getDoubleSumData()); + default: + return UNRECOGNIZED; + } + } + + private static MetricKind convertHistogramType(HistogramData histogramData) { + if (histogramData.getAggregationTemporality() == AggregationTemporality.CUMULATIVE) { + return CUMULATIVE; + } + return UNRECOGNIZED; + } + + private static MetricKind convertSumDataType(SumData sum) { + if (!sum.isMonotonic()) { + return GAUGE; + } + if (sum.getAggregationTemporality() == AggregationTemporality.CUMULATIVE) { + return CUMULATIVE; + } + return UNRECOGNIZED; + } + + private static ValueType convertValueType(MetricDataType metricDataType) { + switch (metricDataType) { + case LONG_GAUGE: + case LONG_SUM: + return INT64; + case DOUBLE_GAUGE: + case DOUBLE_SUM: + return DOUBLE; + case HISTOGRAM: + case EXPONENTIAL_HISTOGRAM: + return DISTRIBUTION; + default: + return ValueType.UNRECOGNIZED; + } + } + + private static Point createPoint( + MetricDataType type, PointData pointData, TimeInterval timeInterval) { + Point.Builder builder = Point.newBuilder().setInterval(timeInterval); + switch (type) { + case HISTOGRAM: + case EXPONENTIAL_HISTOGRAM: + return builder + .setValue( + TypedValue.newBuilder() + .setDistributionValue(convertHistogramData((HistogramPointData) pointData)) + .build()) + .build(); + case DOUBLE_GAUGE: + case DOUBLE_SUM: + return builder + .setValue( + TypedValue.newBuilder() + .setDoubleValue(((DoublePointData) pointData).getValue()) + .build()) + .build(); + case LONG_GAUGE: + case LONG_SUM: + return builder + .setValue(TypedValue.newBuilder().setInt64Value(((LongPointData) pointData).getValue())) + .build(); + default: + logger.log(Level.WARNING, "unsupported metric type"); + return builder.build(); + } + } + + private static Distribution convertHistogramData(HistogramPointData pointData) { + return Distribution.newBuilder() + .setCount(pointData.getCount()) + .setMean(pointData.getCount() == 0L ? 0.0D : pointData.getSum() / pointData.getCount()) + .setBucketOptions( + BucketOptions.newBuilder() + .setExplicitBuckets(Explicit.newBuilder().addAllBounds(pointData.getBoundaries()))) + .addAllBucketCounts(pointData.getCounts()) + .build(); + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index c3e75a7ed54..e6f60090acb 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -1287,14 +1287,20 @@ public Builder setHost(String host) { return this; } - /** Enables gRPC-GCP extension with the default settings. */ + /** + * Enables gRPC-GCP extension with the default settings. Do not set + * GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS to true in combination with this option, as + * Multiplexed sessions are not supported for gRPC-GCP. + */ public Builder enableGrpcGcpExtension() { return this.enableGrpcGcpExtension(null); } /** * Enables gRPC-GCP extension and uses provided options for configuration. The metric registry - * and default Spanner metric labels will be added automatically. + * and default Spanner metric labels will be added automatically. Do not set + * GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS to true in combination with this option, as + * Multiplexed sessions are not supported for gRPC-GCP. */ public Builder enableGrpcGcpExtension(GcpManagedChannelOptions options) { this.grpcGcpExtensionEnabled = true; @@ -1377,6 +1383,7 @@ public Builder setEnableApiTracing(boolean enableApiTracing) { * *

    *
  • db.statement: Contains the SQL statement that is being executed. + *
  • thread.name: The name of the thread that executes the statement. *
*/ public Builder setEnableExtendedTracing(boolean enableExtendedTracing) { @@ -1667,6 +1674,7 @@ public boolean isUseVirtualThreads() { * *
    *
  • db.statement: Contains the SQL statement that is being executed. + *
  • thread.name: The name of the thread that executes the statement. *
*/ public boolean isEnableExtendedTracing() { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TraceWrapper.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TraceWrapper.java index 77dbc010c4d..02638445ae2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TraceWrapper.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TraceWrapper.java @@ -19,6 +19,7 @@ import com.google.cloud.spanner.Options.TagOption; import com.google.cloud.spanner.Options.TransactionOption; import com.google.cloud.spanner.SpannerOptions.TracingFramework; +import com.google.common.base.MoreObjects; import io.opencensus.trace.BlankSpan; import io.opencensus.trace.Span; import io.opencensus.trace.Tracer; @@ -41,6 +42,7 @@ class TraceWrapper { AttributeKey.stringKey("db.statement"); private static final AttributeKey> DB_STATEMENT_ARRAY_KEY = AttributeKey.stringArrayKey("db.statement"); + private static final AttributeKey THREAD_NAME_KEY = AttributeKey.stringKey("thread.name"); private final Tracer openCensusTracer; private final io.opentelemetry.api.trace.Tracer openTelemetryTracer; @@ -154,6 +156,7 @@ Attributes createStatementAttributes(Statement statement, Options options) { AttributesBuilder builder = Attributes.builder(); if (this.enableExtendedTracing) { builder.put(DB_STATEMENT_KEY, statement.getSql()); + builder.put(THREAD_NAME_KEY, getTraceThreadName()); } if (options != null && options.hasTag()) { builder.put(STATEMENT_TAG_KEY, options.tag()); @@ -172,6 +175,7 @@ Attributes createStatementBatchAttributes(Iterable statements, Option StreamSupport.stream(statements.spliterator(), false) .map(Statement::getSql) .collect(Collectors.toList())); + builder.put(THREAD_NAME_KEY, getTraceThreadName()); } if (options != null && options.hasTag()) { builder.put(STATEMENT_TAG_KEY, options.tag()); @@ -180,4 +184,10 @@ Attributes createStatementBatchAttributes(Iterable statements, Option } return Attributes.empty(); } + + private static String getTraceThreadName() { + return MoreObjects.firstNonNull( + Context.current().get(OpenTelemetryContextKeys.THREAD_NAME_KEY), + Thread.currentThread().getName()); + } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java index ff159c681c5..9e431dbc0ba 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java @@ -25,6 +25,7 @@ import com.google.cloud.spanner.BatchTransactionId; import com.google.cloud.spanner.Dialect; import com.google.cloud.spanner.ErrorCode; +import com.google.cloud.spanner.OpenTelemetryContextKeys; import com.google.cloud.spanner.Options.QueryOption; import com.google.cloud.spanner.Options.RpcPriority; import com.google.cloud.spanner.Partition; @@ -47,6 +48,7 @@ import io.grpc.Status; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -358,40 +360,47 @@ public ApiCallContext configure( } }); } - ApiFuture f = statementExecutor.submit(context.wrap(callable)); - final SpannerAsyncExecutionException caller = - callType == CallType.ASYNC - ? new SpannerAsyncExecutionException(statement.getStatement()) - : null; - final ApiFuture future = - ApiFutures.catching( - f, - Throwable.class, - input -> { - if (caller != null) { - input.addSuppressed(caller); + // Register the name of the thread that called this method as the thread name that should be + // traced. + try (Scope ignore = + io.opentelemetry.context.Context.current() + .with(OpenTelemetryContextKeys.THREAD_NAME_KEY, Thread.currentThread().getName()) + .makeCurrent()) { + ApiFuture f = statementExecutor.submit(context.wrap(callable)); + final SpannerAsyncExecutionException caller = + callType == CallType.ASYNC + ? new SpannerAsyncExecutionException(statement.getStatement()) + : null; + final ApiFuture future = + ApiFutures.catching( + f, + Throwable.class, + input -> { + if (caller != null) { + input.addSuppressed(caller); + } + throw SpannerExceptionFactory.asSpannerException(input); + }, + MoreExecutors.directExecutor()); + synchronized (this) { + this.currentlyRunningStatementFuture = future; + } + future.addListener( + new Runnable() { + @Override + public void run() { + synchronized (this) { + if (currentlyRunningStatementFuture == future) { + currentlyRunningStatementFuture = null; + } } - throw SpannerExceptionFactory.asSpannerException(input); - }, - MoreExecutors.directExecutor()); - synchronized (this) { - this.currentlyRunningStatementFuture = future; - } - future.addListener( - new Runnable() { - @Override - public void run() { - synchronized (this) { - if (currentlyRunningStatementFuture == future) { - currentlyRunningStatementFuture = null; + if (isSingleUse()) { + endUnitOfWorkSpan(); } } - if (isSingleUse()) { - endUnitOfWorkSpan(); - } - } - }, - MoreExecutors.directExecutor()); - return future; + }, + MoreExecutors.directExecutor()); + return future; + } } } 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 59c0d6ce16a..b2d4caa9df8 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 @@ -666,6 +666,25 @@ default boolean isDelayTransactionStartUntilFirstWrite() { throw new UnsupportedOperationException("Unimplemented"); } + /** + * Sets whether this connection should keep read/write transactions alive by executing a SELECT 1 + * once every 10 seconds during inactive read/write transactions. + * + *

NOTE: This will keep read/write transactions alive and hold on to locks until it is + * explicitly committed or rolled back. + */ + default void setKeepTransactionAlive(boolean keepTransactionAlive) { + throw new UnsupportedOperationException("Unimplemented"); + } + + /** + * @return true if this connection keeps read/write transactions alive by executing a SELECT 1 + * once every 10 seconds during inactive read/write transactions. + */ + default boolean isKeepTransactionAlive() { + throw new UnsupportedOperationException("Unimplemented"); + } + /** * Commits the current transaction of this connection. All mutations that have been buffered * during the current transaction will be written to the database. 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 4ab3f7fa868..e6edc6caacc 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 @@ -219,6 +219,7 @@ static UnitOfWorkType of(TransactionMode transactionMode) { private boolean readOnly; private boolean returnCommitStats; private boolean delayTransactionStartUntilFirstWrite; + private boolean keepTransactionAlive; private UnitOfWork currentUnitOfWork = null; /** @@ -438,6 +439,7 @@ public void reset() { this.ddlInTransactionMode = options.getDdlInTransactionMode(); this.returnCommitStats = options.isReturnCommitStats(); this.delayTransactionStartUntilFirstWrite = options.isDelayTransactionStartUntilFirstWrite(); + this.keepTransactionAlive = options.isKeepTransactionAlive(); this.dataBoostEnabled = options.isDataBoostEnabled(); this.autoPartitionMode = options.isAutoPartitionMode(); this.maxPartitions = options.getMaxPartitions(); @@ -987,6 +989,20 @@ public boolean isDelayTransactionStartUntilFirstWrite() { return this.delayTransactionStartUntilFirstWrite; } + @Override + public void setKeepTransactionAlive(boolean keepTransactionAlive) { + ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); + ConnectionPreconditions.checkState( + !isTransactionStarted(), "Cannot set KeepTransactionAlive while a transaction is active"); + this.keepTransactionAlive = keepTransactionAlive; + } + + @Override + public boolean isKeepTransactionAlive() { + ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG); + return this.keepTransactionAlive; + } + /** Resets this connection to its default transaction options. */ private void setDefaultTransactionOptions() { if (transactionStack.isEmpty()) { @@ -1908,6 +1924,7 @@ UnitOfWork createNewUnitOfWork( .setUseAutoSavepointsForEmulator(options.useAutoSavepointsForEmulator()) .setDatabaseClient(dbClient) .setDelayTransactionStartUntilFirstWrite(delayTransactionStartUntilFirstWrite) + .setKeepTransactionAlive(keepTransactionAlive) .setRetryAbortsInternally(retryAbortsInternally) .setSavepointSupport(savepointSupport) .setReturnCommitStats(returnCommitStats) 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 00130afe445..f08a9522ea8 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 @@ -192,6 +192,7 @@ public String[] getValidValues() { private static final boolean DEFAULT_LENIENT = false; private static final boolean DEFAULT_ROUTE_TO_LEADER = true; private static final boolean DEFAULT_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE = false; + private static final boolean DEFAULT_KEEP_TRANSACTION_ALIVE = false; private static final boolean DEFAULT_TRACK_SESSION_LEAKS = true; private static final boolean DEFAULT_TRACK_CONNECTION_LEAKS = true; private static final boolean DEFAULT_DATA_BOOST_ENABLED = false; @@ -269,6 +270,8 @@ public String[] getValidValues() { /** Name of the 'delay transaction start until first write' property. */ public static final String DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE_NAME = "delayTransactionStartUntilFirstWrite"; + /** Name of the 'keep transaction alive' property. */ + public static final String KEEP_TRANSACTION_ALIVE_PROPERTY_NAME = "keepTransactionAlive"; /** Name of the 'trackStackTraceOfSessionCheckout' connection property. */ public static final String TRACK_SESSION_LEAKS_PROPERTY_NAME = "trackSessionLeaks"; /** Name of the 'trackStackTraceOfConnectionCreation' connection property. */ @@ -405,6 +408,12 @@ private static String generateGuardedConnectionPropertyError( + "the first write operation in a read/write transaction will be executed using the read/write transaction. Enabling this mode can reduce locking " + "and improve performance for applications that can handle the lower transaction isolation semantics.", DEFAULT_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE), + ConnectionProperty.createBooleanProperty( + KEEP_TRANSACTION_ALIVE_PROPERTY_NAME, + "Enabling this option will trigger the connection to keep read/write transactions alive by executing a SELECT 1 query once every 10 seconds " + + "if no other statements are being executed. This option should be used with caution, as it can keep transactions alive and hold on to locks " + + "longer than intended. This option should typically be used for CLI-type application that might wait for user input for a longer period of time.", + DEFAULT_KEEP_TRANSACTION_ALIVE), ConnectionProperty.createBooleanProperty( TRACK_SESSION_LEAKS_PROPERTY_NAME, "Capture the call stack of the thread that checked out a session of the session pool. This will " @@ -735,6 +744,7 @@ public static Builder newBuilder() { private final RpcPriority rpcPriority; private final DdlInTransactionMode ddlInTransactionMode; private final boolean delayTransactionStartUntilFirstWrite; + private final boolean keepTransactionAlive; private final boolean trackSessionLeaks; private final boolean trackConnectionLeaks; @@ -799,6 +809,7 @@ private ConnectionOptions(Builder builder) { this.rpcPriority = parseRPCPriority(this.uri); this.ddlInTransactionMode = parseDdlInTransactionMode(this.uri); this.delayTransactionStartUntilFirstWrite = parseDelayTransactionStartUntilFirstWrite(this.uri); + this.keepTransactionAlive = parseKeepTransactionAlive(this.uri); this.trackSessionLeaks = parseTrackSessionLeaks(this.uri); this.trackConnectionLeaks = parseTrackConnectionLeaks(this.uri); @@ -1179,6 +1190,12 @@ static boolean parseDelayTransactionStartUntilFirstWrite(String uri) { : DEFAULT_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE; } + @VisibleForTesting + static boolean parseKeepTransactionAlive(String uri) { + String value = parseUriProperty(uri, KEEP_TRANSACTION_ALIVE_PROPERTY_NAME); + return value != null ? Boolean.parseBoolean(value) : DEFAULT_KEEP_TRANSACTION_ALIVE; + } + @VisibleForTesting static boolean parseTrackSessionLeaks(String uri) { String value = parseUriProperty(uri, TRACK_SESSION_LEAKS_PROPERTY_NAME); @@ -1315,6 +1332,14 @@ static List parseProperties(String uri) { return res; } + static long tryParseLong(String value, long defaultValue) { + try { + return Long.parseLong(value); + } catch (NumberFormatException ignore) { + return defaultValue; + } + } + /** * Create a new {@link Connection} from this {@link ConnectionOptions}. Calling this method * multiple times for the same {@link ConnectionOptions} will return multiple instances of {@link @@ -1551,6 +1576,18 @@ boolean isDelayTransactionStartUntilFirstWrite() { return delayTransactionStartUntilFirstWrite; } + /** + * Whether connections created by this {@link ConnectionOptions} should keep read/write + * transactions alive by executing a SELECT 1 once every 10 seconds if no other statements are + * executed. This option should be used with caution, as enabling it can keep transactions alive + * for a very long time, which will hold on to any locks that have been taken by the transaction. + * This option should typically only be enabled for CLI-type applications or other user-input + * applications that might wait for a longer period of time on user input. + */ + boolean isKeepTransactionAlive() { + return keepTransactionAlive; + } + boolean isTrackConnectionLeaks() { return this.trackConnectionLeaks; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java index c098ddf15d7..93415de3cab 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java @@ -91,6 +91,10 @@ StatementResult statementSetDelayTransactionStartUntilFirstWrite( StatementResult statementShowDelayTransactionStartUntilFirstWrite(); + StatementResult statementSetKeepTransactionAlive(Boolean keepTransactionAlive); + + StatementResult statementShowKeepTransactionAlive(); + StatementResult statementSetStatementTag(String tag); StatementResult statementShowStatementTag(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java index 84ebeec1a50..f99cb764cb2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java @@ -31,6 +31,7 @@ import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_DIRECTED_READ; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_EXCLUDE_TXN_FROM_CHANGE_STREAMS; +import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_KEEP_TRANSACTION_ALIVE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_MAX_COMMIT_DELAY; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_MAX_PARTITIONED_PARALLELISM; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_MAX_PARTITIONS; @@ -57,6 +58,7 @@ import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_DIRECTED_READ; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_EXCLUDE_TXN_FROM_CHANGE_STREAMS; +import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_KEEP_TRANSACTION_ALIVE; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_MAX_COMMIT_DELAY; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_MAX_PARTITIONED_PARALLELISM; import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_MAX_PARTITIONS; @@ -388,6 +390,20 @@ public StatementResult statementShowDelayTransactionStartUntilFirstWrite() { SHOW_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE); } + @Override + public StatementResult statementSetKeepTransactionAlive(Boolean keepTransactionAlive) { + getConnection().setKeepTransactionAlive(keepTransactionAlive); + return noResult(SET_KEEP_TRANSACTION_ALIVE); + } + + @Override + public StatementResult statementShowKeepTransactionAlive() { + return resultSet( + String.format("%sKEEP_TRANSACTION_ALIVE", getNamespace(connection.getDialect())), + getConnection().isKeepTransactionAlive(), + SHOW_KEEP_TRANSACTION_ALIVE); + } + @Override public StatementResult statementSetStatementTag(String tag) { getConnection().setStatementTag("".equals(tag) ? null : tag); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadWriteTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadWriteTransaction.java index d651e64d54f..520a2e180e5 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadWriteTransaction.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadWriteTransaction.java @@ -21,6 +21,7 @@ import static com.google.cloud.spanner.connection.AbstractStatementParser.COMMIT_STATEMENT; import static com.google.cloud.spanner.connection.AbstractStatementParser.ROLLBACK_STATEMENT; import static com.google.cloud.spanner.connection.AbstractStatementParser.RUN_BATCH_STATEMENT; +import static com.google.cloud.spanner.connection.ConnectionOptions.tryParseLong; import static com.google.common.base.Preconditions.checkNotNull; import com.google.api.core.ApiFuture; @@ -33,6 +34,7 @@ import com.google.cloud.spanner.AbortedException; import com.google.cloud.spanner.CommitResponse; import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.Dialect; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Mutation; import com.google.cloud.spanner.Options; @@ -45,6 +47,7 @@ import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.SpannerExceptionFactory; import com.google.cloud.spanner.Statement; +import com.google.cloud.spanner.ThreadFactoryUtil; import com.google.cloud.spanner.TransactionContext; import com.google.cloud.spanner.TransactionManager; import com.google.cloud.spanner.connection.AbstractStatementParser.ParsedStatement; @@ -65,7 +68,12 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; @@ -84,6 +92,16 @@ class ReadWriteTransaction extends AbstractMultiUseTransaction { private static final AttributeKey TRANSACTION_RETRIED = AttributeKey.booleanKey("transaction.retried"); private static final Logger logger = Logger.getLogger(ReadWriteTransaction.class.getName()); + private static final ThreadFactory KEEP_ALIVE_THREAD_FACTORY = + ThreadFactoryUtil.createVirtualOrPlatformDaemonThreadFactory( + "read-write-transaction-keep-alive", true); + private static final ScheduledExecutorService KEEP_ALIVE_SERVICE = + Executors.newSingleThreadScheduledExecutor(KEEP_ALIVE_THREAD_FACTORY); + private static final ParsedStatement SELECT1_STATEMENT = + AbstractStatementParser.getInstance(Dialect.GOOGLE_STANDARD_SQL) + .parse(Statement.of("SELECT 1")); + private static final long DEFAULT_KEEP_ALIVE_INTERVAL_MILLIS = 8000L; + private static final AtomicLong ID_GENERATOR = new AtomicLong(); private static final String MAX_INTERNAL_RETRIES_EXCEEDED = "Internal transaction retry maximum exceeded"; @@ -126,6 +144,9 @@ class ReadWriteTransaction extends AbstractMultiUseTransaction { private TransactionManager txManager; private final boolean retryAbortsInternally; private final boolean delayTransactionStartUntilFirstWrite; + private final boolean keepTransactionAlive; + private final long keepAliveIntervalMillis; + private final ReentrantLock keepAliveLock; private final SavepointSupport savepointSupport; private int transactionRetryAttempts; private int successfulRetries; @@ -140,6 +161,7 @@ class ReadWriteTransaction extends AbstractMultiUseTransaction { private final List statements = new ArrayList<>(); private final List mutations = new ArrayList<>(); private Timestamp transactionStarted; + private ScheduledFuture keepAliveFuture; private static final class RollbackToSavepointException extends Exception { private final Savepoint savepoint; @@ -153,11 +175,27 @@ Savepoint getSavepoint() { } } + private final class StatementResultCallback implements ApiFutureCallback { + @Override + public void onFailure(Throwable t) { + if (t instanceof SpannerException) { + handlePossibleInvalidatingException((SpannerException) t); + } + maybeScheduleKeepAlivePing(); + } + + @Override + public void onSuccess(V result) { + maybeScheduleKeepAlivePing(); + } + } + static class Builder extends AbstractMultiUseTransaction.Builder { private boolean useAutoSavepointsForEmulator; private DatabaseClient dbClient; private Boolean retryAbortsInternally; private boolean delayTransactionStartUntilFirstWrite; + private boolean keepTransactionAlive; private boolean returnCommitStats; private Duration maxCommitDelay; private SavepointSupport savepointSupport; @@ -181,6 +219,11 @@ Builder setDelayTransactionStartUntilFirstWrite(boolean delayTransactionStartUnt return this; } + Builder setKeepTransactionAlive(boolean keepTransactionAlive) { + this.keepTransactionAlive = keepTransactionAlive; + return this; + } + Builder setRetryAbortsInternally(boolean retryAbortsInternally) { this.retryAbortsInternally = retryAbortsInternally; return this; @@ -237,6 +280,16 @@ private ReadWriteTransaction(Builder builder) { : DEFAULT_MAX_INTERNAL_RETRIES; this.dbClient = builder.dbClient; this.delayTransactionStartUntilFirstWrite = builder.delayTransactionStartUntilFirstWrite; + this.keepTransactionAlive = builder.keepTransactionAlive; + this.keepAliveIntervalMillis = + this.keepTransactionAlive + ? tryParseLong( + System.getProperty( + "spanner.connection.keep_alive_interval_millis", + String.valueOf(DEFAULT_KEEP_ALIVE_INTERVAL_MILLIS)), + DEFAULT_KEEP_ALIVE_INTERVAL_MILLIS) + : 0L; + this.keepAliveLock = this.keepTransactionAlive ? new ReentrantLock() : null; this.retryAbortsInternally = builder.retryAbortsInternally; this.savepointSupport = builder.savepointSupport; this.transactionRetryListeners = builder.transactionRetryListeners; @@ -357,6 +410,64 @@ private void checkValidStateAndMarkStarted() { } } + private boolean shouldPing() { + return isActive() + && keepAliveLock != null + && keepTransactionAlive + && !timedOutOrCancelled + && rolledBackToSavepointException == null; + } + + private void maybeScheduleKeepAlivePing() { + if (shouldPing()) { + keepAliveLock.lock(); + try { + if (keepAliveFuture == null || keepAliveFuture.isDone()) { + keepAliveFuture = + KEEP_ALIVE_SERVICE.schedule( + new KeepAliveRunnable(), + keepAliveIntervalMillis > 0 + ? keepAliveIntervalMillis + : DEFAULT_KEEP_ALIVE_INTERVAL_MILLIS, + TimeUnit.MILLISECONDS); + } + } finally { + keepAliveLock.unlock(); + } + } + } + + private void cancelScheduledKeepAlivePing() { + if (keepAliveLock != null) { + keepAliveLock.lock(); + try { + if (keepAliveFuture != null) { + keepAliveFuture.cancel(false); + } + } finally { + keepAliveLock.unlock(); + } + } + } + + private class KeepAliveRunnable implements Runnable { + @Override + public void run() { + if (shouldPing()) { + // Do a shoot-and-forget ping and schedule a new ping over 8 seconds after this ping has + // finished. + ApiFuture future = + executeQueryAsync( + CallType.SYNC, + SELECT1_STATEMENT, + AnalyzeMode.NONE, + Options.tag("connection.transaction-keep-alive")); + future.addListener( + ReadWriteTransaction.this::maybeScheduleKeepAlivePing, MoreExecutors.directExecutor()); + } + } + } + private void checkTimedOut() { ConnectionPreconditions.checkState( !timedOutOrCancelled, @@ -532,20 +643,7 @@ public ApiFuture executeQueryAsync( } else { res = super.executeQueryAsync(callType, statement, analyzeMode, options); } - ApiFutures.addCallback( - res, - new ApiFutureCallback() { - @Override - public void onFailure(Throwable t) { - if (t instanceof SpannerException) { - handlePossibleInvalidatingException((SpannerException) t); - } - } - - @Override - public void onSuccess(ResultSet result) {} - }, - MoreExecutors.directExecutor()); + ApiFutures.addCallback(res, new StatementResultCallback<>(), MoreExecutors.directExecutor()); return res; } } @@ -656,20 +754,7 @@ private ApiFuture> internalExecuteUpdateAsync( }, SpannerGrpc.getExecuteSqlMethod()); } - ApiFutures.addCallback( - res, - new ApiFutureCallback>() { - @Override - public void onFailure(Throwable t) { - if (t instanceof SpannerException) { - handlePossibleInvalidatingException((SpannerException) t); - } - } - - @Override - public void onSuccess(Tuple result) {} - }, - MoreExecutors.directExecutor()); + ApiFutures.addCallback(res, new StatementResultCallback<>(), MoreExecutors.directExecutor()); return res; } @@ -730,20 +815,7 @@ public ApiFuture executeBatchUpdateAsync( }, SpannerGrpc.getExecuteBatchDmlMethod()); } - ApiFutures.addCallback( - res, - new ApiFutureCallback() { - @Override - public void onFailure(Throwable t) { - if (t instanceof SpannerException) { - handlePossibleInvalidatingException((SpannerException) t); - } - } - - @Override - public void onSuccess(long[] result) {} - }, - MoreExecutors.directExecutor()); + ApiFutures.addCallback(res, new StatementResultCallback<>(), MoreExecutors.directExecutor()); return res; } } @@ -781,6 +853,7 @@ public Void call() { public ApiFuture commitAsync(CallType callType) { try (Scope ignore = span.makeCurrent()) { checkOrCreateValidTransaction(COMMIT_STATEMENT, callType); + cancelScheduledKeepAlivePing(); state = UnitOfWorkState.COMMITTING; commitResponseFuture = SettableApiFuture.create(); ApiFuture res; @@ -1146,6 +1219,7 @@ private ApiFuture rollbackAsync(CallType callType, boolean updateStatusAnd ConnectionPreconditions.checkState( state == UnitOfWorkState.STARTED || state == UnitOfWorkState.ABORTED, "This transaction has status " + state.name()); + cancelScheduledKeepAlivePing(); if (updateStatusAndEndSpan) { state = UnitOfWorkState.ROLLED_BACK; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java index 345956a4750..23c5d792a77 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java @@ -75,6 +75,8 @@ enum ClientSideStatementType { SET_MAX_COMMIT_DELAY, SHOW_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE, SET_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE, + SHOW_KEEP_TRANSACTION_ALIVE, + SET_KEEP_TRANSACTION_ALIVE, SHOW_STATEMENT_TAG, SET_STATEMENT_TAG, SHOW_TRANSACTION_TAG, diff --git a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json index c1453915a57..76ad4e4e921 100644 --- a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json +++ b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json @@ -185,6 +185,15 @@ "method": "statementShowDelayTransactionStartUntilFirstWrite", "exampleStatements": ["show variable delay_transaction_start_until_first_write"] }, + { + "name": "SHOW VARIABLE KEEP_TRANSACTION_ALIVE", + "executorName": "ClientSideStatementNoParamExecutor", + "resultType": "RESULT_SET", + "statementType": "SHOW_KEEP_TRANSACTION_ALIVE", + "regex": "(?is)\\A\\s*show\\s+variable\\s+keep_transaction_alive\\s*\\z", + "method": "statementShowKeepTransactionAlive", + "exampleStatements": ["show variable keep_transaction_alive"] + }, { "name": "PARTITION ", "executorName": "ClientSideStatementPartitionExecutor", @@ -583,6 +592,21 @@ "converterName": "ClientSideStatementValueConverters$BooleanConverter" } }, + { + "name": "SET KEEP_TRANSACTION_ALIVE = TRUE|FALSE", + "executorName": "ClientSideStatementSetExecutor", + "resultType": "NO_RESULT", + "statementType": "SET_KEEP_TRANSACTION_ALIVE", + "regex": "(?is)\\A\\s*set\\s+keep_transaction_alive\\s*(?:=)\\s*(.*)\\z", + "method": "statementSetKeepTransactionAlive", + "exampleStatements": ["set keep_transaction_alive = true", "set keep_transaction_alive = false"], + "setStatement": { + "propertyName": "KEEP_TRANSACTION_ALIVE", + "separator": "=", + "allowedValues": "(TRUE|FALSE)", + "converterName": "ClientSideStatementValueConverters$BooleanConverter" + } + }, { "name": "SHOW VARIABLE DATA_BOOST_ENABLED", "executorName": "ClientSideStatementNoParamExecutor", diff --git a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/PG_ClientSideStatements.json b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/PG_ClientSideStatements.json index a5ca7cf07df..cd5f492ca3c 100644 --- a/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/PG_ClientSideStatements.json +++ b/google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/PG_ClientSideStatements.json @@ -185,6 +185,15 @@ "method": "statementShowDelayTransactionStartUntilFirstWrite", "exampleStatements": ["show spanner.delay_transaction_start_until_first_write","show variable spanner.delay_transaction_start_until_first_write"] }, + { + "name": "SHOW [VARIABLE] SPANNER.KEEP_TRANSACTION_ALIVE", + "executorName": "ClientSideStatementNoParamExecutor", + "resultType": "RESULT_SET", + "statementType": "SHOW_KEEP_TRANSACTION_ALIVE", + "regex": "(?is)\\A\\s*show\\s+(?:variable\\s+)?spanner\\.keep_transaction_alive\\s*\\z", + "method": "statementShowKeepTransactionAlive", + "exampleStatements": ["show spanner.keep_transaction_alive","show variable spanner.keep_transaction_alive"] + }, { "name": "SHOW [VARIABLE] TRANSACTION ISOLATION LEVEL", "executorName": "ClientSideStatementNoParamExecutor", @@ -773,6 +782,21 @@ "converterName": "ClientSideStatementValueConverters$BooleanConverter" } }, + { + "name": "SET SPANNER.KEEP_TRANSACTION_ALIVE = TRUE|FALSE", + "executorName": "ClientSideStatementSetExecutor", + "resultType": "NO_RESULT", + "statementType": "SET_KEEP_TRANSACTION_ALIVE", + "regex": "(?is)\\A\\s*set\\s+spanner\\.keep_transaction_alive(?:\\s*=\\s*|\\s+to\\s+)(.*)\\z", + "method": "statementSetKeepTransactionAlive", + "exampleStatements": ["set spanner.keep_transaction_alive = true", "set spanner.keep_transaction_alive = false", "set spanner.keep_transaction_alive to true", "set spanner.keep_transaction_alive to false"], + "setStatement": { + "propertyName": "SPANNER.KEEP_TRANSACTION_ALIVE", + "separator": "(?:=|\\s+TO\\s+)", + "allowedValues": "(TRUE|FALSE)", + "converterName": "ClientSideStatementValueConverters$BooleanConverter" + } + }, { "name": "SHOW [VARIABLE] SPANNER.DATA_BOOST_ENABLED", "executorName": "ClientSideStatementNoParamExecutor", 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 index d7d9b7395ed..287fdd0bd0b 100644 --- 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 @@ -16,8 +16,10 @@ package com.google.cloud.spanner; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; @@ -27,6 +29,8 @@ import static org.mockito.Mockito.when; import com.google.cloud.spanner.SessionClient.SessionConsumer; +import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.reflect.Field; import java.time.Clock; import java.time.Duration; @@ -110,10 +114,9 @@ public void testMaintainer() { } @Test - public void testForceDisableEnvVar() throws Exception { + public void testDisableMultiplexedSessionEnvVar() throws Exception { assumeTrue(isJava8() && !isWindows()); - assumeFalse( - System.getenv().containsKey("GOOGLE_CLOUD_SPANNER_FORCE_DISABLE_MULTIPLEXED_SESSIONS")); + assumeFalse(System.getenv().containsKey("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS")); // Assert that the mux sessions setting is respected by default. assertTrue( @@ -129,8 +132,7 @@ public void testForceDisableEnvVar() throws Exception { (Map) field.get(System.getenv()); try { - writeableEnvironmentVariables.put( - "GOOGLE_CLOUD_SPANNER_FORCE_DISABLE_MULTIPLEXED_SESSIONS", "true"); + writeableEnvironmentVariables.put("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS", "false"); // Assert that the env var overrides the mux sessions setting. assertFalse( SessionPoolOptions.newBuilder() @@ -138,8 +140,108 @@ public void testForceDisableEnvVar() throws Exception { .build() .getUseMultiplexedSession()); } finally { - writeableEnvironmentVariables.remove( - "GOOGLE_CLOUD_SPANNER_FORCE_DISABLE_MULTIPLEXED_SESSIONS"); + writeableEnvironmentVariables.remove("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS"); + } + } + + @Test + public void testEnableMultiplexedSessionEnvVar() throws Exception { + assumeTrue(isJava8() && !isWindows()); + assumeFalse(System.getenv().containsKey("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS")); + + // Assert that the mux sessions setting is respected by default. + assertFalse( + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(false) + .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_MULTIPLEXED_SESSIONS", "true"); + // Assert that the env var overrides the mux sessions setting. + assertTrue( + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(false) + .build() + .getUseMultiplexedSession()); + } finally { + writeableEnvironmentVariables.remove("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS"); + } + } + + @Test + public void testIgnoreMultiplexedSessionEnvVar() throws Exception { + assumeTrue(isJava8() && !isWindows()); + assumeFalse(System.getenv().containsKey("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS")); + + // Assert that the mux sessions setting is respected by default. + assertFalse( + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(false) + .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_MULTIPLEXED_SESSIONS", ""); + // Assert that the env var overrides the mux sessions setting. + assertFalse( + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(false) + .build() + .getUseMultiplexedSession()); + } finally { + writeableEnvironmentVariables.remove("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS"); + } + } + + @Test + public void testThrowExceptionMultiplexedSessionEnvVarInvalidValues() throws Exception { + assumeTrue(isJava8() && !isWindows()); + assumeFalse(System.getenv().containsKey("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS")); + + // Assert that the mux sessions setting is respected by default. + assertFalse( + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(false) + .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_MULTIPLEXED_SESSIONS", "test"); + + // setting an invalid GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS value throws error. + IllegalArgumentException e = + assertThrows( + IllegalArgumentException.class, + () -> + SessionPoolOptions.newBuilder() + .setUseMultiplexedSession(false) + .build() + .getUseMultiplexedSession()); + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + assertThat(sw.toString()) + .contains("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS should be either true or false"); + } finally { + writeableEnvironmentVariables.remove("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS"); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterTest.java new file mode 100644 index 00000000000..378db5b6b0d --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterTest.java @@ -0,0 +1,342 @@ +/* + * 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.BuiltInMetricsConstant.CLIENT_NAME_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.CLIENT_UID_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.DATABASE_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.DIRECT_PATH_ENABLED_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.DIRECT_PATH_USED_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.GAX_METER_NAME; +import static com.google.cloud.spanner.BuiltInMetricsConstant.INSTANCE_CONFIG_ID_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.INSTANCE_ID_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.LOCATION_ID_KEY; +import static com.google.cloud.spanner.BuiltInMetricsConstant.OPERATION_COUNT_NAME; +import static com.google.cloud.spanner.BuiltInMetricsConstant.OPERATION_LATENCIES_NAME; +import static com.google.cloud.spanner.BuiltInMetricsConstant.PROJECT_ID_KEY; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.api.Distribution; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.cloud.monitoring.v3.MetricServiceClient; +import com.google.cloud.monitoring.v3.stub.MetricServiceStub; +import com.google.common.collect.ImmutableList; +import com.google.monitoring.v3.CreateTimeSeriesRequest; +import com.google.monitoring.v3.TimeSeries; +import com.google.protobuf.Empty; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.HistogramPointData; +import io.opentelemetry.sdk.metrics.data.LongPointData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableHistogramData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableHistogramPointData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData; +import io.opentelemetry.sdk.resources.Resource; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class SpannerCloudMonitoringExporterTest { + + private static final String projectId = "fake-project"; + private static final String instanceId = "fake-instance"; + private static final String locationId = "global"; + private static final String databaseId = "fake-database"; + private static final String clientName = "spanner-java"; + private static final String instanceConfigId = "fake-instance-config-id"; + + @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock private MetricServiceStub mockMetricServiceStub; + private MetricServiceClient fakeMetricServiceClient; + private SpannerCloudMonitoringExporter exporter; + + private Attributes attributes; + private Resource resource; + private InstrumentationScopeInfo scope; + + @Before + public void setUp() { + fakeMetricServiceClient = new FakeMetricServiceClient(mockMetricServiceStub); + exporter = new SpannerCloudMonitoringExporter(projectId, fakeMetricServiceClient); + + attributes = + Attributes.builder() + .put(PROJECT_ID_KEY, projectId) + .put(INSTANCE_ID_KEY, instanceId) + .put(LOCATION_ID_KEY, locationId) + .put(INSTANCE_CONFIG_ID_KEY, instanceConfigId) + .put(DATABASE_KEY, databaseId) + .put(CLIENT_NAME_KEY, clientName) + .put(String.valueOf(DIRECT_PATH_ENABLED_KEY), true) + .put(String.valueOf(DIRECT_PATH_USED_KEY), true) + .build(); + + resource = Resource.create(Attributes.empty()); + + scope = InstrumentationScopeInfo.create(GAX_METER_NAME); + } + + @After + public void tearDown() {} + + @Test + public void testExportingSumData() { + ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(CreateTimeSeriesRequest.class); + + UnaryCallable mockCallable = Mockito.mock(UnaryCallable.class); + Mockito.when(mockMetricServiceStub.createServiceTimeSeriesCallable()).thenReturn(mockCallable); + ApiFuture future = ApiFutures.immediateFuture(Empty.getDefaultInstance()); + Mockito.when(mockCallable.futureCall(argumentCaptor.capture())).thenReturn(future); + + long fakeValue = 11L; + + long startEpoch = 10; + long endEpoch = 15; + LongPointData longPointData = + ImmutableLongPointData.create(startEpoch, endEpoch, attributes, fakeValue); + + MetricData longData = + ImmutableMetricData.createLongSum( + resource, + scope, + "spanner.googleapis.com/internal/client/" + OPERATION_COUNT_NAME, + "description", + "1", + ImmutableSumData.create( + true, AggregationTemporality.CUMULATIVE, ImmutableList.of(longPointData))); + + exporter.export(Arrays.asList(longData)); + + CreateTimeSeriesRequest request = argumentCaptor.getValue(); + + assertThat(request.getTimeSeriesList()).hasSize(1); + + TimeSeries timeSeries = request.getTimeSeriesList().get(0); + + assertThat(timeSeries.getResource().getLabelsMap()) + .containsExactly( + PROJECT_ID_KEY.getKey(), projectId, + INSTANCE_ID_KEY.getKey(), instanceId, + LOCATION_ID_KEY.getKey(), locationId, + INSTANCE_CONFIG_ID_KEY.getKey(), instanceConfigId); + + assertThat(timeSeries.getResource().getLabelsMap()).hasSize(4); + + assertThat(timeSeries.getMetric().getLabelsMap()) + .containsExactly( + DATABASE_KEY.getKey(), + databaseId, + CLIENT_NAME_KEY.getKey(), + clientName, + DIRECT_PATH_ENABLED_KEY.getKey(), + "true", + DIRECT_PATH_USED_KEY.getKey(), + "true"); + assertThat(timeSeries.getMetric().getLabelsMap()).hasSize(4); + + assertThat(timeSeries.getPoints(0).getValue().getInt64Value()).isEqualTo(fakeValue); + assertThat(timeSeries.getPoints(0).getInterval().getStartTime().getNanos()) + .isEqualTo(startEpoch); + assertThat(timeSeries.getPoints(0).getInterval().getEndTime().getNanos()).isEqualTo(endEpoch); + } + + @Test + public void testExportingHistogramData() { + ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(CreateTimeSeriesRequest.class); + + UnaryCallable mockCallable = mock(UnaryCallable.class); + when(mockMetricServiceStub.createServiceTimeSeriesCallable()).thenReturn(mockCallable); + ApiFuture future = ApiFutures.immediateFuture(Empty.getDefaultInstance()); + when(mockCallable.futureCall(argumentCaptor.capture())).thenReturn(future); + + long startEpoch = 10; + long endEpoch = 15; + HistogramPointData histogramPointData = + ImmutableHistogramPointData.create( + startEpoch, + endEpoch, + attributes, + 3d, + true, + 1d, // min + true, + 2d, // max + Arrays.asList(1.0), + Arrays.asList(1L, 2L)); + + MetricData histogramData = + ImmutableMetricData.createDoubleHistogram( + resource, + scope, + "spanner.googleapis.com/internal/client/" + OPERATION_LATENCIES_NAME, + "description", + "ms", + ImmutableHistogramData.create( + AggregationTemporality.CUMULATIVE, ImmutableList.of(histogramPointData))); + + exporter.export(Arrays.asList(histogramData)); + + CreateTimeSeriesRequest request = argumentCaptor.getValue(); + + assertThat(request.getTimeSeriesList()).hasSize(1); + + TimeSeries timeSeries = request.getTimeSeriesList().get(0); + + assertThat(timeSeries.getResource().getLabelsMap()).hasSize(4); + assertThat(timeSeries.getResource().getLabelsMap()) + .containsExactly( + PROJECT_ID_KEY.getKey(), projectId, + INSTANCE_ID_KEY.getKey(), instanceId, + LOCATION_ID_KEY.getKey(), locationId, + INSTANCE_CONFIG_ID_KEY.getKey(), instanceConfigId); + + assertThat(timeSeries.getMetric().getLabelsMap()).hasSize(4); + assertThat(timeSeries.getMetric().getLabelsMap()) + .containsExactly( + DATABASE_KEY.getKey(), + databaseId, + CLIENT_NAME_KEY.getKey(), + clientName, + DIRECT_PATH_ENABLED_KEY.getKey(), + "true", + DIRECT_PATH_USED_KEY.getKey(), + "true"); + + Distribution distribution = timeSeries.getPoints(0).getValue().getDistributionValue(); + assertThat(distribution.getCount()).isEqualTo(3); + assertThat(timeSeries.getPoints(0).getInterval().getStartTime().getNanos()) + .isEqualTo(startEpoch); + assertThat(timeSeries.getPoints(0).getInterval().getEndTime().getNanos()).isEqualTo(endEpoch); + } + + @Test + public void testExportingSumDataInBatches() { + ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(CreateTimeSeriesRequest.class); + + UnaryCallable mockCallable = mock(UnaryCallable.class); + when(mockMetricServiceStub.createServiceTimeSeriesCallable()).thenReturn(mockCallable); + ApiFuture future = ApiFutures.immediateFuture(Empty.getDefaultInstance()); + when(mockCallable.futureCall(argumentCaptor.capture())).thenReturn(future); + + long startEpoch = 10; + long endEpoch = 15; + + Collection toExport = new ArrayList<>(); + for (int i = 0; i < 250; i++) { + LongPointData longPointData = + ImmutableLongPointData.create( + startEpoch, + endEpoch, + attributes.toBuilder().put(CLIENT_UID_KEY, "client_uid" + i).build(), + i); + + MetricData longData = + ImmutableMetricData.createLongSum( + resource, + scope, + "spanner.googleapis.com/internal/client/" + OPERATION_COUNT_NAME, + "description", + "1", + ImmutableSumData.create( + true, AggregationTemporality.CUMULATIVE, ImmutableList.of(longPointData))); + toExport.add(longData); + } + + exporter.export(toExport); + + assertThat(argumentCaptor.getAllValues()).hasSize(2); + CreateTimeSeriesRequest firstRequest = argumentCaptor.getAllValues().get(0); + CreateTimeSeriesRequest secondRequest = argumentCaptor.getAllValues().get(1); + + assertThat(firstRequest.getTimeSeriesList()).hasSize(200); + assertThat(secondRequest.getTimeSeriesList()).hasSize(50); + + for (int i = 0; i < 250; i++) { + TimeSeries timeSeries; + if (i < 200) { + timeSeries = firstRequest.getTimeSeriesList().get(i); + } else { + timeSeries = secondRequest.getTimeSeriesList().get(i - 200); + } + + assertThat(timeSeries.getResource().getLabelsMap()).hasSize(4); + assertThat(timeSeries.getResource().getLabelsMap()) + .containsExactly( + PROJECT_ID_KEY.getKey(), projectId, + INSTANCE_ID_KEY.getKey(), instanceId, + LOCATION_ID_KEY.getKey(), locationId, + INSTANCE_CONFIG_ID_KEY.getKey(), instanceConfigId); + + assertThat(timeSeries.getMetric().getLabelsMap()).hasSize(5); + assertThat(timeSeries.getMetric().getLabelsMap()) + .containsExactly( + DATABASE_KEY.getKey(), + databaseId, + CLIENT_NAME_KEY.getKey(), + clientName, + DIRECT_PATH_ENABLED_KEY.getKey(), + "true", + DIRECT_PATH_USED_KEY.getKey(), + "true", + CLIENT_UID_KEY.getKey(), + "client_uid" + i); + + assertThat(timeSeries.getPoints(0).getValue().getInt64Value()).isEqualTo(i); + assertThat(timeSeries.getPoints(0).getInterval().getStartTime().getNanos()) + .isEqualTo(startEpoch); + assertThat(timeSeries.getPoints(0).getInterval().getEndTime().getNanos()).isEqualTo(endEpoch); + } + } + + @Test + public void getAggregationTemporality() throws IOException { + SpannerCloudMonitoringExporter actualExporter = + SpannerCloudMonitoringExporter.create(projectId, null); + assertThat(actualExporter.getAggregationTemporality(InstrumentType.COUNTER)) + .isEqualTo(AggregationTemporality.CUMULATIVE); + } + + private static class FakeMetricServiceClient extends MetricServiceClient { + + protected FakeMetricServiceClient(MetricServiceStub stub) { + super(stub); + } + } +} 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 3cf70ed2124..c5b34982255 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 @@ -257,6 +257,11 @@ public void testReset() { false, connection::setDelayTransactionStartUntilFirstWrite, connection::isDelayTransactionStartUntilFirstWrite); + assertResetBooleanProperty( + connection, + false, + connection::setKeepTransactionAlive, + connection::isKeepTransactionAlive); assertResetBooleanProperty( connection, false, connection::setDataBoostEnabled, connection::isDataBoostEnabled); assertResetBooleanProperty( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/OpenTelemetryTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/OpenTelemetryTracingTest.java index bc38761d75e..a8e579feb1a 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/OpenTelemetryTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/OpenTelemetryTracingTest.java @@ -164,6 +164,14 @@ public boolean isEnableExtendedTracing() { "CloudSpannerOperation.ExecuteStreamingQuery", Attributes.of(AttributeKey.stringKey("db.statement"), SELECT1_STATEMENT.getSql()), spans); + SpanData executeQuerySpan = + getSpan( + "CloudSpannerOperation.ExecuteStreamingQuery", + Attributes.of( + AttributeKey.stringKey("db.statement"), SELECT1_STATEMENT.getSql(), + AttributeKey.stringKey("thread.name"), Thread.currentThread().getName()), + spans); + assertParent( "CloudSpannerJdbc.SingleUseTransaction", "CloudSpanner.ReadOnlyTransaction", spans); assertParent( @@ -190,6 +198,14 @@ public void testSingleUseQuery() { "CloudSpannerOperation.ExecuteStreamingQuery", Attributes.of(AttributeKey.stringKey("db.statement"), SELECT1_STATEMENT.getSql()), spans); + SpanData executeQuerySpan = + getSpan( + "CloudSpannerOperation.ExecuteStreamingQuery", + Attributes.of( + AttributeKey.stringKey("db.statement"), SELECT1_STATEMENT.getSql(), + AttributeKey.stringKey("thread.name"), Thread.currentThread().getName()), + spans); + assertParent( "CloudSpannerJdbc.SingleUseTransaction", "CloudSpanner.ReadOnlyTransaction", spans); assertParent( @@ -222,6 +238,13 @@ public void testSingleUseUpdate() { "CloudSpannerOperation.ExecuteUpdate", Attributes.of(AttributeKey.stringKey("db.statement"), INSERT_STATEMENT.getSql()), spans); + SpanData executeQuerySpan = + getSpan( + "CloudSpannerOperation.ExecuteUpdate", + Attributes.of( + AttributeKey.stringKey("db.statement"), INSERT_STATEMENT.getSql(), + AttributeKey.stringKey("thread.name"), Thread.currentThread().getName()), + spans); assertParent("CloudSpanner.ReadWriteTransaction", "CloudSpannerOperation.Commit", spans); } @@ -244,6 +267,15 @@ public void testSingleUseBatchUpdate() { AttributeKey.stringArrayKey("db.statement"), ImmutableList.of(INSERT_STATEMENT.getSql(), INSERT_STATEMENT.getSql())), spans); + SpanData executeQuerySpan = + getSpan( + "CloudSpannerOperation.BatchUpdate", + Attributes.of( + AttributeKey.stringArrayKey("db.statement"), + ImmutableList.of(INSERT_STATEMENT.getSql(), INSERT_STATEMENT.getSql())), + spans); + String threadName = executeQuerySpan.getAttributes().get(AttributeKey.stringKey("thread.name")); + assertEquals(Thread.currentThread().getName(), threadName); assertContains("CloudSpannerOperation.Commit", spans); assertParent( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SavepointMockServerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SavepointMockServerTest.java index e2ab63b3213..e615b78e9de 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SavepointMockServerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SavepointMockServerTest.java @@ -39,6 +39,7 @@ import com.google.spanner.v1.RollbackRequest; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import org.junit.After; import org.junit.Before; @@ -678,4 +679,80 @@ public void testRollbackToSavepointWithoutInternalRetriesInReadOnlyTransaction() } } } + + @Test + public void testKeepAlive() throws InterruptedException, TimeoutException { + System.setProperty("spanner.connection.keep_alive_interval_millis", "1"); + try (Connection connection = createConnection()) { + connection.setSavepointSupport(SavepointSupport.ENABLED); + connection.setKeepTransactionAlive(true); + // Start a transaction by executing a statement. + connection.execute(INSERT_STATEMENT); + // Verify that we get a keep-alive request. + verifyHasKeepAliveRequest(); + // Set a savepoint, execute another statement, and rollback to the savepoint. + // The keep-alive should not be sent after the transaction has been rolled back to the + // savepoint. + connection.savepoint("s1"); + connection.execute(INSERT_STATEMENT); + connection.rollbackToSavepoint("s1"); + mockSpanner.waitForRequestsToContain(RollbackRequest.class, 1000L); + // Wait for up to 2 milliseconds to make sure that any keep-alive requests that were in flight + // have finished. + try { + mockSpanner.waitForRequestsToContain( + r -> { + if (!(r instanceof ExecuteSqlRequest)) { + return false; + } + ExecuteSqlRequest request = (ExecuteSqlRequest) r; + return request.getSql().equals("SELECT 1") + && request + .getRequestOptions() + .getRequestTag() + .equals("connection.transaction-keep-alive"); + }, + 2L); + } catch (TimeoutException ignore) { + } + + // Verify that we don't get any keep-alive requests from this point. + mockSpanner.clearRequests(); + Thread.sleep(2L); + assertEquals(0, countKeepAliveRequest()); + // Resume the transaction and verify that we get a keep-alive again. + connection.execute(INSERT_STATEMENT); + verifyHasKeepAliveRequest(); + } finally { + System.clearProperty("spanner.connection.keep_alive_interval_millis"); + } + } + + private void verifyHasKeepAliveRequest() throws InterruptedException, TimeoutException { + mockSpanner.waitForRequestsToContain( + r -> { + if (!(r instanceof ExecuteSqlRequest)) { + return false; + } + ExecuteSqlRequest request = (ExecuteSqlRequest) r; + return request.getSql().equals("SELECT 1") + && request + .getRequestOptions() + .getRequestTag() + .equals("connection.transaction-keep-alive"); + }, + 1000L); + } + + private long countKeepAliveRequest() { + return mockSpanner.getRequestsOfType(ExecuteSqlRequest.class).stream() + .filter( + request -> + request.getSql().equals("SELECT 1") + && request + .getRequestOptions() + .getRequestTag() + .equals("connection.transaction-keep-alive")) + .count(); + } } 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 efe96032c61..92dc3a67e8f 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 @@ -4387,6 +4387,205 @@ NEW_CONNECTION; @EXPECT EXCEPTION UNIMPLEMENTED show variable/-delay_transaction_start_until_first_write; NEW_CONNECTION; +show variable keep_transaction_alive; +NEW_CONNECTION; +SHOW VARIABLE KEEP_TRANSACTION_ALIVE; +NEW_CONNECTION; +show variable keep_transaction_alive; +NEW_CONNECTION; + show variable keep_transaction_alive; +NEW_CONNECTION; + show variable keep_transaction_alive; +NEW_CONNECTION; + + + +show variable keep_transaction_alive; +NEW_CONNECTION; +show variable keep_transaction_alive ; +NEW_CONNECTION; +show variable keep_transaction_alive ; +NEW_CONNECTION; +show variable keep_transaction_alive + +; +NEW_CONNECTION; +show variable keep_transaction_alive; +NEW_CONNECTION; +show variable keep_transaction_alive; +NEW_CONNECTION; +show +variable +keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive%; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable%keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive_; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable_keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive&; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable&keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive$; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable$keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive@; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable@keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive!; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable!keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive*; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable*keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive(; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable(keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive); +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable)keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive+; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable+keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive-#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-#keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive\; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable\keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive?; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable?keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive-/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-/keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive/#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/#keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-show variable keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable keep_transaction_alive/-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/-keep_transaction_alive; +NEW_CONNECTION; partition select col1, col2 from my_table; NEW_CONNECTION; PARTITION SELECT COL1, COL2 FROM MY_TABLE; @@ -20999,6 +21198,406 @@ NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT set delay_transaction_start_until_first_write =/-false; NEW_CONNECTION; +set keep_transaction_alive = true; +NEW_CONNECTION; +SET KEEP_TRANSACTION_ALIVE = TRUE; +NEW_CONNECTION; +set keep_transaction_alive = true; +NEW_CONNECTION; + set keep_transaction_alive = true; +NEW_CONNECTION; + set keep_transaction_alive = true; +NEW_CONNECTION; + + + +set keep_transaction_alive = true; +NEW_CONNECTION; +set keep_transaction_alive = true ; +NEW_CONNECTION; +set keep_transaction_alive = true ; +NEW_CONNECTION; +set keep_transaction_alive = true + +; +NEW_CONNECTION; +set keep_transaction_alive = true; +NEW_CONNECTION; +set keep_transaction_alive = true; +NEW_CONNECTION; +set +keep_transaction_alive += +true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =%true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =_true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =&true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =$true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =@true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =!true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =*true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =(true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =)true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =-true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =+true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =-#true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =/true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =\true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =?true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =-/true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =/#true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = true/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =/-true; +NEW_CONNECTION; +set keep_transaction_alive = false; +NEW_CONNECTION; +SET KEEP_TRANSACTION_ALIVE = FALSE; +NEW_CONNECTION; +set keep_transaction_alive = false; +NEW_CONNECTION; + set keep_transaction_alive = false; +NEW_CONNECTION; + set keep_transaction_alive = false; +NEW_CONNECTION; + + + +set keep_transaction_alive = false; +NEW_CONNECTION; +set keep_transaction_alive = false ; +NEW_CONNECTION; +set keep_transaction_alive = false ; +NEW_CONNECTION; +set keep_transaction_alive = false + +; +NEW_CONNECTION; +set keep_transaction_alive = false; +NEW_CONNECTION; +set keep_transaction_alive = false; +NEW_CONNECTION; +set +keep_transaction_alive += +false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =%false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =_false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =&false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =$false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =@false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =!false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =*false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =(false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =)false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =-false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =+false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =-#false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =/false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =\false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =?false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =-/false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =/#false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive = false/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set keep_transaction_alive =/-false; +NEW_CONNECTION; show variable data_boost_enabled; NEW_CONNECTION; SHOW VARIABLE DATA_BOOST_ENABLED; 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 22e1470063a..d15677ae693 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-05-31T10:07:25.155000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.155000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:01.652000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:01.652000000Z' 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-05-31T10:07:25.155000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:01.652000000Z'; 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-05-31T10:07:25.270000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.270000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:01.795000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:01.795000000Z' 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-05-31T10:07:25.270000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:01.795000000Z'; 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-05-31T10:07:25.375000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.375000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:01.900000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:01.900000000Z' 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-05-31T10:07:25.375000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:01.900000000Z'; 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-05-31T10:07:25.500000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.500000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:01.998000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:01.998000000Z' 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-05-31T10:07:25.500000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:01.998000000Z'; 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-05-31T10:07:25.591000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.591000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.090000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.090000000Z' 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-05-31T10:07:25.591000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.090000000Z'; 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-05-31T10:07:25.661000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.158000000Z'; 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-05-31T10:07:25.661000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.158000000Z'; 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-05-31T10:07:25.749000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.237000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:25.749000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.237000000Z'; 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-05-31T10:07:25.820000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.820000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.309000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.309000000Z' 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-05-31T10:07:25.820000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.309000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -3245,15 +3245,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:25.911000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.911000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.392000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.392000000Z' 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-05-31T10:07:25.911000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.392000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -3662,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-05-31T10:07:25.981000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.981000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.473000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.473000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -3672,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-05-31T10:07:25.981000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.473000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4081,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-05-31T10:07:26.049000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.543000000Z'; 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-05-31T10:07:26.049000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.543000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4438,13 +4438,13 @@ SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.107000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.601000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.107000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.601000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4877,8 +4877,8 @@ SET TRANSACTION READ ONLY; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.173000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.173000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.663000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.663000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -4888,7 +4888,7 @@ SET TRANSACTION READ ONLY; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.173000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.663000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5288,15 +5288,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET TRANSACTION READ ONLY; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.244000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.244000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.730000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.730000000Z' 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-05-31T10:07:26.244000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.730000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5641,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-05-31T10:07:26.301000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.301000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.792000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.792000000Z' 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-05-31T10:07:26.301000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.792000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -6088,8 +6088,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; ROLLBACK; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.367000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.367000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.852000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.852000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -6099,7 +6099,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; ROLLBACK; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.367000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.852000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -6607,8 +6607,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.470000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.470000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.938000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.938000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -6618,7 +6618,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.470000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.938000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7023,15 +7023,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.542000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.542000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.010000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.010000000Z' 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-05-31T10:07:26.542000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.010000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7394,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-05-31T10:07:26.607000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.066000000Z'; 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-05-31T10:07:26.607000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.066000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7756,13 +7756,13 @@ SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.675000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.136000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; SELECT 1 AS TEST; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.675000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.136000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -8075,14 +8075,14 @@ SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.736000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.736000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.199000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.199000000Z' 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-05-31T10:07:26.736000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.199000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -8392,13 +8392,13 @@ SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.791000000Z'; +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.256000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; START BATCH DDL; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.791000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.256000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -8753,8 +8753,8 @@ SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SET TRANSACTION READ ONLY; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.841000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.841000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.308000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.308000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -8762,7 +8762,7 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SET TRANSACTION READ ONLY; @EXPECT EXCEPTION FAILED_PRECONDITION -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.841000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.308000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -9197,8 +9197,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; UPDATE foo SET bar=1; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.899000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.899000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.368000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.368000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -9206,8 +9206,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; UPDATE foo SET bar=1; COMMIT; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.899000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:26.899000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.368000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.368000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -9593,15 +9593,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.961000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.961000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.454000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.454000000Z' 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-05-31T10:07:26.961000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.454000000Z'; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -9952,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-05-31T10:07:27.018000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.018000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.506000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.506000000Z' 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-05-31T10:07:27.018000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.018000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.506000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.506000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -10320,15 +10320,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; UPDATE foo SET bar=1; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.078000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.078000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.566000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.566000000Z' 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-05-31T10:07:27.078000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.078000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.566000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.566000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -10718,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-05-31T10:07:27.139000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.139000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.625000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.625000000Z' 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-05-31T10:07:27.139000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.139000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.625000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.625000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -11110,15 +11110,15 @@ NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.203000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.203000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.685000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.685000000Z' 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-05-31T10:07:27.203000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.203000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.685000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.685000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -11448,14 +11448,14 @@ SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.264000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.264000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.745000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.745000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; SET AUTOCOMMIT=TRUE; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:27.264000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.264000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.745000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.745000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=FALSE; @@ -11778,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-05-31T10:07:27.315000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.315000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.802000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.802000000Z' 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-05-31T10:07:27.315000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.315000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.802000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.802000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -12193,8 +12193,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.368000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.368000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.862000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.862000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -12202,8 +12202,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:27.368000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.368000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.862000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.862000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -12586,15 +12586,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.432000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.432000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.925000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.925000000Z' 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-05-31T10:07:27.432000000Z'; +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.925000000Z'; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; @@ -12932,15 +12932,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.484000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.484000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.976000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.976000000Z' 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-05-31T10:07:27.484000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.484000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.976000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.976000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -13287,15 +13287,15 @@ NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.563000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.563000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:04.031000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:04.031000000Z' 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-05-31T10:07:27.563000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.563000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:04.031000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:04.031000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; @@ -13612,14 +13612,14 @@ SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; -SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.621000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.621000000Z' +SET READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:04.087000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:04.087000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; SET AUTOCOMMIT=TRUE; -SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:27.621000000Z'; -@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.621000000Z' +SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:04.087000000Z'; +@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:04.087000000Z' SHOW VARIABLE READ_ONLY_STALENESS; NEW_CONNECTION; SET READONLY=TRUE; 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 907a9bff50c..e107990cfd6 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 @@ -8755,6 +8755,403 @@ NEW_CONNECTION; @EXPECT EXCEPTION UNIMPLEMENTED show variable/-spanner.delay_transaction_start_until_first_write; NEW_CONNECTION; +show spanner.keep_transaction_alive; +NEW_CONNECTION; +SHOW SPANNER.KEEP_TRANSACTION_ALIVE; +NEW_CONNECTION; +show spanner.keep_transaction_alive; +NEW_CONNECTION; + show spanner.keep_transaction_alive; +NEW_CONNECTION; + show spanner.keep_transaction_alive; +NEW_CONNECTION; + + + +show spanner.keep_transaction_alive; +NEW_CONNECTION; +show spanner.keep_transaction_alive ; +NEW_CONNECTION; +show spanner.keep_transaction_alive ; +NEW_CONNECTION; +show spanner.keep_transaction_alive + +; +NEW_CONNECTION; +show spanner.keep_transaction_alive; +NEW_CONNECTION; +show spanner.keep_transaction_alive; +NEW_CONNECTION; +show +spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show%spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show_spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show&spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show$spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show@spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show!spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show*spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show(spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show)spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show-spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show+spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show-#spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show/spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show\spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show?spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show-/spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show/#spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-show spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show spanner.keep_transaction_alive/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +show/-spanner.keep_transaction_alive; +NEW_CONNECTION; +show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +SHOW VARIABLE SPANNER.KEEP_TRANSACTION_ALIVE; +NEW_CONNECTION; +show variable spanner.keep_transaction_alive; +NEW_CONNECTION; + show variable spanner.keep_transaction_alive; +NEW_CONNECTION; + show variable spanner.keep_transaction_alive; +NEW_CONNECTION; + + + +show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +show variable spanner.keep_transaction_alive ; +NEW_CONNECTION; +show variable spanner.keep_transaction_alive ; +NEW_CONNECTION; +show variable spanner.keep_transaction_alive + +; +NEW_CONNECTION; +show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +show +variable +spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive%; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable%spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive_; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable_spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive&; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable&spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive$; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable$spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive@; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable@spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive!; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable!spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive*; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable*spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive(; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable(spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive); +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable)spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive+; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable+spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive-#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-#spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive\; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable\spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive?; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable?spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive-/; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable-/spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive/#; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/#spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-show variable spanner.keep_transaction_alive; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable spanner.keep_transaction_alive/-; +NEW_CONNECTION; +@EXPECT EXCEPTION UNIMPLEMENTED +show variable/-spanner.keep_transaction_alive; +NEW_CONNECTION; show transaction isolation level; NEW_CONNECTION; SHOW TRANSACTION ISOLATION LEVEL; @@ -75764,6 +76161,806 @@ NEW_CONNECTION; @EXPECT EXCEPTION INVALID_ARGUMENT set spanner.delay_transaction_start_until_first_write to/-false; NEW_CONNECTION; +set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +SET SPANNER.KEEP_TRANSACTION_ALIVE = TRUE; +NEW_CONNECTION; +set spanner.keep_transaction_alive = true; +NEW_CONNECTION; + set spanner.keep_transaction_alive = true; +NEW_CONNECTION; + set spanner.keep_transaction_alive = true; +NEW_CONNECTION; + + + +set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +set spanner.keep_transaction_alive = true ; +NEW_CONNECTION; +set spanner.keep_transaction_alive = true ; +NEW_CONNECTION; +set spanner.keep_transaction_alive = true + +; +NEW_CONNECTION; +set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +set +spanner.keep_transaction_alive += +true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =%true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =_true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =&true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =$true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =@true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =!true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =*true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =(true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =)true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =-true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =+true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =-#true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =/true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =\true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =?true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =-/true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =/#true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.keep_transaction_alive = true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = true/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =/-true; +NEW_CONNECTION; +set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +SET SPANNER.KEEP_TRANSACTION_ALIVE = FALSE; +NEW_CONNECTION; +set spanner.keep_transaction_alive = false; +NEW_CONNECTION; + set spanner.keep_transaction_alive = false; +NEW_CONNECTION; + set spanner.keep_transaction_alive = false; +NEW_CONNECTION; + + + +set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +set spanner.keep_transaction_alive = false ; +NEW_CONNECTION; +set spanner.keep_transaction_alive = false ; +NEW_CONNECTION; +set spanner.keep_transaction_alive = false + +; +NEW_CONNECTION; +set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +set +spanner.keep_transaction_alive += +false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =%false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =_false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =&false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =$false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =@false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =!false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =*false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =(false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =)false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =-false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =+false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =-#false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =/false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =\false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =?false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =-/false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =/#false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.keep_transaction_alive = false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive = false/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive =/-false; +NEW_CONNECTION; +set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +SET SPANNER.KEEP_TRANSACTION_ALIVE TO TRUE; +NEW_CONNECTION; +set spanner.keep_transaction_alive to true; +NEW_CONNECTION; + set spanner.keep_transaction_alive to true; +NEW_CONNECTION; + set spanner.keep_transaction_alive to true; +NEW_CONNECTION; + + + +set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +set spanner.keep_transaction_alive to true ; +NEW_CONNECTION; +set spanner.keep_transaction_alive to true ; +NEW_CONNECTION; +set spanner.keep_transaction_alive to true + +; +NEW_CONNECTION; +set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +set +spanner.keep_transaction_alive +to +true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to%true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to_true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to&true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to$true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to@true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to!true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to*true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to(true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to)true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to-true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to+true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to-#true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to/true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to\true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to?true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to-/true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to/#true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.keep_transaction_alive to true; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to true/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to/-true; +NEW_CONNECTION; +set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +SET SPANNER.KEEP_TRANSACTION_ALIVE TO FALSE; +NEW_CONNECTION; +set spanner.keep_transaction_alive to false; +NEW_CONNECTION; + set spanner.keep_transaction_alive to false; +NEW_CONNECTION; + set spanner.keep_transaction_alive to false; +NEW_CONNECTION; + + + +set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +set spanner.keep_transaction_alive to false ; +NEW_CONNECTION; +set spanner.keep_transaction_alive to false ; +NEW_CONNECTION; +set spanner.keep_transaction_alive to false + +; +NEW_CONNECTION; +set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +set +spanner.keep_transaction_alive +to +false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +foo set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false bar; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +%set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false%; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to%false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +_set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false_; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to_false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +&set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false&; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to&false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +$set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false$; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to$false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +@set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false@; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to@false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +!set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false!; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to!false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +*set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false*; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to*false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +(set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false(; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to(false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +)set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false); +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to)false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to-false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT ++set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false+; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to+false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-#set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false-#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to-#false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to/false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +\set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false\; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to\false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +?set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false?; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to?false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +-/set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false-/; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to-/false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/#set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false/#; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to/#false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +/-set spanner.keep_transaction_alive to false; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to false/-; +NEW_CONNECTION; +@EXPECT EXCEPTION INVALID_ARGUMENT +set spanner.keep_transaction_alive to/-false; +NEW_CONNECTION; show spanner.data_boost_enabled; NEW_CONNECTION; SHOW SPANNER.DATA_BOOST_ENABLED; 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 135598adb76..f1649809313 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-05-31T10:07:25.218000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.218000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:01.733000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:01.733000000Z' 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-05-31T10:07:25.218000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:01.733000000Z'; 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-05-31T10:07:25.324000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.324000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:01.851000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:01.851000000Z' 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-05-31T10:07:25.324000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:01.851000000Z'; 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-05-31T10:07:25.450000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.450000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:01.953000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:01.953000000Z' 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-05-31T10:07:25.450000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:01.953000000Z'; 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-05-31T10:07:25.552000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.552000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.049000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.049000000Z' 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-05-31T10:07:25.552000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.049000000Z'; 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-05-31T10:07:25.624000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.624000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.123000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.123000000Z' 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-05-31T10:07:25.624000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.123000000Z'; 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-05-31T10:07:25.706000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.196000000Z'; 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-05-31T10:07:25.706000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.196000000Z'; 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-05-31T10:07:25.786000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.273000000Z'; 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-05-31T10:07:25.786000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.273000000Z'; 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-05-31T10:07:25.851000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.851000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.339000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.339000000Z' 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-05-31T10:07:25.851000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.339000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=FALSE; @@ -3245,15 +3245,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:25.947000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:25.947000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.430000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.430000000Z' 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-05-31T10:07:25.947000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.430000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -3662,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-05-31T10:07:26.016000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.016000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.511000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.511000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -3672,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-05-31T10:07:26.016000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.511000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4081,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-05-31T10:07:26.078000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.574000000Z'; 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-05-31T10:07:26.078000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.574000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4438,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-05-31T10:07:26.139000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.628000000Z'; 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-05-31T10:07:26.139000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.628000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -4877,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-05-31T10:07:26.211000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.211000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.699000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.699000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -4888,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-05-31T10:07:26.211000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.699000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5288,15 +5288,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; SET TRANSACTION READ ONLY; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.272000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.272000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.760000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.760000000Z' 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-05-31T10:07:26.272000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.760000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -5641,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-05-31T10:07:26.333000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.333000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.820000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.820000000Z' 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-05-31T10:07:26.333000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.820000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -6088,8 +6088,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; ROLLBACK; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.405000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.405000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.892000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.892000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -6099,7 +6099,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; ROLLBACK; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.405000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.892000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -6607,8 +6607,8 @@ BEGIN TRANSACTION; @EXPECT RESULT_SET 'TEST',1 SELECT 1 AS TEST; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.508000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.508000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:02.976000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:02.976000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -6618,7 +6618,7 @@ BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; @EXPECT EXCEPTION FAILED_PRECONDITION -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.508000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:02.976000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7023,15 +7023,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; BEGIN TRANSACTION; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.575000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.575000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.036000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.036000000Z' 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-05-31T10:07:26.575000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.036000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7394,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-05-31T10:07:26.642000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.099000000Z'; 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-05-31T10:07:26.642000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.099000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -7756,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-05-31T10:07:26.707000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.170000000Z'; 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-05-31T10:07:26.707000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.170000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -8075,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-05-31T10:07:26.762000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.762000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.227000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.227000000Z' 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-05-31T10:07:26.762000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.227000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=FALSE; @@ -8392,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-05-31T10:07:26.816000000Z'; +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.282000000Z'; 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-05-31T10:07:26.816000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.282000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -8753,8 +8753,8 @@ SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SET TRANSACTION READ ONLY; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.865000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.865000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.333000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.333000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -8762,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-05-31T10:07:26.865000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.333000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -9197,8 +9197,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; UPDATE foo SET bar=1; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.932000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.932000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.406000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.406000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -9206,8 +9206,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; UPDATE foo SET bar=1; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:26.932000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:26.932000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.406000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.406000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -9593,15 +9593,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:26.987000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:26.987000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.479000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.479000000Z' 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-05-31T10:07:26.987000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.479000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; @@ -9952,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-05-31T10:07:27.047000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.047000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.536000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.536000000Z' 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-05-31T10:07:27.047000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.047000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.536000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.536000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -10320,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-05-31T10:07:27.109000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.109000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.596000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.596000000Z' 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-05-31T10:07:27.109000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.109000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.596000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.596000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -10718,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-05-31T10:07:27.169000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.169000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.656000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.656000000Z' 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-05-31T10:07:27.169000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.169000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.656000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.656000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -11110,15 +11110,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.235000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.235000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.716000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.716000000Z' 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-05-31T10:07:27.235000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.235000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.716000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.716000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -11448,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-05-31T10:07:27.290000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.290000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.772000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.772000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; SET AUTOCOMMIT=TRUE; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:27.290000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.290000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.772000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.772000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=FALSE; @@ -11778,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-05-31T10:07:27.340000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.340000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.830000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.830000000Z' 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-05-31T10:07:27.340000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.340000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.830000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.830000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -12193,8 +12193,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.399000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.399000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.896000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.896000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -12202,8 +12202,8 @@ SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; SELECT 1 AS TEST; COMMIT; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:27.399000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.399000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.896000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:03.896000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -12586,15 +12586,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; BEGIN TRANSACTION; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.456000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.456000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:03.950000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:03.950000000Z' 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-05-31T10:07:27.456000000Z'; +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:03.950000000Z'; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; @@ -12932,15 +12932,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.532000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.532000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:04.003000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:04.003000000Z' 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-05-31T10:07:27.532000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.532000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:04.003000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:04.003000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -13287,15 +13287,15 @@ NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; SELECT 1 AS TEST; -SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-05-31T10:07:27.592000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.592000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:04.059000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:04.059000000Z' 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-05-31T10:07:27.592000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.592000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:04.059000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:04.059000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; @@ -13612,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-05-31T10:07:27.645000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-05-31T10:07:27.645000000Z' +SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2024-06-10T06:28:04.111000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2024-06-10T06:28:04.111000000Z' SHOW VARIABLE SPANNER.READ_ONLY_STALENESS; NEW_CONNECTION; SET SPANNER.READONLY=TRUE; SET AUTOCOMMIT=TRUE; -SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-05-31T10:07:27.645000000Z'; -@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-05-31T10:07:27.645000000Z' +SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2024-06-10T06:28:04.111000000Z'; +@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2024-06-10T06:28:04.111000000Z' 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 56d481f443b..d5e8fbb36be 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.70.0 + 6.71.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.70.0 + 6.71.0 diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 00b3a95e1d9..9cf83ee4f31 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.70.0 + 6.71.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.70.0 + 6.71.0 diff --git a/grpc-google-cloud-spanner-executor-v1/pom.xml b/grpc-google-cloud-spanner-executor-v1/pom.xml index 339a3838a17..2f22fe1d990 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.70.0 + 6.71.0 grpc-google-cloud-spanner-executor-v1 GRPC library for google-cloud-spanner com.google.cloud google-cloud-spanner-parent - 6.70.0 + 6.71.0 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 33aea326940..3811e8ed439 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.70.0 + 6.71.0 grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.70.0 + 6.71.0 diff --git a/pom.xml b/pom.xml index daeced9b94f..ecef9ba83cf 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 6.70.0 + 6.71.0 Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -61,47 +61,47 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.70.0 + 6.71.0 com.google.api.grpc proto-google-cloud-spanner-executor-v1 - 6.70.0 + 6.71.0 com.google.api.grpc grpc-google-cloud-spanner-executor-v1 - 6.70.0 + 6.71.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.70.0 + 6.71.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.70.0 + 6.71.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.70.0 + 6.71.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.70.0 + 6.71.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.70.0 + 6.71.0 com.google.cloud google-cloud-spanner - 6.70.0 + 6.71.0 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index 9944c83bb6f..e62834bdd4e 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.70.0 + 6.71.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.70.0 + 6.71.0 diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index a78325680a8..9f8f0642e78 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.70.0 + 6.71.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.70.0 + 6.71.0 diff --git a/proto-google-cloud-spanner-executor-v1/pom.xml b/proto-google-cloud-spanner-executor-v1/pom.xml index 08517ef0243..201a72217c1 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.70.0 + 6.71.0 proto-google-cloud-spanner-executor-v1 Proto library for google-cloud-spanner com.google.cloud google-cloud-spanner-parent - 6.70.0 + 6.71.0 diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 4f994648c4c..12b4bc94bec 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.70.0 + 6.71.0 proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.70.0 + 6.71.0 diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 20138194f92..0730871b890 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -32,7 +32,7 @@ com.google.cloud google-cloud-spanner - 6.70.0 + 6.71.0 diff --git a/versions.txt b/versions.txt index 9bfdf737fb1..52b39f63231 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.70.0:6.70.0 -proto-google-cloud-spanner-v1:6.70.0:6.70.0 -proto-google-cloud-spanner-admin-database-v1:6.70.0:6.70.0 -grpc-google-cloud-spanner-v1:6.70.0:6.70.0 -grpc-google-cloud-spanner-admin-instance-v1:6.70.0:6.70.0 -grpc-google-cloud-spanner-admin-database-v1:6.70.0:6.70.0 -google-cloud-spanner:6.70.0:6.70.0 -google-cloud-spanner-executor:6.70.0:6.70.0 -proto-google-cloud-spanner-executor-v1:6.70.0:6.70.0 -grpc-google-cloud-spanner-executor-v1:6.70.0:6.70.0 +proto-google-cloud-spanner-admin-instance-v1:6.71.0:6.71.0 +proto-google-cloud-spanner-v1:6.71.0:6.71.0 +proto-google-cloud-spanner-admin-database-v1:6.71.0:6.71.0 +grpc-google-cloud-spanner-v1:6.71.0:6.71.0 +grpc-google-cloud-spanner-admin-instance-v1:6.71.0:6.71.0 +grpc-google-cloud-spanner-admin-database-v1:6.71.0:6.71.0 +google-cloud-spanner:6.71.0:6.71.0 +google-cloud-spanner-executor:6.71.0:6.71.0 +proto-google-cloud-spanner-executor-v1:6.71.0:6.71.0 +grpc-google-cloud-spanner-executor-v1:6.71.0:6.71.0