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