Repository: GoogleCloudPlatform/pgadapter (java)

Issue:
Add support for aliased SELECT CURRENT_SCHEMA() AS SCHEMA as used by Beekeper Stuidio and by Doctrine Migrations tools (Symfony)
If you run the command `SELECT CURRENT_SCHEMA() AS SCHEMA` in the emulator it complains with the error message:

> ERROR:  Postgres function current_schema() is not supported - Statement: 'select current_schema() as schema'

but everything works fine if I manually run the unaliased statement: `SELECT CURRENT_SCHEMA()` that returns:

>  current_schema 
> ----------------
> public
> (1 row)

Is there a fix or a workaround for that? Mind that I cannot write my own SQL commands, the DBAL/ORM do that for me.

Pull request description:
feat: support SELECT CURRENT_SCHEMA() AS SCHEMA
Add support for `SELECT CURRENT_SCHEMA() AS SCHEMA` that is generated by Symfony.

Fixes #3165

Patch:
diff --git a/pom.xml b/pom.xml
index 772471af..4ba26eed 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,7 +78,7 @@
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>google-cloud-spanner-bom</artifactId>
-        <version>6.90.0</version>
+        <version>6.91.0</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
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 738b46b6..80dba8fd 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
@@ -315,7 +315,7 @@ public class BackendConnection {
                 .hasReplacementStatement()) {
           LocalStatement localStatement =
               Objects.requireNonNull(localStatements.get().get(statement.getSql()));
-          result.set(localStatement.execute(BackendConnection.this));
+          result.set(localStatement.execute(BackendConnection.this, statement));
         } else if (sessionStatement != null) {
           result.set(sessionStatement.execute(sessionState, spannerConnection));
         } else if (connectionState == ConnectionState.ABORTED
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/AbortTransaction.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/AbortTransaction.java
index 867ec963..8a7c5517 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/AbortTransaction.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/AbortTransaction.java
@@ -46,7 +46,7 @@ public class AbortTransaction implements LocalStatement {
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     // This should not be possible.
     throw new UnsupportedOperationException();
   }
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesStatement.java
index 127cabde..46f66d8b 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesStatement.java
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
 import com.google.cloud.spanner.connection.StatementResult;
@@ -58,7 +59,7 @@ public class DjangoGetTableNamesStatement implements LocalStatement {
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     ResultSet resultSet =
         ClientSideResultSet.forRows(
             Type.struct(
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 14772d00..074391b6 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
@@ -21,6 +21,7 @@ import com.google.cloud.spanner.Dialect;
 import com.google.cloud.spanner.InstanceId;
 import com.google.cloud.spanner.ResultSet;
 import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -67,7 +68,7 @@ public class ListDatabasesStatement implements LocalStatement {
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     Connection connection = backendConnection.getSpannerConnection();
     Spanner spanner = connection.getSpanner();
     InstanceId defaultInstanceId =
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 e0439d17..f8be7bcf 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
@@ -47,5 +47,5 @@ public interface LocalStatement {
   }
 
   /** Executes the local statement and returns the result. */
-  StatementResult execute(BackendConnection backendConnection);
+  StatementResult execute(BackendConnection backendConnection, Statement statement);
 }
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
index e0fcfea9..0462e44d 100644
--- 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
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -50,7 +51,7 @@ public class SelectCurrentCatalogStatement implements LocalStatement {
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     ResultSet resultSet =
         ClientSideResultSet.forRows(
             Type.struct(StructField.of("current_catalog", Type.string())),
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
index 1e173b97..e20bc7ba 100644
--- 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
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -51,7 +52,7 @@ public class SelectCurrentDatabaseStatement implements LocalStatement {
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     ResultSet resultSet =
         ClientSideResultSet.forRows(
             Type.struct(StructField.of("current_database", Type.string())),
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
index c22d8510..e85021f5 100644
--- 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
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -46,20 +47,24 @@ public class SelectCurrentSchemaStatement implements LocalStatement {
       "SELECT * FROM current_schema()",
       "SELECT * FROM CURRENT_SCHEMA()",
       "select * from current_schema",
-      "SELECT * FROM current_schema"
+      "SELECT * FROM current_schema",
+      "SELECT CURRENT_SCHEMA() AS SCHEMA"
     };
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
+    String alias = "current_schema";
+    if (statement.getSql().equals("SELECT CURRENT_SCHEMA() AS SCHEMA")) {
+      // PostgreSQL folds all identifiers to lower-case, so even though the select statement uses
+      // upper-case, the alias will be returned in lower-case.
+      alias = "schema";
+    }
     ResultSet resultSet =
         ClientSideResultSet.forRows(
-            Type.struct(StructField.of("current_schema", Type.string())),
+            Type.struct(StructField.of(alias, Type.string())),
             ImmutableList.of(
-                Struct.newBuilder()
-                    .set("current_schema")
-                    .to(backendConnection.getCurrentSchema())
-                    .build()));
+                Struct.newBuilder().set(alias).to(backendConnection.getCurrentSchema()).build()));
     return new QueryResult(resultSet);
   }
 }
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectGolangMigrateAdvisoryLockStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectGolangMigrateAdvisoryLockStatement.java
index a3ed3a04..9bac8f4e 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectGolangMigrateAdvisoryLockStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectGolangMigrateAdvisoryLockStatement.java
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -44,7 +45,7 @@ public class SelectGolangMigrateAdvisoryLockStatement implements LocalStatement
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     ResultSet resultSet =
         ClientSideResultSet.forRows(
             Type.struct(StructField.of("pg_advisory_lock", Type.int64())),
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectGolangMigrateAdvisoryUnlockStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectGolangMigrateAdvisoryUnlockStatement.java
index e13323f7..7565f891 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectGolangMigrateAdvisoryUnlockStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectGolangMigrateAdvisoryUnlockStatement.java
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -44,7 +45,7 @@ public class SelectGolangMigrateAdvisoryUnlockStatement implements LocalStatemen
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     ResultSet resultSet =
         ClientSideResultSet.forRows(
             Type.struct(StructField.of("pg_advisory_unlock", Type.bool())),
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectPrismaAdvisoryLockStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectPrismaAdvisoryLockStatement.java
index 4fb7a67b..1f6c52c8 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectPrismaAdvisoryLockStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectPrismaAdvisoryLockStatement.java
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -40,7 +41,7 @@ public class SelectPrismaAdvisoryLockStatement implements LocalStatement {
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     ResultSet resultSet =
         ClientSideResultSet.forRows(
             Type.struct(StructField.of("pg_advisory_lock", Type.string())),
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectPrismaAdvisoryUnlockStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectPrismaAdvisoryUnlockStatement.java
index e592b731..814e53a9 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectPrismaAdvisoryUnlockStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectPrismaAdvisoryUnlockStatement.java
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -40,7 +41,7 @@ public class SelectPrismaAdvisoryUnlockStatement implements LocalStatement {
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     ResultSet resultSet =
         ClientSideResultSet.forRows(
             Type.struct(StructField.of("pg_advisory_unlock", Type.bool())),
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectVersionStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectVersionStatement.java
index 3fbfe1fe..b211a083 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectVersionStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/SelectVersionStatement.java
@@ -16,6 +16,7 @@ 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.Statement;
 import com.google.cloud.spanner.Struct;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.Type.StructField;
@@ -62,7 +63,7 @@ public class SelectVersionStatement implements LocalStatement {
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     ResultSet resultSet =
         ClientSideResultSet.forRows(
             Type.struct(StructField.of("version", Type.string())),
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/StartTransactionIsolationLevelRepeatableRead.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/StartTransactionIsolationLevelRepeatableRead.java
index c3409285..980cf972 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/StartTransactionIsolationLevelRepeatableRead.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/StartTransactionIsolationLevelRepeatableRead.java
@@ -47,7 +47,7 @@ public class StartTransactionIsolationLevelRepeatableRead implements LocalStatem
   }
 
   @Override
-  public StatementResult execute(BackendConnection backendConnection) {
+  public StatementResult execute(BackendConnection backendConnection, Statement statement) {
     // This should not be possible.
     throw new UnsupportedOperationException();
   }


Test patch:
diff --git a/src/test/golang/pgadapter_pgx5_tests/go.mod b/src/test/golang/pgadapter_pgx5_tests/go.mod
index fed69cde..170707ed 100644
--- a/src/test/golang/pgadapter_pgx5_tests/go.mod
+++ b/src/test/golang/pgadapter_pgx5_tests/go.mod
@@ -1,6 +1,8 @@
 module cloud.google.com/pgadapter_pgx5_tests
 
-go 1.19
+go 1.23.0
+
+toolchain go1.24.2
 
 require (
 	github.com/jackc/pgtype v1.14.0
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/JdbcBatchMockServerTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/JdbcBatchMockServerTest.java
index 7893fea1..437b2567 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/JdbcBatchMockServerTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/JdbcBatchMockServerTest.java
@@ -35,7 +35,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -573,7 +572,7 @@ public class JdbcBatchMockServerTest extends AbstractMockServerTest {
         assertFalse(
             statement.execute(
                 String.format(
-                    "%s; %s;",
+                    "%s;%s;",
                     "CREATE TABLE FOO (id bigint primary key)",
                     "CREATE TABLE BAR (id bigint primary key)")));
         assertEquals(0, statement.getUpdateCount());
@@ -601,7 +600,6 @@ public class JdbcBatchMockServerTest extends AbstractMockServerTest {
     assertEquals("CREATE TABLE BAR (id bigint primary key)", request.getStatements(1));
   }
 
-  @Ignore("https://github.com/pgjdbc/pgjdbc/issues/3007")
   @Test
   public void testBeginTransactionWithOptions() throws SQLException {
     String sql = "BEGIN TRANSACTION; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;";
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 e7e56014..35d49171 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/JdbcMockServerTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/JdbcMockServerTest.java
@@ -5815,7 +5815,7 @@ public class JdbcMockServerTest extends AbstractMockServerTest {
           assertTrue(request.hasTransaction());
           assertTrue(request.getTransaction().hasBegin());
           assertEquals(
-              translationIsolationLevel(isolation),
+              translateIsolationLevel(isolation),
               request.getTransaction().getBegin().getIsolationLevel());
 
           mockSpanner.clearRequests();
@@ -5838,7 +5838,7 @@ public class JdbcMockServerTest extends AbstractMockServerTest {
           assertTrue(request.hasTransaction());
           assertTrue(request.getTransaction().hasBegin());
           assertEquals(
-              translationIsolationLevel(isolation),
+              translateIsolationLevel(isolation),
               request.getTransaction().getBegin().getIsolationLevel());
 
           mockSpanner.clearRequests();
@@ -5865,7 +5865,7 @@ public class JdbcMockServerTest extends AbstractMockServerTest {
           // TODO: Change this when https://github.com/googleapis/java-spanner/pull/3718 has been
           // released and merged into PGAdapter.
           assertEquals(
-              IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED,
+              translateIsolationLevel(isolation),
               request.getTransaction().getBegin().getIsolationLevel());
 
           mockSpanner.clearRequests();
@@ -5874,7 +5874,7 @@ public class JdbcMockServerTest extends AbstractMockServerTest {
     }
   }
 
-  private static IsolationLevel translationIsolationLevel(int jdbcLevel) {
+  private static IsolationLevel translateIsolationLevel(int jdbcLevel) {
     switch (jdbcLevel) {
       case Connection.TRANSACTION_SERIALIZABLE:
         return IsolationLevel.SERIALIZABLE;
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/nodejs/PrismaMockServerTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/nodejs/PrismaMockServerTest.java
index 9ec4d779..2ba98a16 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/nodejs/PrismaMockServerTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/nodejs/PrismaMockServerTest.java
@@ -1777,9 +1777,8 @@ public class PrismaMockServerTest extends AbstractMockServerTest {
     assertTrue(describeRequest.hasTransaction());
     assertTrue(describeRequest.getTransaction().hasBegin());
     assertTrue(describeRequest.getTransaction().getBegin().hasReadWrite());
-    // TODO: Fix this once 'set transaction isolation level' is supported.
     assertEquals(
-        IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED,
+        IsolationLevel.REPEATABLE_READ,
         describeRequest.getTransaction().getBegin().getIsolationLevel());
   }
 
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/nodejs/SequelizeMockServerTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/nodejs/SequelizeMockServerTest.java
index 818e42a1..cb734c42 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/nodejs/SequelizeMockServerTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/nodejs/SequelizeMockServerTest.java
@@ -372,10 +372,8 @@ public class SequelizeMockServerTest extends AbstractMockServerTest {
   @Test
   public void testManagedReadWriteTransactionWithIsolationLevel()
       throws IOException, InterruptedException {
-    // TODO: Fix once 'set transaction isolation level repeatable read' is supported.
     testTransaction(
-        "testManagedReadWriteTransactionWithIsolationLevel",
-        IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED);
+        "testManagedReadWriteTransactionWithIsolationLevel", IsolationLevel.REPEATABLE_READ);
   }
 
   private void testTransaction(String methodName, IsolationLevel expectedIsolationLevel)
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/python/sqlalchemy/SqlAlchemyBasicsTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/python/sqlalchemy/SqlAlchemyBasicsTest.java
index d03c7cee..9e9da812 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/python/sqlalchemy/SqlAlchemyBasicsTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/python/sqlalchemy/SqlAlchemyBasicsTest.java
@@ -239,7 +239,7 @@ public class SqlAlchemyBasicsTest extends AbstractMockServerTest {
             + "\tfullname VARCHAR, \n"
             + "\tPRIMARY KEY (id)\n"
             + ")",
-        requests.get(0).getStatements(0));
+        requests.get(0).getStatements(0).trim());
     assertEquals(
         "CREATE TABLE address (\n"
             + "\tid SERIAL NOT NULL, \n"
@@ -248,7 +248,7 @@ public class SqlAlchemyBasicsTest extends AbstractMockServerTest {
             + "\tPRIMARY KEY (id), \n"
             + "\tFOREIGN KEY(user_id) REFERENCES user_account (id)\n"
             + ")",
-        requests.get(0).getStatements(1));
+        requests.get(0).getStatements(1).trim());
   }
 
   @Test
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/python/sqlalchemy/SqlAlchemySampleTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/python/sqlalchemy/SqlAlchemySampleTest.java
index 6882e556..7f7c68b7 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/python/sqlalchemy/SqlAlchemySampleTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/python/sqlalchemy/SqlAlchemySampleTest.java
@@ -785,7 +785,7 @@ public class SqlAlchemySampleTest extends AbstractMockServerTest {
             + "\tactive BOOLEAN, \n"
             + "\tPRIMARY KEY (id)\n"
             + ")",
-        requests.get(0).getStatements(0));
+        requests.get(0).getStatements(0).trim());
     assertEquals(
         "CREATE TABLE venues (\n"
             + "\tid VARCHAR NOT NULL, \n"
@@ -796,7 +796,7 @@ public class SqlAlchemySampleTest extends AbstractMockServerTest {
             + "\tdescription JSONB, \n"
             + "\tPRIMARY KEY (id)\n"
             + ")",
-        requests.get(0).getStatements(1));
+        requests.get(0).getStatements(1).trim());
     assertEquals(
         "CREATE TABLE albums (\n"
             + "\tid VARCHAR NOT NULL, \n"
@@ -811,7 +811,7 @@ public class SqlAlchemySampleTest extends AbstractMockServerTest {
             + "\tPRIMARY KEY (id), \n"
             + "\tFOREIGN KEY(singer_id) REFERENCES singers (id)\n"
             + ")",
-        requests.get(0).getStatements(2));
+        requests.get(0).getStatements(2).trim());
     assertEquals(
         "CREATE TABLE concerts (\n"
             + "\tid VARCHAR NOT NULL, \n"
@@ -827,7 +827,7 @@ public class SqlAlchemySampleTest extends AbstractMockServerTest {
             + "\tFOREIGN KEY(venue_id) REFERENCES venues (id), \n"
             + "\tFOREIGN KEY(singer_id) REFERENCES singers (id)\n"
             + ")",
-        requests.get(0).getStatements(3));
+        requests.get(0).getStatements(3).trim());
     // The 'tracks' table is not generated 100% according to what we would want, but that is because
     // the PostgreSQL SQLAlchemy provider does not understand interleaved tables.
     assertEquals(
@@ -842,7 +842,7 @@ public class SqlAlchemySampleTest extends AbstractMockServerTest {
             + "\tPRIMARY KEY (id, track_number), \n"
             + "\tFOREIGN KEY(id) REFERENCES albums (id)\n"
             + ")",
-        requests.get(0).getStatements(4));
+        requests.get(0).getStatements(4).trim());
   }
 
   @Test
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 7edfa78a..b9a1faf5 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
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -385,7 +386,9 @@ public class BackendConnectionTest {
     ListDatabasesStatement listDatabasesStatement = mock(ListDatabasesStatement.class);
     when(listDatabasesStatement.getSql())
         .thenReturn(new String[] {ListDatabasesStatement.LIST_DATABASES_SQL});
-    when(listDatabasesStatement.execute(any(BackendConnection.class)))
+    when(listDatabasesStatement.execute(
+            any(BackendConnection.class),
+            eq(Statement.of(ListDatabasesStatement.LIST_DATABASES_SQL))))
         .thenReturn(listDatabasesResult);
     ImmutableList<LocalStatement> localStatements = ImmutableList.of(listDatabasesStatement);
     ParsedStatement parsedListDatabasesStatement = mock(ParsedStatement.class);
@@ -412,7 +415,8 @@ public class BackendConnectionTest {
             Function.identity());
     backendConnection.flush();
 
-    verify(listDatabasesStatement).execute(backendConnection);
+    verify(listDatabasesStatement)
+        .execute(backendConnection, Statement.of(ListDatabasesStatement.LIST_DATABASES_SQL));
     assertTrue(resultFuture.isDone());
     assertEquals(listDatabasesResult, resultFuture.get());
   }
@@ -450,7 +454,7 @@ public class BackendConnectionTest {
         backendConnection.execute("SELECT", parsedStatement, statement, Function.identity());
     backendConnection.flush();
 
-    verify(listDatabasesStatement, never()).execute(backendConnection);
+    verify(listDatabasesStatement, never()).execute(backendConnection, statement);
     assertTrue(resultFuture.isDone());
     assertEquals(statementResult, resultFuture.get());
   }
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesTest.java
index 17fe8a4e..e4de586d 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesTest.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.assertFalse;
 import static org.mockito.Mockito.mock;
 
 import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.Type;
 import com.google.cloud.spanner.connection.StatementResult;
 import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
@@ -60,7 +61,9 @@ public class DjangoGetTableNamesTest {
 
     DjangoGetTableNamesStatement djangoGetTableNamesStatement =
         DjangoGetTableNamesStatement.INSTANCE;
-    StatementResult statementResult = djangoGetTableNamesStatement.execute(backendConnection);
+    StatementResult statementResult =
+        djangoGetTableNamesStatement.execute(
+            backendConnection, Statement.of(djangoGetTableNamesSql));
     ResultSet resultSet = statementResult.getResultSet();
     assertFalse(resultSet.next());
     assertEquals(2, resultSet.getColumnCount());
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 1b5dfa30..aa0ebdbb 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
@@ -30,6 +30,7 @@ import com.google.cloud.spanner.Dialect;
 import com.google.cloud.spanner.InstanceId;
 import com.google.cloud.spanner.ResultSet;
 import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.connection.Connection;
 import com.google.cloud.spanner.connection.ConnectionOptionsHelperTest;
 import com.google.cloud.spanner.connection.StatementResult;
@@ -108,7 +109,9 @@ public class ListDatabasesStatementTest {
     when(backendConnection.getSpannerConnection()).thenReturn(connection);
 
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
-    StatementResult result = statement.execute(backendConnection);
+    StatementResult result =
+        statement.execute(
+            backendConnection, Statement.of(ListDatabasesStatement.LIST_DATABASES_SQL));
 
     assertEquals(ResultType.RESULT_SET, result.getResultType());
     ResultSet resultSet = result.getResultSet();
@@ -151,7 +154,9 @@ public class ListDatabasesStatementTest {
     when(backendConnection.getSpannerConnection()).thenReturn(connection);
 
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
-    StatementResult result = statement.execute(backendConnection);
+    StatementResult result =
+        statement.execute(
+            backendConnection, Statement.of(ListDatabasesStatement.LIST_DATABASES_SQL));
 
     assertEquals(ResultType.RESULT_SET, result.getResultType());
     ResultSet resultSet = result.getResultSet();
@@ -195,7 +200,9 @@ public class ListDatabasesStatementTest {
     when(backendConnection.getSpannerConnection()).thenReturn(connection);
 
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
-    StatementResult result = statement.execute(backendConnection);
+    StatementResult result =
+        statement.execute(
+            backendConnection, Statement.of(ListDatabasesStatement.LIST_DATABASES_SQL));
 
     assertEquals(ResultType.RESULT_SET, result.getResultType());
     ResultSet resultSet = result.getResultSet();
@@ -233,7 +240,9 @@ public class ListDatabasesStatementTest {
     when(backendConnection.getSpannerConnection()).thenReturn(connection);
 
     ListDatabasesStatement statement = new ListDatabasesStatement(connectionHandler);
-    StatementResult result = statement.execute(backendConnection);
+    StatementResult result =
+        statement.execute(
+            backendConnection, Statement.of(ListDatabasesStatement.LIST_DATABASES_SQL));
 
     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
index 42ef0c0d..f258fb2e 100644
--- 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
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -36,7 +37,9 @@ public class SelectCurrentCatalogStatementTest {
       when(backendConnection.getCurrentDatabase()).thenReturn(database);
 
       try (ResultSet resultSet =
-          SelectCurrentCatalogStatement.INSTANCE.execute(backendConnection).getResultSet()) {
+          SelectCurrentCatalogStatement.INSTANCE
+              .execute(backendConnection, Statement.of("select current_catalog"))
+              .getResultSet()) {
         assertTrue(resultSet.next());
         assertEquals(1, resultSet.getColumnCount());
         assertEquals(database, resultSet.getString("current_catalog"));
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
index a956323e..b1ed37ab 100644
--- 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
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -36,7 +37,9 @@ public class SelectCurrentDatabaseStatementTest {
       when(backendConnection.getCurrentDatabase()).thenReturn(database);
 
       try (ResultSet resultSet =
-          SelectCurrentDatabaseStatement.INSTANCE.execute(backendConnection).getResultSet()) {
+          SelectCurrentDatabaseStatement.INSTANCE
+              .execute(backendConnection, Statement.of("select current_database"))
+              .getResultSet()) {
         assertTrue(resultSet.next());
         assertEquals(1, resultSet.getColumnCount());
         assertEquals(database, resultSet.getString("current_database"));
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
index 4be9fb5f..4b5eb1aa 100644
--- 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
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -36,7 +37,9 @@ public class SelectCurrentSchemaStatementTest {
       when(backendConnection.getCurrentSchema()).thenReturn(schema);
 
       try (ResultSet resultSet =
-          SelectCurrentSchemaStatement.INSTANCE.execute(backendConnection).getResultSet()) {
+          SelectCurrentSchemaStatement.INSTANCE
+              .execute(backendConnection, Statement.of("select current_schema"))
+              .getResultSet()) {
         assertTrue(resultSet.next());
         assertEquals(1, resultSet.getColumnCount());
         assertEquals(schema, resultSet.getString("current_schema"));
@@ -44,4 +47,22 @@ public class SelectCurrentSchemaStatementTest {
       }
     }
   }
+
+  @Test
+  public void testExecuteSelectCurrentSchemaAsSchema() {
+    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, Statement.of("SELECT CURRENT_SCHEMA() AS SCHEMA"))
+              .getResultSet()) {
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getColumnCount());
+        assertEquals(schema, resultSet.getString("schema"));
+        assertFalse(resultSet.next());
+      }
+    }
+  }
 }
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectVersionStatementTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectVersionStatementTest.java
index 6f414bc0..71a1eb10 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectVersionStatementTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/SelectVersionStatementTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.pgadapter.session.PGSetting;
 import com.google.cloud.spanner.pgadapter.session.SessionState;
 import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
@@ -41,7 +42,9 @@ public class SelectVersionStatementTest {
       when(pgSetting.getSetting()).thenReturn(version);
 
       try (ResultSet resultSet =
-          SelectVersionStatement.INSTANCE.execute(backendConnection).getResultSet()) {
+          SelectVersionStatement.INSTANCE
+              .execute(backendConnection, Statement.of("select server_version"))
+              .getResultSet()) {
         assertTrue(resultSet.next());
         assertEquals(1, resultSet.getColumnCount());
         assertEquals("PostgreSQL " + version, resultSet.getString("version"));