Repository: googleapis/java-spanner-jdbc
Pull request #92 (2020-03-18 17:42:30)

chore: use java helper for templates
We are cleaning up usage of common templates in synthtool. This allows us the cleanup usage in a centralized place rather than in 60+ repos

codecov[bot]: # [Codecov](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92?src=pr&el=h1) Report
> Merging [#92](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92?src=pr&el=desc) into [master](https://codecov.io/gh/googleapis/java-spanner-jdbc/commit/3adc247d9a673e720e466b7aa818cc6e9b13a338?src=pr&el=desc) will **increase** coverage by `0.01%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92/graphs/tree.svg?width=650&token=ODlczvbGrj&height=150&src=pr)](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92?src=pr&el=tree)

```diff
@@             Coverage Diff              @@
##             master      #92      +/-   ##
============================================
+ Coverage     77.79%   77.81%   +0.01%     
  Complexity     1723     1723              
============================================
  Files            60       60              
  Lines          5836     5836              
  Branches        769      769              
============================================
+ Hits           4540     4541       +1     
+ Misses          923      922       -1     
  Partials        373      373
```


| [Impacted Files](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92?src=pr&el=tree) | Coverage Δ | Complexity Δ | |
|---|---|---|---|
| [...oogle/cloud/spanner/jdbc/SingleUseTransaction.java](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92/diff?src=pr&el=tree#diff-c3JjL21haW4vamF2YS9jb20vZ29vZ2xlL2Nsb3VkL3NwYW5uZXIvamRiYy9TaW5nbGVVc2VUcmFuc2FjdGlvbi5qYXZh) | `86.5% <0%> (+0.5%)` | `36% <0%> (ø)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92?src=pr&el=footer). Last update [3adc247...08811e4](https://codecov.io/gh/googleapis/java-spanner-jdbc/pull/92?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3fbddec..d3d90e7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,38 @@
 # Changelog
 
+## [1.14.0](https://www.github.com/googleapis/java-spanner-jdbc/compare/v1.13.0...v1.14.0) (2020-03-18)
+
+
+### Features
+
+* add support for foreign keys ([#78](https://www.github.com/googleapis/java-spanner-jdbc/issues/78)) ([9e770f2](https://www.github.com/googleapis/java-spanner-jdbc/commit/9e770f281c03a1e9c034e5ff3ddee44fa20a7b30)), closes [#77](https://www.github.com/googleapis/java-spanner-jdbc/issues/77)
+
+
+### Bug Fixes
+
+* add missing netty-shaded lib for über-jar ([#80](https://www.github.com/googleapis/java-spanner-jdbc/issues/80)) ([3d6f356](https://www.github.com/googleapis/java-spanner-jdbc/commit/3d6f35669671194e6772fe327ce48f27e5bf4643))
+* fix deprecation warnings in JDBC (test) files ([#81](https://www.github.com/googleapis/java-spanner-jdbc/issues/81)) ([a5e031d](https://www.github.com/googleapis/java-spanner-jdbc/commit/a5e031d3183f8fe88a621500f235ca2b0242f50b))
+* include Spanner gRPC test dependencies ([#63](https://www.github.com/googleapis/java-spanner-jdbc/issues/63)) ([a34bfc0](https://www.github.com/googleapis/java-spanner-jdbc/commit/a34bfc0ff1c2ddeef077dbfae4c56bdd53febcb2))
+
+
+### Dependencies
+
+* update core dependencies ([1ae098e](https://www.github.com/googleapis/java-spanner-jdbc/commit/1ae098e924c2a488cfddd0a3aee9511274b7a515))
+* update core dependencies ([#40](https://www.github.com/googleapis/java-spanner-jdbc/issues/40)) ([18c3a1b](https://www.github.com/googleapis/java-spanner-jdbc/commit/18c3a1b069cb507a91d0320e64a8bf8ae8efe394))
+* update core dependencies ([#73](https://www.github.com/googleapis/java-spanner-jdbc/issues/73)) ([cfa1539](https://www.github.com/googleapis/java-spanner-jdbc/commit/cfa153997599c36f1243e87f1ea0760694657dfe))
+* update core dependencies to v1.27.1 ([#61](https://www.github.com/googleapis/java-spanner-jdbc/issues/61)) ([181991b](https://www.github.com/googleapis/java-spanner-jdbc/commit/181991bda1f66de707d27dad9658b9177626595a))
+* update core dependencies to v1.27.2 ([#71](https://www.github.com/googleapis/java-spanner-jdbc/issues/71)) ([12425fc](https://www.github.com/googleapis/java-spanner-jdbc/commit/12425fcb4382449e4a7a0edad4c812b7ce15aa71))
+* update core dependencies to v1.54.0 ([#72](https://www.github.com/googleapis/java-spanner-jdbc/issues/72)) ([5676021](https://www.github.com/googleapis/java-spanner-jdbc/commit/567602177e05fa198eaa011fbca05cfe4b72fb13))
+* update core dependencies to v1.92.5 ([#53](https://www.github.com/googleapis/java-spanner-jdbc/issues/53)) ([604ee2b](https://www.github.com/googleapis/java-spanner-jdbc/commit/604ee2b75204ad52eaf724c3fb71e8c13540af7c))
+* update core transport dependencies to v1.34.1 ([#43](https://www.github.com/googleapis/java-spanner-jdbc/issues/43)) ([2b6f04d](https://www.github.com/googleapis/java-spanner-jdbc/commit/2b6f04da3aeebac778fb664c4564fb8b58bf3be4))
+* update core transport dependencies to v1.34.2 ([#62](https://www.github.com/googleapis/java-spanner-jdbc/issues/62)) ([8739015](https://www.github.com/googleapis/java-spanner-jdbc/commit/8739015f62289adb92fd55b19a5bff8762da20a9))
+* update dependency com.google.api-client:google-api-client-bom to v1.30.8 ([#46](https://www.github.com/googleapis/java-spanner-jdbc/issues/46)) ([ef891b0](https://www.github.com/googleapis/java-spanner-jdbc/commit/ef891b000045d1f39f91b6a0ed3abaab19c5f05e))
+* update dependency com.google.api-client:google-api-client-bom to v1.30.9 ([#74](https://www.github.com/googleapis/java-spanner-jdbc/issues/74)) ([3b62299](https://www.github.com/googleapis/java-spanner-jdbc/commit/3b622999b9f9645a6086e5efd3206f4d7b0806bc))
+* update dependency com.google.truth:truth to v1.0.1 ([#32](https://www.github.com/googleapis/java-spanner-jdbc/issues/32)) ([5205863](https://www.github.com/googleapis/java-spanner-jdbc/commit/52058636e10951e883523204f0f161db8a972d62))
+* update protobuf.version to v3.11.3 ([#48](https://www.github.com/googleapis/java-spanner-jdbc/issues/48)) ([0779fcb](https://www.github.com/googleapis/java-spanner-jdbc/commit/0779fcb0bfe935c3c302fa8442f733c7e3629761))
+* update protobuf.version to v3.11.4 ([#64](https://www.github.com/googleapis/java-spanner-jdbc/issues/64)) ([f485cff](https://www.github.com/googleapis/java-spanner-jdbc/commit/f485cfffa0de27ce35f5d16c689c31c6ea22138e))
+* update spanner.version to v1.51.0 ([#75](https://www.github.com/googleapis/java-spanner-jdbc/issues/75)) ([4fff168](https://www.github.com/googleapis/java-spanner-jdbc/commit/4fff168eae61fb55933cf3afd67f24ca65dfde54))
+
 ## [1.13.0](https://www.github.com/googleapis/java-spanner-jdbc/compare/1.12.0...v1.13.0) (2020-01-28)
 
 
diff --git a/README.md b/README.md
index db50ef1..4a14e5b 100644
--- a/README.md
+++ b/README.md
@@ -11,16 +11,16 @@ If you are using Maven, add this to your pom.xml file
 <dependency>
   <groupId>com.google.cloud</groupId>
   <artifactId>google-cloud-spanner-jdbc</artifactId>
-  <version>1.13.0</version>
+  <version>1.14.0</version>
 </dependency>
 ```
 If you are using Gradle, add this to your dependencies
 ```Groovy
-compile 'com.google.cloud:google-cloud-spanner-jdbc:1.13.0'
+compile 'com.google.cloud:google-cloud-spanner-jdbc:1.14.0'
 ```
 If you are using SBT, add this to your dependencies
 ```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-spanner-jdbc" % "1.13.0"
+libraryDependencies += "com.google.cloud" % "google-cloud-spanner-jdbc" % "1.14.0"
 ```
 [//]: # ({x-version-update-end})
 
diff --git a/pom.xml b/pom.xml
index c78553f..b850ccf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <artifactId>google-cloud-spanner-jdbc</artifactId>
-  <version>1.13.1-SNAPSHOT</version><!-- {x-version-update:google-cloud-spanner-jdbc:current} -->
+  <version>1.14.1-SNAPSHOT</version><!-- {x-version-update:google-cloud-spanner-jdbc:current} -->
   <packaging>jar</packaging>
   <name>Google Cloud Spanner JDBC</name>
   <url>https://github.com/googleapis/java-spanner-jdbc</url>
@@ -58,7 +58,7 @@
   </licenses>
   <properties>
     <site.installationModule>google-cloud-spanner-jdbc</site.installationModule>
-    <grpc.version>1.28.0</grpc.version>
+    <grpc.version>1.27.2</grpc.version>
     <api-client.version>1.30.9</api-client.version>
     <google.core.version>1.93.3</google.core.version>
     <gax.version>1.54.0</gax.version>
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/ClientSideStatementValueConverters.java b/src/main/java/com/google/cloud/spanner/jdbc/ClientSideStatementValueConverters.java
index ddeb394..92368fe 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/ClientSideStatementValueConverters.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/ClientSideStatementValueConverters.java
@@ -213,6 +213,20 @@ class ClientSideStatementValueConverters {
     }
   }
 
+  static class StringValueConverter implements ClientSideStatementValueConverter<String> {
+    public StringValueConverter(String allowedValues) {}
+
+    @Override
+    public Class<String> getParameterClass() {
+      return String.class;
+    }
+
+    @Override
+    public String convert(String value) {
+      return value;
+    }
+  }
+
   /** Converter for converting string values to {@link TransactionMode} values. */
   static class TransactionModeConverter
       implements ClientSideStatementValueConverter<TransactionMode> {
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/Connection.java b/src/main/java/com/google/cloud/spanner/jdbc/Connection.java
index 0ae8ed5..c3b32f8 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/Connection.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/Connection.java
@@ -78,6 +78,11 @@ import java.util.concurrent.TimeUnit;
  *   <li><code>
  *       SET READ_ONLY_STALENESS='STRONG' | 'MIN_READ_TIMESTAMP &lt;timestamp&gt;' | 'READ_TIMESTAMP &lt;timestamp&gt;' | 'MAX_STALENESS &lt;int64&gt;s|ms|mus|ns' | 'EXACT_STALENESS (&lt;int64&gt;s|ms|mus|ns)'
  *       </code>: Sets the value of <code>READ_ONLY_STALENESS</code> for this connection.
+ *   <li><code>SHOW OPTIMIZER_VERSION</code>: Returns the current value of <code>
+ *       OPTIMIZER_VERSION</code> of this connection as a {@link ResultSet}
+ *   <li><code>
+ *       SET OPTIMIZER_VERSION='&lt;version&gt;' | 'LATEST'
+ *       </code>: Sets the value of <code>OPTIMIZER_VERSION</code> for this connection.
  *   <li><code>BEGIN [TRANSACTION]</code>: Begins a new transaction. This statement is optional when
  *       the connection is not in autocommit mode, as a new transaction will automatically be
  *       started when a query or update statement is issued. In autocommit mode, this statement will
@@ -384,6 +389,24 @@ interface Connection extends AutoCloseable {
    */
   TimestampBound getReadOnlyStaleness();
 
+  /**
+   * Sets the query optimizer version to use for this connection.
+   *
+   * @param optimizerVersion The query optimizer version to use. Must be a valid optimizer version
+   *     number, the string <code>LATEST</code> or an empty string. The empty string will instruct
+   *     the connection to use the optimizer version that is defined in the environment variable
+   *     <code>SPANNER_OPTIMIZER_VERSION</code>. If no value is specified in the environment
+   *     variable, the default query optimizer of Cloud Spanner is used.
+   */
+  void setOptimizerVersion(String optimizerVersion);
+
+  /**
+   * Gets the current query optimizer version of this connection.
+   *
+   * @return The query optimizer version that is currently used by this connection.
+   */
+  String getOptimizerVersion();
+
   /**
    * Commits the current transaction of this connection. All mutations that have been buffered
    * during the current transaction will be written to the database.
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/ConnectionImpl.java b/src/main/java/com/google/cloud/spanner/jdbc/ConnectionImpl.java
index 8490dfc..2a83fca 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/ConnectionImpl.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/ConnectionImpl.java
@@ -35,6 +35,7 @@ import com.google.cloud.spanner.jdbc.StatementParser.StatementType;
 import com.google.cloud.spanner.jdbc.UnitOfWork.UnitOfWorkState;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
+import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -192,6 +193,7 @@ class ConnectionImpl implements Connection {
   private final List<TransactionRetryListener> transactionRetryListeners = new ArrayList<>();
   private AutocommitDmlMode autocommitDmlMode = AutocommitDmlMode.TRANSACTIONAL;
   private TimestampBound readOnlyStaleness = TimestampBound.strong();
+  private QueryOptions queryOptions = QueryOptions.getDefaultInstance();
 
   /** Create a connection and register it in the SpannerPool. */
   ConnectionImpl(ConnectionOptions options) {
@@ -204,6 +206,7 @@ class ConnectionImpl implements Connection {
     this.retryAbortsInternally = options.isRetryAbortsInternally();
     this.readOnly = options.isReadOnly();
     this.autocommit = options.isAutocommit();
+    this.queryOptions = this.queryOptions.toBuilder().mergeFrom(options.getQueryOptions()).build();
     this.ddlClient = createDdlClient();
     setDefaultTransactionOptions();
   }
@@ -389,6 +392,19 @@ class ConnectionImpl implements Connection {
     return this.readOnlyStaleness;
   }
 
+  @Override
+  public void setOptimizerVersion(String optimizerVersion) {
+    Preconditions.checkNotNull(optimizerVersion);
+    ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
+    this.queryOptions = queryOptions.toBuilder().setOptimizerVersion(optimizerVersion).build();
+  }
+
+  @Override
+  public String getOptimizerVersion() {
+    ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
+    return this.queryOptions.getOptimizerVersion();
+  }
+
   @Override
   public void setStatementTimeout(long timeout, TimeUnit unit) {
     Preconditions.checkArgument(timeout > 0L, "Zero or negative timeout values are not allowed");
@@ -639,7 +655,7 @@ class ConnectionImpl implements Connection {
   public StatementResult execute(Statement statement) {
     Preconditions.checkNotNull(statement);
     ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
-    ParsedStatement parsedStatement = parser.parse(statement);
+    ParsedStatement parsedStatement = parser.parse(statement, this.queryOptions);
     switch (parsedStatement.getType()) {
       case CLIENT_SIDE:
         return parsedStatement
@@ -680,7 +696,7 @@ class ConnectionImpl implements Connection {
     Preconditions.checkNotNull(query);
     Preconditions.checkNotNull(analyzeMode);
     ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
-    ParsedStatement parsedStatement = parser.parse(query);
+    ParsedStatement parsedStatement = parser.parse(query, this.queryOptions);
     if (parsedStatement.isQuery()) {
       switch (parsedStatement.getType()) {
         case CLIENT_SIDE:
@@ -809,7 +825,8 @@ class ConnectionImpl implements Connection {
    * Returns the current {@link UnitOfWork} of this connection, or creates a new one based on the
    * current transaction settings of the connection and returns that.
    */
-  private UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() {
+  @VisibleForTesting
+  UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() {
     if (this.currentUnitOfWork == null || !this.currentUnitOfWork.isActive()) {
       this.currentUnitOfWork = createNewUnitOfWork();
     }
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/ConnectionOptions.java b/src/main/java/com/google/cloud/spanner/jdbc/ConnectionOptions.java
index f2e4358..4ec727c 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/ConnectionOptions.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/ConnectionOptions.java
@@ -31,6 +31,7 @@ import com.google.cloud.spanner.SpannerOptions;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
+import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -144,6 +145,7 @@ class ConnectionOptions {
   private static final String DEFAULT_OAUTH_TOKEN = null;
   private static final String DEFAULT_NUM_CHANNELS = null;
   private static final String DEFAULT_USER_AGENT = null;
+  private static final String DEFAULT_OPTIMIZER_VERSION = "";
 
   private static final String PLAIN_TEXT_PROTOCOL = "http:";
   private static final String HOST_PROTOCOL = "https:";
@@ -166,6 +168,8 @@ class ConnectionOptions {
   public static final String NUM_CHANNELS_PROPERTY_NAME = "numChannels";
   /** Custom user agent string is only for other Google libraries. */
   private static final String USER_AGENT_PROPERTY_NAME = "userAgent";
+  /** Query optimizer version to use for a connection. */
+  private static final String OPTIMIZER_VERSION_PROPERTY_NAME = "optimizerVersion";
 
   /** All valid connection properties. */
   public static final Set<ConnectionProperty> VALID_PROPERTIES =
@@ -183,7 +187,8 @@ class ConnectionOptions {
                   ConnectionProperty.createStringProperty(NUM_CHANNELS_PROPERTY_NAME, ""),
                   ConnectionProperty.createBooleanProperty(
                       USE_PLAIN_TEXT_PROPERTY_NAME, "", DEFAULT_USE_PLAIN_TEXT),
-                  ConnectionProperty.createStringProperty(USER_AGENT_PROPERTY_NAME, ""))));
+                  ConnectionProperty.createStringProperty(USER_AGENT_PROPERTY_NAME, ""),
+                  ConnectionProperty.createStringProperty(OPTIMIZER_VERSION_PROPERTY_NAME, ""))));
 
   private static final Set<ConnectionProperty> INTERNAL_PROPERTIES =
       Collections.unmodifiableSet(
@@ -281,6 +286,7 @@ class ConnectionOptions {
      *       false.
      *   <li>retryAbortsInternally (boolean): Sets the initial retryAbortsInternally mode for the
      *       connection. Default is true.
+     *   <li>optimizerVersion (string): Sets the query optimizer version to use for the connection.
      * </ul>
      *
      * @param uri The URI of the Spanner database to connect to.
@@ -373,6 +379,7 @@ class ConnectionOptions {
   private final Credentials credentials;
   private final Integer numChannels;
   private final String userAgent;
+  private final QueryOptions queryOptions;
 
   private final boolean autocommit;
   private final boolean readOnly;
@@ -397,6 +404,9 @@ class ConnectionOptions {
 
     this.usePlainText = parseUsePlainText(this.uri);
     this.userAgent = parseUserAgent(this.uri);
+    QueryOptions.Builder queryOptionsBuilder = QueryOptions.newBuilder();
+    queryOptionsBuilder.setOptimizerVersion(parseOptimizerVersion(this.uri));
+    this.queryOptions = queryOptionsBuilder.build();
 
     this.host =
         matcher.group(Builder.HOST_GROUP) == null
@@ -501,6 +511,12 @@ class ConnectionOptions {
     return value != null ? value : DEFAULT_USER_AGENT;
   }
 
+  @VisibleForTesting
+  static String parseOptimizerVersion(String uri) {
+    String value = parseUriProperty(uri, OPTIMIZER_VERSION_PROPERTY_NAME);
+    return value != null ? value : DEFAULT_OPTIMIZER_VERSION;
+  }
+
   @VisibleForTesting
   static String parseUriProperty(String uri, String property) {
     Pattern pattern = Pattern.compile(String.format("(?is)(?:;|\\?)%s=(.*?)(?:;|$)", property));
@@ -633,6 +649,11 @@ class ConnectionOptions {
     return userAgent;
   }
 
+  /** The {@link QueryOptions} to use for the connection. */
+  QueryOptions getQueryOptions() {
+    return queryOptions;
+  }
+
   /** Interceptors that should be executed after each statement */
   List<StatementExecutionInterceptor> getStatementExecutionInterceptors() {
     return statementExecutionInterceptors;
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutor.java b/src/main/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutor.java
index 4e79f25..4de1f3f 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutor.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutor.java
@@ -60,6 +60,10 @@ interface ConnectionStatementExecutor {
 
   StatementResult statementShowReadOnlyStaleness();
 
+  StatementResult statementSetOptimizerVersion(String optimizerVersion);
+
+  StatementResult statementShowOptimizerVersion();
+
   StatementResult statementBeginTransaction();
 
   StatementResult statementCommit();
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutorImpl.java b/src/main/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutorImpl.java
index 7f7a5cf..c8aa40d 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutorImpl.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutorImpl.java
@@ -23,6 +23,7 @@ import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementT
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.RUN_BATCH;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SET_AUTOCOMMIT;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SET_AUTOCOMMIT_DML_MODE;
+import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SET_OPTIMIZER_VERSION;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SET_READONLY;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SET_READ_ONLY_STALENESS;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SET_RETRY_ABORTS_INTERNALLY;
@@ -31,6 +32,7 @@ import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementT
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SHOW_AUTOCOMMIT;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SHOW_AUTOCOMMIT_DML_MODE;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SHOW_COMMIT_TIMESTAMP;
+import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SHOW_OPTIMIZER_VERSION;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SHOW_READONLY;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SHOW_READ_ONLY_STALENESS;
 import static com.google.cloud.spanner.jdbc.StatementResult.ClientSideStatementType.SHOW_READ_TIMESTAMP;
@@ -183,6 +185,18 @@ class ConnectionStatementExecutorImpl implements ConnectionStatementExecutor {
         SHOW_READ_ONLY_STALENESS);
   }
 
+  @Override
+  public StatementResult statementSetOptimizerVersion(String optimizerVersion) {
+    getConnection().setOptimizerVersion(optimizerVersion);
+    return noResult(SET_OPTIMIZER_VERSION);
+  }
+
+  @Override
+  public StatementResult statementShowOptimizerVersion() {
+    return resultSet(
+        "OPTIMIZER_VERSION", getConnection().getOptimizerVersion(), SHOW_OPTIMIZER_VERSION);
+  }
+
   @Override
   public StatementResult statementBeginTransaction() {
     getConnection().beginTransaction();
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java b/src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java
index c43f979..229c0a6 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java
@@ -86,6 +86,7 @@ import java.util.regex.Pattern;
  *       connection. Default is true. @see {@link
  *       com.google.cloud.spanner.jdbc.CloudSpannerJdbcConnection#setRetryAbortsInternally(boolean)}
  *       for more information.
+ *   <li>optimizerVersion (string): The query optimizer version to use for the connection. The value must be either a valid version number or <code>LATEST</code>. If no value is specified, the query optimizer version specified in the environment variable <code>SPANNER_OPTIMIZER_VERSION<code> will be used. If no query optimizer version is specified in the connection URL or in the environment variable, the default query optimizer version of Cloud Spanner will be used.
  * </ul>
  */
 public class JdbcDriver implements Driver {
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/StatementParser.java b/src/main/java/com/google/cloud/spanner/jdbc/StatementParser.java
index e43a097..e3e998a 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/StatementParser.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/StatementParser.java
@@ -20,10 +20,13 @@ import com.google.cloud.spanner.ErrorCode;
 import com.google.cloud.spanner.SpannerExceptionFactory;
 import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.jdbc.ClientSideStatementImpl.CompileException;
+import com.google.cloud.spanner.jdbc.StatementParser.ParsedStatement;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
+import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
 import java.util.Collections;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -66,8 +69,10 @@ class StatementParser {
       return new ParsedStatement(StatementType.DDL, statement, sqlWithoutComments);
     }
 
-    private static ParsedStatement query(Statement statement, String sqlWithoutComments) {
-      return new ParsedStatement(StatementType.QUERY, statement, sqlWithoutComments);
+    private static ParsedStatement query(
+        Statement statement, String sqlWithoutComments, QueryOptions defaultQueryOptions) {
+      return new ParsedStatement(
+          StatementType.QUERY, statement, sqlWithoutComments, defaultQueryOptions);
     }
 
     private static ParsedStatement update(Statement statement, String sqlWithoutComments) {
@@ -91,14 +96,40 @@ class StatementParser {
     }
 
     private ParsedStatement(StatementType type, Statement statement, String sqlWithoutComments) {
+      this(type, statement, sqlWithoutComments, null);
+    }
+
+    private ParsedStatement(
+        StatementType type,
+        Statement statement,
+        String sqlWithoutComments,
+        QueryOptions defaultQueryOptions) {
       Preconditions.checkNotNull(type);
       Preconditions.checkNotNull(statement);
       this.type = type;
       this.clientSideStatement = null;
-      this.statement = statement;
+      this.statement = mergeQueryOptions(statement, defaultQueryOptions);
       this.sqlWithoutComments = sqlWithoutComments;
     }
 
+    @Override
+    public int hashCode() {
+      return Objects.hash(
+          this.type, this.clientSideStatement, this.statement, this.sqlWithoutComments);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+      if (!(other instanceof ParsedStatement)) {
+        return false;
+      }
+      ParsedStatement o = (ParsedStatement) other;
+      return Objects.equals(this.type, o.type)
+          && Objects.equals(this.clientSideStatement, o.clientSideStatement)
+          && Objects.equals(this.statement, o.statement)
+          && Objects.equals(this.sqlWithoutComments, o.sqlWithoutComments);
+    }
+
     StatementType getType() {
       return type;
     }
@@ -148,6 +179,26 @@ class StatementParser {
       return statement;
     }
 
+    /**
+     * Merges the {@link QueryOptions} of the {@link Statement} with the current {@link
+     * QueryOptions} of this connection. The {@link QueryOptions} that are already present on the
+     * statement take precedence above the connection {@link QueryOptions}.
+     */
+    Statement mergeQueryOptions(Statement statement, QueryOptions defaultQueryOptions) {
+      if (defaultQueryOptions == null
+          || defaultQueryOptions.equals(QueryOptions.getDefaultInstance())) {
+        return statement;
+      }
+      if (statement.getQueryOptions() == null) {
+        return statement.toBuilder().withQueryOptions(defaultQueryOptions).build();
+      }
+      return statement
+          .toBuilder()
+          .withQueryOptions(
+              defaultQueryOptions.toBuilder().mergeFrom(statement.getQueryOptions()).build())
+          .build();
+    }
+
     String getSqlWithoutComments() {
       return sqlWithoutComments;
     }
@@ -183,12 +234,16 @@ class StatementParser {
    * @return the parsed and categorized statement.
    */
   ParsedStatement parse(Statement statement) {
+    return parse(statement, null);
+  }
+
+  ParsedStatement parse(Statement statement, QueryOptions defaultQueryOptions) {
     String sql = removeCommentsAndTrim(statement.getSql());
     ClientSideStatementImpl client = parseClientSideStatement(sql);
     if (client != null) {
       return ParsedStatement.clientSideStatement(client, statement, sql);
     } else if (isQuery(sql)) {
-      return ParsedStatement.query(statement, sql);
+      return ParsedStatement.query(statement, sql, defaultQueryOptions);
     } else if (isUpdateStatement(sql)) {
       return ParsedStatement.update(statement, sql);
     } else if (isDdlStatement(sql)) {
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/StatementResult.java b/src/main/java/com/google/cloud/spanner/jdbc/StatementResult.java
index 78cde9a..9820716 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/StatementResult.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/StatementResult.java
@@ -60,6 +60,8 @@ interface StatementResult {
     SHOW_COMMIT_TIMESTAMP,
     SHOW_READ_ONLY_STALENESS,
     SET_READ_ONLY_STALENESS,
+    SHOW_OPTIMIZER_VERSION,
+    SET_OPTIMIZER_VERSION,
     BEGIN,
     COMMIT,
     ROLLBACK,
diff --git a/src/main/resources/com/google/cloud/spanner/jdbc/ClientSideStatements.json b/src/main/resources/com/google/cloud/spanner/jdbc/ClientSideStatements.json
index 28c20a5..8d8cca2 100644
--- a/src/main/resources/com/google/cloud/spanner/jdbc/ClientSideStatements.json
+++ b/src/main/resources/com/google/cloud/spanner/jdbc/ClientSideStatements.json
@@ -68,6 +68,14 @@
 	  "method": "statementShowReadOnlyStaleness",
 	  "exampleStatements": ["show variable read_only_staleness"]
 	},
+	{
+	  "name": "SHOW VARIABLE OPTIMIZER_VERSION",
+	  "executorName": "ClientSideStatementNoParamExecutor",
+	  "resultType": "RESULT_SET",
+	  "regex": "(?is)\\A\\s*show\\s+variable\\s+optimizer_version\\s*\\z",
+	  "method": "statementShowOptimizerVersion",
+	  "exampleStatements": ["show variable optimizer_version"]
+	},
 	{
 	  "name": "BEGIN TRANSACTION",
 	  "executorName": "ClientSideStatementNoParamExecutor",
@@ -241,6 +249,20 @@
 	    "allowedValues": "'((STRONG)|(MIN_READ_TIMESTAMP)[\\t ]+((\\d{4})-(\\d{2})-(\\d{2})([Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.\\d{1,9})?)([Zz]|([+-])(\\d{2}):(\\d{2})))|(READ_TIMESTAMP)[\\t ]+((\\d{4})-(\\d{2})-(\\d{2})([Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.\\d{1,9})?)([Zz]|([+-])(\\d{2}):(\\d{2})))|(MAX_STALENESS)[\\t ]+((\\d{1,19})(s|ms|us|ns))|(EXACT_STALENESS)[\\t ]+((\\d{1,19})(s|ms|us|ns)))'",
 	    "converterName": "ClientSideStatementValueConverters$ReadOnlyStalenessConverter"
 	  }
+	},
+	{
+	  "name": "SET OPTIMIZER_VERSION = '<version>'|'LATEST'|''",
+	  "executorName": "ClientSideStatementSetExecutor",
+	  "resultType": "NO_RESULT",
+	  "regex": "(?is)\\A\\s*set\\s+optimizer_version\\s*(?:=)\\s*(.*)\\z",
+	  "method": "statementSetOptimizerVersion",
+	  "exampleStatements": ["set optimizer_version='1'", "set optimizer_version='200'", "set optimizer_version='LATEST'", "set optimizer_version=''"],
+	  "setStatement": {
+	    "propertyName": "OPTIMIZER_VERSION",
+	    "separator": "=",
+	    "allowedValues": "'((\\d{1,20})|(LATEST)|())'",
+	    "converterName": "ClientSideStatementValueConverters$StringValueConverter"
+	  }
 	}
 	]
 }
\ No newline at end of file
diff --git a/synth.py b/synth.py
index 259352e..a5ea146 100644
--- a/synth.py
+++ b/synth.py
@@ -14,12 +14,8 @@
 
 """This script is used to synthesize generated parts of this library."""
 
-import synthtool as s
-import synthtool.gcp as gcp
+import synthtool.languages.java as java
 
-
-common_templates = gcp.CommonTemplates()
-templates = common_templates.java_library()
-s.copy(templates, excludes=[
+java.common_templates(excludes=[
     'README.md'
-])
\ No newline at end of file
+])
diff --git a/versions.txt b/versions.txt
index 72f0ebd..ce565c7 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,4 +1,4 @@
 # Format:
 # module:released-version:current-version
 
-google-cloud-spanner-jdbc:1.13.0:1.13.1-SNAPSHOT
+google-cloud-spanner-jdbc:1.14.0:1.14.1-SNAPSHOT


Test patch:
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/AbortedTest.java b/src/test/java/com/google/cloud/spanner/jdbc/AbortedTest.java
index 4346bde..d10508b 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/AbortedTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/AbortedTest.java
@@ -20,128 +20,18 @@ import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import com.google.cloud.spanner.MockSpannerServiceImpl;
 import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
 import com.google.cloud.spanner.ResultSet;
 import com.google.cloud.spanner.Statement;
-import com.google.cloud.spanner.admin.database.v1.MockDatabaseAdminImpl;
-import com.google.cloud.spanner.admin.instance.v1.MockInstanceAdminImpl;
 import com.google.cloud.spanner.jdbc.ITAbstractSpannerTest.AbortInterceptor;
 import com.google.cloud.spanner.jdbc.ITAbstractSpannerTest.ITConnection;
 import com.google.cloud.spanner.jdbc.it.ITTransactionRetryTest.CountTransactionRetryListener;
-import com.google.protobuf.ListValue;
-import com.google.protobuf.Value;
-import com.google.spanner.v1.ResultSetMetadata;
-import com.google.spanner.v1.StructType;
-import com.google.spanner.v1.StructType.Field;
-import com.google.spanner.v1.Type;
-import com.google.spanner.v1.TypeCode;
-import io.grpc.Server;
-import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.Arrays;
-import java.util.List;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
-public class AbortedTest {
-  private static final Statement SELECT_COUNT =
-      Statement.of("SELECT COUNT(*) AS C FROM TEST WHERE ID=1");
-  private static final ResultSetMetadata SELECT_COUNT_METADATA =
-      ResultSetMetadata.newBuilder()
-          .setRowType(
-              StructType.newBuilder()
-                  .addFields(
-                      Field.newBuilder()
-                          .setName("C")
-                          .setType(Type.newBuilder().setCode(TypeCode.INT64).build())
-                          .build())
-                  .build())
-          .build();
-  private static final com.google.spanner.v1.ResultSet SELECT_COUNT_RESULTSET_BEFORE_INSERT =
-      com.google.spanner.v1.ResultSet.newBuilder()
-          .addRows(
-              ListValue.newBuilder()
-                  .addValues(Value.newBuilder().setStringValue("0").build())
-                  .build())
-          .setMetadata(SELECT_COUNT_METADATA)
-          .build();
-  private static final com.google.spanner.v1.ResultSet SELECT_COUNT_RESULTSET_AFTER_INSERT =
-      com.google.spanner.v1.ResultSet.newBuilder()
-          .addRows(
-              ListValue.newBuilder()
-                  .addValues(Value.newBuilder().setStringValue("1").build())
-                  .build())
-          .setMetadata(SELECT_COUNT_METADATA)
-          .build();
-  private static final Statement INSERT_STATEMENT =
-      Statement.of("INSERT INTO TEST (ID, NAME) VALUES (1, 'test aborted')");
-  private static final int UPDATE_COUNT = 1;
-
-  private static MockSpannerServiceImpl mockSpanner;
-  private static MockInstanceAdminImpl mockInstanceAdmin;
-  private static MockDatabaseAdminImpl mockDatabaseAdmin;
-  private static Server server;
-  private static InetSocketAddress address;
-
-  @BeforeClass
-  public static void startStaticServer() throws IOException {
-    mockSpanner = new MockSpannerServiceImpl();
-    mockSpanner.setAbortProbability(0.0D); // We don't want any unpredictable aborted transactions.
-    mockInstanceAdmin = new MockInstanceAdminImpl();
-    mockDatabaseAdmin = new MockDatabaseAdminImpl();
-    address = new InetSocketAddress("localhost", 0);
-    server =
-        NettyServerBuilder.forAddress(address)
-            .addService(mockSpanner)
-            .addService(mockInstanceAdmin)
-            .addService(mockDatabaseAdmin)
-            .build()
-            .start();
-  }
-
-  @AfterClass
-  public static void stopServer() throws Exception {
-    SpannerPool.closeSpannerPool();
-    server.shutdown();
-    server.awaitTermination();
-  }
-
-  public ITConnection createConnection(
-      AbortInterceptor interceptor, TransactionRetryListener transactionRetryListener) {
-    return createConnection(
-        Arrays.<StatementExecutionInterceptor>asList(interceptor),
-        Arrays.<TransactionRetryListener>asList(transactionRetryListener));
-  }
-
-  public ITConnection createConnection(
-      List<StatementExecutionInterceptor> interceptors,
-      List<TransactionRetryListener> transactionRetryListeners) {
-    StringBuilder url =
-        new StringBuilder(
-            String.format(
-                "cloudspanner://localhost:%d/projects/proj/instances/inst/databases/db?usePlainText=true;autocommit=false;retryAbortsInternally=true",
-                server.getPort()));
-    ConnectionOptions.Builder builder =
-        ConnectionOptions.newBuilder()
-            .setUri(url.toString())
-            .setStatementExecutionInterceptors(interceptors);
-    ConnectionOptions options = builder.build();
-    ITConnection connection = createITConnection(options);
-    for (TransactionRetryListener listener : transactionRetryListeners) {
-      connection.addTransactionRetryListener(listener);
-    }
-    return connection;
-  }
-
-  private ITConnection createITConnection(ConnectionOptions options) {
-    return new ITConnectionImpl(options);
-  }
+public class AbortedTest extends AbstractMockServerTest {
 
   @Test
   public void testCommitAborted() {
@@ -149,7 +39,7 @@ public class AbortedTest {
     // transaction is the most recent transaction of that session.
     for (int i = 0; i < 2; i++) {
       mockSpanner.putStatementResult(
-          StatementResult.query(SELECT_COUNT, SELECT_COUNT_RESULTSET_BEFORE_INSERT));
+          StatementResult.query(SELECT_COUNT_STATEMENT, SELECT_COUNT_RESULTSET_BEFORE_INSERT));
       mockSpanner.putStatementResult(StatementResult.update(INSERT_STATEMENT, UPDATE_COUNT));
       AbortInterceptor interceptor = new AbortInterceptor(0);
       try (ITConnection connection =
@@ -170,7 +60,7 @@ public class AbortedTest {
         // do a commit that will first abort, and then on retry will succeed
         connection.commit();
         mockSpanner.putStatementResult(
-            StatementResult.query(SELECT_COUNT, SELECT_COUNT_RESULTSET_AFTER_INSERT));
+            StatementResult.query(SELECT_COUNT_STATEMENT, SELECT_COUNT_RESULTSET_AFTER_INSERT));
         // verify that the insert succeeded
         try (ResultSet rs =
             connection.executeQuery(Statement.of("SELECT COUNT(*) AS C FROM TEST WHERE ID=1"))) {
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/AbstractConnectionImplTest.java b/src/test/java/com/google/cloud/spanner/jdbc/AbstractConnectionImplTest.java
index 8b4bdf7..f12f5e8 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/AbstractConnectionImplTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/AbstractConnectionImplTest.java
@@ -608,6 +608,51 @@ public abstract class AbstractConnectionImplTest {
     }
   }
 
+  boolean isSetOptimizerVersionAllowed() {
+    return !getConnection().isClosed();
+  }
+
+  @Test
+  public void testSetOptimizerVersion() {
+    try (Connection connection = getConnection()) {
+      if (isSetOptimizerVersionAllowed()) {
+        for (String version : new String[] {"1", "2", "latest", ""}) {
+          log("SET OPTIMIZER_VERSION='" + version + "';");
+          connection.setOptimizerVersion(version);
+
+          log("@EXPECT RESULT_SET 'OPTIMIZER_VERSION','" + version + "'");
+          log("SHOW VARIABLE OPTIMIZER_VERSION;");
+          assertThat(connection.getOptimizerVersion(), is(equalTo(version)));
+        }
+      } else {
+        log("@EXPECT EXCEPTION FAILED_PRECONDITION");
+        log("SET OPTIMIZER_VERSION='1';");
+        exception.expect(matchCode(ErrorCode.FAILED_PRECONDITION));
+        connection.setOptimizerVersion("1");
+      }
+    }
+  }
+
+  boolean isGetOptimizerVersionAllowed() {
+    return !getConnection().isClosed();
+  }
+
+  @Test
+  public void testGetOptimizerVersion() {
+    try (Connection connection = getConnection()) {
+      if (isGetOptimizerVersionAllowed()) {
+        log("@EXPECT RESULT_SET 'OPTIMIZER_VERSION'");
+        log("SHOW VARIABLE OPTIMIZER_VERSION;");
+        assertThat(connection.getOptimizerVersion(), is(notNullValue()));
+      } else {
+        log("@EXPECT EXCEPTION FAILED_PRECONDITION");
+        log("SHOW VARIABLE OPTIMIZER_VERSION;");
+        exception.expect(matchCode(ErrorCode.FAILED_PRECONDITION));
+        connection.getOptimizerVersion();
+      }
+    }
+  }
+
   abstract boolean isCommitAllowed();
 
   @Test
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/AbstractMockServerTest.java b/src/test/java/com/google/cloud/spanner/jdbc/AbstractMockServerTest.java
new file mode 100644
index 0000000..4117eed
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/jdbc/AbstractMockServerTest.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2020 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.jdbc;
+
+import com.google.cloud.spanner.MockSpannerServiceImpl;
+import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
+import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.admin.database.v1.MockDatabaseAdminImpl;
+import com.google.cloud.spanner.admin.instance.v1.MockInstanceAdminImpl;
+import com.google.cloud.spanner.jdbc.ITAbstractSpannerTest.AbortInterceptor;
+import com.google.cloud.spanner.jdbc.ITAbstractSpannerTest.ITConnection;
+import com.google.protobuf.AbstractMessage;
+import com.google.protobuf.ListValue;
+import com.google.protobuf.Value;
+import com.google.spanner.v1.ExecuteSqlRequest;
+import com.google.spanner.v1.ResultSetMetadata;
+import com.google.spanner.v1.StructType;
+import com.google.spanner.v1.StructType.Field;
+import com.google.spanner.v1.Type;
+import com.google.spanner.v1.TypeCode;
+import io.grpc.Server;
+import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public abstract class AbstractMockServerTest {
+  static final long COUNT_BEFORE_INSERT = 0L;
+  static final long COUNT_AFTER_INSERT = 1L;
+  static final Statement SELECT_COUNT_STATEMENT =
+      Statement.of("SELECT COUNT(*) AS C FROM TEST WHERE ID=1");
+  private static final ResultSetMetadata SELECT_COUNT_METADATA =
+      ResultSetMetadata.newBuilder()
+          .setRowType(
+              StructType.newBuilder()
+                  .addFields(
+                      Field.newBuilder()
+                          .setName("C")
+                          .setType(Type.newBuilder().setCode(TypeCode.INT64).build())
+                          .build())
+                  .build())
+          .build();
+  static final com.google.spanner.v1.ResultSet SELECT_COUNT_RESULTSET_BEFORE_INSERT =
+      com.google.spanner.v1.ResultSet.newBuilder()
+          .addRows(
+              ListValue.newBuilder()
+                  .addValues(
+                      Value.newBuilder()
+                          .setStringValue(String.valueOf(COUNT_BEFORE_INSERT))
+                          .build())
+                  .build())
+          .setMetadata(SELECT_COUNT_METADATA)
+          .build();
+  static final com.google.spanner.v1.ResultSet SELECT_COUNT_RESULTSET_AFTER_INSERT =
+      com.google.spanner.v1.ResultSet.newBuilder()
+          .addRows(
+              ListValue.newBuilder()
+                  .addValues(
+                      Value.newBuilder().setStringValue(String.valueOf(COUNT_AFTER_INSERT)).build())
+                  .build())
+          .setMetadata(SELECT_COUNT_METADATA)
+          .build();
+  static final Statement INSERT_STATEMENT =
+      Statement.of("INSERT INTO TEST (ID, NAME) VALUES (1, 'test aborted')");
+  static final int UPDATE_COUNT = 1;
+
+  static MockSpannerServiceImpl mockSpanner;
+  static MockInstanceAdminImpl mockInstanceAdmin;
+  static MockDatabaseAdminImpl mockDatabaseAdmin;
+  private static Server server;
+  private static InetSocketAddress address;
+
+  @BeforeClass
+  public static void startStaticServer() throws IOException {
+    mockSpanner = new MockSpannerServiceImpl();
+    mockSpanner.setAbortProbability(0.0D); // We don't want any unpredictable aborted transactions.
+    mockInstanceAdmin = new MockInstanceAdminImpl();
+    mockDatabaseAdmin = new MockDatabaseAdminImpl();
+    address = new InetSocketAddress("localhost", 0);
+    server =
+        NettyServerBuilder.forAddress(address)
+            .addService(mockSpanner)
+            .addService(mockInstanceAdmin)
+            .addService(mockDatabaseAdmin)
+            .build()
+            .start();
+    mockSpanner.putStatementResult(
+        StatementResult.query(SELECT_COUNT_STATEMENT, SELECT_COUNT_RESULTSET_BEFORE_INSERT));
+    mockSpanner.putStatementResult(StatementResult.update(INSERT_STATEMENT, UPDATE_COUNT));
+  }
+
+  @AfterClass
+  public static void stopServer() throws Exception {
+    SpannerPool.closeSpannerPool();
+    server.shutdown();
+    server.awaitTermination();
+  }
+
+  @Before
+  public void setupResults() {
+    mockSpanner.reset();
+  }
+
+  @After
+  public void closeSpannerPool() {
+    SpannerPool.closeSpannerPool();
+  }
+
+  java.sql.Connection createJdbcConnection() throws SQLException {
+    return DriverManager.getConnection("jdbc:" + getBaseUrl());
+  }
+
+  ITConnection createConnection() {
+    return createConnection(
+        Collections.<StatementExecutionInterceptor>emptyList(),
+        Collections.<TransactionRetryListener>emptyList());
+  }
+
+  ITConnection createConnection(
+      AbortInterceptor interceptor, TransactionRetryListener transactionRetryListener) {
+    return createConnection(
+        Arrays.<StatementExecutionInterceptor>asList(interceptor),
+        Arrays.<TransactionRetryListener>asList(transactionRetryListener));
+  }
+
+  ITConnection createConnection(
+      List<StatementExecutionInterceptor> interceptors,
+      List<TransactionRetryListener> transactionRetryListeners) {
+    StringBuilder url = new StringBuilder(getBaseUrl());
+    ConnectionOptions.Builder builder =
+        ConnectionOptions.newBuilder()
+            .setUri(url.toString())
+            .setStatementExecutionInterceptors(interceptors);
+    ConnectionOptions options = builder.build();
+    ITConnection connection = createITConnection(options);
+    for (TransactionRetryListener listener : transactionRetryListeners) {
+      connection.addTransactionRetryListener(listener);
+    }
+    return connection;
+  }
+
+  String getBaseUrl() {
+    return String.format(
+        "cloudspanner://localhost:%d/projects/proj/instances/inst/databases/db?usePlainText=true;autocommit=false;retryAbortsInternally=true",
+        server.getPort());
+  }
+
+  ExecuteSqlRequest getLastExecuteSqlRequest() {
+    List<AbstractMessage> requests = mockSpanner.getRequests();
+    for (int i = requests.size() - 1; i >= 0; i--) {
+      if (requests.get(i) instanceof ExecuteSqlRequest) {
+        return (ExecuteSqlRequest) requests.get(i);
+      }
+    }
+    throw new IllegalStateException("No ExecuteSqlRequest found in requests");
+  }
+
+  private ITConnection createITConnection(ConnectionOptions options) {
+    return new ITConnectionImpl(options);
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionImplTest.java b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionImplTest.java
index 38c9787..2c2cb96 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionImplTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionImplTest.java
@@ -24,10 +24,12 @@ import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyListOf;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import com.google.api.core.ApiFuture;
@@ -38,6 +40,8 @@ import com.google.cloud.Timestamp;
 import com.google.cloud.spanner.DatabaseClient;
 import com.google.cloud.spanner.ErrorCode;
 import com.google.cloud.spanner.ForwardingResultSet;
+import com.google.cloud.spanner.Options;
+import com.google.cloud.spanner.Options.QueryOption;
 import com.google.cloud.spanner.ReadContext.QueryAnalyzeMode;
 import com.google.cloud.spanner.ReadOnlyTransaction;
 import com.google.cloud.spanner.ResultSet;
@@ -57,6 +61,7 @@ import com.google.cloud.spanner.jdbc.ConnectionStatementExecutorImpl.StatementTi
 import com.google.cloud.spanner.jdbc.ReadOnlyStalenessUtil.GetExactStaleness;
 import com.google.cloud.spanner.jdbc.StatementResult.ResultType;
 import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
 import com.google.spanner.v1.ResultSetStats;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -523,6 +528,76 @@ public class ConnectionImplTest {
     }
   }
 
+  @Test
+  public void testExecuteSetOptimizerVersion() {
+    try (ConnectionImpl subject =
+        createConnection(
+            ConnectionOptions.newBuilder()
+                .setCredentials(NoCredentials.getInstance())
+                .setUri(URI)
+                .build())) {
+      assertThat(subject.getOptimizerVersion(), is(equalTo("")));
+
+      StatementResult res = subject.execute(Statement.of("set optimizer_version='1'"));
+      assertThat(res.getResultType(), is(equalTo(ResultType.NO_RESULT)));
+      assertThat(subject.getOptimizerVersion(), is(equalTo("1")));
+
+      res = subject.execute(Statement.of("set optimizer_version='1000'"));
+      assertThat(res.getResultType(), is(equalTo(ResultType.NO_RESULT)));
+      assertThat(subject.getOptimizerVersion(), is(equalTo("1000")));
+
+      res = subject.execute(Statement.of("set optimizer_version='latest'"));
+      assertThat(res.getResultType(), is(equalTo(ResultType.NO_RESULT)));
+      assertThat(subject.getOptimizerVersion(), is(equalTo("latest")));
+
+      res = subject.execute(Statement.of("set optimizer_version=''"));
+      assertThat(res.getResultType(), is(equalTo(ResultType.NO_RESULT)));
+      assertThat(subject.getOptimizerVersion(), is(equalTo("")));
+    }
+  }
+
+  @Test
+  public void testExecuteSetOptimizerVersionInvalidValue() {
+    try (ConnectionImpl subject =
+        createConnection(
+            ConnectionOptions.newBuilder()
+                .setCredentials(NoCredentials.getInstance())
+                .setUri(URI)
+                .build())) {
+      assertThat(subject.getOptimizerVersion(), is(equalTo("")));
+
+      try {
+        subject.execute(Statement.of("set optimizer_version='NOT_A_VERSION'"));
+        fail("Missing expected exception");
+      } catch (SpannerException e) {
+        assertThat(e.getErrorCode(), is(equalTo(ErrorCode.INVALID_ARGUMENT)));
+      }
+    }
+  }
+
+  @Test
+  public void testExecuteGetOptimizerVersion() {
+    try (ConnectionImpl subject =
+        createConnection(
+            ConnectionOptions.newBuilder()
+                .setCredentials(NoCredentials.getInstance())
+                .setUri(URI)
+                .build())) {
+      assertThat(subject.getOptimizerVersion(), is(equalTo("")));
+
+      StatementResult res = subject.execute(Statement.of("show variable optimizer_version"));
+      assertThat(res.getResultType(), is(equalTo(ResultType.RESULT_SET)));
+      assertThat(res.getResultSet().next(), is(true));
+      assertThat(res.getResultSet().getString("OPTIMIZER_VERSION"), is(equalTo("")));
+
+      subject.execute(Statement.of("set optimizer_version='1'"));
+      res = subject.execute(Statement.of("show variable optimizer_version"));
+      assertThat(res.getResultType(), is(equalTo(ResultType.RESULT_SET)));
+      assertThat(res.getResultSet().next(), is(true));
+      assertThat(res.getResultSet().getString("OPTIMIZER_VERSION"), is(equalTo("1")));
+    }
+  }
+
   @Test
   public void testExecuteSetStatementTimeout() {
     try (ConnectionImpl subject =
@@ -1114,4 +1189,73 @@ public class ConnectionImplTest {
       assertThat(subject.removeTransactionRetryListener(listener), is(false));
     }
   }
+
+  @Test
+  public void testMergeQueryOptions() {
+    ConnectionOptions connectionOptions = mock(ConnectionOptions.class);
+    SpannerPool spannerPool = mock(SpannerPool.class);
+    DdlClient ddlClient = mock(DdlClient.class);
+    DatabaseClient dbClient = mock(DatabaseClient.class);
+    final UnitOfWork unitOfWork = mock(UnitOfWork.class);
+    try (ConnectionImpl impl =
+        new ConnectionImpl(connectionOptions, spannerPool, ddlClient, dbClient) {
+          @Override
+          UnitOfWork getCurrentUnitOfWorkOrStartNewUnitOfWork() {
+            return unitOfWork;
+          }
+        }) {
+      // Execute query with an optimizer version set on the connection.
+      impl.setOptimizerVersion("1");
+      impl.executeQuery(Statement.of("SELECT FOO FROM BAR"));
+      verify(unitOfWork)
+          .executeQuery(
+              StatementParser.INSTANCE.parse(
+                  Statement.newBuilder("SELECT FOO FROM BAR")
+                      .withQueryOptions(QueryOptions.newBuilder().setOptimizerVersion("1").build())
+                      .build()),
+              AnalyzeMode.NONE);
+
+      // Execute query with an optimizer version set on the connection.
+      impl.setOptimizerVersion("2");
+      impl.executeQuery(Statement.of("SELECT FOO FROM BAR"));
+      verify(unitOfWork)
+          .executeQuery(
+              StatementParser.INSTANCE.parse(
+                  Statement.newBuilder("SELECT FOO FROM BAR")
+                      .withQueryOptions(QueryOptions.newBuilder().setOptimizerVersion("2").build())
+                      .build()),
+              AnalyzeMode.NONE);
+
+      // Execute query with an optimizer version set on the connection and PrefetchChunks query
+      // option specified for the query.
+      QueryOption prefetchOption = Options.prefetchChunks(100);
+      impl.setOptimizerVersion("3");
+      impl.executeQuery(Statement.of("SELECT FOO FROM BAR"), prefetchOption);
+      verify(unitOfWork)
+          .executeQuery(
+              StatementParser.INSTANCE.parse(
+                  Statement.newBuilder("SELECT FOO FROM BAR")
+                      .withQueryOptions(QueryOptions.newBuilder().setOptimizerVersion("3").build())
+                      .build()),
+              AnalyzeMode.NONE,
+              prefetchOption);
+
+      // Execute query with an optimizer version set on the connection, and the same options also
+      // passed in to the query. The specific options passed in to the query should take precedence.
+      impl.setOptimizerVersion("4");
+      impl.executeQuery(
+          Statement.newBuilder("SELECT FOO FROM BAR")
+              .withQueryOptions(QueryOptions.newBuilder().setOptimizerVersion("5").build())
+              .build(),
+          prefetchOption);
+      verify(unitOfWork)
+          .executeQuery(
+              StatementParser.INSTANCE.parse(
+                  Statement.newBuilder("SELECT FOO FROM BAR")
+                      .withQueryOptions(QueryOptions.newBuilder().setOptimizerVersion("5").build())
+                      .build()),
+              AnalyzeMode.NONE,
+              prefetchOption);
+    }
+  }
 }
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutorTest.java b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutorTest.java
index debd02b..6e524c4 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutorTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementExecutorTest.java
@@ -95,6 +95,12 @@ public class ConnectionStatementExecutorTest {
     verify(connection).getReadOnlyStaleness();
   }
 
+  @Test
+  public void testStatementGetOptimizerVersion() {
+    subject.statementShowOptimizerVersion();
+    verify(connection).getOptimizerVersion();
+  }
+
   @Test
   public void testStatementGetReadTimestamp() {
     subject.statementShowReadTimestamp();
@@ -167,6 +173,16 @@ public class ConnectionStatementExecutorTest {
         .setReadOnlyStaleness(TimestampBound.ofMaxStaleness(20L, TimeUnit.MILLISECONDS));
   }
 
+  @Test
+  public void testStatementSetOptimizerVersion() {
+    subject.statementSetOptimizerVersion("1");
+    verify(connection).setOptimizerVersion("1");
+    subject.statementSetOptimizerVersion("");
+    verify(connection).setOptimizerVersion("");
+    subject.statementSetOptimizerVersion("LATEST");
+    verify(connection).setOptimizerVersion("LATEST");
+  }
+
   @Test
   public void testStatementSetStatementTimeout() {
     subject.statementSetStatementTimeout(Duration.newBuilder().setNanos(100).build());
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementWithNoParametersTest.java b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementWithNoParametersTest.java
index e106bcd..51aa8ab 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementWithNoParametersTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementWithNoParametersTest.java
@@ -114,6 +114,18 @@ public class ConnectionStatementWithNoParametersTest {
     verify(connection, times(1)).getReadOnlyStaleness();
   }
 
+  @Test
+  public void testExecuteGetOptimizerVersion() throws Exception {
+    ParsedStatement statement = parser.parse(Statement.of("show variable optimizer_version"));
+    ConnectionImpl connection = mock(ConnectionImpl.class);
+    ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class);
+    when(executor.getConnection()).thenReturn(connection);
+    when(executor.statementShowOptimizerVersion()).thenCallRealMethod();
+    when(connection.getOptimizerVersion()).thenReturn("1");
+    statement.getClientSideStatement().execute(executor, "show variable optimizer_version");
+    verify(connection, times(1)).getOptimizerVersion();
+  }
+
   @Test
   public void testExecuteBegin() throws Exception {
     ParsedStatement subject = parser.parse(Statement.of("begin"));
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementWithOneParameterTest.java b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementWithOneParameterTest.java
index de5354f..b9ebf1e 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementWithOneParameterTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionStatementWithOneParameterTest.java
@@ -148,6 +148,21 @@ public class ConnectionStatementWithOneParameterTest {
     }
   }
 
+  @Test
+  public void testExecuteSetOptimizerVersion() throws Exception {
+    ParsedStatement subject = parser.parse(Statement.of("set optimizer_version='foo'"));
+    ConnectionImpl connection = mock(ConnectionImpl.class);
+    ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class);
+    when(executor.getConnection()).thenReturn(connection);
+    when(executor.statementSetOptimizerVersion(any(String.class))).thenCallRealMethod();
+    for (String version : new String[] {"1", "200", "", "LATEST"}) {
+      subject
+          .getClientSideStatement()
+          .execute(executor, String.format("set optimizer_version='%s'", version));
+      verify(connection, times(1)).setOptimizerVersion(version);
+    }
+  }
+
   @Test
   public void testExecuteSetTransaction() throws Exception {
     ParsedStatement subject = parser.parse(Statement.of("set transaction read_only"));
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/ConnectionTest.java b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionTest.java
new file mode 100644
index 0000000..d99b9a7
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/jdbc/ConnectionTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 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.jdbc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.Statement;
+import com.google.spanner.v1.ExecuteSqlRequest;
+import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
+import java.sql.SQLException;
+import org.junit.Test;
+
+public class ConnectionTest extends AbstractMockServerTest {
+  @Test
+  public void testDefaultOptimizerVersion() throws SQLException {
+    try (Connection connection = createConnection()) {
+      try (ResultSet rs =
+          connection.executeQuery(Statement.of("SHOW VARIABLE OPTIMIZER_VERSION"))) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("");
+        assertThat(rs.next()).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void testUseOptimizerVersionFromEnvironment() throws SQLException {
+    try {
+      SpannerOptions.useEnvironment(
+          new SpannerOptions.SpannerEnvironment() {
+            @Override
+            public String getOptimizerVersion() {
+              return "20";
+            }
+          });
+      try (Connection connection = createConnection()) {
+        // Do a query and verify that the version from the environment is used.
+        try (ResultSet rs = connection.executeQuery(SELECT_COUNT_STATEMENT)) {
+          assertThat(rs.next()).isTrue();
+          assertThat(rs.getLong(0)).isEqualTo(COUNT_BEFORE_INSERT);
+          assertThat(rs.next()).isFalse();
+          // Verify query options from the environment.
+          ExecuteSqlRequest request = getLastExecuteSqlRequest();
+          assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("20");
+        }
+        // Now set one of the query options on the connection. That option should be used in
+        // combination with the other option from the environment.
+        connection.execute(Statement.of("SET OPTIMIZER_VERSION='30'"));
+        try (ResultSet rs = connection.executeQuery(SELECT_COUNT_STATEMENT)) {
+          assertThat(rs.next()).isTrue();
+          assertThat(rs.getLong(0)).isEqualTo(COUNT_BEFORE_INSERT);
+          assertThat(rs.next()).isFalse();
+
+          ExecuteSqlRequest request = getLastExecuteSqlRequest();
+          // Optimizer version should come from the connection.
+          assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("30");
+        }
+        // Now specify options directly for the query. These should override both the environment
+        // and what is set on the connection.
+        try (ResultSet rs =
+            connection.executeQuery(
+                Statement.newBuilder(SELECT_COUNT_STATEMENT.getSql())
+                    .withQueryOptions(
+                        QueryOptions.newBuilder()
+                            .setOptimizerVersion("user-defined-version")
+                            .build())
+                    .build())) {
+          assertThat(rs.next()).isTrue();
+          assertThat(rs.getLong(0)).isEqualTo(COUNT_BEFORE_INSERT);
+          assertThat(rs.next()).isFalse();
+
+          ExecuteSqlRequest request = getLastExecuteSqlRequest();
+          // Optimizer version should come from the query.
+          assertThat(request.getQueryOptions().getOptimizerVersion())
+              .isEqualTo("user-defined-version");
+        }
+      }
+    } finally {
+      SpannerOptions.useDefaultEnvironment();
+    }
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/JdbcQueryOptionsTest.java b/src/test/java/com/google/cloud/spanner/jdbc/JdbcQueryOptionsTest.java
new file mode 100644
index 0000000..460e07f
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/jdbc/JdbcQueryOptionsTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2020 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.jdbc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.Statement;
+import com.google.common.base.MoreObjects;
+import com.google.spanner.v1.ExecuteSqlRequest;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class JdbcQueryOptionsTest extends AbstractMockServerTest {
+  @Test
+  public void testDefaultOptimizerVersion() throws SQLException {
+    try (java.sql.Connection connection = createJdbcConnection()) {
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("");
+        assertThat(rs.next()).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void testOptimizerVersionInConnectionUrl() throws SQLException {
+    try (java.sql.Connection connection =
+        DriverManager.getConnection(
+            String.format("jdbc:%s;optimizerVersion=%s", getBaseUrl(), "100"))) {
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("100");
+        assertThat(rs.next()).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void testSetOptimizerVersion() throws SQLException {
+    try (java.sql.Connection connection = createJdbcConnection()) {
+      connection.createStatement().execute("SET OPTIMIZER_VERSION='20'");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("20");
+        assertThat(rs.next()).isFalse();
+      }
+      connection.createStatement().execute("SET OPTIMIZER_VERSION='latest'");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("latest");
+        assertThat(rs.next()).isFalse();
+      }
+      connection.createStatement().execute("SET OPTIMIZER_VERSION=''");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("");
+        assertThat(rs.next()).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void testSetAndUseOptimizerVersion() throws SQLException {
+    try (java.sql.Connection connection = createJdbcConnection()) {
+      connection.createStatement().execute("SET OPTIMIZER_VERSION='20'");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
+        assertThat(rs.next()).isFalse();
+        // Verify that the last ExecuteSqlRequest that the server received specified optimizer
+        // version 20.
+        ExecuteSqlRequest request = getLastExecuteSqlRequest();
+        assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("20");
+      }
+
+      // Do another query, but now with optimizer version 'latest'.
+      connection.createStatement().execute("SET OPTIMIZER_VERSION='latest'");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
+        assertThat(rs.next()).isFalse();
+        // Verify that the last ExecuteSqlRequest that the server received specified optimizer
+        // version 'latest'.
+        ExecuteSqlRequest request = getLastExecuteSqlRequest();
+        assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("latest");
+      }
+
+      // Set the optimizer version to ''. This will do a fallback to the default, meaning that it
+      // will be read from the environment variable SPANNER_OPTIMIZER_VERSION as we have nothing set
+      // on the connection URL.
+      connection.createStatement().execute("SET OPTIMIZER_VERSION=''");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
+        assertThat(rs.next()).isFalse();
+        // Verify that the last ExecuteSqlRequest that the server received specified an optimizer
+        // version equal to the environment default.
+        ExecuteSqlRequest request = getLastExecuteSqlRequest();
+        assertThat(request.getQueryOptions().getOptimizerVersion())
+            .isEqualTo(MoreObjects.firstNonNull(System.getenv("SPANNER_OPTIMIZER_VERSION"), ""));
+      }
+    }
+  }
+
+  @Test
+  public void testUseOptimizerVersionFromConnectionUrl() throws SQLException {
+    try (java.sql.Connection connection =
+        DriverManager.getConnection(String.format("jdbc:%s;optimizerVersion=10", getBaseUrl()))) {
+      // Do a query and verify that the version from the connection URL is used.
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
+        assertThat(rs.next()).isFalse();
+        // The optimizer version used should be '10' from the connection URL.
+        ExecuteSqlRequest request = getLastExecuteSqlRequest();
+        assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("10");
+      }
+    }
+  }
+
+  @Test
+  public void testUseOptimizerVersionFromEnvironment() throws SQLException {
+    try {
+      SpannerOptions.useEnvironment(
+          new SpannerOptions.SpannerEnvironment() {
+            @Override
+            public String getOptimizerVersion() {
+              return "20";
+            }
+          });
+      try (java.sql.Connection connection =
+          DriverManager.getConnection(String.format("jdbc:%s", getBaseUrl()))) {
+        // Do a query and verify that the version from the environment is used.
+        try (java.sql.ResultSet rs =
+            connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
+          assertThat(rs.next()).isTrue();
+          assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
+          assertThat(rs.next()).isFalse();
+          // Verify query options from the environment.
+          ExecuteSqlRequest request = getLastExecuteSqlRequest();
+          assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("20");
+        }
+        // Now set one of the query options on the connection. That option should be used in
+        // combination with the other option from the environment.
+        connection.createStatement().execute("SET OPTIMIZER_VERSION='30'");
+        try (java.sql.ResultSet rs =
+            connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
+          assertThat(rs.next()).isTrue();
+          assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
+          assertThat(rs.next()).isFalse();
+
+          ExecuteSqlRequest request = getLastExecuteSqlRequest();
+          // Optimizer version should come from the connection.
+          assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("30");
+        }
+      }
+    } finally {
+      SpannerOptions.useDefaultEnvironment();
+    }
+  }
+
+  @Test
+  public void testUseQueryHint() throws SQLException {
+    mockSpanner.putStatementResult(
+        StatementResult.query(
+            Statement.of(
+                String.format("@{optimizer_version=1} %s", SELECT_COUNT_STATEMENT.getSql())),
+            SELECT_COUNT_RESULTSET_BEFORE_INSERT));
+    try (java.sql.Connection connection =
+        DriverManager.getConnection(String.format("jdbc:%s", getBaseUrl()))) {
+      try (java.sql.ResultSet rs =
+          connection
+              .createStatement()
+              .executeQuery(
+                  String.format("@{optimizer_version=1} %s", SELECT_COUNT_STATEMENT.getSql()))) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
+        assertThat(rs.next()).isFalse();
+        // The optimizer version used in the ExecuteSqlRequest should be empty as the query hint is
+        // parsed by the backend.
+        ExecuteSqlRequest request = getLastExecuteSqlRequest();
+        assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("");
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/JdbcTypeConverterTest.java b/src/test/java/com/google/cloud/spanner/jdbc/JdbcTypeConverterTest.java
index 773fcf9..328c01f 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/JdbcTypeConverterTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/JdbcTypeConverterTest.java
@@ -50,6 +50,7 @@ import java.util.Arrays;
 import java.util.Calendar;
 import java.util.List;
 import java.util.TimeZone;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -580,6 +581,7 @@ public class JdbcTypeConverterTest {
     }
   }
 
+  @Ignore("ignore until java-core 1.93.3 is available")
   @SuppressWarnings("deprecation")
   @Test
   public void testToGoogleTimestamp() {
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcQueryOptionsTest.java b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcQueryOptionsTest.java
new file mode 100644
index 0000000..8e72aa2
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcQueryOptionsTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2020 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.jdbc.it;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.cloud.spanner.IntegrationTest;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.jdbc.ITAbstractJdbcTest;
+import com.google.cloud.spanner.jdbc.JdbcSqlException;
+import com.google.cloud.spanner.jdbc.SpannerPool;
+import com.google.rpc.Code;
+import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * {@link QueryOptions} can be used with the JDBC driver on three different levels:
+ *
+ * <ol>
+ *   <li>Specify {@link QueryOptions} in environment variables.
+ *   <li>Specify {@link QueryOptions} in the connection URL or by setting these using <code>
+ *       SET &lt;query_option&gt; = '&lt;value&gt;'</code> statements.
+ *   <li>Specify {@link QueryOptions} in a query hint.
+ * </ol>
+ *
+ * This class tests all three possibilities.
+ */
+@Category(IntegrationTest.class)
+@RunWith(JUnit4.class)
+public class ITJdbcQueryOptionsTest extends ITAbstractJdbcTest {
+  private String connectionUriSuffix;
+
+  @Before
+  public void resetConnectionUriSuffix() {
+    connectionUriSuffix = "";
+  }
+
+  @After
+  public void closeSpannerPool() {
+    // Close the pool after each test to prevent side effects from one test case to affect following
+    // test cases.
+    SpannerPool.closeSpannerPool();
+  }
+
+  @Override
+  protected void appendConnectionUri(StringBuilder uri) {
+    uri.append(connectionUriSuffix);
+  }
+
+  private void verifyOptimizerVersion(Connection connection, String expectedVersion)
+      throws SQLException {
+    try (ResultSet rs =
+        connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
+      assertThat(rs.next()).isTrue();
+      assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo(expectedVersion);
+      assertThat(rs.next()).isFalse();
+    }
+  }
+
+  @Test
+  public void connectionUrl() throws SQLException {
+    this.connectionUriSuffix = ";optimizerVersion=1";
+    try (Connection connection = createConnection()) {
+      verifyOptimizerVersion(connection, "1");
+      try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(1L);
+        assertThat(rs.next()).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void connectionUrlWithInvalidOptimizerVersion() throws SQLException {
+    this.connectionUriSuffix = ";optimizerVersion=9999999";
+    try (Connection connection = createConnection()) {
+      try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
+        fail("missing expected exception");
+      } catch (SQLException e) {
+        assertThat((Throwable) e).isInstanceOf(JdbcSqlException.class);
+        JdbcSqlException je = (JdbcSqlException) e;
+        assertThat(je.getCode()).isEqualTo(Code.INVALID_ARGUMENT);
+      }
+    }
+  }
+
+  @Test
+  public void setOptimizerVersion() throws SQLException {
+    try (Connection connection = createConnection()) {
+      verifyOptimizerVersion(connection, "");
+      connection.createStatement().execute("SET OPTIMIZER_VERSION='1'");
+      verifyOptimizerVersion(connection, "1");
+      try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(1L);
+        assertThat(rs.next()).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void setLatestOptimizerVersion() throws SQLException {
+    try (Connection connection = createConnection()) {
+      verifyOptimizerVersion(connection, "");
+      connection.createStatement().execute("SET OPTIMIZER_VERSION='LATEST'");
+      verifyOptimizerVersion(connection, "LATEST");
+      try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(1L);
+        assertThat(rs.next()).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void setInvalidOptimizerVersion() throws SQLException {
+    try (Connection connection = createConnection()) {
+      connection.createStatement().execute("SET OPTIMIZER_VERSION='9999999'");
+      try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
+        fail("missing expected exception");
+      } catch (SQLException e) {
+        assertThat((Throwable) e).isInstanceOf(JdbcSqlException.class);
+        JdbcSqlException je = (JdbcSqlException) e;
+        assertThat(je.getCode()).isEqualTo(Code.INVALID_ARGUMENT);
+      }
+    }
+  }
+
+  @Test
+  public void optimizerVersionInQueryHint() throws SQLException {
+    try (Connection connection = createConnection()) {
+      verifyOptimizerVersion(connection, "");
+      try (ResultSet rs =
+          connection.createStatement().executeQuery("@{optimizer_version=1} SELECT 1")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(1L);
+        assertThat(rs.next()).isFalse();
+      }
+      try (ResultSet rs =
+          connection.createStatement().executeQuery("@{optimizer_version=latest} SELECT 1")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getLong(1)).isEqualTo(1L);
+        assertThat(rs.next()).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void optimizerVersionInEnvironment() throws SQLException {
+    try {
+      SpannerOptions.useEnvironment(
+          new SpannerOptions.SpannerEnvironment() {
+            @Override
+            public String getOptimizerVersion() {
+              return "1";
+            }
+          });
+      try (Connection connection = createConnection()) {
+        // Environment query options are not visible to the connection.
+        verifyOptimizerVersion(connection, "");
+        try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
+          assertThat(rs.next()).isTrue();
+          assertThat(rs.getLong(1)).isEqualTo(1L);
+          assertThat(rs.next()).isFalse();
+        }
+      }
+      // Close the pool to force re-initialization of any cached connections.
+      SpannerPool.closeSpannerPool();
+
+      // Now set an invalid version on the environment. The query will now fail.
+      SpannerOptions.useEnvironment(
+          new SpannerOptions.SpannerEnvironment() {
+            @Override
+            public String getOptimizerVersion() {
+              return "9999999";
+            }
+          });
+      try (Connection connection = createConnection()) {
+        try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
+          fail("missing expected exception");
+        } catch (SQLException e) {
+          assertThat((Throwable) e).isInstanceOf(JdbcSqlException.class);
+          JdbcSqlException je = (JdbcSqlException) e;
+          assertThat(je.getCode()).isEqualTo(Code.INVALID_ARGUMENT);
+        }
+      }
+    } finally {
+      SpannerOptions.useDefaultEnvironment();
+    }
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcSqlScriptTest.java b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcSqlScriptTest.java
index f8154dc..87f5abe 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcSqlScriptTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcSqlScriptTest.java
@@ -61,6 +61,7 @@ public class ITJdbcSqlScriptTest extends ITAbstractJdbcTest {
       "ITSqlScriptTest_TestAutocommitDmlMode.sql";
   private static final String TEST_AUTOCOMMIT_READ_ONLY =
       "ITSqlScriptTest_TestAutocommitReadOnly.sql";
+  private static final String TEST_QUERY_OPTIONS = "ITSqlScriptTest_TestQueryOptions.sql";
   private static final String TEST_STATEMENT_TIMEOUT = "ITSqlScriptTest_TestStatementTimeout.sql";
   private static final String TEST_SET_STATEMENTS = "ITSqlScriptTest_TestSetStatements.sql";
   private static final String TEST_INVALID_STATEMENTS = "ITSqlScriptTest_TestInvalidStatements.sql";
@@ -208,4 +209,12 @@ public class ITJdbcSqlScriptTest extends ITAbstractJdbcTest {
           JdbcGenericConnection.of(connection), TEST_INVALID_STATEMENTS, SqlScriptVerifier.class);
     }
   }
+
+  @Test
+  public void test14_TestQueryOptions() throws Exception {
+    try (Connection connection = createConnection()) {
+      verifier.verifyStatementsInFile(
+          JdbcGenericConnection.of(connection), TEST_QUERY_OPTIONS, SqlScriptVerifier.class);
+    }
+  }
 }
diff --git a/src/test/resources/com/google/cloud/spanner/jdbc/ClientSideStatementsTest.sql b/src/test/resources/com/google/cloud/spanner/jdbc/ClientSideStatementsTest.sql
index fe8afd8..56d8041 100644
--- a/src/test/resources/com/google/cloud/spanner/jdbc/ClientSideStatementsTest.sql
+++ b/src/test/resources/com/google/cloud/spanner/jdbc/ClientSideStatementsTest.sql
@@ -1931,6 +1931,205 @@ NEW_CONNECTION;
 @EXPECT EXCEPTION INVALID_ARGUMENT
 show variable/-read_only_staleness;
 NEW_CONNECTION;
+show variable optimizer_version;
+NEW_CONNECTION;
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+show variable optimizer_version;
+NEW_CONNECTION;
+   show variable optimizer_version;
+NEW_CONNECTION;
+			show variable optimizer_version;
+NEW_CONNECTION;
+
+
+
+show variable optimizer_version;
+NEW_CONNECTION;
+show variable optimizer_version  ;
+NEW_CONNECTION;
+show variable optimizer_version		;
+NEW_CONNECTION;
+show variable optimizer_version
+
+;
+NEW_CONNECTION;
+show   variable   optimizer_version;
+NEW_CONNECTION;
+show	variable	optimizer_version;
+NEW_CONNECTION;
+show
+variable
+optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable%optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable_optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable&optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable$optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable@optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable!optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable*optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable(optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version);
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable)optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable-optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable+optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable-#optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable/optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable\optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable?optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable-/optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable/#optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-show variable optimizer_version;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable optimizer_version/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+show variable/-optimizer_version;
+NEW_CONNECTION;
 begin;
 NEW_CONNECTION;
 BEGIN;
@@ -11076,3 +11275,795 @@ set read_only_staleness='EXACT_STALENESS 9999ns'/-;
 NEW_CONNECTION;
 @EXPECT EXCEPTION INVALID_ARGUMENT
 set read_only_staleness='EXACT_STALENESS/-9999ns';
+NEW_CONNECTION;
+set optimizer_version='1';
+NEW_CONNECTION;
+SET OPTIMIZER_VERSION='1';
+NEW_CONNECTION;
+set optimizer_version='1';
+NEW_CONNECTION;
+   set optimizer_version='1';
+NEW_CONNECTION;
+			set optimizer_version='1';
+NEW_CONNECTION;
+
+
+
+set optimizer_version='1';
+NEW_CONNECTION;
+set optimizer_version='1'  ;
+NEW_CONNECTION;
+set optimizer_version='1'		;
+NEW_CONNECTION;
+set optimizer_version='1'
+
+;
+NEW_CONNECTION;
+set   optimizer_version='1';
+NEW_CONNECTION;
+set	optimizer_version='1';
+NEW_CONNECTION;
+set
+optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1' bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set%optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set_optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set&optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set$optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set@optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set!optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set*optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set(optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1');
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set)optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set+optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-#optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set\optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set?optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-/optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/#optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-set optimizer_version='1';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='1'/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/-optimizer_version='1';
+NEW_CONNECTION;
+set optimizer_version='200';
+NEW_CONNECTION;
+SET OPTIMIZER_VERSION='200';
+NEW_CONNECTION;
+set optimizer_version='200';
+NEW_CONNECTION;
+   set optimizer_version='200';
+NEW_CONNECTION;
+			set optimizer_version='200';
+NEW_CONNECTION;
+
+
+
+set optimizer_version='200';
+NEW_CONNECTION;
+set optimizer_version='200'  ;
+NEW_CONNECTION;
+set optimizer_version='200'		;
+NEW_CONNECTION;
+set optimizer_version='200'
+
+;
+NEW_CONNECTION;
+set   optimizer_version='200';
+NEW_CONNECTION;
+set	optimizer_version='200';
+NEW_CONNECTION;
+set
+optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200' bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set%optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set_optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set&optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set$optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set@optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set!optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set*optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set(optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200');
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set)optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set+optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-#optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set\optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set?optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-/optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/#optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-set optimizer_version='200';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='200'/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/-optimizer_version='200';
+NEW_CONNECTION;
+set optimizer_version='LATEST';
+NEW_CONNECTION;
+SET OPTIMIZER_VERSION='LATEST';
+NEW_CONNECTION;
+set optimizer_version='latest';
+NEW_CONNECTION;
+   set optimizer_version='LATEST';
+NEW_CONNECTION;
+			set optimizer_version='LATEST';
+NEW_CONNECTION;
+
+
+
+set optimizer_version='LATEST';
+NEW_CONNECTION;
+set optimizer_version='LATEST'  ;
+NEW_CONNECTION;
+set optimizer_version='LATEST'		;
+NEW_CONNECTION;
+set optimizer_version='LATEST'
+
+;
+NEW_CONNECTION;
+set   optimizer_version='LATEST';
+NEW_CONNECTION;
+set	optimizer_version='LATEST';
+NEW_CONNECTION;
+set
+optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST' bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set%optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set_optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set&optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set$optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set@optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set!optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set*optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set(optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST');
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set)optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set+optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-#optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set\optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set?optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-/optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/#optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-set optimizer_version='LATEST';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='LATEST'/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/-optimizer_version='LATEST';
+NEW_CONNECTION;
+set optimizer_version='';
+NEW_CONNECTION;
+SET OPTIMIZER_VERSION='';
+NEW_CONNECTION;
+set optimizer_version='';
+NEW_CONNECTION;
+   set optimizer_version='';
+NEW_CONNECTION;
+			set optimizer_version='';
+NEW_CONNECTION;
+
+
+
+set optimizer_version='';
+NEW_CONNECTION;
+set optimizer_version=''  ;
+NEW_CONNECTION;
+set optimizer_version=''		;
+NEW_CONNECTION;
+set optimizer_version=''
+
+;
+NEW_CONNECTION;
+set   optimizer_version='';
+NEW_CONNECTION;
+set	optimizer_version='';
+NEW_CONNECTION;
+set
+optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+foo set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='' bar;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+%set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''%;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set%optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+_set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''_;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set_optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+&set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''&;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set&optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+$set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''$;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set$optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+@set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''@;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set@optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+!set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''!;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set!optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+*set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''*;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set*optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+(set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''(;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set(optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+)set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version='');
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set)optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
++set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''+;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set+optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-#set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''-#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-#optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+\set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''\;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set\optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+?set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''?;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set?optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+-/set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''-/;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set-/optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/#set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''/#;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/#optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+/-set optimizer_version='';
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set optimizer_version=''/-;
+NEW_CONNECTION;
+@EXPECT EXCEPTION INVALID_ARGUMENT
+set/-optimizer_version='';
diff --git a/src/test/resources/com/google/cloud/spanner/jdbc/ConnectionImplGeneratedSqlScriptTest.sql b/src/test/resources/com/google/cloud/spanner/jdbc/ConnectionImplGeneratedSqlScriptTest.sql
index c765085..a4d68cd 100644
--- a/src/test/resources/com/google/cloud/spanner/jdbc/ConnectionImplGeneratedSqlScriptTest.sql
+++ b/src/test/resources/com/google/cloud/spanner/jdbc/ConnectionImplGeneratedSqlScriptTest.sql
@@ -2,6 +2,16 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -142,15 +152,15 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:54.904000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:54.904000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:57.888000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:57.888000000Z'
 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 2019-07-31T10:46:54.904000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:57.888000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
@@ -179,6 +189,26 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
@@ -272,6 +302,16 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -422,15 +462,15 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:54.986000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:54.986000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.128000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.128000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:54.986000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:54.986000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.128000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.128000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
@@ -461,6 +501,26 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
@@ -561,6 +621,16 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -711,15 +781,15 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.049000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.049000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.214000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.214000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.049000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.049000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.214000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.214000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
@@ -750,6 +820,26 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
@@ -850,6 +940,16 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SET READ_ONLY_STALENESS='MAX_STALENESS 10s';
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SET READ_ONLY_STALENESS='MAX_STALENESS 10s';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SET READ_ONLY_STALENESS='MAX_STALENESS 10s';
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -1000,15 +1100,15 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SET READ_ONLY_STALENESS='MAX_STALENESS 10s';
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.100000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.100000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.271000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.271000000Z'
 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 2019-07-31T10:46:55.100000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.100000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.271000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.271000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
@@ -1039,6 +1139,26 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
 SET READ_ONLY_STALENESS='MAX_STALENESS 10s';
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SET READ_ONLY_STALENESS='MAX_STALENESS 10s';
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+SET READ_ONLY_STALENESS='MAX_STALENESS 10s';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
@@ -1141,6 +1261,20 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 SELECT 1 AS TEST;
 COMMIT;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+SELECT 1 AS TEST;
+COMMIT;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+SELECT 1 AS TEST;
+COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -1345,8 +1479,8 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 SELECT 1 AS TEST;
 COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.147000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.147000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.339000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.339000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
@@ -1354,8 +1488,8 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 SELECT 1 AS TEST;
 COMMIT;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.147000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.147000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.339000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.339000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
@@ -1396,6 +1530,30 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 SELECT 1 AS TEST;
 COMMIT;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+SELECT 1 AS TEST;
+COMMIT;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+SELECT 1 AS TEST;
+COMMIT;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
@@ -1515,6 +1673,14 @@ COMMIT;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -1638,14 +1804,14 @@ SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.196000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.196000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.423000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.423000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.196000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.196000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.423000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.423000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
@@ -1671,6 +1837,24 @@ SET AUTOCOMMIT=TRUE;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=TRUE;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=TRUE;
@@ -1762,6 +1946,18 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 SET TRANSACTION READ ONLY;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+SET TRANSACTION READ ONLY;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+SET TRANSACTION READ ONLY;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -1928,8 +2124,8 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 SET TRANSACTION READ ONLY;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.237000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.237000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.470000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.470000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -1937,7 +2133,7 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 SET TRANSACTION READ ONLY;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.237000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.470000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -1971,6 +2167,28 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 SET TRANSACTION READ ONLY;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+SET TRANSACTION READ ONLY;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+SET TRANSACTION READ ONLY;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -2074,6 +2292,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -2218,15 +2446,15 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.284000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.284000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.514000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.514000000Z'
 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 2019-07-31T10:46:55.284000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.514000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -2255,6 +2483,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -2348,6 +2596,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -2512,15 +2770,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 2019-07-31T10:46:55.377000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.377000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.580000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.580000000Z'
 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 2019-07-31T10:46:55.377000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.377000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.580000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.580000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -2551,6 +2809,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -2651,6 +2929,18 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -2842,16 +3132,16 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.430000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.430000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.663000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.663000000Z'
 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 2019-07-31T10:46:55.430000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.430000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.663000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.663000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -2887,6 +3177,28 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -2996,6 +3308,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -3160,15 +3482,15 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.491000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.491000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.751000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.751000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.491000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.491000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.751000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.751000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -3199,6 +3521,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 SELECT 1 AS TEST;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+SELECT 1 AS TEST;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -3298,6 +3640,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 START BATCH DDL;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+START BATCH DDL;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+START BATCH DDL;
 ABORT BATCH;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -3439,13 +3791,13 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 START BATCH DDL;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.524000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.797000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 START BATCH DDL;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.524000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.797000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -3472,6 +3824,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 START BATCH DDL;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+START BATCH DDL;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+START BATCH DDL;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -3567,6 +3939,20 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 UPDATE foo SET bar=1;
 COMMIT;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+UPDATE foo SET bar=1;
+COMMIT;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+UPDATE foo SET bar=1;
+COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -3785,8 +4171,8 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 UPDATE foo SET bar=1;
 COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.594000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.594000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.850000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.850000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -3794,8 +4180,8 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 UPDATE foo SET bar=1;
 COMMIT;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.594000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.594000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.850000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.850000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -3836,6 +4222,30 @@ SET AUTOCOMMIT=TRUE;
 BEGIN TRANSACTION;
 UPDATE foo SET bar=1;
 COMMIT;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+UPDATE foo SET bar=1;
+COMMIT;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+BEGIN TRANSACTION;
+UPDATE foo SET bar=1;
+COMMIT;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -3955,6 +4365,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 UPDATE foo SET bar=1;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+UPDATE foo SET bar=1;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+UPDATE foo SET bar=1;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -4119,15 +4539,15 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 UPDATE foo SET bar=1;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.650000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.650000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.947000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.947000000Z'
 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 2019-07-31T10:46:55.650000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.650000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.947000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.947000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -4158,6 +4578,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
 UPDATE foo SET bar=1;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+UPDATE foo SET bar=1;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+UPDATE foo SET bar=1;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -4256,6 +4696,14 @@ UPDATE foo SET bar=1;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -4393,14 +4841,14 @@ SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.687000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.687000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:58.985000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:58.985000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.687000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2019-07-31T10:46:55.687000000Z'
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:58.985000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','MIN_READ_TIMESTAMP 2020-03-05T17:56:58.985000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -4426,6 +4874,24 @@ SET AUTOCOMMIT=TRUE;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=TRUE;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=TRUE;
@@ -4515,6 +4981,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 BEGIN TRANSACTION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -4659,15 +5135,15 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 BEGIN TRANSACTION;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.716000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.716000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.013000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.013000000Z'
 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 2019-07-31T10:46:55.716000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.013000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -4696,6 +5172,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 BEGIN TRANSACTION;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -4792,6 +5288,22 @@ SET TRANSACTION READ ONLY;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET TRANSACTION READ ONLY;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET TRANSACTION READ ONLY;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -5031,8 +5543,8 @@ SET TRANSACTION READ ONLY;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.754000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.754000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.061000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.061000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -5042,7 +5554,7 @@ SET TRANSACTION READ ONLY;
 SELECT 1 AS TEST;
 COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.754000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.061000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -5086,6 +5598,32 @@ SET TRANSACTION READ ONLY;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET TRANSACTION READ ONLY;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET TRANSACTION READ ONLY;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -5214,6 +5752,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 COMMIT;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+COMMIT;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -5372,15 +5920,15 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.806000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.806000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.106000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.106000000Z'
 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 2019-07-31T10:46:55.806000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.106000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -5409,6 +5957,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 COMMIT;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+COMMIT;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+COMMIT;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -5509,6 +6077,20 @@ SET AUTOCOMMIT=FALSE;
 START BATCH DDL;
 CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
 RUN BATCH;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+RUN BATCH;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+RUN BATCH;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -5721,8 +6303,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 2019-07-31T10:46:55.836000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.836000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.155000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.155000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -5731,7 +6313,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 2019-07-31T10:46:55.836000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.155000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -5770,6 +6352,30 @@ SET AUTOCOMMIT=FALSE;
 START BATCH DDL;
 CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
 RUN BATCH;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+RUN BATCH;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+RUN BATCH;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -5891,6 +6497,22 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 ROLLBACK;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+ROLLBACK;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+ROLLBACK;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -6130,8 +6752,8 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 ROLLBACK;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.874000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.874000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.218000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.218000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -6141,7 +6763,7 @@ BEGIN TRANSACTION;
 SELECT 1 AS TEST;
 ROLLBACK;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.874000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.218000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -6185,6 +6807,32 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 ROLLBACK;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+ROLLBACK;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+ROLLBACK;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -6314,6 +6962,18 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -6487,14 +7147,14 @@ SET AUTOCOMMIT=FALSE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.915000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.279000000Z';
 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 2019-07-31T10:46:55.915000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.279000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -6526,6 +7186,28 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -6629,6 +7311,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SELECT 1 AS TEST;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -6775,13 +7467,13 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.970000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.328000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:55.970000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.328000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -6808,6 +7500,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SELECT 1 AS TEST;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SELECT 1 AS TEST;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -6901,6 +7613,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -7059,15 +7781,15 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:55.995000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:55.995000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.396000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.396000000Z'
 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 2019-07-31T10:46:55.995000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.396000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -7096,6 +7818,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -7194,6 +7936,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SET TRANSACTION READ ONLY;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET TRANSACTION READ ONLY;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET TRANSACTION READ ONLY;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -7333,15 +8085,15 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SET TRANSACTION READ ONLY;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.013000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.013000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.425000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.425000000Z'
 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 2019-07-31T10:46:56.013000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.425000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -7370,6 +8122,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 SET TRANSACTION READ ONLY;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET TRANSACTION READ ONLY;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+SET TRANSACTION READ ONLY;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -7463,6 +8235,16 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 START BATCH DDL;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
 ABORT BATCH;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -7604,13 +8386,13 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 START BATCH DDL;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.029000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.451000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 START BATCH DDL;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:56.029000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.451000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -7637,6 +8419,26 @@ NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 START BATCH DDL;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -7733,6 +8535,22 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -7972,8 +8790,8 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.066000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.066000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.493000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.493000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -7983,7 +8801,7 @@ BEGIN TRANSACTION;
 SELECT 1 AS TEST;
 COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:56.066000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.493000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -8027,6 +8845,32 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -8156,6 +9000,18 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 START BATCH DDL;
 CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+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 RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
 ABORT BATCH;
 NEW_CONNECTION;
 SET READONLY=FALSE;
@@ -8324,14 +9180,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 2019-07-31T10:46:56.104000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.539000000Z';
 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 2019-07-31T10:46:56.104000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.539000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -8363,6 +9219,28 @@ SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 START BATCH DDL;
 CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+START BATCH DDL;
+CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -8465,6 +9343,14 @@ CREATE TABLE foo (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY (id);
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -8596,14 +9482,14 @@ SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.132000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.132000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.575000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.575000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:56.132000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.575000000Z';
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -8627,6 +9513,24 @@ SET AUTOCOMMIT=FALSE;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
+NEW_CONNECTION;
+SET READONLY=FALSE;
+SET AUTOCOMMIT=FALSE;
 NEW_CONNECTION;
 SET READONLY=FALSE;
 SET AUTOCOMMIT=FALSE;
@@ -8715,6 +9619,16 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 BEGIN TRANSACTION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -8855,15 +9769,15 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 BEGIN TRANSACTION;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.157000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.157000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.601000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.601000000Z'
 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 2019-07-31T10:46:56.157000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.601000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -8892,6 +9806,26 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 BEGIN TRANSACTION;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -8985,6 +9919,16 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 COMMIT;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+COMMIT;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -9133,15 +10077,15 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.175000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.175000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.621000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.621000000Z'
 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 2019-07-31T10:46:56.175000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.621000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -9170,6 +10114,26 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 COMMIT;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+COMMIT;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+COMMIT;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -9272,6 +10236,22 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 ROLLBACK;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+ROLLBACK;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+ROLLBACK;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -9501,8 +10481,8 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 ROLLBACK;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.203000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.203000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.654000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.654000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
@@ -9512,7 +10492,7 @@ BEGIN TRANSACTION;
 SELECT 1 AS TEST;
 ROLLBACK;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:56.203000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.654000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -9556,6 +10536,32 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 ROLLBACK;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+ROLLBACK;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+ROLLBACK;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -9686,6 +10692,18 @@ SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -9854,14 +10872,14 @@ SET AUTOCOMMIT=FALSE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.262000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.711000000Z';
 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 2019-07-31T10:46:56.262000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.711000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -9893,6 +10911,28 @@ SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -9996,6 +11036,16 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+SELECT 1 AS TEST;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -10137,13 +11187,13 @@ SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.291000000Z';
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.762000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 SELECT 1 AS TEST;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:56.291000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.762000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -10170,6 +11220,26 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 SELECT 1 AS TEST;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+SELECT 1 AS TEST;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+SELECT 1 AS TEST;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -10263,6 +11333,16 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -10411,15 +11491,15 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.311000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.311000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.805000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.805000000Z'
 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 2019-07-31T10:46:56.311000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.805000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -10448,6 +11528,26 @@ NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+SET READ_ONLY_STALENESS='EXACT_STALENESS 10s';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -10550,6 +11650,22 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -10779,8 +11895,8 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.334000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.334000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.849000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.849000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
@@ -10790,7 +11906,7 @@ BEGIN TRANSACTION;
 SELECT 1 AS TEST;
 COMMIT;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:56.334000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.849000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -10834,6 +11950,32 @@ BEGIN TRANSACTION;
 @EXPECT RESULT_SET 'TEST',1
 SELECT 1 AS TEST;
 COMMIT;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+BEGIN TRANSACTION;
+@EXPECT RESULT_SET 'TEST',1
+SELECT 1 AS TEST;
+COMMIT;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -10962,6 +12104,14 @@ COMMIT;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION'
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
 @EXPECT EXCEPTION FAILED_PRECONDITION
 ABORT BATCH;
 NEW_CONNECTION;
@@ -11083,14 +12233,14 @@ SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
-SET READ_ONLY_STALENESS='READ_TIMESTAMP 2019-07-31T10:46:56.355000000Z';
-@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2019-07-31T10:46:56.355000000Z'
+SET READ_ONLY_STALENESS='READ_TIMESTAMP 2020-03-05T17:56:59.879000000Z';
+@EXPECT RESULT_SET 'READ_ONLY_STALENESS','READ_TIMESTAMP 2020-03-05T17:56:59.879000000Z'
 SHOW VARIABLE READ_ONLY_STALENESS;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
 @EXPECT EXCEPTION FAILED_PRECONDITION
-SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2019-07-31T10:46:56.355000000Z';
+SET READ_ONLY_STALENESS='MIN_READ_TIMESTAMP 2020-03-05T17:56:59.879000000Z';
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
@@ -11114,6 +12264,24 @@ SET AUTOCOMMIT=FALSE;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
+SET OPTIMIZER_VERSION='1';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='2';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','2'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='latest';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','latest'
+SHOW VARIABLE OPTIMIZER_VERSION;
+SET OPTIMIZER_VERSION='';
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
+NEW_CONNECTION;
+SET READONLY=TRUE;
+SET AUTOCOMMIT=FALSE;
 NEW_CONNECTION;
 SET READONLY=TRUE;
 SET AUTOCOMMIT=FALSE;
diff --git a/src/test/resources/com/google/cloud/spanner/jdbc/ITSqlScriptTest_TestQueryOptions.sql b/src/test/resources/com/google/cloud/spanner/jdbc/ITSqlScriptTest_TestQueryOptions.sql
new file mode 100644
index 0000000..923cc97
--- /dev/null
+++ b/src/test/resources/com/google/cloud/spanner/jdbc/ITSqlScriptTest_TestQueryOptions.sql
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 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.
+ */
+
+/*
+ * Test setting and getting the optimizer version to use.
+ */
+
+-- Set and get valid values.
+@EXPECT NO_RESULT
+SET OPTIMIZER_VERSION = '1';
+
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','1'
+SHOW VARIABLE OPTIMIZER_VERSION;
+
+@EXPECT NO_RESULT
+SET OPTIMIZER_VERSION = '555';
+
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','555'
+SHOW VARIABLE OPTIMIZER_VERSION;
+
+@EXPECT NO_RESULT
+SET OPTIMIZER_VERSION = 'LATEST';
+
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION','LATEST'
+SHOW VARIABLE OPTIMIZER_VERSION;
+
+@EXPECT NO_RESULT
+SET OPTIMIZER_VERSION = '';
+
+@EXPECT RESULT_SET 'OPTIMIZER_VERSION',''
+SHOW VARIABLE OPTIMIZER_VERSION;
+
+-- Try to set invalid values.
+@EXPECT EXCEPTION INVALID_ARGUMENT 'INVALID_ARGUMENT: Unknown value for OPTIMIZER_VERSION: 'None''
+SET OPTIMIZER_VERSION = 'None';
+
+@EXPECT EXCEPTION INVALID_ARGUMENT 'INVALID_ARGUMENT: Unknown value for OPTIMIZER_VERSION: 'v1''
+SET OPTIMIZER_VERSION = 'v1';