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