diff --git a/README.md b/README.md index 1e1173092d..c69143b96f 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,13 @@ implementation 'com.google.cloud:google-cloud-spanner' If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-spanner:6.38.2' +implementation 'com.google.cloud:google-cloud-spanner:6.39.0' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.38.2" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.39.0" ``` @@ -411,7 +411,7 @@ Java is a registered trademark of Oracle and/or its affiliates. [kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java11.html [stability-image]: https://img.shields.io/badge/stability-stable-green [maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-spanner.svg -[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.38.2 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.39.0 [authentication]: https://github.com/googleapis/google-cloud-java#authentication [auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes [predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index 637ca06280..67e9663747 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -222,4 +222,30 @@ com/google/cloud/spanner/connection/Connection com.google.cloud.spanner.ResultSet analyzeUpdateStatement(com.google.cloud.spanner.Statement, com.google.cloud.spanner.ReadContext$QueryAnalyzeMode, com.google.cloud.spanner.Options$UpdateOption[]) + + + 7012 + com/google/cloud/spanner/connection/Connection + void setSavepointSupport(com.google.cloud.spanner.connection.SavepointSupport) + + + 7012 + com/google/cloud/spanner/connection/Connection + com.google.cloud.spanner.connection.SavepointSupport getSavepointSupport() + + + 7012 + com/google/cloud/spanner/connection/Connection + void savepoint(java.lang.String) + + + 7012 + com/google/cloud/spanner/connection/Connection + void releaseSavepoint(java.lang.String) + + + 7012 + com/google/cloud/spanner/connection/Connection + void rollbackToSavepoint(java.lang.String) + diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java index e911728785..9961920222 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java @@ -21,6 +21,7 @@ import com.google.api.gax.grpc.GrpcCallContext; import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.rpc.ApiCallContext; +import com.google.cloud.spanner.Dialect; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Options.RpcPriority; import com.google.cloud.spanner.SpannerException; @@ -45,6 +46,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; @@ -128,6 +130,33 @@ B setRpcPriority(@Nullable RpcPriority rpcPriority) { this.rpcPriority = builder.rpcPriority; } + /** + * Returns a descriptive name for the type of transaction / unit of work. This is used in error + * messages. + */ + abstract String getUnitOfWorkName(); + + @Override + public void savepoint(@Nonnull String name, @Nonnull Dialect dialect) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.FAILED_PRECONDITION, "Savepoint is not supported for " + getUnitOfWorkName()); + } + + @Override + public void releaseSavepoint(@Nonnull String name) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.FAILED_PRECONDITION, + "Release savepoint is not supported for " + getUnitOfWorkName()); + } + + @Override + public void rollbackToSavepoint( + @Nonnull String name, @Nonnull SavepointSupport savepointSupport) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.FAILED_PRECONDITION, + "Rollback to savepoint is not supported for " + getUnitOfWorkName()); + } + StatementExecutor getStatementExecutor() { return statementExecutor; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractMultiUseTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractMultiUseTransaction.java index 88dabb7763..fd06e774ca 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractMultiUseTransaction.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractMultiUseTransaction.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner.connection; import com.google.api.core.ApiFuture; +import com.google.cloud.spanner.Dialect; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Options.QueryOption; import com.google.cloud.spanner.ReadContext; @@ -24,8 +25,13 @@ import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.SpannerExceptionFactory; import com.google.cloud.spanner.connection.AbstractStatementParser.ParsedStatement; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import com.google.spanner.v1.SpannerGrpc; +import java.util.LinkedList; +import java.util.Objects; +import javax.annotation.Nonnull; /** * Base class for {@link Connection}-based transactions that can be used for multiple read and @@ -33,6 +39,49 @@ */ abstract class AbstractMultiUseTransaction extends AbstractBaseUnitOfWork { + /** In-memory savepoint implementation that is used by the Connection API. */ + static class Savepoint { + private final String name; + + static Savepoint of(String name) { + return new Savepoint(name); + } + + Savepoint(String name) { + this.name = name; + } + + /** Returns the index of the first statement that was executed after this savepoint. */ + int getStatementPosition() { + return -1; + } + + /** Returns the index of the first mutation that was executed after this savepoint. */ + int getMutationPosition() { + return -1; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Savepoint)) { + return false; + } + return Objects.equals(((Savepoint) o).name, name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return name; + } + } + + private final LinkedList savepoints = new LinkedList<>(); + AbstractMultiUseTransaction(Builder builder) { super(builder); } @@ -94,4 +143,53 @@ public void abortBatch() { throw SpannerExceptionFactory.newSpannerException( ErrorCode.FAILED_PRECONDITION, "Run batch is not supported for transactions"); } + + abstract Savepoint savepoint(String name); + + abstract void rollbackToSavepoint(Savepoint savepoint); + + @VisibleForTesting + ImmutableList getSavepoints() { + return ImmutableList.copyOf(savepoints); + } + + @Override + public void savepoint(@Nonnull String name, @Nonnull Dialect dialect) { + if (dialect != Dialect.POSTGRESQL) { + // Check that there is no savepoint with this name. Note that PostgreSQL allows multiple + // savepoints in a transaction with the same name, so we don't execute this check for PG. + if (savepoints.stream().anyMatch(savepoint -> savepoint.name.equals(name))) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, "Savepoint with name " + name + " already exists"); + } + } + savepoints.add(savepoint(name)); + } + + @Override + public void releaseSavepoint(@Nonnull String name) { + // Remove the given savepoint and all later savepoints from the transaction. + savepoints.subList(getSavepointIndex(name), savepoints.size()).clear(); + } + + @Override + public void rollbackToSavepoint( + @Nonnull String name, @Nonnull SavepointSupport savepointSupport) { + int index = getSavepointIndex(name); + rollbackToSavepoint(savepoints.get(index)); + if (index < (savepoints.size() - 1)) { + // Remove all savepoints that come after this savepoint from the transaction. + // Rolling back to a savepoint does not remove that savepoint, only the ones that come after. + savepoints.subList(index + 1, savepoints.size()).clear(); + } + } + + private int getSavepointIndex(String name) { + int index = savepoints.lastIndexOf(savepoint(name)); + if (index == -1) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, "Savepoint with name " + name + " does not exist"); + } + return index; + } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java index 1c834ada10..a7752ab667 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ClientSideStatementValueConverters.java @@ -457,6 +457,25 @@ public Priority convert(String value) { } } + /** Converter for converting strings to {@link SavepointSupport} values. */ + static class SavepointSupportConverter + implements ClientSideStatementValueConverter { + private final CaseInsensitiveEnumMap values = + new CaseInsensitiveEnumMap<>(SavepointSupport.class); + + public SavepointSupportConverter(String allowedValues) {} + + @Override + public Class getParameterClass() { + return SavepointSupport.class; + } + + @Override + public SavepointSupport convert(String value) { + return values.get(value); + } + } + static class ExplainCommandConverter implements ClientSideStatementValueConverter { @Override public Class getParameterClass() { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java index beb36f1b56..ed8125f99c 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java @@ -713,6 +713,61 @@ default RpcPriority getRPCPriority() { */ ApiFuture 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 ad52cc5da6..824c3f237e 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 459a813187..8cda355858 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 c076ea702a..4fa74d99e5 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 2c1084ec4c..5caa9a9985 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 dded72844d..a1571ec15c 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 b9384006d4..e0d225d922 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 e391819c42..22c165bbe1 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 169ca1e529..9d238d3d55 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 0000000000..37882e4883 --- /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 9cfd095df3..9724491263 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 a489f3f199..8d4cf203e0 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 42470acf6f..b7e051c411 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 860c0238e0..dd8c0900f4 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 af1fc59f4a..e2c7e463ff 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 aae85bcec6..1101bba399 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 0000000000..537617f4a0 --- /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 0000000000..e5ec5c9478 --- /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 0000000000..2a0995713e --- /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 4fe25d53b0..4a10fe34e5 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 e68315ec53..6c99bb62a1 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 d633f9335d..0e02a2b65c 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;