rollbackAsync();
+ /** Returns the current savepoint support for this connection. */
+ SavepointSupport getSavepointSupport();
+
+ /** Sets how savepoints should be supported on this connection. */
+ void setSavepointSupport(SavepointSupport savepointSupport);
+
+ /**
+ * Creates a savepoint with the given name.
+ *
+ * The uniqueness constraints on a savepoint name depends on the database dialect that is used:
+ *
+ *
+ * - {@link Dialect#GOOGLE_STANDARD_SQL} requires that savepoint names are unique within a
+ * transaction. The name of a savepoint that has been released or destroyed because the
+ * transaction has rolled back to a savepoint that was defined before that savepoint can be
+ * re-used within the transaction.
+ *
- {@link Dialect#POSTGRESQL} follows the rules for savepoint names in PostgreSQL. This
+ * means that multiple savepoints in one transaction can have the same name, but only the
+ * last savepoint with a given name is visible. See PostgreSQL savepoint
+ * documentation for more information.
+ *
+ *
+ * @param name the name of the savepoint to create
+ * @throws SpannerException if a savepoint with the same name already exists and the dialect that
+ * is used is {@link Dialect#GOOGLE_STANDARD_SQL}
+ * @throws SpannerException if there is no transaction on this connection
+ * @throws SpannerException if internal retries have been disabled for this connection
+ */
+ void savepoint(String name);
+
+ /**
+ * Releases the savepoint with the given name. The savepoint and all later savepoints will be
+ * removed from the current transaction and can no longer be used.
+ *
+ * @param name the name of the savepoint to release
+ * @throws SpannerException if no savepoint with the given name exists
+ */
+ void releaseSavepoint(String name);
+
+ /**
+ * Rolls back to the given savepoint. Rolling back to a savepoint undoes all changes and releases
+ * all internal locks that have been taken by the transaction after the savepoint. Rolling back to
+ * a savepoint does not remove the savepoint from the transaction, and it is possible to roll back
+ * to the same savepoint multiple times. All savepoints that have been defined after the given
+ * savepoint are removed from the transaction.
+ *
+ * @param name the name of the savepoint to roll back to.
+ * @throws SpannerException if no savepoint with the given name exists.
+ * @throws AbortedDueToConcurrentModificationException if rolling back to the savepoint failed
+ * because another transaction has modified the data that has been read or modified by this
+ * transaction
+ */
+ void rollbackToSavepoint(String name);
+
/**
* @return true
if this connection has a transaction (that has not necessarily
* started). This method will only return false when the {@link Connection} is in autocommit
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 ad52cc5da64..824c3f237eb 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
@@ -17,6 +17,7 @@
package com.google.cloud.spanner.connection;
import static com.google.cloud.spanner.SpannerApiFutures.get;
+import static com.google.cloud.spanner.connection.ConnectionPreconditions.checkValidIdentifier;
import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutures;
@@ -213,6 +214,7 @@ static UnitOfWorkType of(TransactionMode transactionMode) {
private TimestampBound readOnlyStaleness = TimestampBound.strong();
private QueryOptions queryOptions = QueryOptions.getDefaultInstance();
private RpcPriority rpcPriority = null;
+ private SavepointSupport savepointSupport = SavepointSupport.FAIL_AFTER_ROLLBACK;
private String transactionTag;
private String statementTag;
@@ -840,6 +842,46 @@ private ApiFuture endCurrentTransactionAsync(EndTransactionMethod endTrans
return res;
}
+ @Override
+ public SavepointSupport getSavepointSupport() {
+ return this.savepointSupport;
+ }
+
+ @Override
+ public void setSavepointSupport(SavepointSupport savepointSupport) {
+ ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
+ ConnectionPreconditions.checkState(
+ !isBatchActive(), "Cannot set SavepointSupport while in a batch");
+ ConnectionPreconditions.checkState(
+ !isTransactionStarted(), "Cannot set SavepointSupport while a transaction is active");
+ this.savepointSupport = savepointSupport;
+ }
+
+ @Override
+ public void savepoint(String name) {
+ ConnectionPreconditions.checkState(isInTransaction(), "This connection has no transaction");
+ ConnectionPreconditions.checkState(
+ savepointSupport.isSavepointCreationAllowed(),
+ "This connection does not allow the creation of savepoints. Current value of SavepointSupport: "
+ + savepointSupport);
+ getCurrentUnitOfWorkOrStartNewUnitOfWork().savepoint(checkValidIdentifier(name), getDialect());
+ }
+
+ @Override
+ public void releaseSavepoint(String name) {
+ ConnectionPreconditions.checkState(
+ isTransactionStarted(), "This connection has no active transaction");
+ getCurrentUnitOfWorkOrStartNewUnitOfWork().releaseSavepoint(checkValidIdentifier(name));
+ }
+
+ @Override
+ public void rollbackToSavepoint(String name) {
+ ConnectionPreconditions.checkState(
+ isTransactionStarted(), "This connection has no active transaction");
+ getCurrentUnitOfWorkOrStartNewUnitOfWork()
+ .rollbackToSavepoint(checkValidIdentifier(name), savepointSupport);
+ }
+
@Override
public StatementResult execute(Statement statement) {
Preconditions.checkNotNull(statement);
@@ -1302,6 +1344,7 @@ UnitOfWork createNewUnitOfWork() {
return ReadWriteTransaction.newBuilder()
.setDatabaseClient(dbClient)
.setRetryAbortsInternally(retryAbortsInternally)
+ .setSavepointSupport(savepointSupport)
.setReturnCommitStats(returnCommitStats)
.setTransactionRetryListeners(transactionRetryListeners)
.setStatementTimeout(statementTimeout)
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionPreconditions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionPreconditions.java
index 459a8131874..8cda355858e 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionPreconditions.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionPreconditions.java
@@ -19,6 +19,7 @@
import com.google.cloud.spanner.ErrorCode;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
+import com.google.common.base.Strings;
import javax.annotation.Nullable;
/**
@@ -42,4 +43,24 @@ static void checkState(boolean expression, @Nullable Object errorMessage) {
ErrorCode.FAILED_PRECONDITION, String.valueOf(errorMessage));
}
}
+
+ static void checkArgument(boolean expression, String message) {
+ if (!expression) {
+ throw SpannerExceptionFactory.newSpannerException(ErrorCode.INVALID_ARGUMENT, message);
+ }
+ }
+
+ /** Verifies that the given identifier is a valid identifier for the given dialect. */
+ static String checkValidIdentifier(String identifier) {
+ checkArgument(!Strings.isNullOrEmpty(identifier), "Identifier may not be null or empty");
+ checkArgument(
+ Character.isJavaIdentifierStart(identifier.charAt(0)), "Invalid identifier: " + identifier);
+ for (int i = 1; i < identifier.length(); i++) {
+ checkArgument(
+ Character.isJavaIdentifierPart(identifier.charAt(i)),
+ "Invalid identifier: " + identifier);
+ }
+ checkArgument(identifier.length() <= 128, "Max identifier length is 128 characters");
+ return identifier;
+ }
}
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 c076ea702ab..4fa74d99e5e 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
@@ -113,6 +113,10 @@ StatementResult statementSetPgSessionCharacteristicsTransactionMode(
StatementResult statementShowRPCPriority();
+ StatementResult statementSetSavepointSupport(SavepointSupport savepointSupport);
+
+ StatementResult statementShowSavepointSupport();
+
StatementResult statementShowTransactionIsolationLevel();
StatementResult statementExplain(String sql);
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java
index 2c1084ec4c0..5caa9a9985a 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
@@ -32,6 +32,7 @@
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_RETRY_ABORTS_INTERNALLY;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_RETURN_COMMIT_STATS;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_RPC_PRIORITY;
+import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_SAVEPOINT_SUPPORT;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_STATEMENT_TAG;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_STATEMENT_TIMEOUT;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_TRANSACTION_MODE;
@@ -48,6 +49,7 @@
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_RETRY_ABORTS_INTERNALLY;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_RETURN_COMMIT_STATS;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_RPC_PRIORITY;
+import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_SAVEPOINT_SUPPORT;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_STATEMENT_TAG;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_STATEMENT_TIMEOUT;
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_TRANSACTION_ISOLATION_LEVEL;
@@ -454,6 +456,20 @@ public StatementResult statementShowRPCPriority() {
SHOW_RPC_PRIORITY);
}
+ @Override
+ public StatementResult statementSetSavepointSupport(SavepointSupport savepointSupport) {
+ getConnection().setSavepointSupport(savepointSupport);
+ return noResult(SET_SAVEPOINT_SUPPORT);
+ }
+
+ @Override
+ public StatementResult statementShowSavepointSupport() {
+ return resultSet(
+ String.format("%SAVEPOINT_SUPPORT", getNamespace(connection.getDialect())),
+ getConnection().getSavepointSupport(),
+ SHOW_SAVEPOINT_SUPPORT);
+ }
+
@Override
public StatementResult statementShowTransactionIsolationLevel() {
return resultSet("transaction_isolation", "serializable", SHOW_TRANSACTION_ISOLATION_LEVEL);
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java
index dded72844de..a1571ec15c4 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java
@@ -296,4 +296,9 @@ public ApiFuture rollbackAsync() {
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.FAILED_PRECONDITION, "Rollback is not allowed for DDL batches.");
}
+
+ @Override
+ String getUnitOfWorkName() {
+ return "DDL batch";
+ }
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DmlBatch.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DmlBatch.java
index b9384006d49..e0d225d9222 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DmlBatch.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DmlBatch.java
@@ -249,4 +249,9 @@ public ApiFuture rollbackAsync() {
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.FAILED_PRECONDITION, "Rollback is not allowed for DML batches.");
}
+
+ @Override
+ String getUnitOfWorkName() {
+ return "DML batch";
+ }
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadOnlyTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadOnlyTransaction.java
index e391819c427..22c165bbe10 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadOnlyTransaction.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadOnlyTransaction.java
@@ -30,6 +30,7 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.TimestampBound;
import com.google.cloud.spanner.connection.AbstractStatementParser.ParsedStatement;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
/**
@@ -72,7 +73,8 @@ static Builder newBuilder() {
return new Builder();
}
- private ReadOnlyTransaction(Builder builder) {
+ @VisibleForTesting
+ ReadOnlyTransaction(Builder builder) {
super(builder);
this.dbClient = builder.dbClient;
this.readOnlyStaleness = builder.readOnlyStaleness;
@@ -202,4 +204,19 @@ public ApiFuture rollbackAsync() {
this.state = UnitOfWorkState.ROLLED_BACK;
return ApiFutures.immediateFuture(null);
}
+
+ @Override
+ String getUnitOfWorkName() {
+ return "read-only transaction";
+ }
+
+ Savepoint savepoint(String name) {
+ // Read-only transactions do not keep track of the executed statements as they also do not take
+ // any locks. There is therefore no savepoint positions that must be rolled back to.
+ return Savepoint.of(name);
+ }
+
+ void rollbackToSavepoint(Savepoint savepoint) {
+ // no-op for read-only transactions
+ }
}
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 169ca1e529a..9d238d3d552 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
@@ -80,8 +80,10 @@ class ReadWriteTransaction extends AbstractMultiUseTransaction {
private static final int MAX_INTERNAL_RETRIES = 50;
private final long transactionId;
private final DatabaseClient dbClient;
- private final TransactionManager txManager;
+ private final TransactionOption[] transactionOptions;
+ private TransactionManager txManager;
private final boolean retryAbortsInternally;
+ private final SavepointSupport savepointSupport;
private int transactionRetryAttempts;
private int successfulRetries;
private final List transactionRetryListeners;
@@ -89,16 +91,20 @@ class ReadWriteTransaction extends AbstractMultiUseTransaction {
private volatile SettableApiFuture commitResponseFuture;
private volatile UnitOfWorkState state = UnitOfWorkState.STARTED;
private volatile AbortedException abortedException;
+ private AbortedException rolledBackToSavepointException;
private boolean timedOutOrCancelled = false;
private final List statements = new ArrayList<>();
private final List mutations = new ArrayList<>();
private Timestamp transactionStarted;
final Object abortedLock = new Object();
+ private static final class RollbackToSavepointException extends Exception {}
+
static class Builder extends AbstractMultiUseTransaction.Builder {
private DatabaseClient dbClient;
private Boolean retryAbortsInternally;
private boolean returnCommitStats;
+ private SavepointSupport savepointSupport;
private List transactionRetryListeners;
private Builder() {}
@@ -119,6 +125,11 @@ Builder setReturnCommitStats(boolean returnCommitStats) {
return this;
}
+ Builder setSavepointSupport(SavepointSupport savepointSupport) {
+ this.savepointSupport = savepointSupport;
+ return this;
+ }
+
Builder setTransactionRetryListeners(List listeners) {
Preconditions.checkNotNull(listeners);
this.transactionRetryListeners = listeners;
@@ -132,6 +143,7 @@ ReadWriteTransaction build() {
retryAbortsInternally != null, "RetryAbortsInternally is not specified");
Preconditions.checkState(
transactionRetryListeners != null, "TransactionRetryListeners are not specified");
+ Preconditions.checkState(savepointSupport != null, "SavepointSupport is not specified");
return new ReadWriteTransaction(this);
}
}
@@ -145,8 +157,10 @@ private ReadWriteTransaction(Builder builder) {
this.transactionId = ID_GENERATOR.incrementAndGet();
this.dbClient = builder.dbClient;
this.retryAbortsInternally = builder.retryAbortsInternally;
+ this.savepointSupport = builder.savepointSupport;
this.transactionRetryListeners = builder.transactionRetryListeners;
- this.txManager = dbClient.transactionManager(extractOptions(builder));
+ this.transactionOptions = extractOptions(builder);
+ this.txManager = dbClient.transactionManager(this.transactionOptions);
}
private TransactionOption[] extractOptions(Builder builder) {
@@ -231,6 +245,11 @@ private void checkValidState() {
+ "or "
+ UnitOfWorkState.ABORTED
+ " is allowed.");
+ ConnectionPreconditions.checkState(
+ this.retryAbortsInternally || this.rolledBackToSavepointException == null,
+ "Cannot resume execution after rolling back to a savepoint if internal retries have been disabled. "
+ + "Call Connection#setRetryAbortsInternally(true) or execute `SET RETRY_ABORTS_INTERNALLY=TRUE` to enable "
+ + "resuming execution after rolling back to a savepoint.");
checkTimedOut();
}
@@ -274,6 +293,22 @@ void checkAborted() {
}
}
+ void checkRolledBackToSavepoint() {
+ if (this.rolledBackToSavepointException != null) {
+ if (savepointSupport == SavepointSupport.FAIL_AFTER_ROLLBACK) {
+ throw SpannerExceptionFactory.newSpannerException(
+ ErrorCode.FAILED_PRECONDITION,
+ "Using a read/write transaction after rolling back to a savepoint is not supported "
+ + "with SavepointSupport="
+ + savepointSupport);
+ } else {
+ AbortedException exception = this.rolledBackToSavepointException;
+ this.rolledBackToSavepointException = null;
+ throw exception;
+ }
+ }
+ }
+
@Override
TransactionContext getReadContext() {
ConnectionPreconditions.checkState(txContextFuture != null, "Missing transaction context");
@@ -690,6 +725,7 @@ T runWithRetry(Callable callable) throws SpannerException {
synchronized (abortedLock) {
checkAborted();
try {
+ checkRolledBackToSavepoint();
return callable.call();
} catch (final AbortedException aborted) {
handleAborted(aborted);
@@ -792,7 +828,12 @@ private void handleAborted(AbortedException aborted) {
ErrorCode.CANCELLED, "The statement was cancelled");
}
try {
- txContextFuture = ApiFutures.immediateFuture(txManager.resetForRetry());
+ if (aborted.getCause() instanceof RollbackToSavepointException) {
+ txManager = dbClient.transactionManager(transactionOptions);
+ txContextFuture = ApiFutures.immediateFuture(txManager.begin());
+ } else {
+ txContextFuture = ApiFutures.immediateFuture(txManager.resetForRetry());
+ }
// Inform listeners about the transaction retry that is about to start.
invokeTransactionRetryListenersOnStart();
// Then retry all transaction statements.
@@ -899,7 +940,7 @@ private void invokeTransactionRetryListenersOnFinish(RetryResult result) {
@Override
public Void call() {
try {
- if (state != UnitOfWorkState.ABORTED) {
+ if (state != UnitOfWorkState.ABORTED && rolledBackToSavepointException == null) {
// Make sure the transaction has actually started before we try to rollback.
get(txContextFuture);
txManager.rollback();
@@ -913,10 +954,16 @@ public Void call() {
@Override
public ApiFuture rollbackAsync() {
+ return rollbackAsync(true);
+ }
+
+ private ApiFuture rollbackAsync(boolean updateStatus) {
ConnectionPreconditions.checkState(
state == UnitOfWorkState.STARTED || state == UnitOfWorkState.ABORTED,
"This transaction has status " + state.name());
- state = UnitOfWorkState.ROLLED_BACK;
+ if (updateStatus) {
+ state = UnitOfWorkState.ROLLED_BACK;
+ }
if (txContextFuture != null && state != UnitOfWorkState.ABORTED) {
return executeStatementAsync(
ROLLBACK_STATEMENT, rollbackCallable, SpannerGrpc.getRollbackMethod());
@@ -925,6 +972,53 @@ public ApiFuture rollbackAsync() {
}
}
+ @Override
+ String getUnitOfWorkName() {
+ return "read/write transaction";
+ }
+
+ static class ReadWriteSavepoint extends Savepoint {
+ private final int statementPosition;
+ private final int mutationPosition;
+
+ ReadWriteSavepoint(String name, int statementPosition, int mutationPosition) {
+ super(name);
+ this.statementPosition = statementPosition;
+ this.mutationPosition = mutationPosition;
+ }
+
+ @Override
+ int getStatementPosition() {
+ return this.statementPosition;
+ }
+
+ @Override
+ int getMutationPosition() {
+ return this.mutationPosition;
+ }
+ }
+
+ @Override
+ Savepoint savepoint(String name) {
+ return new ReadWriteSavepoint(name, statements.size(), mutations.size());
+ }
+
+ @Override
+ void rollbackToSavepoint(Savepoint savepoint) {
+ get(rollbackAsync(false));
+ // Mark the state of the transaction as rolled back to a savepoint. This will ensure that the
+ // transaction will retry the next time a statement is actually executed.
+ this.rolledBackToSavepointException =
+ (AbortedException)
+ SpannerExceptionFactory.newSpannerException(
+ ErrorCode.ABORTED,
+ "Transaction has been rolled back to a savepoint",
+ new RollbackToSavepointException());
+ // Clear all statements and mutations after the savepoint.
+ this.statements.subList(savepoint.getStatementPosition(), this.statements.size()).clear();
+ this.mutations.subList(savepoint.getMutationPosition(), this.mutations.size()).clear();
+ }
+
/**
* A retriable statement is a query or DML statement during a read/write transaction that can be
* retried if the original transaction aborted.
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SavepointSupport.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SavepointSupport.java
new file mode 100644
index 00000000000..37882e48830
--- /dev/null
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SavepointSupport.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner.connection;
+
+/** Option value used for determining the behavior of savepoints. */
+public enum SavepointSupport {
+ /**
+ * Savepoints are enabled and can be used on the connection. Rolling back to a savepoint will
+ * trigger a retry of the transaction up to the point where the savepoint was set.
+ */
+ ENABLED,
+ /**
+ * Savepoints are enabled and can be used on the connection. Rolling back to a savepoint will not
+ * trigger a retry. Further attempts to use a read/write transaction after a rollback to savepoint
+ * will fail. This mode can be used for frameworks that require savepoint support, for example if
+ * the framework automatically creates a savepoint for a specific feature, but that do not need to
+ * support rolling back to a savepoint. This value should also be used for transactions that
+ * return non-deterministic data, for example auto-generated primary key values, as retries would
+ * always fail. This option will not affect rolling back to a savepoint in a read-only
+ * transaction, as those transactions do not require a retry after rolling back to a savepoint.
+ */
+ FAIL_AFTER_ROLLBACK,
+ /** Savepoints are disabled. Any attempt to create a savepoint will fail. */
+ DISABLED {
+ @Override
+ public boolean isSavepointCreationAllowed() {
+ return false;
+ }
+ };
+
+ /** Returns true if this mode allows the creation of savepoints. */
+ public boolean isSavepointCreationAllowed() {
+ return true;
+ }
+}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java
index 9cfd095df3d..9724491263d 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java
@@ -558,6 +558,11 @@ public ApiFuture rollbackAsync() {
ErrorCode.FAILED_PRECONDITION, "Rollback is not supported for single-use transactions");
}
+ @Override
+ String getUnitOfWorkName() {
+ return "single-use transaction";
+ }
+
@Override
public ApiFuture runBatchAsync() {
throw SpannerExceptionFactory.newSpannerException(
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 a489f3f1993..8d4cf203e08 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
@@ -85,6 +85,8 @@ enum ClientSideStatementType {
SET_RPC_PRIORITY,
SHOW_RPC_PRIORITY,
SHOW_TRANSACTION_ISOLATION_LEVEL,
+ SHOW_SAVEPOINT_SUPPORT,
+ SET_SAVEPOINT_SUPPORT,
EXPLAIN
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/UnitOfWork.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/UnitOfWork.java
index 42470acf6f5..b7e051c4115 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/UnitOfWork.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/UnitOfWork.java
@@ -20,6 +20,7 @@
import com.google.api.core.InternalApi;
import com.google.cloud.Timestamp;
import com.google.cloud.spanner.CommitResponse;
+import com.google.cloud.spanner.Dialect;
import com.google.cloud.spanner.Mutation;
import com.google.cloud.spanner.Options.QueryOption;
import com.google.cloud.spanner.Options.UpdateOption;
@@ -30,6 +31,7 @@
import com.google.cloud.spanner.connection.AbstractStatementParser.ParsedStatement;
import com.google.spanner.v1.ResultSetStats;
import java.util.concurrent.ExecutionException;
+import javax.annotation.Nonnull;
/** Internal interface for transactions and batches on {@link Connection}s. */
@InternalApi
@@ -87,6 +89,15 @@ public boolean isActive() {
*/
ApiFuture rollbackAsync();
+ /** @see Connection#savepoint(String) */
+ void savepoint(@Nonnull String name, @Nonnull Dialect dialect);
+
+ /** @see Connection#releaseSavepoint(String) */
+ void releaseSavepoint(@Nonnull String name);
+
+ /** @see Connection#rollbackToSavepoint(String) */
+ void rollbackToSavepoint(@Nonnull String name, @Nonnull SavepointSupport savepointSupport);
+
/**
* Sends the currently buffered statements in this unit of work to the database and ends the
* batch. This method will throw a {@link SpannerException} if called for a {@link
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 860c0238e06..dd8c0900f4b 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
@@ -140,6 +140,15 @@
"method": "statementShowRPCPriority",
"exampleStatements": ["show variable rpc_priority"]
},
+ {
+ "name": "SHOW VARIABLE SAVEPOINT_SUPPORT",
+ "executorName": "ClientSideStatementNoParamExecutor",
+ "resultType": "RESULT_SET",
+ "statementType": "SHOW_SAVEPOINT_SUPPORT",
+ "regex": "(?is)\\A\\s*show\\s+variable\\s+savepoint_support\\s*\\z",
+ "method": "statementShowSavepointSupport",
+ "exampleStatements": ["show variable savepoint_support"]
+ },
{
"name": "BEGIN TRANSACTION",
"executorName": "ClientSideStatementNoParamExecutor",
@@ -423,6 +432,24 @@
"allowedValues": "'(HIGH|MEDIUM|LOW|NULL)'",
"converterName": "ClientSideStatementValueConverters$RpcPriorityConverter"
}
+ },
+ {
+ "name": "SET SAVEPOINT_SUPPORT = 'ENABLED'|'FAIL_AFTER_ROLLBACK'|'DISABLED'",
+ "executorName": "ClientSideStatementSetExecutor",
+ "resultType": "NO_RESULT",
+ "statementType": "SET_SAVEPOINT_SUPPORT",
+ "regex": "(?is)\\A\\s*set\\s+savepoint_support\\s*(?:=)\\s*(.*)\\z",
+ "method": "statementSetSavepointSupport",
+ "exampleStatements": [
+ "set savepoint_support='ENABLED'",
+ "set savepoint_support='FAIL_AFTER_ROLLBACK'",
+ "set savepoint_support='DISABLED'"],
+ "setStatement": {
+ "propertyName": "SAVEPOINT_SUPPORT",
+ "separator": "=",
+ "allowedValues": "'(ENABLED|FAIL_AFTER_ROLLBACK|DISABLED)'",
+ "converterName": "ClientSideStatementValueConverters$SavepointSupportConverter"
+ }
}
]
}
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 af1fc59f4a2..e2c7e463ff3 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
@@ -140,6 +140,15 @@
"method": "statementShowRPCPriority",
"exampleStatements": ["show spanner.rpc_priority","show variable spanner.rpc_priority"]
},
+ {
+ "name": "SHOW [VARIABLE] SPANNER.SAVEPOINT_SUPPORT",
+ "executorName": "ClientSideStatementNoParamExecutor",
+ "resultType": "RESULT_SET",
+ "statementType": "SHOW_SAVEPOINT_SUPPORT",
+ "regex": "(?is)\\A\\s*show\\s+(?:variable\\s+)?spanner\\.savepoint_support\\s*\\z",
+ "method": "statementShowSavepointSupport",
+ "exampleStatements": ["show spanner.savepoint_support","show variable spanner.savepoint_support"]
+ },
{
"name": "SHOW [VARIABLE] TRANSACTION ISOLATION LEVEL",
"executorName": "ClientSideStatementNoParamExecutor",
@@ -604,6 +613,28 @@
"allowedValues": "'(HIGH|MEDIUM|LOW|NULL)'",
"converterName": "ClientSideStatementValueConverters$RpcPriorityConverter"
}
+ },
+ {
+ "name": "SET SPANNER.SAVEPOINT_SUPPORT =|TO 'ENABLED'|'FAIL_AFTER_ROLLBACK'|'DISABLED'",
+ "executorName": "ClientSideStatementSetExecutor",
+ "resultType": "NO_RESULT",
+ "statementType": "SET_SAVEPOINT_SUPPORT",
+ "regex": "(?is)\\A\\s*set\\s+spanner\\.savepoint_support(?:\\s*=\\s*|\\s+to\\s+)(.*)\\z",
+ "method": "statementSetSavepointSupport",
+ "exampleStatements": [
+ "set spanner.savepoint_support='ENABLED'",
+ "set spanner.savepoint_support='FAIL_AFTER_ROLLBACK'",
+ "set spanner.savepoint_support='DISABLED'",
+ "set spanner.savepoint_support to 'ENABLED'",
+ "set spanner.savepoint_support to 'FAIL_AFTER_ROLLBACK'",
+ "set spanner.savepoint_support to 'DISABLED'"
+ ],
+ "setStatement": {
+ "propertyName": "SPANNER.SAVEPOINT_SUPPORT",
+ "separator": "(?:=|\\s+TO\\s+)",
+ "allowedValues": "'(ENABLED|FAIL_AFTER_ROLLBACK|DISABLED)'",
+ "converterName": "ClientSideStatementValueConverters$SavepointSupportConverter"
+ }
}
]
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java
index aae85bcec62..1101bba399e 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java
@@ -168,6 +168,7 @@ private ReadWriteTransaction createSubject(
return ReadWriteTransaction.newBuilder()
.setDatabaseClient(client)
.setRetryAbortsInternally(withRetry)
+ .setSavepointSupport(SavepointSupport.FAIL_AFTER_ROLLBACK)
.setTransactionRetryListeners(Collections.emptyList())
.withStatementExecutor(new StatementExecutor())
.build();
@@ -460,6 +461,7 @@ public void testRetry() {
ReadWriteTransaction subject =
ReadWriteTransaction.newBuilder()
.setRetryAbortsInternally(true)
+ .setSavepointSupport(SavepointSupport.FAIL_AFTER_ROLLBACK)
.setTransactionRetryListeners(Collections.emptyList())
.setDatabaseClient(client)
.withStatementExecutor(new StatementExecutor())
@@ -487,6 +489,7 @@ public void testChecksumResultSet() {
ReadWriteTransaction transaction =
ReadWriteTransaction.newBuilder()
.setRetryAbortsInternally(true)
+ .setSavepointSupport(SavepointSupport.FAIL_AFTER_ROLLBACK)
.setTransactionRetryListeners(Collections.emptyList())
.setDatabaseClient(client)
.withStatementExecutor(new StatementExecutor())
@@ -653,6 +656,7 @@ public void testChecksumResultSetWithArray() {
ReadWriteTransaction transaction =
ReadWriteTransaction.newBuilder()
.setRetryAbortsInternally(true)
+ .setSavepointSupport(SavepointSupport.FAIL_AFTER_ROLLBACK)
.setTransactionRetryListeners(Collections.emptyList())
.setDatabaseClient(client)
.withStatementExecutor(new StatementExecutor())
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
new file mode 100644
index 00000000000..537617f4a0c
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SavepointMockServerTest.java
@@ -0,0 +1,650 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner.connection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import com.google.cloud.spanner.AbortedDueToConcurrentModificationException;
+import com.google.cloud.spanner.Dialect;
+import com.google.cloud.spanner.ErrorCode;
+import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
+import com.google.cloud.spanner.Mutation;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.SpannerException;
+import com.google.cloud.spanner.Statement;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.protobuf.AbstractMessage;
+import com.google.spanner.v1.BeginTransactionRequest;
+import com.google.spanner.v1.CommitRequest;
+import com.google.spanner.v1.ExecuteBatchDmlRequest;
+import com.google.spanner.v1.ExecuteSqlRequest;
+import com.google.spanner.v1.RollbackRequest;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SavepointMockServerTest extends AbstractMockServerTest {
+
+ @Parameters(name = "dialect = {0}")
+ public static Object[] data() {
+ return Dialect.values();
+ }
+
+ @Parameter public Dialect dialect;
+
+ @Before
+ public void setupDialect() {
+ mockSpanner.putStatementResult(StatementResult.detectDialectResult(dialect));
+ }
+
+ @After
+ public void clearRequests() {
+ mockSpanner.clearRequests();
+ SpannerPool.closeSpannerPool();
+ }
+
+ @Test
+ public void testCreateSavepoint() {
+ try (Connection connection = createConnection()) {
+ connection.savepoint("s1");
+
+ if (dialect == Dialect.POSTGRESQL) {
+ // PostgreSQL allows multiple savepoints with the same name.
+ connection.savepoint("s1");
+ } else {
+ assertThrows(SpannerException.class, () -> connection.savepoint("s1"));
+ }
+
+ // Test invalid identifiers.
+ assertThrows(SpannerException.class, () -> connection.savepoint(null));
+ assertThrows(SpannerException.class, () -> connection.savepoint(""));
+ assertThrows(SpannerException.class, () -> connection.savepoint("1"));
+ assertThrows(SpannerException.class, () -> connection.savepoint("-foo"));
+ assertThrows(SpannerException.class, () -> connection.savepoint(Strings.repeat("t", 129)));
+ }
+ }
+
+ @Test
+ public void testCreateSavepointWhenDisabled() {
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.DISABLED);
+ assertThrows(SpannerException.class, () -> connection.savepoint("s1"));
+ }
+ }
+
+ @Test
+ public void testReleaseSavepoint() {
+ try (Connection connection = createConnection()) {
+ connection.savepoint("s1");
+ connection.releaseSavepoint("s1");
+ assertThrows(SpannerException.class, () -> connection.releaseSavepoint("s1"));
+
+ connection.savepoint("s1");
+ connection.savepoint("s2");
+ connection.releaseSavepoint("s1");
+ // Releasing a savepoint also removes all savepoints after it.
+ assertThrows(SpannerException.class, () -> connection.releaseSavepoint("s2"));
+
+ if (dialect == Dialect.POSTGRESQL) {
+ // PostgreSQL allows multiple savepoints with the same name.
+ connection.savepoint("s1");
+ connection.savepoint("s2");
+ connection.savepoint("s1");
+ connection.releaseSavepoint("s1");
+ connection.releaseSavepoint("s2");
+ connection.releaseSavepoint("s1");
+ assertThrows(SpannerException.class, () -> connection.releaseSavepoint("s1"));
+ }
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepoint() {
+ for (SavepointSupport savepointSupport :
+ new SavepointSupport[] {SavepointSupport.ENABLED, SavepointSupport.FAIL_AFTER_ROLLBACK}) {
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(savepointSupport);
+
+ connection.savepoint("s1");
+ connection.rollbackToSavepoint("s1");
+ // Rolling back to a savepoint does not remove it, so we can roll back multiple times to the
+ // same savepoint.
+ connection.rollbackToSavepoint("s1");
+
+ connection.savepoint("s2");
+ connection.rollbackToSavepoint("s1");
+ // Rolling back to a savepoint removes all savepoints after it.
+ assertThrows(SpannerException.class, () -> connection.rollbackToSavepoint("s2"));
+
+ if (dialect == Dialect.POSTGRESQL) {
+ // PostgreSQL allows multiple savepoints with the same name.
+ connection.savepoint("s2");
+ connection.savepoint("s1");
+ connection.rollbackToSavepoint("s1");
+ connection.rollbackToSavepoint("s2");
+ connection.rollbackToSavepoint("s1");
+ connection.rollbackToSavepoint("s1");
+ connection.releaseSavepoint("s1");
+ assertThrows(SpannerException.class, () -> connection.rollbackToSavepoint("s1"));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testSavepointInAutoCommit() {
+ try (Connection connection = createConnection()) {
+ connection.setAutocommit(true);
+ assertThrows(SpannerException.class, () -> connection.savepoint("s1"));
+
+ // Starting a 'manual' transaction in autocommit mode should enable savepoints.
+ connection.beginTransaction();
+ connection.savepoint("s1");
+ connection.releaseSavepoint("s1");
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepointInReadOnlyTransaction() {
+ for (SavepointSupport savepointSupport :
+ new SavepointSupport[] {SavepointSupport.ENABLED, SavepointSupport.FAIL_AFTER_ROLLBACK}) {
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(savepointSupport);
+ connection.setReadOnly(true);
+
+ // Read-only transactions also support savepoints, but they do not do anything. This feature
+ // is here purely for compatibility.
+ connection.savepoint("s1");
+ try (ResultSet resultSet = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(RANDOM_RESULT_SET_ROW_COUNT, count);
+ }
+
+ connection.rollbackToSavepoint("s1");
+ try (ResultSet resultSet = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(RANDOM_RESULT_SET_ROW_COUNT, count);
+ }
+ // Committing a read-only transaction is necessary to mark the end of the transaction.
+ // It is a no-op on Cloud Spanner.
+ connection.commit();
+
+ assertEquals(1, mockSpanner.countRequestsOfType(BeginTransactionRequest.class));
+ BeginTransactionRequest beginRequest =
+ mockSpanner.getRequestsOfType(BeginTransactionRequest.class).get(0);
+ assertTrue(beginRequest.getOptions().hasReadOnly());
+ assertEquals(0, mockSpanner.countRequestsOfType(CommitRequest.class));
+ }
+ mockSpanner.clearRequests();
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepointInReadWriteTransaction() {
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+
+ connection.savepoint("s1");
+ try (ResultSet resultSet = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(RANDOM_RESULT_SET_ROW_COUNT, count);
+ }
+
+ connection.rollbackToSavepoint("s1");
+ try (ResultSet resultSet = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(RANDOM_RESULT_SET_ROW_COUNT, count);
+ }
+ connection.commit();
+
+ // Read/write transactions are started with inlined Begin transaction options.
+ assertEquals(0, mockSpanner.countRequestsOfType(BeginTransactionRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(RollbackRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(CommitRequest.class));
+ assertEquals(2, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+
+ List requests =
+ mockSpanner.getRequests().stream()
+ .filter(
+ request ->
+ request instanceof ExecuteSqlRequest
+ || request instanceof RollbackRequest
+ || request instanceof CommitRequest)
+ .collect(Collectors.toList());
+ assertEquals(4, requests.size());
+ int index = 0;
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(RollbackRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(CommitRequest.class, requests.get(index++).getClass());
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepointWithDmlStatements() {
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+
+ // First do a query that is included in the transaction.
+ try (ResultSet resultSet = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(RANDOM_RESULT_SET_ROW_COUNT, count);
+ }
+ // Set a savepoint and execute a couple of DML statements.
+ connection.savepoint("s1");
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.savepoint("s2");
+ connection.executeUpdate(INSERT_STATEMENT);
+ // Rollback the last DML statement and commit.
+ connection.rollbackToSavepoint("s2");
+
+ connection.commit();
+
+ // Read/write transactions are started with inlined Begin transaction options.
+ assertEquals(0, mockSpanner.countRequestsOfType(BeginTransactionRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(RollbackRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(CommitRequest.class));
+ assertEquals(5, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+
+ List requests =
+ mockSpanner.getRequests().stream()
+ .filter(
+ request ->
+ request instanceof ExecuteSqlRequest
+ || request instanceof RollbackRequest
+ || request instanceof CommitRequest)
+ .collect(Collectors.toList());
+ assertEquals(7, requests.size());
+ int index = 0;
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(RollbackRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(CommitRequest.class, requests.get(index++).getClass());
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepointFails() {
+ Statement statement = Statement.of("select * from foo where bar=true");
+ int numRows = 10;
+ RandomResultSetGenerator generator = new RandomResultSetGenerator(numRows);
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+
+ try (ResultSet resultSet = connection.executeQuery(statement)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(numRows, count);
+ }
+ // Set a savepoint and execute a couple of DML statements.
+ connection.savepoint("s1");
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.executeUpdate(INSERT_STATEMENT);
+ // Change the result of the initial query.
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ // Rollback to before the DML statements.
+ // This will succeed as long as we don't execute any further statements.
+ connection.rollbackToSavepoint("s1");
+
+ // Trying to commit the transaction or execute any other statements on the transaction will
+ // fail.
+ assertThrows(AbortedDueToConcurrentModificationException.class, connection::commit);
+
+ // Read/write transactions are started with inlined Begin transaction options.
+ assertEquals(0, mockSpanner.countRequestsOfType(BeginTransactionRequest.class));
+ assertEquals(2, mockSpanner.countRequestsOfType(RollbackRequest.class));
+ assertEquals(0, mockSpanner.countRequestsOfType(CommitRequest.class));
+ assertEquals(4, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+
+ List requests =
+ mockSpanner.getRequests().stream()
+ .filter(
+ request ->
+ request instanceof ExecuteSqlRequest
+ || request instanceof RollbackRequest
+ || request instanceof CommitRequest)
+ .collect(Collectors.toList());
+ assertEquals(6, requests.size());
+ int index = 0;
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(RollbackRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(RollbackRequest.class, requests.get(index++).getClass());
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepointWithFailAfterRollback() {
+ Statement statement = Statement.of("select * from foo where bar=true");
+ int numRows = 10;
+ RandomResultSetGenerator generator = new RandomResultSetGenerator(numRows);
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.FAIL_AFTER_ROLLBACK);
+
+ try (ResultSet resultSet = connection.executeQuery(statement)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(numRows, count);
+ }
+ // Set a savepoint and execute a couple of DML statements.
+ connection.savepoint("s1");
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.executeUpdate(INSERT_STATEMENT);
+ // Rollback to before the DML statements.
+ // This will succeed as long as we don't execute any further statements.
+ connection.rollbackToSavepoint("s1");
+
+ // Trying to commit the transaction or execute any other statements on the transaction will
+ // fail with an FAILED_PRECONDITION error, as using a transaction after a rollback to
+ // savepoint has been disabled.
+ SpannerException exception = assertThrows(SpannerException.class, connection::commit);
+ assertEquals(ErrorCode.FAILED_PRECONDITION, exception.getErrorCode());
+ assertEquals(
+ "FAILED_PRECONDITION: Using a read/write transaction after rolling back to a "
+ + "savepoint is not supported with SavepointSupport=FAIL_AFTER_ROLLBACK",
+ exception.getMessage());
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepointSucceedsWithRollback() {
+ for (SavepointSupport savepointSupport :
+ new SavepointSupport[] {SavepointSupport.ENABLED, SavepointSupport.FAIL_AFTER_ROLLBACK}) {
+ Statement statement = Statement.of("select * from foo where bar=true");
+ int numRows = 10;
+ RandomResultSetGenerator generator = new RandomResultSetGenerator(numRows);
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(savepointSupport);
+
+ try (ResultSet resultSet = connection.executeQuery(statement)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(numRows, count);
+ }
+ // Change the result of the initial query and set a savepoint.
+ connection.savepoint("s1");
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ // This will succeed as long as we don't execute any further statements.
+ connection.rollbackToSavepoint("s1");
+
+ // Rolling back the transaction should now be a no-op, as it has already been rolled back.
+ connection.rollback();
+
+ // Read/write transactions are started with inlined Begin transaction options.
+ assertEquals(0, mockSpanner.countRequestsOfType(BeginTransactionRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(RollbackRequest.class));
+ assertEquals(0, mockSpanner.countRequestsOfType(CommitRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+ }
+ mockSpanner.clearRequests();
+ }
+ }
+
+ @Test
+ public void testMultipleRollbacksWithChangedResults() {
+ Statement statement = Statement.of("select * from foo where bar=true");
+ int numRows = 10;
+ RandomResultSetGenerator generator = new RandomResultSetGenerator(numRows);
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ try (Connection connection = createConnection()) {
+ try (ResultSet resultSet = connection.executeQuery(statement)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(numRows, count);
+ }
+ connection.savepoint("s1");
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.savepoint("s2");
+ connection.executeUpdate(INSERT_STATEMENT);
+
+ // Change the result of the initial query to make sure that any retry will fail.
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ // This will succeed as long as we don't execute any further statements.
+ connection.rollbackToSavepoint("s2");
+ // Rolling back one further should also work.
+ connection.rollbackToSavepoint("s1");
+
+ // Rolling back the transaction should now be a no-op, as it has already been rolled back.
+ connection.rollback();
+
+ assertEquals(1, mockSpanner.countRequestsOfType(RollbackRequest.class));
+ assertEquals(0, mockSpanner.countRequestsOfType(CommitRequest.class));
+ assertEquals(3, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+ }
+ }
+
+ @Test
+ public void testMultipleRollbacks() {
+ Statement statement = Statement.of("select * from foo where bar=true");
+ int numRows = 10;
+ RandomResultSetGenerator generator = new RandomResultSetGenerator(numRows);
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+
+ try (ResultSet resultSet = connection.executeQuery(statement)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(numRows, count);
+ }
+ connection.savepoint("s1");
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.savepoint("s2");
+ connection.executeUpdate(INSERT_STATEMENT);
+
+ // First roll back one step and then one more.
+ connection.rollbackToSavepoint("s2");
+ connection.rollbackToSavepoint("s1");
+
+ // This will only commit the SELECT query.
+ connection.commit();
+
+ assertEquals(1, mockSpanner.countRequestsOfType(RollbackRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(CommitRequest.class));
+ assertEquals(4, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+
+ List requests =
+ mockSpanner.getRequests().stream()
+ .filter(
+ request ->
+ request instanceof ExecuteSqlRequest
+ || request instanceof RollbackRequest
+ || request instanceof CommitRequest)
+ .collect(Collectors.toList());
+ assertEquals(6, requests.size());
+ int index = 0;
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(RollbackRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(CommitRequest.class, requests.get(index++).getClass());
+ }
+ }
+
+ @Test
+ public void testRollbackMutations() {
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+
+ connection.bufferedWrite(Mutation.newInsertBuilder("foo1").build());
+ connection.savepoint("s1");
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.bufferedWrite(Mutation.newInsertBuilder("foo2").build());
+ connection.savepoint("s2");
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.bufferedWrite(Mutation.newInsertBuilder("foo3").build());
+
+ connection.rollbackToSavepoint("s1");
+
+ // This will only commit the first mutation.
+ connection.commit();
+
+ assertEquals(1, mockSpanner.countRequestsOfType(RollbackRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(CommitRequest.class));
+ assertEquals(2, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+ CommitRequest commitRequest = mockSpanner.getRequestsOfType(CommitRequest.class).get(0);
+ assertEquals(1, commitRequest.getMutationsCount());
+ assertEquals("foo1", commitRequest.getMutations(0).getInsert().getTable());
+ }
+ }
+
+ @Test
+ public void testRollbackBatchDml() {
+ try (Connection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.savepoint("s1");
+ connection.executeBatchUpdate(ImmutableList.of(INSERT_STATEMENT, INSERT_STATEMENT));
+ connection.savepoint("s2");
+
+ connection.executeUpdate(INSERT_STATEMENT);
+ connection.savepoint("s3");
+ connection.executeBatchUpdate(ImmutableList.of(INSERT_STATEMENT, INSERT_STATEMENT));
+ connection.savepoint("s4");
+
+ connection.rollbackToSavepoint("s2");
+
+ connection.commit();
+
+ assertEquals(1, mockSpanner.countRequestsOfType(RollbackRequest.class));
+ assertEquals(1, mockSpanner.countRequestsOfType(CommitRequest.class));
+ assertEquals(3, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+ assertEquals(3, mockSpanner.countRequestsOfType(ExecuteBatchDmlRequest.class));
+
+ List requests =
+ mockSpanner.getRequests().stream()
+ .filter(
+ request ->
+ request instanceof ExecuteSqlRequest
+ || request instanceof RollbackRequest
+ || request instanceof CommitRequest
+ || request instanceof ExecuteBatchDmlRequest)
+ .collect(Collectors.toList());
+ assertEquals(8, requests.size());
+ int index = 0;
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteBatchDmlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteBatchDmlRequest.class, requests.get(index++).getClass());
+ assertEquals(RollbackRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteSqlRequest.class, requests.get(index++).getClass());
+ assertEquals(ExecuteBatchDmlRequest.class, requests.get(index++).getClass());
+ assertEquals(CommitRequest.class, requests.get(index++).getClass());
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepointWithoutInternalRetries() {
+ Statement statement = Statement.of("select * from foo where bar=true");
+ int numRows = 10;
+ RandomResultSetGenerator generator = new RandomResultSetGenerator(numRows);
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ try (Connection connection = createConnection()) {
+ connection.setRetryAbortsInternally(false);
+
+ connection.savepoint("s1");
+ try (ResultSet resultSet = connection.executeQuery(statement)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(numRows, count);
+ }
+ // This should work.
+ connection.rollbackToSavepoint("s1");
+ // Resuming after a rollback is not supported without internal retries enabled.
+ assertThrows(SpannerException.class, () -> connection.executeUpdate(INSERT_STATEMENT));
+ }
+ }
+
+ @Test
+ public void testRollbackToSavepointWithoutInternalRetriesInReadOnlyTransaction() {
+ Statement statement = Statement.of("select * from foo where bar=true");
+ int numRows = 10;
+ RandomResultSetGenerator generator = new RandomResultSetGenerator(numRows);
+ mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
+ try (Connection connection = createConnection()) {
+ connection.setRetryAbortsInternally(false);
+ connection.setReadOnly(true);
+
+ connection.savepoint("s1");
+ try (ResultSet resultSet = connection.executeQuery(statement)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(numRows, count);
+ }
+
+ // Both rolling back and resuming after a rollback are supported in a read-only transaction,
+ // even if internal retries have been disabled.
+ connection.rollbackToSavepoint("s1");
+ try (ResultSet resultSet = connection.executeQuery(statement)) {
+ int count = 0;
+ while (resultSet.next()) {
+ count++;
+ }
+ assertEquals(numRows, count);
+ }
+ }
+ }
+}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SavepointTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SavepointTest.java
new file mode 100644
index 00000000000..e5ec5c9478c
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SavepointTest.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner.connection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+
+import com.google.cloud.spanner.Dialect;
+import com.google.cloud.spanner.SpannerException;
+import com.google.cloud.spanner.connection.AbstractMultiUseTransaction.Savepoint;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SavepointTest {
+ static class TestTransaction extends ReadOnlyTransaction {
+ TestTransaction() {
+ super(ReadOnlyTransaction.newBuilder().withStatementExecutor(mock(StatementExecutor.class)));
+ }
+ }
+
+ @Test
+ public void testCreateSavepoint_GoogleSql() {
+ Dialect dialect = Dialect.GOOGLE_STANDARD_SQL;
+ TestTransaction transaction = new TestTransaction();
+
+ transaction.savepoint("s1", dialect);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+
+ // GoogleSql does not allow duplicate savepoint names.
+ assertThrows(SpannerException.class, () -> transaction.savepoint("s1", dialect));
+ assertThrows(SpannerException.class, () -> transaction.savepoint("s2", dialect));
+ }
+
+ @Test
+ public void testCreateSavepoint_PostgreSQL() {
+ Dialect dialect = Dialect.POSTGRESQL;
+ TestTransaction transaction = new TestTransaction();
+
+ transaction.savepoint("s1", dialect);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+
+ // PostgreSQL allows duplicate savepoint names.
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2"), Savepoint.of("s2")),
+ transaction.getSavepoints());
+ transaction.savepoint("s1", dialect);
+ assertEquals(
+ ImmutableList.of(
+ Savepoint.of("s1"), Savepoint.of("s2"), Savepoint.of("s2"), Savepoint.of("s1")),
+ transaction.getSavepoints());
+ }
+
+ @Test
+ public void testReleaseSavepoint_GoogleSql() {
+ Dialect dialect = Dialect.GOOGLE_STANDARD_SQL;
+ TestTransaction transaction = new TestTransaction();
+
+ transaction.savepoint("s1", dialect);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+ transaction.releaseSavepoint("s1");
+ assertEquals(ImmutableList.of(), transaction.getSavepoints());
+
+ transaction.savepoint("s1", dialect);
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ transaction.releaseSavepoint("s2");
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ transaction.releaseSavepoint("s1");
+ assertEquals(ImmutableList.of(), transaction.getSavepoints());
+
+ assertThrows(SpannerException.class, () -> transaction.releaseSavepoint("s1"));
+
+ transaction.savepoint("s1", dialect);
+ assertThrows(SpannerException.class, () -> transaction.releaseSavepoint("s2"));
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+ }
+
+ @Test
+ public void testReleaseSavepoint_PostgreSQL() {
+ Dialect dialect = Dialect.POSTGRESQL;
+ TestTransaction transaction = new TestTransaction();
+
+ transaction.savepoint("s1", dialect);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+ transaction.releaseSavepoint("s1");
+ assertEquals(ImmutableList.of(), transaction.getSavepoints());
+
+ transaction.savepoint("s1", dialect);
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ transaction.releaseSavepoint("s2");
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ transaction.releaseSavepoint("s1");
+ assertEquals(ImmutableList.of(), transaction.getSavepoints());
+
+ assertThrows(SpannerException.class, () -> transaction.releaseSavepoint("s1"));
+
+ transaction.savepoint("s1", dialect);
+ assertThrows(SpannerException.class, () -> transaction.releaseSavepoint("s2"));
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ transaction.savepoint("s2", dialect);
+ transaction.savepoint("s1", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2"), Savepoint.of("s1")),
+ transaction.getSavepoints());
+ transaction.releaseSavepoint("s1");
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ }
+
+ @Test
+ public void testRollbackToSavepoint_GoogleSql() {
+ Dialect dialect = Dialect.GOOGLE_STANDARD_SQL;
+ TestTransaction transaction = new TestTransaction();
+
+ transaction.savepoint("s1", dialect);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+ transaction.rollbackToSavepoint("s1", SavepointSupport.ENABLED);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ transaction.rollbackToSavepoint("s2", SavepointSupport.ENABLED);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ transaction.rollbackToSavepoint("s1", SavepointSupport.ENABLED);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ assertThrows(
+ SpannerException.class,
+ () -> transaction.rollbackToSavepoint("s2", SavepointSupport.ENABLED));
+ }
+
+ @Test
+ public void testRollbackToSavepoint_PostgreSQL() {
+ Dialect dialect = Dialect.POSTGRESQL;
+ TestTransaction transaction = new TestTransaction();
+
+ transaction.savepoint("s1", dialect);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+ transaction.rollbackToSavepoint("s1", SavepointSupport.ENABLED);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ transaction.savepoint("s2", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ transaction.rollbackToSavepoint("s2", SavepointSupport.ENABLED);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2")), transaction.getSavepoints());
+ transaction.rollbackToSavepoint("s1", SavepointSupport.ENABLED);
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ assertThrows(
+ SpannerException.class,
+ () -> transaction.rollbackToSavepoint("s2", SavepointSupport.ENABLED));
+ assertEquals(ImmutableList.of(Savepoint.of("s1")), transaction.getSavepoints());
+
+ transaction.savepoint("s2", dialect);
+ transaction.savepoint("s1", dialect);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2"), Savepoint.of("s1")),
+ transaction.getSavepoints());
+ transaction.rollbackToSavepoint("s1", SavepointSupport.ENABLED);
+ assertEquals(
+ ImmutableList.of(Savepoint.of("s1"), Savepoint.of("s2"), Savepoint.of("s1")),
+ transaction.getSavepoints());
+ }
+}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSavepointTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSavepointTest.java
new file mode 100644
index 00000000000..2a0995713e1
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSavepointTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner.connection.it;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.cloud.spanner.KeySet;
+import com.google.cloud.spanner.Mutation;
+import com.google.cloud.spanner.ParallelIntegrationTest;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.connection.ITAbstractSpannerTest;
+import com.google.cloud.spanner.connection.SavepointSupport;
+import com.google.common.collect.ImmutableList;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@Category(ParallelIntegrationTest.class)
+@RunWith(JUnit4.class)
+public class ITSavepointTest extends ITAbstractSpannerTest {
+ @Override
+ public void appendConnectionUri(StringBuilder uri) {
+ uri.append(";autocommit=false");
+ }
+
+ @Override
+ public boolean doCreateDefaultTestTable() {
+ return true;
+ }
+
+ @Before
+ public void clearTestData() {
+ try (ITConnection connection = createConnection()) {
+ connection.bufferedWrite(Mutation.delete("TEST", KeySet.all()));
+ connection.commit();
+ }
+ }
+
+ @Test
+ public void testRollbackDmlStatement() {
+ try (ITConnection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+ assertEquals(
+ 1L,
+ connection.executeUpdate(
+ Statement.newBuilder("insert into test (id, name) values (@id, @name)")
+ .bind("id")
+ .to(1L)
+ .bind("name")
+ .to("One")
+ .build()));
+ connection.savepoint("s1");
+ assertEquals(
+ 1L,
+ connection.executeUpdate(
+ Statement.newBuilder("insert into test (id, name) values (@id, @name)")
+ .bind("id")
+ .to(2L)
+ .bind("name")
+ .to("Two")
+ .build()));
+
+ connection.rollbackToSavepoint("s1");
+ connection.commit();
+
+ try (ResultSet resultSet = connection.executeQuery(Statement.of("select * from test"))) {
+ assertTrue(resultSet.next());
+ assertEquals(1L, resultSet.getLong(0));
+ assertEquals("One", resultSet.getString(1));
+ assertFalse(resultSet.next());
+ }
+ }
+ }
+
+ @Test
+ public void testRollbackMutations() {
+ try (ITConnection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+ connection.bufferedWrite(
+ Mutation.newInsertBuilder("test").set("id").to(1L).set("name").to("One").build());
+ connection.savepoint("s1");
+ connection.bufferedWrite(
+ Mutation.newInsertBuilder("test").set("id").to(2L).set("name").to("Two").build());
+ connection.savepoint("s2");
+ connection.bufferedWrite(
+ Mutation.newInsertBuilder("test").set("id").to(3L).set("name").to("Three").build());
+ connection.savepoint("s3");
+ connection.bufferedWrite(
+ Mutation.newInsertBuilder("test").set("id").to(4L).set("name").to("Four").build());
+ connection.savepoint("s4");
+
+ connection.rollbackToSavepoint("s2");
+ connection.commit();
+
+ try (ResultSet resultSet =
+ connection.executeQuery(Statement.of("select * from test order by id"))) {
+ assertTrue(resultSet.next());
+ assertEquals(1L, resultSet.getLong(0));
+ assertEquals("One", resultSet.getString(1));
+ assertTrue(resultSet.next());
+ assertEquals(2L, resultSet.getLong(0));
+ assertEquals("Two", resultSet.getString(1));
+ assertFalse(resultSet.next());
+ }
+ }
+ }
+
+ @Test
+ public void testRollbackBatchDmlStatement() {
+ try (ITConnection connection = createConnection()) {
+ connection.setSavepointSupport(SavepointSupport.ENABLED);
+ assertArrayEquals(
+ new long[] {1L, 1L},
+ connection.executeBatchUpdate(
+ ImmutableList.of(
+ Statement.newBuilder("insert into test (id, name) values (@id, @name)")
+ .bind("id")
+ .to(1L)
+ .bind("name")
+ .to("One")
+ .build(),
+ Statement.newBuilder("insert into test (id, name) values (@id, @name)")
+ .bind("id")
+ .to(2L)
+ .bind("name")
+ .to("Two")
+ .build())));
+ connection.savepoint("s1");
+ assertArrayEquals(
+ new long[] {1L, 1L},
+ connection.executeBatchUpdate(
+ ImmutableList.of(
+ Statement.newBuilder("insert into test (id, name) values (@id, @name)")
+ .bind("id")
+ .to(3L)
+ .bind("name")
+ .to("Three")
+ .build(),
+ Statement.newBuilder("insert into test (id, name) values (@id, @name)")
+ .bind("id")
+ .to(4L)
+ .bind("name")
+ .to("Four")
+ .build())));
+
+ connection.rollbackToSavepoint("s1");
+ connection.commit();
+
+ try (ResultSet resultSet =
+ connection.executeQuery(Statement.of("select * from test order by id"))) {
+ assertTrue(resultSet.next());
+ assertEquals(1L, resultSet.getLong(0));
+ assertEquals("One", resultSet.getString(1));
+ assertTrue(resultSet.next());
+ assertEquals(2L, resultSet.getLong(0));
+ assertEquals("Two", resultSet.getString(1));
+ assertFalse(resultSet.next());
+ }
+ }
+ }
+}
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 4fe25d53b05..4a10fe34e51 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
@@ -3392,6 +3392,205 @@ NEW_CONNECTION;
@EXPECT EXCEPTION UNIMPLEMENTED
show variable/-rpc_priority;
NEW_CONNECTION;
+show variable savepoint_support;
+NEW_CONNECTION;
+SHOW VARIABLE SAVEPOINT_SUPPORT;
+NEW_CONNECTION;
+show variable savepoint_support;
+NEW_CONNECTION;
+ show variable savepoint_support;
+NEW_CONNECTION;
+ show variable savepoint_support;
+NEW_CONNECTION;
+
+
+
+show variable savepoint_support;
+NEW_CONNECTION;
+show variable savepoint_support ;
+NEW_CONNECTION;
+show variable savepoint_support ;
+NEW_CONNECTION;
+show variable savepoint_support
+
+;
+NEW_CONNECTION;
+show variable savepoint_support;
+NEW_CONNECTION;
+show variable savepoint_support;
+NEW_CONNECTION;
+show
+variable
+savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable%savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable_savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable&savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable$savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable@savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable!savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable*savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable(savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support);
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable)savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable-savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable+savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable-#savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable/savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable\savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable?savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable-/savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable/#savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-show variable savepoint_support;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable savepoint_support/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION UNIMPLEMENTED
+show variable/-savepoint_support;
+NEW_CONNECTION;
begin;
NEW_CONNECTION;
BEGIN;
@@ -16309,3 +16508,597 @@ set rpc_priority='NULL'/-;
NEW_CONNECTION;
@EXPECT EXCEPTION INVALID_ARGUMENT
set/-rpc_priority='NULL';
+NEW_CONNECTION;
+set savepoint_support='ENABLED';
+NEW_CONNECTION;
+SET SAVEPOINT_SUPPORT='ENABLED';
+NEW_CONNECTION;
+set savepoint_support='enabled';
+NEW_CONNECTION;
+ set savepoint_support='ENABLED';
+NEW_CONNECTION;
+ set savepoint_support='ENABLED';
+NEW_CONNECTION;
+
+
+
+set savepoint_support='ENABLED';
+NEW_CONNECTION;
+set savepoint_support='ENABLED' ;
+NEW_CONNECTION;
+set savepoint_support='ENABLED' ;
+NEW_CONNECTION;
+set savepoint_support='ENABLED'
+
+;
+NEW_CONNECTION;
+set savepoint_support='ENABLED';
+NEW_CONNECTION;
+set savepoint_support='ENABLED';
+NEW_CONNECTION;
+set
+savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED' bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set%savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set_savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set&savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set$savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set@savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set!savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set*savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set(savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED');
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set)savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set+savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-#savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set\savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set?savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-/savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/#savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-set savepoint_support='ENABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='ENABLED'/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/-savepoint_support='ENABLED';
+NEW_CONNECTION;
+set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+SET SAVEPOINT_SUPPORT='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+set savepoint_support='fail_after_rollback';
+NEW_CONNECTION;
+ set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+ set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+
+
+
+set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+set savepoint_support='FAIL_AFTER_ROLLBACK' ;
+NEW_CONNECTION;
+set savepoint_support='FAIL_AFTER_ROLLBACK' ;
+NEW_CONNECTION;
+set savepoint_support='FAIL_AFTER_ROLLBACK'
+
+;
+NEW_CONNECTION;
+set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+set
+savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK' bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set%savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set_savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set&savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set$savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set@savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set!savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set*savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set(savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK');
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set)savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set+savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-#savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set\savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set?savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-/savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/#savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-set savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='FAIL_AFTER_ROLLBACK'/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/-savepoint_support='FAIL_AFTER_ROLLBACK';
+NEW_CONNECTION;
+set savepoint_support='DISABLED';
+NEW_CONNECTION;
+SET SAVEPOINT_SUPPORT='DISABLED';
+NEW_CONNECTION;
+set savepoint_support='disabled';
+NEW_CONNECTION;
+ set savepoint_support='DISABLED';
+NEW_CONNECTION;
+ set savepoint_support='DISABLED';
+NEW_CONNECTION;
+
+
+
+set savepoint_support='DISABLED';
+NEW_CONNECTION;
+set savepoint_support='DISABLED' ;
+NEW_CONNECTION;
+set savepoint_support='DISABLED' ;
+NEW_CONNECTION;
+set savepoint_support='DISABLED'
+
+;
+NEW_CONNECTION;
+set savepoint_support='DISABLED';
+NEW_CONNECTION;
+set savepoint_support='DISABLED';
+NEW_CONNECTION;
+set
+savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED' bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set%savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set_savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set&savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set$savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set@savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set!savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set*savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set(savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED');
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set)savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set+savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-#savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set\savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set?savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-/savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/#savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-set savepoint_support='DISABLED';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set savepoint_support='DISABLED'/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/-savepoint_support='DISABLED';
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 e68315ec537..6c99bb62a1c 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 2022-10-28T19:20:03.218000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:03.218000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:19.066000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:19.066000000Z'
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 2022-10-28T19:20:03.218000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:19.066000000Z';
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 2022-10-28T19:20:03.689000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:03.689000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:19.596000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:19.596000000Z'
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 2022-10-28T19:20:03.689000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:19.596000000Z';
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 2022-10-28T19:20:04.116000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:04.116000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:19.974000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:19.974000000Z'
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 2022-10-28T19:20:04.116000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:19.974000000Z';
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 2022-10-28T19:20:04.576000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:04.576000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:20.454000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:20.454000000Z'
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 2022-10-28T19:20:04.576000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:20.454000000Z';
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 2022-10-28T19:20:04.992000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:04.992000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:20.889000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:20.889000000Z'
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 2022-10-28T19:20:04.992000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:20.889000000Z';
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 2022-10-28T19:20:05.305000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:21.210000000Z';
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 2022-10-28T19:20:05.305000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:21.210000000Z';
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 2022-10-28T19:20:05.695000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:21.613000000Z';
NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=FALSE;
SELECT 1 AS TEST;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:05.695000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:21.613000000Z';
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 2022-10-28T19:20:06.064000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:06.064000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:21.961000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:21.961000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=FALSE;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:06.064000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:21.961000000Z';
NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=FALSE;
@@ -3246,15 +3246,15 @@ NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:06.481000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:06.481000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:22.371000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:22.371000000Z'
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 2022-10-28T19:20:06.481000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:22.371000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -3664,8 +3664,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 2022-10-28T19:20:06.786000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:06.786000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:22.712000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:22.712000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -3674,7 +3674,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 2022-10-28T19:20:06.786000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:22.712000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -4083,14 +4083,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 2022-10-28T19:20:07.091000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:23.005000000Z';
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 2022-10-28T19:20:07.091000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:23.005000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -4440,13 +4440,13 @@ SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
START BATCH DDL;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:07.423000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:23.272000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
START BATCH DDL;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:07.423000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:23.272000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -4880,8 +4880,8 @@ SET TRANSACTION READ ONLY;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:07.711000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:07.711000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:23.554000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:23.554000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -4891,7 +4891,7 @@ SET TRANSACTION READ ONLY;
SELECT 1 AS TEST;
COMMIT;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:07.711000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:23.554000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -5291,15 +5291,15 @@ NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
SET TRANSACTION READ ONLY;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:08.036000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:08.036000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:23.885000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:23.885000000Z'
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 2022-10-28T19:20:08.036000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:23.885000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -5645,15 +5645,15 @@ NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:08.315000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:08.315000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:24.164000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:24.164000000Z'
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 2022-10-28T19:20:08.315000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:24.164000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -6093,8 +6093,8 @@ BEGIN TRANSACTION;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
ROLLBACK;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:08.600000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:08.600000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:24.479000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:24.479000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -6104,7 +6104,7 @@ BEGIN TRANSACTION;
SELECT 1 AS TEST;
ROLLBACK;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:08.600000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:24.479000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -6613,8 +6613,8 @@ BEGIN TRANSACTION;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:09.004000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:09.004000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:24.872000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:24.872000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -6624,7 +6624,7 @@ BEGIN TRANSACTION;
SELECT 1 AS TEST;
COMMIT;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:09.004000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:24.872000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -7029,15 +7029,15 @@ NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
BEGIN TRANSACTION;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:09.350000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:09.350000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:25.222000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:25.222000000Z'
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 2022-10-28T19:20:09.350000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:25.222000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -7400,14 +7400,14 @@ SET AUTOCOMMIT=FALSE;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:09.614000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:25.508000000Z';
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 2022-10-28T19:20:09.614000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:25.508000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -7762,13 +7762,13 @@ SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
SELECT 1 AS TEST;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:09.939000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:25.829000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
SELECT 1 AS TEST;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:09.939000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:25.829000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -8082,14 +8082,14 @@ SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:10.269000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:10.269000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:26.148000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:26.148000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:10.269000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:26.148000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -8399,13 +8399,13 @@ SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
START BATCH DDL;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:10.525000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:26.426000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
START BATCH DDL;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:10.525000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:26.426000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
@@ -8760,8 +8760,8 @@ SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
SET TRANSACTION READ ONLY;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:10.792000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:10.792000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:26.727000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:26.727000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -8769,7 +8769,7 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
SET TRANSACTION READ ONLY;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:10.792000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:26.727000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
@@ -9204,8 +9204,8 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
UPDATE foo SET bar=1;
COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:11.068000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:11.068000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:27.036000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:27.036000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -9213,8 +9213,8 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
UPDATE foo SET bar=1;
COMMIT;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:11.068000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:11.068000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:27.036000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:27.036000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -9600,15 +9600,15 @@ NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:11.424000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:11.424000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:27.365000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:27.365000000Z'
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 2022-10-28T19:20:11.424000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:27.365000000Z';
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
@@ -9959,15 +9959,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 2022-10-28T19:20:11.707000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:11.707000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:27.649000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:27.649000000Z'
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 2022-10-28T19:20:11.707000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:11.707000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:27.649000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:27.649000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -10327,15 +10327,15 @@ NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
UPDATE foo SET bar=1;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:12.017000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:12.017000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:28.057000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:28.057000000Z'
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 2022-10-28T19:20:12.017000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:12.017000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:28.057000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:28.057000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -10725,16 +10725,16 @@ SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:12.424000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:12.424000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:28.508000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:28.508000000Z'
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 2022-10-28T19:20:12.424000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:12.424000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:28.508000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:28.508000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -11117,15 +11117,15 @@ NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:12.743000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:12.743000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:28.912000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:28.912000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:12.743000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:12.743000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:28.912000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:28.912000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -11455,14 +11455,14 @@ SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:13.035000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:13.035000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:29.304000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:29.304000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:13.035000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:13.035000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:29.304000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:29.304000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=FALSE;
@@ -11785,15 +11785,15 @@ NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
SET READ_ONLY_STALENESS='MAX_STALENESS 10s';
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:13.310000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:13.310000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:29.656000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:29.656000000Z'
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 2022-10-28T19:20:13.310000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:13.310000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:29.656000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:29.656000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
@@ -12200,8 +12200,8 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
SELECT 1 AS TEST;
COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:13.591000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:13.591000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:30.062000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:30.062000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
@@ -12209,8 +12209,8 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
SELECT 1 AS TEST;
COMMIT;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:13.591000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:13.591000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:30.062000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:30.062000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
@@ -12593,15 +12593,15 @@ NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:13.914000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:13.914000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:30.469000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:30.469000000Z'
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 2022-10-28T19:20:13.914000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:30.469000000Z';
NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
@@ -12939,15 +12939,15 @@ NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:14.189000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:14.189000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:30.862000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:30.862000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:14.189000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:14.189000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:30.862000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:30.862000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
@@ -13294,15 +13294,15 @@ NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:14.486000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:14.486000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:31.255000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:31.255000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:14.486000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:14.486000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:31.255000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:31.255000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
@@ -13619,14 +13619,14 @@ SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:14.772000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:14.772000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:31.641000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:31.641000000Z'
SHOW VARIABLE READ_ONLY_STALENESS;
NEW_CONNECTION;
SET READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:14.772000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:14.772000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:31.641000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:31.641000000Z'
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/ConnectionImplGeneratedSqlScriptTest.sql b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/postgresql/ConnectionImplGeneratedSqlScriptTest.sql
index d633f9335d8..0e02a2b65c4 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 2022-10-28T19:20:03.457000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:03.457000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:19.343000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:19.343000000Z'
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 2022-10-28T19:20:03.457000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:19.343000000Z';
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 2022-10-28T19:20:03.863000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:03.863000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:19.772000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:19.772000000Z'
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 2022-10-28T19:20:03.863000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:19.772000000Z';
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 2022-10-28T19:20:04.369000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:04.369000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:20.243000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:20.243000000Z'
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 2022-10-28T19:20:04.369000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:20.243000000Z';
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 2022-10-28T19:20:04.820000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:04.820000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:20.701000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:20.701000000Z'
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 2022-10-28T19:20:04.820000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:20.701000000Z';
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 2022-10-28T19:20:05.129000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:05.129000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:21.041000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:21.041000000Z'
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 2022-10-28T19:20:05.129000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:21.041000000Z';
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 2022-10-28T19:20:05.486000000Z';
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:21.396000000Z';
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 2022-10-28T19:20:05.486000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:21.396000000Z';
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 2022-10-28T19:20:05.892000000Z';
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:21.795000000Z';
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 2022-10-28T19:20:05.892000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:21.795000000Z';
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 2022-10-28T19:20:06.209000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:06.209000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:22.110000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:22.110000000Z'
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 2022-10-28T19:20:06.209000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:22.110000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
SET AUTOCOMMIT=FALSE;
@@ -3246,15 +3246,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
COMMIT;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:06.622000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:06.622000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:22.517000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:22.517000000Z'
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 2022-10-28T19:20:06.622000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:22.517000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -3664,8 +3664,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 2022-10-28T19:20:06.941000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:06.941000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:22.872000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:22.872000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -3674,7 +3674,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 2022-10-28T19:20:06.941000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:22.872000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -4083,14 +4083,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 2022-10-28T19:20:07.222000000Z';
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:23.146000000Z';
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 2022-10-28T19:20:07.222000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:23.146000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -4440,13 +4440,13 @@ SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
START BATCH DDL;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:07.545000000Z';
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:23.395000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
START BATCH DDL;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:07.545000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:23.395000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -4880,8 +4880,8 @@ SET TRANSACTION READ ONLY;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
COMMIT;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:07.893000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:07.893000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:23.741000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:23.741000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -4891,7 +4891,7 @@ SET TRANSACTION READ ONLY;
SELECT 1 AS TEST;
COMMIT;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:07.893000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:23.741000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -5291,15 +5291,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
SET TRANSACTION READ ONLY;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:08.172000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:08.172000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:24.018000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:24.018000000Z'
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 2022-10-28T19:20:08.172000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:24.018000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -5645,15 +5645,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 2022-10-28T19:20:08.442000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:08.442000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:24.316000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:24.316000000Z'
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 2022-10-28T19:20:08.442000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:24.316000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -6093,8 +6093,8 @@ BEGIN TRANSACTION;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
ROLLBACK;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:08.787000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:08.787000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:24.656000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:24.656000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -6104,7 +6104,7 @@ BEGIN TRANSACTION;
SELECT 1 AS TEST;
ROLLBACK;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:08.787000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:24.656000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -6613,8 +6613,8 @@ BEGIN TRANSACTION;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
COMMIT;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:09.203000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:09.203000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:25.076000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:25.076000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -6624,7 +6624,7 @@ BEGIN TRANSACTION;
SELECT 1 AS TEST;
COMMIT;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:09.203000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:25.076000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -7029,15 +7029,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
BEGIN TRANSACTION;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:09.473000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:09.473000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:25.357000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:25.357000000Z'
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 2022-10-28T19:20:09.473000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:25.357000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -7400,14 +7400,14 @@ SET AUTOCOMMIT=FALSE;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:09.790000000Z';
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:25.667000000Z';
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 2022-10-28T19:20:09.790000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:25.667000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -7762,13 +7762,13 @@ SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
SELECT 1 AS TEST;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:10.126000000Z';
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:25.999000000Z';
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 2022-10-28T19:20:10.126000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:25.999000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -8082,14 +8082,14 @@ SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:10.401000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:10.401000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:26.285000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:26.285000000Z'
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 2022-10-28T19:20:10.401000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:26.285000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=FALSE;
@@ -8399,13 +8399,13 @@ SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
START BATCH DDL;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:10.660000000Z';
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:26.589000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
START BATCH DDL;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:10.660000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:26.590000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
@@ -8760,8 +8760,8 @@ SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
SET TRANSACTION READ ONLY;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:10.914000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:10.914000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:26.865000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:26.865000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -8769,7 +8769,7 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
SET TRANSACTION READ ONLY;
@EXPECT EXCEPTION FAILED_PRECONDITION
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:10.914000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:26.865000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
@@ -9204,8 +9204,8 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
UPDATE foo SET bar=1;
COMMIT;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:11.258000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:11.258000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:27.216000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:27.216000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -9213,8 +9213,8 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
UPDATE foo SET bar=1;
COMMIT;
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:11.258000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:11.258000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:27.216000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:27.216000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -9600,15 +9600,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:11.555000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:11.555000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:27.498000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:27.498000000Z'
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 2022-10-28T19:20:11.555000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:27.498000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
@@ -9959,15 +9959,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 2022-10-28T19:20:11.865000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:11.865000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:27.862000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:27.862000000Z'
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 2022-10-28T19:20:11.865000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:11.865000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:27.862000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:27.862000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -10327,15 +10327,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
UPDATE foo SET bar=1;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:12.219000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:12.219000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:28.287000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:28.287000000Z'
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 2022-10-28T19:20:12.219000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:12.219000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:28.287000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:28.287000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -10725,16 +10725,16 @@ SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
@EXPECT RESULT_SET 'TEST',1
SELECT 1 AS TEST;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:12.582000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:12.582000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:28.714000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:28.714000000Z'
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 2022-10-28T19:20:12.582000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:12.582000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:28.714000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:28.714000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -11117,15 +11117,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:12.892000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:12.892000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:29.104000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:29.104000000Z'
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 2022-10-28T19:20:12.892000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:12.892000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:29.104000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:29.104000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -11455,14 +11455,14 @@ SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:13.175000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:13.175000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:29.481000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:29.481000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
SET AUTOCOMMIT=TRUE;
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:13.175000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:13.175000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:29.481000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:29.481000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=FALSE;
@@ -11785,15 +11785,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 2022-10-28T19:20:13.444000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:13.444000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:29.860000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:29.860000000Z'
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 2022-10-28T19:20:13.444000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:13.444000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:29.860000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:29.860000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
@@ -12200,8 +12200,8 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
SELECT 1 AS TEST;
COMMIT;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:13.763000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:13.763000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:30.271000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:30.271000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
@@ -12209,8 +12209,8 @@ SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
SELECT 1 AS TEST;
COMMIT;
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:13.763000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:13.763000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:30.271000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:30.271000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
@@ -12593,15 +12593,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
BEGIN TRANSACTION;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:14.050000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:14.050000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:30.648000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:30.648000000Z'
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 2022-10-28T19:20:14.050000000Z';
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:30.648000000Z';
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
@@ -12939,15 +12939,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:14.340000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:14.340000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:31.059000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:31.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 2022-10-28T19:20:14.340000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:14.340000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:31.059000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:31.059000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
@@ -13294,15 +13294,15 @@ NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
SELECT 1 AS TEST;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:14.630000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:14.630000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:31.453000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:31.453000000Z'
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 2022-10-28T19:20:14.630000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:14.630000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:31.453000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:31.453000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
@@ -13619,14 +13619,14 @@ SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
-SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2022-10-28T19:20:14.899000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2022-10-28T19:20:14.899000000Z'
+SET SPANNER.READ_ONLY_STALENESS='READ_TIMESTAMP 2023-03-21T18:40:31.817000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','READ_TIMESTAMP 2023-03-21T18:40:31.817000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;
SET AUTOCOMMIT=TRUE;
-SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2022-10-28T19:20:14.899000000Z';
-@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2022-10-28T19:20:14.899000000Z'
+SET SPANNER.READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2023-03-21T18:40:31.817000000Z';
+@EXPECT RESULT_SET 'SPANNER.READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2023-03-21T18:40:31.817000000Z'
SHOW VARIABLE SPANNER.READ_ONLY_STALENESS;
NEW_CONNECTION;
SET SPANNER.READONLY=TRUE;