Repository: googleapis/java-spanner-jdbc
Pull request #498 (2021-06-09 09:58:44)

deps: update dependency com.google.cloud:google-cloud-spanner-bom to v6.6.0
Updates to Spanner client 6.6.0 and adds tests for optimizer stats package.

Replaces #497



Patch:
diff --git a/pom.xml b/pom.xml
index 2ab9e32..056534b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,7 +71,7 @@
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>google-cloud-spanner-bom</artifactId>
-        <version>6.5.0</version>
+        <version>6.6.0</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>


Test patch:
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/JdbcQueryOptionsTest.java b/src/test/java/com/google/cloud/spanner/jdbc/JdbcQueryOptionsTest.java
index d26aba5..d1aeeb9 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/JdbcQueryOptionsTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/JdbcQueryOptionsTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
 
 import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
 import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.SpannerOptions.SpannerEnvironment;
 import com.google.cloud.spanner.Statement;
 import com.google.cloud.spanner.connection.AbstractMockServerTest;
 import com.google.common.base.MoreObjects;
@@ -40,7 +41,7 @@ public class JdbcQueryOptionsTest extends AbstractMockServerTest {
   }
 
   @Test
-  public void testDefaultOptimizerVersion() throws SQLException {
+  public void testDefaultOptions() throws SQLException {
     try (java.sql.Connection connection = createJdbcConnection()) {
       try (java.sql.ResultSet rs =
           connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
@@ -48,25 +49,39 @@ public class JdbcQueryOptionsTest extends AbstractMockServerTest {
         assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("");
         assertThat(rs.next()).isFalse();
       }
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_STATISTICS_PACKAGE")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_STATISTICS_PACKAGE")).isEqualTo("");
+        assertThat(rs.next()).isFalse();
+      }
     }
   }
 
   @Test
-  public void testOptimizerVersionInConnectionUrl() throws SQLException {
+  public void testOptionsInConnectionUrl() throws SQLException {
     try (java.sql.Connection connection =
         DriverManager.getConnection(
-            String.format("jdbc:%s;optimizerVersion=%s", getBaseUrl(), "100"))) {
+            String.format(
+                "jdbc:%s;optimizerVersion=%s;optimizerStatisticsPackage=%s",
+                getBaseUrl(), "100", "url_package"))) {
       try (java.sql.ResultSet rs =
           connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
         assertThat(rs.next()).isTrue();
         assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("100");
         assertThat(rs.next()).isFalse();
       }
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_STATISTICS_PACKAGE")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_STATISTICS_PACKAGE")).isEqualTo("url_package");
+        assertThat(rs.next()).isFalse();
+      }
     }
   }
 
   @Test
-  public void testSetOptimizerVersion() throws SQLException {
+  public void testSetOptions() throws SQLException {
     try (java.sql.Connection connection = createJdbcConnection()) {
       connection.createStatement().execute("SET OPTIMIZER_VERSION='20'");
       try (java.sql.ResultSet rs =
@@ -89,41 +104,64 @@ public class JdbcQueryOptionsTest extends AbstractMockServerTest {
         assertThat(rs.getString("OPTIMIZER_VERSION")).isEqualTo("");
         assertThat(rs.next()).isFalse();
       }
+
+      connection.createStatement().execute("SET OPTIMIZER_STATISTICS_PACKAGE='20210609'");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_STATISTICS_PACKAGE")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_STATISTICS_PACKAGE")).isEqualTo("20210609");
+        assertThat(rs.next()).isFalse();
+      }
+      connection.createStatement().execute("SET OPTIMIZER_STATISTICS_PACKAGE='latest'");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_STATISTICS_PACKAGE")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_STATISTICS_PACKAGE")).isEqualTo("latest");
+        assertThat(rs.next()).isFalse();
+      }
+      connection.createStatement().execute("SET OPTIMIZER_STATISTICS_PACKAGE=''");
+      try (java.sql.ResultSet rs =
+          connection.createStatement().executeQuery("SHOW VARIABLE OPTIMIZER_STATISTICS_PACKAGE")) {
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString("OPTIMIZER_STATISTICS_PACKAGE")).isEqualTo("");
+        assertThat(rs.next()).isFalse();
+      }
     }
   }
 
   @Test
-  public void testSetAndUseOptimizerVersion() throws SQLException {
+  public void testSetAndUseOptions() throws SQLException {
     try (java.sql.Connection connection = createJdbcConnection()) {
       connection.createStatement().execute("SET OPTIMIZER_VERSION='20'");
+      connection.createStatement().execute("SET OPTIMIZER_STATISTICS_PACKAGE='20210609'");
       try (java.sql.ResultSet rs =
           connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
         assertThat(rs.next()).isTrue();
         assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
         assertThat(rs.next()).isFalse();
-        // Verify that the last ExecuteSqlRequest that the server received specified optimizer
-        // version 20.
+        // Verify that the last ExecuteSqlRequest that the server received used the options that
+        // were set.
         ExecuteSqlRequest request = getLastExecuteSqlRequest();
         assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("20");
+        assertThat(request.getQueryOptions().getOptimizerStatisticsPackage()).isEqualTo("20210609");
       }
 
-      // Do another query, but now with optimizer version 'latest'.
       connection.createStatement().execute("SET OPTIMIZER_VERSION='latest'");
+      connection.createStatement().execute("SET OPTIMIZER_STATISTICS_PACKAGE='latest'");
       try (java.sql.ResultSet rs =
           connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
         assertThat(rs.next()).isTrue();
         assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
         assertThat(rs.next()).isFalse();
-        // Verify that the last ExecuteSqlRequest that the server received specified optimizer
-        // version 'latest'.
         ExecuteSqlRequest request = getLastExecuteSqlRequest();
         assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("latest");
+        assertThat(request.getQueryOptions().getOptimizerStatisticsPackage()).isEqualTo("latest");
       }
 
-      // Set the optimizer version to ''. This will do a fallback to the default, meaning that it
-      // will be read from the environment variable SPANNER_OPTIMIZER_VERSION as we have nothing set
-      // on the connection URL.
+      // Set the options to ''. This will do a fallback to the default, meaning that it will be read
+      // from the environment variables as we have nothing set on the connection URL.
       connection.createStatement().execute("SET OPTIMIZER_VERSION=''");
+      connection.createStatement().execute("SET OPTIMIZER_STATISTICS_PACKAGE=''");
       try (java.sql.ResultSet rs =
           connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
         assertThat(rs.next()).isTrue();
@@ -134,31 +172,49 @@ public class JdbcQueryOptionsTest extends AbstractMockServerTest {
         ExecuteSqlRequest request = getLastExecuteSqlRequest();
         assertThat(request.getQueryOptions().getOptimizerVersion())
             .isEqualTo(MoreObjects.firstNonNull(System.getenv("SPANNER_OPTIMIZER_VERSION"), ""));
+        assertThat(request.getQueryOptions().getOptimizerStatisticsPackage())
+            .isEqualTo(MoreObjects.firstNonNull(System.getenv("OPTIMIZER_STATISTICS_PACKAGE"), ""));
       }
     }
   }
 
   @Test
-  public void testUseOptimizerVersionFromConnectionUrl() throws SQLException {
+  public void testUseOptionsFromConnectionUrl() throws SQLException {
     try (java.sql.Connection connection =
-        DriverManager.getConnection(String.format("jdbc:%s;optimizerVersion=10", getBaseUrl()))) {
+        DriverManager.getConnection(
+            String.format(
+                "jdbc:%s;optimizerVersion=10;optimizerStatisticsPackage=20210609_10_00_00",
+                getBaseUrl()))) {
       // Do a query and verify that the version from the connection URL is used.
       try (java.sql.ResultSet rs =
           connection.createStatement().executeQuery(SELECT_COUNT_STATEMENT.getSql())) {
         assertThat(rs.next()).isTrue();
         assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
         assertThat(rs.next()).isFalse();
-        // The optimizer version used should be '10' from the connection URL.
+        // The options should come from the connection URL.
         ExecuteSqlRequest request = getLastExecuteSqlRequest();
         assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("10");
+        assertThat(request.getQueryOptions().getOptimizerStatisticsPackage())
+            .isEqualTo("20210609_10_00_00");
       }
     }
   }
 
   @Test
-  public void testUseOptimizerVersionFromEnvironment() throws SQLException {
+  public void testUseOptionsFromEnvironment() throws SQLException {
     try {
-      SpannerOptions.useEnvironment(() -> "20");
+      SpannerOptions.useEnvironment(
+          new SpannerEnvironment() {
+            @Override
+            public String getOptimizerVersion() {
+              return "20";
+            }
+
+            @Override
+            public String getOptimizerStatisticsPackage() {
+              return "env_package";
+            }
+          });
       try (java.sql.Connection connection =
           DriverManager.getConnection(String.format("jdbc:%s", getBaseUrl()))) {
         // Do a query and verify that the version from the environment is used.
@@ -170,6 +226,8 @@ public class JdbcQueryOptionsTest extends AbstractMockServerTest {
           // Verify query options from the environment.
           ExecuteSqlRequest request = getLastExecuteSqlRequest();
           assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("20");
+          assertThat(request.getQueryOptions().getOptimizerStatisticsPackage())
+              .isEqualTo("env_package");
         }
         // Now set one of the query options on the connection. That option should be used in
         // combination with the other option from the environment.
@@ -183,6 +241,9 @@ public class JdbcQueryOptionsTest extends AbstractMockServerTest {
           ExecuteSqlRequest request = getLastExecuteSqlRequest();
           // Optimizer version should come from the connection.
           assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("30");
+          // Optimizer statistics package should come from the environment.
+          assertThat(request.getQueryOptions().getOptimizerStatisticsPackage())
+              .isEqualTo("env_package");
         }
       }
     } finally {
@@ -195,7 +256,9 @@ public class JdbcQueryOptionsTest extends AbstractMockServerTest {
     mockSpanner.putStatementResult(
         StatementResult.query(
             Statement.of(
-                String.format("@{optimizer_version=1} %s", SELECT_COUNT_STATEMENT.getSql())),
+                String.format(
+                    "@{optimizer_version=1, optimizer_statistics_package=hint_package} %s",
+                    SELECT_COUNT_STATEMENT.getSql())),
             SELECT_COUNT_RESULTSET_BEFORE_INSERT));
     try (java.sql.Connection connection =
         DriverManager.getConnection(String.format("jdbc:%s", getBaseUrl()))) {
@@ -203,14 +266,17 @@ public class JdbcQueryOptionsTest extends AbstractMockServerTest {
           connection
               .createStatement()
               .executeQuery(
-                  String.format("@{optimizer_version=1} %s", SELECT_COUNT_STATEMENT.getSql()))) {
+                  String.format(
+                      "@{optimizer_version=1, optimizer_statistics_package=hint_package} %s",
+                      SELECT_COUNT_STATEMENT.getSql()))) {
         assertThat(rs.next()).isTrue();
         assertThat(rs.getLong(1)).isEqualTo(COUNT_BEFORE_INSERT);
         assertThat(rs.next()).isFalse();
-        // The optimizer version used in the ExecuteSqlRequest should be empty as the query hint is
-        // parsed by the backend.
+        // The options used in the ExecuteSqlRequest should be empty as the query hint is parsed by
+        // the backend.
         ExecuteSqlRequest request = getLastExecuteSqlRequest();
         assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("");
+        assertThat(request.getQueryOptions().getOptimizerStatisticsPackage()).isEqualTo("");
       }
     }
   }
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcQueryOptionsTest.java b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcQueryOptionsTest.java
index 7ca650d..ac90687 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcQueryOptionsTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcQueryOptionsTest.java
@@ -17,6 +17,9 @@
 package com.google.cloud.spanner.jdbc.it;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
 
@@ -25,6 +28,7 @@ import com.google.cloud.spanner.SpannerOptions;
 import com.google.cloud.spanner.connection.SpannerPool;
 import com.google.cloud.spanner.jdbc.ITAbstractJdbcTest;
 import com.google.cloud.spanner.jdbc.JdbcSqlException;
+import com.google.cloud.spanner.testing.EmulatorSpannerHelper;
 import com.google.rpc.Code;
 import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
 import java.sql.Connection;
@@ -96,7 +100,8 @@ public class ITJdbcQueryOptionsTest extends ITAbstractJdbcTest {
 
   @Test
   public void connectionUrlWithInvalidOptimizerVersion() throws SQLException {
-    assumeFalse("optimizer version is ignored on emulator", env.getTestHelper().isEmulator());
+    assumeFalse(
+        "optimizer version is ignored on emulator", EmulatorSpannerHelper.isUsingEmulator());
     this.connectionUriSuffix = ";optimizerVersion=9999999";
     try (Connection connection = createConnection()) {
       try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
@@ -139,7 +144,8 @@ public class ITJdbcQueryOptionsTest extends ITAbstractJdbcTest {
 
   @Test
   public void setInvalidOptimizerVersion() throws SQLException {
-    assumeFalse("optimizer version is ignored on emulator", env.getTestHelper().isEmulator());
+    assumeFalse(
+        "optimizer version is ignored on emulator", EmulatorSpannerHelper.isUsingEmulator());
     try (Connection connection = createConnection()) {
       connection.createStatement().execute("SET OPTIMIZER_VERSION='9999999'");
       try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
@@ -156,7 +162,7 @@ public class ITJdbcQueryOptionsTest extends ITAbstractJdbcTest {
   public void optimizerVersionInQueryHint() throws SQLException {
     assumeFalse(
         "optimizer version in query hint is not supported on emulator",
-        env.getTestHelper().isEmulator());
+        EmulatorSpannerHelper.isUsingEmulator());
     try (Connection connection = createConnection()) {
       verifyOptimizerVersion(connection, "");
       try (ResultSet rs =
@@ -175,8 +181,9 @@ public class ITJdbcQueryOptionsTest extends ITAbstractJdbcTest {
   }
 
   @Test
-  public void optimizerVersionInEnvironment() throws SQLException {
-    assumeFalse("optimizer version is ignored on emulator", env.getTestHelper().isEmulator());
+  public void testOptionsInEnvironment() throws SQLException {
+    assumeFalse(
+        "optimizer version is ignored on emulator", EmulatorSpannerHelper.isUsingEmulator());
     try {
       SpannerOptions.useEnvironment(
           new SpannerOptions.SpannerEnvironment() {
@@ -184,6 +191,11 @@ public class ITJdbcQueryOptionsTest extends ITAbstractJdbcTest {
             public String getOptimizerVersion() {
               return "1";
             }
+
+            @Override
+            public String getOptimizerStatisticsPackage() {
+              return "latest";
+            }
           });
       try (Connection connection = createConnection()) {
         // Environment query options are not visible to the connection.
@@ -204,15 +216,19 @@ public class ITJdbcQueryOptionsTest extends ITAbstractJdbcTest {
             public String getOptimizerVersion() {
               return "9999999";
             }
+
+            @Override
+            public String getOptimizerStatisticsPackage() {
+              return "latest";
+            }
           });
       try (Connection connection = createConnection()) {
-        try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1")) {
-          fail("missing expected exception");
-        } catch (SQLException e) {
-          assertThat((Throwable) e).isInstanceOf(JdbcSqlException.class);
-          JdbcSqlException je = (JdbcSqlException) e;
-          assertThat(je.getCode()).isEqualTo(Code.INVALID_ARGUMENT);
-        }
+        SQLException e =
+            assertThrows(
+                SQLException.class, () -> connection.createStatement().executeQuery("SELECT 1"));
+        assertTrue(e instanceof JdbcSqlException);
+        JdbcSqlException je = (JdbcSqlException) e;
+        assertEquals(Code.INVALID_ARGUMENT, je.getCode());
       }
     } finally {
       SpannerOptions.useDefaultEnvironment();