Repository: GoogleCloudPlatform/pgadapter
Pull request #273 (2022-07-10 14:11:05)

feat: select current_schema
Many tools and drivers execute `select current_schema()` to get the current
schema of the connection. This is not yet supported by Cloud Spanner, and
therefore handled locally by PGAdapter.

codecov[bot]: # [Codecov](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) Report
> Merging [#273](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) (82129e0) into [postgresql-dialect](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/commit/78dac56398b001bdbf9f50e747ace1d8208869f8?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) (78dac56) will **increase** coverage by `0.09%`.
> The diff coverage is `97.22%`.

```diff
@@                   Coverage Diff                    @@
##             postgresql-dialect     #273      +/-   ##
========================================================
+ Coverage                 81.08%   81.18%   +0.09%     
- Complexity                 1223     1228       +5     
========================================================
  Files                        99      100       +1     
  Lines                      4208     4235      +27     
  Branches                    511      515       +4     
========================================================
+ Hits                       3412     3438      +26     
  Misses                      616      616              
- Partials                    180      181       +1     
```

| Flag | Coverage Δ | |
|---|---|---|
| all_tests | `81.18% <97.22%> (+0.09%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) | Coverage Δ | |
|---|---|---|
| [...ud/spanner/pgadapter/metadata/OptionsMetadata.java](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#diff-c3JjL21haW4vamF2YS9jb20vZ29vZ2xlL2Nsb3VkL3NwYW5uZXIvcGdhZGFwdGVyL21ldGFkYXRhL09wdGlvbnNNZXRhZGF0YS5qYXZh) | `78.05% <80.00%> (+0.04%)` | :arrow_up: |
| [...panner/pgadapter/statements/BackendConnection.java](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#diff-c3JjL21haW4vamF2YS9jb20vZ29vZ2xlL2Nsb3VkL3NwYW5uZXIvcGdhZGFwdGVyL3N0YXRlbWVudHMvQmFja2VuZENvbm5lY3Rpb24uamF2YQ==) | `90.40% <100.00%> (+0.02%)` | :arrow_up: |
| [...apter/statements/local/ListDatabasesStatement.java](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#diff-c3JjL21haW4vamF2YS9jb20vZ29vZ2xlL2Nsb3VkL3NwYW5uZXIvcGdhZGFwdGVyL3N0YXRlbWVudHMvbG9jYWwvTGlzdERhdGFiYXNlc1N0YXRlbWVudC5qYXZh) | `100.00% <100.00%> (ø)` | |
| [...statements/local/SelectCurrentSchemaStatement.java](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#diff-c3JjL21haW4vamF2YS9jb20vZ29vZ2xlL2Nsb3VkL3NwYW5uZXIvcGdhZGFwdGVyL3N0YXRlbWVudHMvbG9jYWwvU2VsZWN0Q3VycmVudFNjaGVtYVN0YXRlbWVudC5qYXZh) | `100.00% <100.00%> (ø)` | |
| [...ud/spanner/pgadapter/utils/ClientAutoDetector.java](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#diff-c3JjL21haW4vamF2YS9jb20vZ29vZ2xlL2Nsb3VkL3NwYW5uZXIvcGdhZGFwdGVyL3V0aWxzL0NsaWVudEF1dG9EZXRlY3Rvci5qYXZh) | `97.43% <100.00%> (+0.76%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform). Last update [78dac56...82129e0](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/273?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform).


Patch:
diff --git a/clirr-ignored-differences.xml b/clirr-ignored-differences.xml
index bcf56385..1a609e8d 100644
--- a/clirr-ignored-differences.xml
+++ b/clirr-ignored-differences.xml
@@ -19,6 +19,36 @@
     <className>com/google/cloud/spanner/pgadapter/parsers/copy/Copy</className>
     <method>void copyFrom()</method>
   </difference>
+  <!-- Changed to BackendConnection. This is only for internal use. -->
+  <difference>
+    <differenceType>7005</differenceType>
+    <className>com/google/cloud/spanner/pgadapter/statements/local/LocalStatement</className>
+    <method>com.google.cloud.spanner.connection.StatementResult execute(com.google.cloud.spanner.connection.Connection)</method>
+    <to>com.google.cloud.spanner.connection.StatementResult execute(com.google.cloud.spanner.pgadapter.statements.BackendConnection)</to>
+  </difference>
+  <!-- Return type changed to String[]. This is only for internal use. -->
+  <difference>
+    <differenceType>7006</differenceType>
+    <className>com/google/cloud/spanner/pgadapter/statements/local/LocalStatement</className>
+    <method>java.lang.String getSql()</method>
+    <from>java.lang.String</from>
+    <to>java.lang.String[]</to>
+  </difference>
+  <!-- Changed to BackendConnection. This is only for internal use. -->
+  <difference>
+    <differenceType>7005</differenceType>
+    <className>com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatement</className>
+    <method>com.google.cloud.spanner.connection.StatementResult execute(com.google.cloud.spanner.connection.Connection)</method>
+    <to>com.google.cloud.spanner.connection.StatementResult execute(com.google.cloud.spanner.pgadapter.statements.BackendConnection)</to>
+  </difference>
+  <!-- Return type changed to String[]. This is only for internal use. -->
+  <difference>
+    <differenceType>7006</differenceType>
+    <className>com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatement</className>
+    <method>java.lang.String getSql()</method>
+    <from>java.lang.String</from>
+    <to>java.lang.String[]</to>
+  </difference>
 
   <!-- Add ignores for all sub packages, as these are considered internal. -->
   <difference>
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java b/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java
index 626be410..eaa1b91d 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java
@@ -77,6 +77,8 @@ public class OptionsMetadata {
   private static final String OPTION_BINARY_FORMAT = "b";
   private static final String OPTION_AUTHENTICATE = "a";
   private static final String OPTION_DISABLE_AUTO_DETECT_CLIENT = "disable_auto_detect_client";
+  private static final String OPTION_DISABLE_DEFAULT_LOCAL_STATEMENTS =
+      "disable_default_local_statements";
   private static final String OPTION_PSQL_MODE = "q";
   private static final String OPTION_DDL_TRANSACTION_MODE = "ddl";
   private static final String OPTION_JDBC_MODE = "jdbc";
@@ -107,6 +109,7 @@ public class OptionsMetadata {
   private final boolean binaryFormat;
   private final boolean authenticate;
   private final boolean disableAutoDetectClient;
+  private final boolean disableDefaultLocalStatements;
   private final boolean requiresMatcher;
   private final DdlTransactionMode ddlTransactionMode;
   private final boolean replaceJdbcMetadataQueries;
@@ -157,6 +160,8 @@ public class OptionsMetadata {
     this.binaryFormat = commandLine.hasOption(OPTION_BINARY_FORMAT);
     this.authenticate = commandLine.hasOption(OPTION_AUTHENTICATE);
     this.disableAutoDetectClient = commandLine.hasOption(OPTION_DISABLE_AUTO_DETECT_CLIENT);
+    this.disableDefaultLocalStatements =
+        commandLine.hasOption(OPTION_DISABLE_DEFAULT_LOCAL_STATEMENTS);
     this.requiresMatcher =
         commandLine.hasOption(OPTION_PSQL_MODE)
             || commandLine.hasOption(OPTION_COMMAND_METADATA_FILE);
@@ -212,6 +217,7 @@ public class OptionsMetadata {
     this.binaryFormat = forceBinary;
     this.authenticate = authenticate;
     this.disableAutoDetectClient = false;
+    this.disableDefaultLocalStatements = false;
     this.requiresMatcher = requiresMatcher;
     this.ddlTransactionMode = DdlTransactionMode.AutocommitImplicitTransaction;
     this.replaceJdbcMetadataQueries = replaceJdbcMetadataQueries;
@@ -502,6 +508,14 @@ public class OptionsMetadata {
         "This option turns off automatic detection of well-known clients. "
             + "Use this option if you do not want PGAdapter to automatically apply query "
             + "replacements based on the client that is connected to PGAdapter.");
+    options.addOption(
+        null,
+        OPTION_DISABLE_DEFAULT_LOCAL_STATEMENTS,
+        false,
+        "This option turns off translations for commonly used statements that are "
+            + "currently not supported by Cloud Spanner (e.g. `select current_schema`). "
+            + "Use this option if you do not want PGAdapter to automatically apply query "
+            + "replacements for these statements.");
     options.addOption(
         OPTION_PSQL_MODE,
         "psql-mode",
@@ -726,6 +740,10 @@ public class OptionsMetadata {
     return !this.disableAutoDetectClient;
   }
 
+  public boolean useDefaultLocalStatements() {
+    return !this.disableDefaultLocalStatements;
+  }
+
   public boolean requiresMatcher() {
     return this.requiresMatcher;
   }
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/BackendConnection.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/BackendConnection.java
index 0d1463eb..4ce6ffe4 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/BackendConnection.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/BackendConnection.java
@@ -42,6 +42,7 @@ import com.google.cloud.spanner.connection.Connection;
 import com.google.cloud.spanner.connection.ConnectionOptionsHelper;
 import com.google.cloud.spanner.connection.StatementResult;
 import com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType;
+import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata;
 import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata.DdlTransactionMode;
 import com.google.cloud.spanner.pgadapter.statements.DdlExecutor.NotExecuted;
 import com.google.cloud.spanner.pgadapter.statements.local.LocalStatement;
@@ -54,6 +55,7 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
@@ -161,7 +163,7 @@ public class BackendConnection {
         if (!localStatements.isEmpty() && localStatements.containsKey(statement.getSql())) {
           result.set(
               Objects.requireNonNull(localStatements.get(statement.getSql()))
-                  .execute(spannerConnection));
+                  .execute(BackendConnection.this));
         } else if (connectionState == ConnectionState.ABORTED
             && !spannerConnection.isInTransaction()
             && (isRollback(parsedStatement) || isCommit(parsedStatement))) {
@@ -305,7 +307,7 @@ public class BackendConnection {
   private final Connection spannerConnection;
   private final DatabaseId databaseId;
   private final DdlExecutor ddlExecutor;
-  private final DdlTransactionMode ddlTransactionMode;
+  private final OptionsMetadata optionsMetadata;
 
   /**
    * Creates a PG backend connection that uses the given Spanner {@link Connection} and {@link
@@ -314,22 +316,23 @@ public class BackendConnection {
   BackendConnection(
       DatabaseId databaseId,
       Connection spannerConnection,
-      DdlTransactionMode ddlTransactionMode,
+      OptionsMetadata optionsMetadata,
       ImmutableList<LocalStatement> localStatements) {
     this.spannerConnection = spannerConnection;
     this.databaseId = databaseId;
     this.ddlExecutor = new DdlExecutor(databaseId, this);
-    this.ddlTransactionMode = ddlTransactionMode;
-    //noinspection UnstableApiUsage
-    this.localStatements =
-        localStatements.isEmpty()
-            ? EMPTY_LOCAL_STATEMENTS
-            : ImmutableMap.copyOf(
-                localStatements.stream()
-                    .map(
-                        localStatement ->
-                            new SimpleImmutableEntry<>(localStatement.getSql(), localStatement))
-                    .collect(Collectors.toList()));
+    this.optionsMetadata = optionsMetadata;
+    if (localStatements.isEmpty()) {
+      this.localStatements = EMPTY_LOCAL_STATEMENTS;
+    } else {
+      Builder<String, LocalStatement> builder = ImmutableMap.builder();
+      for (LocalStatement localStatement : localStatements) {
+        for (String sql : localStatement.getSql()) {
+          builder.put(new SimpleImmutableEntry<>(sql, localStatement));
+        }
+      }
+      this.localStatements = builder.build();
+    }
   }
 
   /** Returns the current connection state. */
@@ -388,14 +391,26 @@ public class BackendConnection {
     }
   }
 
-  Connection getSpannerConnection() {
+  /** Returns the Spanner connection used by this {@link BackendConnection}. */
+  public Connection getSpannerConnection() {
     return this.spannerConnection;
   }
 
-  String getCurrentSchema() {
+  /** Returns the current schema that is used by this {@link BackendConnection}. */
+  public String getCurrentSchema() {
     return this.currentSchema;
   }
 
+  /** Returns the id of the database that this connection uses. */
+  public String getCurrentDatabase() {
+    return this.databaseId.getDatabase();
+  }
+
+  /** Returns the options that are used for this connection. */
+  public OptionsMetadata getOptionsMetadata() {
+    return this.optionsMetadata;
+  }
+
   /**
    * Flushes all buffered statements to Cloud Spanner and commits/rolls back the transaction at the
    * end if isSync=true.
@@ -512,6 +527,7 @@ public class BackendConnection {
    * allowed.
    */
   private void prepareExecuteDdl(BufferedStatement<?> bufferedStatement) {
+    DdlTransactionMode ddlTransactionMode = this.optionsMetadata.getDdlTransactionMode();
     try {
       // Single statements are simpler to check, so we do that in a separate check.
       if (bufferedStatements.size() == 1) {
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/ExtendedQueryProtocolHandler.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/ExtendedQueryProtocolHandler.java
index 861d02bf..5fb0626c 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/ExtendedQueryProtocolHandler.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/ExtendedQueryProtocolHandler.java
@@ -14,13 +14,9 @@
 
 package com.google.cloud.spanner.pgadapter.statements;
 
-import static com.google.cloud.spanner.pgadapter.utils.ClientAutoDetector.EMPTY_LOCAL_STATEMENTS;
-
 import com.google.cloud.spanner.pgadapter.ConnectionHandler;
-import com.google.cloud.spanner.pgadapter.statements.local.LocalStatement;
 import com.google.cloud.spanner.pgadapter.wireprotocol.AbstractQueryProtocolMessage;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
@@ -35,16 +31,12 @@ public class ExtendedQueryProtocolHandler {
 
   /** Creates an {@link ExtendedQueryProtocolHandler} for the given connection. */
   public ExtendedQueryProtocolHandler(ConnectionHandler connectionHandler) {
-    ImmutableList<LocalStatement> localStatements =
-        connectionHandler.getWellKnownClient() == null
-            ? EMPTY_LOCAL_STATEMENTS
-            : connectionHandler.getWellKnownClient().getLocalStatements(connectionHandler);
     this.backendConnection =
         new BackendConnection(
             connectionHandler.getDatabaseId(),
             connectionHandler.getSpannerConnection(),
-            connectionHandler.getServer().getOptions().getDdlTransactionMode(),
-            localStatements);
+            connectionHandler.getServer().getOptions(),
+            connectionHandler.getWellKnownClient().getLocalStatements(connectionHandler));
   }
 
   /** Constructor only intended for testing. */
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatement.java
index 2f304223..d9f18960 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatement.java
@@ -29,6 +29,7 @@ import com.google.cloud.spanner.connection.Connection;
 import com.google.cloud.spanner.connection.ConnectionOptionsHelper;
 import com.google.cloud.spanner.connection.StatementResult;
 import com.google.cloud.spanner.pgadapter.ConnectionHandler;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
 import com.google.cloud.spanner.pgadapter.statements.BackendConnection.QueryResult;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -62,12 +63,13 @@ public class ListDatabasesStatement implements LocalStatement {
   }
 
   @Override
-  public String getSql() {
-    return LIST_DATABASES_SQL;
+  public String[] getSql() {
+    return new String[] {LIST_DATABASES_SQL};
   }
 
   @Override
-  public StatementResult execute(Connection connection) {
+  public StatementResult execute(BackendConnection backendConnection) {
+    Connection connection = backendConnection.getSpannerConnection();
     Spanner spanner = ConnectionOptionsHelper.getSpanner(connection);
     InstanceId defaultInstanceId =
         connectionHandler.getServer().getOptions().getDefaultInstanceId();
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/LocalStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/LocalStatement.java
index 7a5e3760..7e853b4e 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/LocalStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/LocalStatement.java
@@ -14,17 +14,24 @@
 
 package com.google.cloud.spanner.pgadapter.statements.local;
 
-import com.google.cloud.spanner.connection.Connection;
 import com.google.cloud.spanner.connection.StatementResult;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
 
 /**
  * Interface for statements that are handled locally in PGAdapter instead of being sent to
  * Connection API.
  */
 public interface LocalStatement {
-  /** Returns the static SQL string associated with this local statement. */
-  String getSql();
+  /**
+   * Returns the static SQL string associated with this local statement. A statement should include
+   * a SQL statement for each variant that can reasonably be expected to be generated by a
+   * framework, but does not need to include a variant for each theoretically possible variant. The
+   * given SQL strings will be used as the keys in a {@link java.util.Map} for quick lookup. This
+   * means that it will not match all possible variants of the statement, which is OK, as this is
+   * only intended to cover auto-generated query strings from frameworks/tools.
+   */
+  String[] getSql();
 
   /** Executes the local statement and returns the result. */
-  StatementResult execute(Connection connection);
+  StatementResult execute(BackendConnection backendConnection);
 }
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentCatalogStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentCatalogStatement.java
new file mode 100644
index 00000000..aabbfdfe
--- /dev/null
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentCatalogStatement.java
@@ -0,0 +1,64 @@
+// Copyright 2022 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.pgadapter.statements.local;
+
+import com.google.api.core.InternalApi;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.ResultSets;
+import com.google.cloud.spanner.Struct;
+import com.google.cloud.spanner.Type;
+import com.google.cloud.spanner.Type.StructField;
+import com.google.cloud.spanner.connection.StatementResult;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection.QueryResult;
+import com.google.common.collect.ImmutableList;
+
+@InternalApi
+public class SelectCurrentCatalogStatement implements LocalStatement {
+  public static final SelectCurrentCatalogStatement INSTANCE = new SelectCurrentCatalogStatement();
+
+  private SelectCurrentCatalogStatement() {}
+
+  @Override
+  public String[] getSql() {
+    return new String[] {
+      "select current_catalog",
+      "SELECT current_catalog",
+      "Select current_catalog",
+      "select CURRENT_CATALOG",
+      "SELECT CURRENT_CATALOG",
+      "Select CURRENT_CATALOG",
+      "select * from current_catalog",
+      "SELECT * FROM current_catalog",
+      "Select * from current_catalog",
+      "select * from CURRENT_CATALOG",
+      "SELECT * FROM CURRENT_CATALOG",
+      "Select * from CURRENT_CATALOG"
+    };
+  }
+
+  @Override
+  public StatementResult execute(BackendConnection backendConnection) {
+    ResultSet resultSet =
+        ResultSets.forRows(
+            Type.struct(StructField.of("current_catalog", Type.string())),
+            ImmutableList.of(
+                Struct.newBuilder()
+                    .set("current_catalog")
+                    .to(backendConnection.getCurrentDatabase())
+                    .build()));
+    return new QueryResult(resultSet);
+  }
+}
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentDatabaseStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentDatabaseStatement.java
new file mode 100644
index 00000000..2eefe9c3
--- /dev/null
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentDatabaseStatement.java
@@ -0,0 +1,65 @@
+// Copyright 2022 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.pgadapter.statements.local;
+
+import com.google.api.core.InternalApi;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.ResultSets;
+import com.google.cloud.spanner.Struct;
+import com.google.cloud.spanner.Type;
+import com.google.cloud.spanner.Type.StructField;
+import com.google.cloud.spanner.connection.StatementResult;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection.QueryResult;
+import com.google.common.collect.ImmutableList;
+
+@InternalApi
+public class SelectCurrentDatabaseStatement implements LocalStatement {
+  public static final SelectCurrentDatabaseStatement INSTANCE =
+      new SelectCurrentDatabaseStatement();
+
+  private SelectCurrentDatabaseStatement() {}
+
+  @Override
+  public String[] getSql() {
+    return new String[] {
+      "select current_database()",
+      "SELECT current_database()",
+      "Select current_database()",
+      "select CURRENT_DATABASE()",
+      "SELECT CURRENT_DATABASE()",
+      "Select CURRENT_DATABASE()",
+      "select * from current_database()",
+      "SELECT * FROM current_database()",
+      "Select * FROM current_database()",
+      "select * from CURRENT_DATABASE()",
+      "SELECT * FROM CURRENT_DATABASE()",
+      "Select * FROM CURRENT_DATABASE()",
+    };
+  }
+
+  @Override
+  public StatementResult execute(BackendConnection backendConnection) {
+    ResultSet resultSet =
+        ResultSets.forRows(
+            Type.struct(StructField.of("current_database", Type.string())),
+            ImmutableList.of(
+                Struct.newBuilder()
+                    .set("current_database")
+                    .to(backendConnection.getCurrentDatabase())
+                    .build()));
+    return new QueryResult(resultSet);
+  }
+}
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentSchemaStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentSchemaStatement.java
new file mode 100644
index 00000000..bba360e0
--- /dev/null
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentSchemaStatement.java
@@ -0,0 +1,62 @@
+// Copyright 2022 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.pgadapter.statements.local;
+
+import com.google.api.core.InternalApi;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.ResultSets;
+import com.google.cloud.spanner.Struct;
+import com.google.cloud.spanner.Type;
+import com.google.cloud.spanner.Type.StructField;
+import com.google.cloud.spanner.connection.StatementResult;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection.QueryResult;
+import com.google.common.collect.ImmutableList;
+
+@InternalApi
+public class SelectCurrentSchemaStatement implements LocalStatement {
+  public static final SelectCurrentSchemaStatement INSTANCE = new SelectCurrentSchemaStatement();
+
+  private SelectCurrentSchemaStatement() {}
+
+  @Override
+  public String[] getSql() {
+    return new String[] {
+      "select current_schema()",
+      "SELECT current_schema()",
+      "Select current_schema()",
+      "select current_schema",
+      "SELECT current_schema",
+      "Select current_schema",
+      "select * from current_schema()",
+      "SELECT * FROM current_schema()",
+      "select * from current_schema",
+      "SELECT * FROM current_schema"
+    };
+  }
+
+  @Override
+  public StatementResult execute(BackendConnection backendConnection) {
+    ResultSet resultSet =
+        ResultSets.forRows(
+            Type.struct(StructField.of("current_schema", Type.string())),
+            ImmutableList.of(
+                Struct.newBuilder()
+                    .set("current_schema")
+                    .to(backendConnection.getCurrentSchema())
+                    .build()));
+    return new QueryResult(resultSet);
+  }
+}
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/ShowServerVersionStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/ShowServerVersionStatement.java
new file mode 100644
index 00000000..abf96f23
--- /dev/null
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/ShowServerVersionStatement.java
@@ -0,0 +1,51 @@
+// Copyright 2022 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.pgadapter.statements.local;
+
+import com.google.api.core.InternalApi;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.ResultSets;
+import com.google.cloud.spanner.Struct;
+import com.google.cloud.spanner.Type;
+import com.google.cloud.spanner.Type.StructField;
+import com.google.cloud.spanner.connection.StatementResult;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection.QueryResult;
+import com.google.common.collect.ImmutableList;
+
+@InternalApi
+public class ShowServerVersionStatement implements LocalStatement {
+  public static final ShowServerVersionStatement INSTANCE = new ShowServerVersionStatement();
+
+  private ShowServerVersionStatement() {}
+
+  @Override
+  public String[] getSql() {
+    return new String[] {"show server_version", "SHOW server_version", "SHOW SERVER_VERSION"};
+  }
+
+  @Override
+  public StatementResult execute(BackendConnection backendConnection) {
+    ResultSet resultSet =
+        ResultSets.forRows(
+            Type.struct(StructField.of("server_version", Type.string())),
+            ImmutableList.of(
+                Struct.newBuilder()
+                    .set("server_version")
+                    .to(backendConnection.getOptionsMetadata().getServerVersion())
+                    .build()));
+    return new QueryResult(resultSet);
+  }
+}
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetector.java b/src/main/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetector.java
index 404d9661..77e26dbd 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetector.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetector.java
@@ -18,9 +18,14 @@ import com.google.api.core.InternalApi;
 import com.google.cloud.spanner.pgadapter.ConnectionHandler;
 import com.google.cloud.spanner.pgadapter.statements.local.ListDatabasesStatement;
 import com.google.cloud.spanner.pgadapter.statements.local.LocalStatement;
+import com.google.cloud.spanner.pgadapter.statements.local.SelectCurrentCatalogStatement;
+import com.google.cloud.spanner.pgadapter.statements.local.SelectCurrentDatabaseStatement;
+import com.google.cloud.spanner.pgadapter.statements.local.SelectCurrentSchemaStatement;
+import com.google.cloud.spanner.pgadapter.statements.local.ShowServerVersionStatement;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Nonnull;
 
 /**
  * Utility class that tries to automatically detect well-known clients and drivers that are
@@ -29,6 +34,12 @@ import java.util.Map;
 @InternalApi
 public class ClientAutoDetector {
   public static final ImmutableList<LocalStatement> EMPTY_LOCAL_STATEMENTS = ImmutableList.of();
+  public static final ImmutableList<LocalStatement> DEFAULT_LOCAL_STATEMENTS =
+      ImmutableList.of(
+          SelectCurrentSchemaStatement.INSTANCE,
+          SelectCurrentDatabaseStatement.INSTANCE,
+          SelectCurrentCatalogStatement.INSTANCE,
+          ShowServerVersionStatement.INSTANCE);
 
   public enum WellKnownClient {
     PSQL {
@@ -42,6 +53,12 @@ public class ClientAutoDetector {
 
       @Override
       public ImmutableList<LocalStatement> getLocalStatements(ConnectionHandler connectionHandler) {
+        if (connectionHandler.getServer().getOptions().useDefaultLocalStatements()) {
+          return ImmutableList.<LocalStatement>builder()
+              .addAll(DEFAULT_LOCAL_STATEMENTS)
+              .add(new ListDatabasesStatement(connectionHandler))
+              .build();
+        }
         return ImmutableList.of(new ListDatabasesStatement(connectionHandler));
       }
     },
@@ -85,26 +102,39 @@ public class ClientAutoDetector {
         // pgx does not send enough unique parameters for it to be auto-detected.
         return false;
       }
+    },
+    UNSPECIFIED {
+      @Override
+      boolean isClient(List<String> orderedParameterKeys, Map<String, String> parameters) {
+        // Use UNSPECIFIED as default to prevent null checks everywhere and to ease the use of any
+        // defaults defined in this enum.
+        return true;
+      }
     };
 
     abstract boolean isClient(List<String> orderedParameterKeys, Map<String, String> parameters);
 
     public ImmutableList<LocalStatement> getLocalStatements(ConnectionHandler connectionHandler) {
+      if (connectionHandler.getServer().getOptions().useDefaultLocalStatements()) {
+        return DEFAULT_LOCAL_STATEMENTS;
+      }
       return EMPTY_LOCAL_STATEMENTS;
     }
   }
 
   /**
    * Returns the {@link WellKnownClient} that the detector thinks is connecting to PGAdapter based
-   * purely on the list of parameters.
+   * purely on the list of parameters. It will return UNSPECIFIED if no specific client could be
+   * determined.
    */
-  public static WellKnownClient detectClient(
+  public static @Nonnull WellKnownClient detectClient(
       List<String> orderParameterKeys, Map<String, String> parameters) {
     for (WellKnownClient client : WellKnownClient.values()) {
       if (client.isClient(orderParameterKeys, parameters)) {
         return client;
       }
     }
-    return null;
+    // The following line should never be reached.
+    throw new IllegalStateException("UNSPECIFIED.isClient() should have returned true");
   }
 }
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/StartupMessage.java b/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/StartupMessage.java
index 787a74bc..23826301 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/StartupMessage.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/StartupMessage.java
@@ -50,15 +50,17 @@ public class StartupMessage extends BootstrapMessage {
     if (connection.getServer().getOptions().shouldAutoDetectClient()) {
       WellKnownClient wellKnownClient =
           ClientAutoDetector.detectClient(this.parseParameterKeys(rawParameters), this.parameters);
-      if (wellKnownClient != null) {
+      connection.setWellKnownClient(wellKnownClient);
+      if (wellKnownClient != WellKnownClient.UNSPECIFIED) {
         logger.log(
             Level.INFO,
             () ->
                 String.format(
                     "Well-known client %s detected for connection %d.",
                     wellKnownClient, connection.getConnectionId()));
-        connection.setWellKnownClient(wellKnownClient);
       }
+    } else {
+      connection.setWellKnownClient(WellKnownClient.UNSPECIFIED);
     }
   }
 


Test patch:
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/ITJdbcTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/ITJdbcTest.java
index 9975ae86..fa2c0120 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/ITJdbcTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/ITJdbcTest.java
@@ -160,6 +160,18 @@ public class ITJdbcTest implements IntegrationTest {
     }
   }
 
+  @Test
+  public void testSelectCurrentSchema() throws SQLException {
+    try (Connection connection = DriverManager.getConnection(getConnectionUrl())) {
+      try (ResultSet resultSet =
+          connection.createStatement().executeQuery("select current_schema()")) {
+        assertTrue(resultSet.next());
+        assertEquals("public", resultSet.getString(1));
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
   @Test
   public void testCreateTableIfNotExists() throws SQLException {
     try (Connection connection = DriverManager.getConnection(getConnectionUrl())) {
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/JdbcMockServerTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/JdbcMockServerTest.java
index f268235f..27975c86 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/JdbcMockServerTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/JdbcMockServerTest.java
@@ -123,6 +123,81 @@ public class JdbcMockServerTest extends AbstractMockServerTest {
     }
   }
 
+  @Test
+  public void testSelectCurrentSchema() throws SQLException {
+    String sql = "SELECT current_schema";
+
+    try (Connection connection = DriverManager.getConnection(createUrl())) {
+      try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
+        assertTrue(resultSet.next());
+        assertEquals("public", resultSet.getString("current_schema"));
+        assertFalse(resultSet.next());
+      }
+    }
+
+    // The statement is handled locally and not sent to Cloud Spanner.
+    assertEquals(0, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+  }
+
+  @Test
+  public void testSelectCurrentDatabase() throws SQLException {
+    for (String sql :
+        new String[] {
+          "SELECT current_database()",
+          "select current_database()",
+          "select * from CURRENT_DATABASE()"
+        }) {
+
+      try (Connection connection = DriverManager.getConnection(createUrl())) {
+        try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
+          assertTrue(resultSet.next());
+          assertEquals("d", resultSet.getString("current_database"));
+          assertFalse(resultSet.next());
+        }
+      }
+    }
+
+    // The statement is handled locally and not sent to Cloud Spanner.
+    assertEquals(0, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+  }
+
+  @Test
+  public void testSelectCurrentCatalog() throws SQLException {
+    for (String sql :
+        new String[] {
+          "SELECT current_catalog", "select current_catalog", "select * from CURRENT_CATALOG"
+        }) {
+
+      try (Connection connection = DriverManager.getConnection(createUrl())) {
+        try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
+          assertTrue(resultSet.next());
+          assertEquals("d", resultSet.getString("current_catalog"));
+          assertFalse(resultSet.next());
+        }
+      }
+    }
+
+    // The statement is handled locally and not sent to Cloud Spanner.
+    assertEquals(0, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+  }
+
+  @Test
+  public void testShowServerVersion() throws SQLException {
+    String sql = "show server_version";
+
+    try (Connection connection = DriverManager.getConnection(createUrl())) {
+      try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
+        assertTrue(resultSet.next());
+        assertEquals(
+            pgServer.getOptions().getServerVersion(), resultSet.getString("server_version"));
+        assertFalse(resultSet.next());
+      }
+    }
+
+    // The statement is handled locally and not sent to Cloud Spanner.
+    assertEquals(0, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+  }
+
   @Test
   public void testQueryHint() throws SQLException {
     String sql = "/* @OPTIMIZER_VERSION=1 */ SELECT 1";
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/BackendConnectionTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/BackendConnectionTest.java
index f1636edd..9f283d16 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/statements/BackendConnectionTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/BackendConnectionTest.java
@@ -37,7 +37,7 @@ import com.google.cloud.spanner.connection.AbstractStatementParser.ParsedStateme
 import com.google.cloud.spanner.connection.Connection;
 import com.google.cloud.spanner.connection.StatementResult;
 import com.google.cloud.spanner.connection.StatementResult.ResultType;
-import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata.DdlTransactionMode;
+import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata;
 import com.google.cloud.spanner.pgadapter.statements.BackendConnection.NoResult;
 import com.google.cloud.spanner.pgadapter.statements.BackendConnection.QueryResult;
 import com.google.cloud.spanner.pgadapter.statements.DdlExecutor.NotExecuted;
@@ -128,7 +128,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     Future<StatementResult> result =
         backendConnection.executeCopy(parsedStatement, statement, receiver, writer, executor);
@@ -165,7 +165,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     onlyDmlStatements.execute(parsedUpdateStatement, updateStatement);
     onlyDmlStatements.execute(parsedUpdateStatement, updateStatement);
@@ -176,7 +176,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     onlyCopyStatements.executeCopy(parsedCopyStatement, copyStatement, receiver, writer, executor);
     onlyCopyStatements.executeCopy(parsedCopyStatement, copyStatement, receiver, writer, executor);
@@ -187,7 +187,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     dmlAndCopyStatements.execute(parsedUpdateStatement, updateStatement);
     dmlAndCopyStatements.executeCopy(
@@ -199,7 +199,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     onlySelectStatements.execute(parsedSelectStatement, selectStatement);
     onlySelectStatements.execute(parsedSelectStatement, selectStatement);
@@ -210,7 +210,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     onlyClientSideStatements.execute(parsedClientSideStatement, clientSideStatement);
     onlyClientSideStatements.execute(parsedClientSideStatement, clientSideStatement);
@@ -221,7 +221,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     onlyUnknownStatements.execute(parsedUnknownStatement, unknownStatement);
     onlyUnknownStatements.execute(parsedUnknownStatement, unknownStatement);
@@ -232,7 +232,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     dmlAndSelectStatements.execute(parsedUpdateStatement, updateStatement);
     dmlAndSelectStatements.execute(parsedSelectStatement, selectStatement);
@@ -243,7 +243,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     copyAndSelectStatements.executeCopy(
         parsedCopyStatement, copyStatement, receiver, writer, executor);
@@ -255,7 +255,7 @@ public class BackendConnectionTest {
         new BackendConnection(
             DatabaseId.of("p", "i", "d"),
             spannerConnection,
-            DdlTransactionMode.Batch,
+            mock(OptionsMetadata.class),
             ImmutableList.of());
     copyAndUnknownStatements.executeCopy(
         parsedCopyStatement, copyStatement, receiver, writer, executor);
@@ -270,8 +270,10 @@ public class BackendConnectionTest {
     StatementResult listDatabasesResult = mock(StatementResult.class);
     when(listDatabasesResult.getResultType()).thenReturn(ResultType.RESULT_SET);
     ListDatabasesStatement listDatabasesStatement = mock(ListDatabasesStatement.class);
-    when(listDatabasesStatement.getSql()).thenReturn(ListDatabasesStatement.LIST_DATABASES_SQL);
-    when(listDatabasesStatement.execute(connection)).thenReturn(listDatabasesResult);
+    when(listDatabasesStatement.getSql())
+        .thenReturn(new String[] {ListDatabasesStatement.LIST_DATABASES_SQL});
+    when(listDatabasesStatement.execute(any(BackendConnection.class)))
+        .thenReturn(listDatabasesResult);
     ImmutableList<LocalStatement> localStatements = ImmutableList.of(listDatabasesStatement);
     ParsedStatement parsedListDatabasesStatement = mock(ParsedStatement.class);
     when(parsedListDatabasesStatement.getSqlWithoutComments())
@@ -279,13 +281,13 @@ public class BackendConnectionTest {
 
     BackendConnection backendConnection =
         new BackendConnection(
-            DatabaseId.of("p", "i", "d"), connection, DdlTransactionMode.Batch, localStatements);
+            DatabaseId.of("p", "i", "d"), connection, mock(OptionsMetadata.class), localStatements);
     Future<StatementResult> resultFuture =
         backendConnection.execute(
             parsedListDatabasesStatement, Statement.of(ListDatabasesStatement.LIST_DATABASES_SQL));
     backendConnection.flush();
 
-    verify(listDatabasesStatement).execute(connection);
+    verify(listDatabasesStatement).execute(backendConnection);
     assertTrue(resultFuture.isDone());
     assertEquals(listDatabasesResult, resultFuture.get());
   }
@@ -295,7 +297,8 @@ public class BackendConnectionTest {
       throws ExecutionException, InterruptedException {
     Connection connection = mock(Connection.class);
     ListDatabasesStatement listDatabasesStatement = mock(ListDatabasesStatement.class);
-    when(listDatabasesStatement.getSql()).thenReturn(ListDatabasesStatement.LIST_DATABASES_SQL);
+    when(listDatabasesStatement.getSql())
+        .thenReturn(new String[] {ListDatabasesStatement.LIST_DATABASES_SQL});
     ImmutableList<LocalStatement> localStatements = ImmutableList.of(listDatabasesStatement);
 
     StatementResult statementResult = mock(StatementResult.class);
@@ -308,11 +311,11 @@ public class BackendConnectionTest {
 
     BackendConnection backendConnection =
         new BackendConnection(
-            DatabaseId.of("p", "i", "d"), connection, DdlTransactionMode.Batch, localStatements);
+            DatabaseId.of("p", "i", "d"), connection, mock(OptionsMetadata.class), localStatements);
     Future<StatementResult> resultFuture = backendConnection.execute(parsedStatement, statement);
     backendConnection.flush();
 
-    verify(listDatabasesStatement, never()).execute(connection);
+    verify(listDatabasesStatement, never()).execute(backendConnection);
     assertTrue(resultFuture.isDone());
     assertEquals(statementResult, resultFuture.get());
   }
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/StatementTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/StatementTest.java
index 1dc80753..78c6be11 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/statements/StatementTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/StatementTest.java
@@ -45,7 +45,6 @@ import com.google.cloud.spanner.pgadapter.ConnectionHandler;
 import com.google.cloud.spanner.pgadapter.ProxyServer;
 import com.google.cloud.spanner.pgadapter.metadata.ConnectionMetadata;
 import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata;
-import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata.DdlTransactionMode;
 import com.google.cloud.spanner.pgadapter.utils.MutationWriter;
 import com.google.cloud.spanner.pgadapter.wireprotocol.ControlMessage;
 import com.google.cloud.spanner.pgadapter.wireprotocol.QueryMessage;
@@ -174,10 +173,7 @@ public class StatementTest {
             connectionHandler, options, "", parse(sql), Statement.of(sql));
     BackendConnection backendConnection =
         new BackendConnection(
-            connectionHandler.getDatabaseId(),
-            connection,
-            DdlTransactionMode.Batch,
-            EMPTY_LOCAL_STATEMENTS);
+            connectionHandler.getDatabaseId(), connection, options, EMPTY_LOCAL_STATEMENTS);
 
     assertFalse(intermediateStatement.isExecuted());
     assertEquals("UPDATE", intermediateStatement.getCommand());
@@ -253,10 +249,7 @@ public class StatementTest {
             connectionHandler, options, "", parse(sql), Statement.of(sql));
     BackendConnection backendConnection =
         new BackendConnection(
-            connectionHandler.getDatabaseId(),
-            connection,
-            DdlTransactionMode.Batch,
-            EMPTY_LOCAL_STATEMENTS);
+            connectionHandler.getDatabaseId(), connection, options, EMPTY_LOCAL_STATEMENTS);
 
     intermediateStatement.executeAsync(backendConnection);
     backendConnection.flush();
@@ -283,10 +276,7 @@ public class StatementTest {
             .build();
     BackendConnection backendConnection =
         new BackendConnection(
-            connectionHandler.getDatabaseId(),
-            connection,
-            DdlTransactionMode.Batch,
-            EMPTY_LOCAL_STATEMENTS);
+            connectionHandler.getDatabaseId(), connection, options, EMPTY_LOCAL_STATEMENTS);
 
     IntermediatePreparedStatement intermediateStatement =
         new IntermediatePreparedStatement(
@@ -357,10 +347,7 @@ public class StatementTest {
             connectionHandler, options, "", parse(sqlStatement), Statement.of(sqlStatement));
     BackendConnection backendConnection =
         new BackendConnection(
-            connectionHandler.getDatabaseId(),
-            connection,
-            DdlTransactionMode.Batch,
-            EMPTY_LOCAL_STATEMENTS);
+            connectionHandler.getDatabaseId(), connection, options, EMPTY_LOCAL_STATEMENTS);
 
     intermediateStatement.describeAsync(backendConnection);
     backendConnection.flush();
@@ -406,10 +393,7 @@ public class StatementTest {
             connectionHandler, options, "", parse(sqlStatement), Statement.of(sqlStatement));
     BackendConnection backendConnection =
         new BackendConnection(
-            connectionHandler.getDatabaseId(),
-            connection,
-            DdlTransactionMode.Batch,
-            EMPTY_LOCAL_STATEMENTS);
+            connectionHandler.getDatabaseId(), connection, options, EMPTY_LOCAL_STATEMENTS);
 
     when(connection.execute(Statement.of(sqlStatement)))
         .thenThrow(
@@ -462,7 +446,7 @@ public class StatementTest {
 
     BackendConnection backendConnection =
         new BackendConnection(
-            DatabaseId.of("p", "i", "d"), connection, DdlTransactionMode.Batch, ImmutableList.of());
+            DatabaseId.of("p", "i", "d"), connection, options, ImmutableList.of());
     statement.executeAsync(backendConnection);
 
     byte[] payload = "2 3\n".getBytes();
@@ -520,10 +504,7 @@ public class StatementTest {
             connectionHandler, options, "", parse(sql), Statement.of(sql));
     BackendConnection backendConnection =
         new BackendConnection(
-            connectionHandler.getDatabaseId(),
-            connection,
-            DdlTransactionMode.Batch,
-            EMPTY_LOCAL_STATEMENTS);
+            connectionHandler.getDatabaseId(), connection, options, EMPTY_LOCAL_STATEMENTS);
 
     intermediateStatement.executeAsync(backendConnection);
 
@@ -537,7 +518,7 @@ public class StatementTest {
     setupQueryInformationSchemaResults();
     BackendConnection backendConnection =
         new BackendConnection(
-            DatabaseId.of("p", "i", "d"), connection, DdlTransactionMode.Batch, ImmutableList.of());
+            DatabaseId.of("p", "i", "d"), connection, options, ImmutableList.of());
 
     byte[] payload = Files.readAllBytes(Paths.get("./src/test/resources/batch-size-test.txt"));
 
@@ -578,7 +559,7 @@ public class StatementTest {
     setupQueryInformationSchemaResults();
     BackendConnection backendConnection =
         new BackendConnection(
-            DatabaseId.of("p", "i", "d"), connection, DdlTransactionMode.Batch, ImmutableList.of());
+            DatabaseId.of("p", "i", "d"), connection, options, ImmutableList.of());
 
     byte[] payload = "1\t'one'\n2".getBytes();
 
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatementTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatementTest.java
index f58a0f39..1b5dfa30 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatementTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/ListDatabasesStatementTest.java
@@ -14,6 +14,7 @@
 
 package com.google.cloud.spanner.pgadapter.statements.local;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -36,6 +37,7 @@ import com.google.cloud.spanner.connection.StatementResult.ResultType;
 import com.google.cloud.spanner.pgadapter.ConnectionHandler;
 import com.google.cloud.spanner.pgadapter.ProxyServer;
 import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
 import com.google.common.collect.ImmutableList;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -49,7 +51,7 @@ public class ListDatabasesStatementTest {
     ConnectionHandler connectionHandler = mock(ConnectionHandler.class);
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
 
-    assertEquals(ListDatabasesStatement.LIST_DATABASES_SQL, statement.getSql());
+    assertArrayEquals(new String[] {ListDatabasesStatement.LIST_DATABASES_SQL}, statement.getSql());
   }
 
   @Test
@@ -102,9 +104,11 @@ public class ListDatabasesStatementTest {
         createMockPage(ImmutableList.of(otherPgDatabase, otherGsqlDatabase, currentDatabase));
     when(databaseAdminClient.listDatabases(currentDatabaseId.getInstanceId().getInstance()))
         .thenReturn(page);
+    BackendConnection backendConnection = mock(BackendConnection.class);
+    when(backendConnection.getSpannerConnection()).thenReturn(connection);
 
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
-    StatementResult result = statement.execute(connection);
+    StatementResult result = statement.execute(backendConnection);
 
     assertEquals(ResultType.RESULT_SET, result.getResultType());
     ResultSet resultSet = result.getResultSet();
@@ -143,9 +147,11 @@ public class ListDatabasesStatementTest {
         createMockPage(ImmutableList.of(otherPgDatabase, otherGsqlDatabase, currentDatabase));
     when(databaseAdminClient.listDatabases(currentDatabaseId.getInstanceId().getInstance()))
         .thenReturn(page);
+    BackendConnection backendConnection = mock(BackendConnection.class);
+    when(backendConnection.getSpannerConnection()).thenReturn(connection);
 
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
-    StatementResult result = statement.execute(connection);
+    StatementResult result = statement.execute(backendConnection);
 
     assertEquals(ResultType.RESULT_SET, result.getResultType());
     ResultSet resultSet = result.getResultSet();
@@ -185,9 +191,11 @@ public class ListDatabasesStatementTest {
         createMockPage(ImmutableList.of(otherPgDatabase, otherGsqlDatabase, currentDatabase));
     when(databaseAdminClient.listDatabases(currentDatabaseId.getInstanceId().getInstance()))
         .thenReturn(page);
+    BackendConnection backendConnection = mock(BackendConnection.class);
+    when(backendConnection.getSpannerConnection()).thenReturn(connection);
 
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
-    StatementResult result = statement.execute(connection);
+    StatementResult result = statement.execute(backendConnection);
 
     assertEquals(ResultType.RESULT_SET, result.getResultType());
     ResultSet resultSet = result.getResultSet();
@@ -221,8 +229,11 @@ public class ListDatabasesStatementTest {
     when(databaseBuilder.build()).thenReturn(currentDatabase);
     when(databaseAdminClient.newDatabaseBuilder(currentDatabaseId)).thenReturn(databaseBuilder);
 
+    BackendConnection backendConnection = mock(BackendConnection.class);
+    when(backendConnection.getSpannerConnection()).thenReturn(connection);
+
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
-    StatementResult result = statement.execute(connection);
+    StatementResult result = statement.execute(backendConnection);
 
     assertEquals(ResultType.RESULT_SET, result.getResultType());
     ResultSet resultSet = result.getResultSet();
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentCatalogStatementTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentCatalogStatementTest.java
new file mode 100644
index 00000000..42ef0c0d
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentCatalogStatementTest.java
@@ -0,0 +1,47 @@
+// Copyright 2022 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.pgadapter.statements.local;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SelectCurrentCatalogStatementTest {
+
+  @Test
+  public void testExecute() {
+    for (String database : new String[] {"mydb", "foo"}) {
+      BackendConnection backendConnection = mock(BackendConnection.class);
+      when(backendConnection.getCurrentDatabase()).thenReturn(database);
+
+      try (ResultSet resultSet =
+          SelectCurrentCatalogStatement.INSTANCE.execute(backendConnection).getResultSet()) {
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getColumnCount());
+        assertEquals(database, resultSet.getString("current_catalog"));
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentDatabaseStatementTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentDatabaseStatementTest.java
new file mode 100644
index 00000000..a956323e
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentDatabaseStatementTest.java
@@ -0,0 +1,47 @@
+// Copyright 2022 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.pgadapter.statements.local;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SelectCurrentDatabaseStatementTest {
+
+  @Test
+  public void testExecute() {
+    for (String database : new String[] {"mydb", "foo"}) {
+      BackendConnection backendConnection = mock(BackendConnection.class);
+      when(backendConnection.getCurrentDatabase()).thenReturn(database);
+
+      try (ResultSet resultSet =
+          SelectCurrentDatabaseStatement.INSTANCE.execute(backendConnection).getResultSet()) {
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getColumnCount());
+        assertEquals(database, resultSet.getString("current_database"));
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentSchemaStatementTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentSchemaStatementTest.java
new file mode 100644
index 00000000..4be9fb5f
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectCurrentSchemaStatementTest.java
@@ -0,0 +1,47 @@
+// Copyright 2022 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.pgadapter.statements.local;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SelectCurrentSchemaStatementTest {
+
+  @Test
+  public void testExecute() {
+    for (String schema : new String[] {"public", "information_schema", "foo"}) {
+      BackendConnection backendConnection = mock(BackendConnection.class);
+      when(backendConnection.getCurrentSchema()).thenReturn(schema);
+
+      try (ResultSet resultSet =
+          SelectCurrentSchemaStatement.INSTANCE.execute(backendConnection).getResultSet()) {
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getColumnCount());
+        assertEquals(schema, resultSet.getString("current_schema"));
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/ShowServerVersionStatementTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/ShowServerVersionStatementTest.java
new file mode 100644
index 00000000..1106d662
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/ShowServerVersionStatementTest.java
@@ -0,0 +1,50 @@
+// Copyright 2022 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.pgadapter.statements.local;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ShowServerVersionStatementTest {
+
+  @Test
+  public void testExecute() {
+    for (String version : new String[] {"1.0.0", "14.0.1"}) {
+      BackendConnection backendConnection = mock(BackendConnection.class);
+      OptionsMetadata options = mock(OptionsMetadata.class);
+      when(options.getServerVersion()).thenReturn(version);
+      when(backendConnection.getOptionsMetadata()).thenReturn(options);
+
+      try (ResultSet resultSet =
+          ShowServerVersionStatement.INSTANCE.execute(backendConnection).getResultSet()) {
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getColumnCount());
+        assertEquals(version, resultSet.getString("server_version"));
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetectorTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetectorTest.java
index b5c94e88..b3ab055b 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetectorTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetectorTest.java
@@ -14,12 +14,16 @@
 
 package com.google.cloud.spanner.pgadapter.utils;
 
+import static com.google.cloud.spanner.pgadapter.utils.ClientAutoDetector.DEFAULT_LOCAL_STATEMENTS;
 import static com.google.cloud.spanner.pgadapter.utils.ClientAutoDetector.EMPTY_LOCAL_STATEMENTS;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.cloud.spanner.pgadapter.ConnectionHandler;
+import com.google.cloud.spanner.pgadapter.ProxyServer;
+import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata;
 import com.google.cloud.spanner.pgadapter.statements.local.ListDatabasesStatement;
 import com.google.cloud.spanner.pgadapter.utils.ClientAutoDetector.WellKnownClient;
 import com.google.common.collect.ImmutableList;
@@ -148,9 +152,21 @@ public class ClientAutoDetectorTest {
                   "TimeZone", "some-time-zone")));
     }
 
-    assertEquals(
-        EMPTY_LOCAL_STATEMENTS,
-        WellKnownClient.JDBC.getLocalStatements(mock(ConnectionHandler.class)));
+    ConnectionHandler connectionHandler = mock(ConnectionHandler.class);
+    ProxyServer server = mock(ProxyServer.class);
+    OptionsMetadata options = mock(OptionsMetadata.class);
+    when(connectionHandler.getServer()).thenReturn(server);
+    when(server.getOptions()).thenReturn(options);
+    for (boolean useDefaultLocalStatements : new boolean[] {true, false}) {
+      when(options.useDefaultLocalStatements()).thenReturn(useDefaultLocalStatements);
+      if (useDefaultLocalStatements) {
+        assertEquals(
+            DEFAULT_LOCAL_STATEMENTS, WellKnownClient.JDBC.getLocalStatements(connectionHandler));
+      } else {
+        assertEquals(
+            EMPTY_LOCAL_STATEMENTS, WellKnownClient.JDBC.getLocalStatements(connectionHandler));
+      }
+    }
   }
 
   @Test
@@ -192,6 +208,10 @@ public class ClientAutoDetectorTest {
             ImmutableList.of("application_name"), ImmutableMap.of("application_name", "PSQL")));
 
     ConnectionHandler connectionHandler = mock(ConnectionHandler.class);
+    ProxyServer server = mock(ProxyServer.class);
+    OptionsMetadata options = mock(OptionsMetadata.class);
+    when(connectionHandler.getServer()).thenReturn(server);
+    when(server.getOptions()).thenReturn(options);
     assertEquals(
         ImmutableList.of(new ListDatabasesStatement(connectionHandler)),
         WellKnownClient.PSQL.getLocalStatements(connectionHandler));
@@ -207,8 +227,20 @@ public class ClientAutoDetectorTest {
         ClientAutoDetector.detectClient(
             ImmutableList.of("some-param"), ImmutableMap.of("some-param", "some-value")));
 
-    assertEquals(
-        EMPTY_LOCAL_STATEMENTS,
-        WellKnownClient.PGX.getLocalStatements(mock(ConnectionHandler.class)));
+    ConnectionHandler connectionHandler = mock(ConnectionHandler.class);
+    ProxyServer server = mock(ProxyServer.class);
+    OptionsMetadata options = mock(OptionsMetadata.class);
+    when(connectionHandler.getServer()).thenReturn(server);
+    when(server.getOptions()).thenReturn(options);
+    for (boolean useDefaultLocalStatements : new boolean[] {true, false}) {
+      when(options.useDefaultLocalStatements()).thenReturn(useDefaultLocalStatements);
+      if (useDefaultLocalStatements) {
+        assertEquals(
+            DEFAULT_LOCAL_STATEMENTS, WellKnownClient.PGX.getLocalStatements(connectionHandler));
+      } else {
+        assertEquals(
+            EMPTY_LOCAL_STATEMENTS, WellKnownClient.PGX.getLocalStatements(connectionHandler));
+      }
+    }
   }
 }