From 123a7bcd9825b20bfbf7e9b057c2bd0f5213cac3 Mon Sep 17 00:00:00 2001 From: Sagnik Ghosh Date: Wed, 8 Jan 2025 19:35:37 +0530 Subject: [PATCH] feat: support for spanner external host (#1884) * feat(spanner): jdbc support for spanner external host * added unit tests for the new introduced pattern --- .../google/cloud/spanner/jdbc/JdbcDriver.java | 9 +++++- .../cloud/spanner/jdbc/JdbcDriverTest.java | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java b/src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java index 6bb70283..3fb70106 100644 --- a/src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java +++ b/src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java @@ -25,6 +25,7 @@ import com.google.cloud.spanner.connection.ConnectionOptionsHelper; import com.google.cloud.spanner.connection.ConnectionPropertiesHelper; import com.google.cloud.spanner.connection.ConnectionProperty; +import com.google.common.annotations.VisibleForTesting; import com.google.rpc.Code; import io.opentelemetry.api.OpenTelemetry; import java.sql.Connection; @@ -145,6 +146,11 @@ public class JdbcDriver implements Driver { private static final String JDBC_URL_FORMAT = "jdbc:" + ConnectionOptions.Builder.SPANNER_URI_FORMAT; private static final Pattern URL_PATTERN = Pattern.compile(JDBC_URL_FORMAT); + private static final String JDBC_EXTERNAL_HOST_FORMAT = + "jdbc:" + ConnectionOptions.Builder.EXTERNAL_HOST_FORMAT; + + @VisibleForTesting + static final Pattern EXTERNAL_HOST_URL_PATTERN = Pattern.compile(JDBC_EXTERNAL_HOST_FORMAT); @InternalApi public static String getClientLibToken() { @@ -213,7 +219,8 @@ public Connection connect(String url, Properties info) throws SQLException { if (url != null && url.startsWith("jdbc:cloudspanner")) { try { Matcher matcher = URL_PATTERN.matcher(url); - if (matcher.matches()) { + Matcher matcherExternalHost = EXTERNAL_HOST_URL_PATTERN.matcher(url); + if (matcher.matches() || matcherExternalHost.matches()) { // strip 'jdbc:' from the URL, add any extra properties and pass on to the generic // Connection API String connectionUri = appendPropertiesToUrl(url.substring(5), info); diff --git a/src/test/java/com/google/cloud/spanner/jdbc/JdbcDriverTest.java b/src/test/java/com/google/cloud/spanner/jdbc/JdbcDriverTest.java index 020848e1..b4ae04f5 100644 --- a/src/test/java/com/google/cloud/spanner/jdbc/JdbcDriverTest.java +++ b/src/test/java/com/google/cloud/spanner/jdbc/JdbcDriverTest.java @@ -16,8 +16,10 @@ package com.google.cloud.spanner.jdbc; +import static com.google.cloud.spanner.jdbc.JdbcDriver.EXTERNAL_HOST_URL_PATTERN; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -47,6 +49,7 @@ import java.util.Collection; import java.util.Objects; import java.util.Properties; +import java.util.regex.Matcher; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -211,4 +214,32 @@ public void testLenient() throws SQLException { assertThat(jdbc.getCode()).isEqualTo(Code.INVALID_ARGUMENT); } } + + @Test + public void testJdbcExternalHostFormat() { + Matcher matcherWithoutInstance = + EXTERNAL_HOST_URL_PATTERN.matcher("jdbc:cloudspanner://localhost:15000/databases/test-db"); + assertTrue(matcherWithoutInstance.matches()); + assertEquals("test-db", matcherWithoutInstance.group("DATABASEGROUP")); + Matcher matcherWithProperty = + EXTERNAL_HOST_URL_PATTERN.matcher( + "jdbc:cloudspanner://localhost:15000/instances/default/databases/singers-db?usePlainText=true"); + assertTrue(matcherWithProperty.matches()); + assertEquals("default", matcherWithProperty.group("INSTANCEGROUP")); + assertEquals("singers-db", matcherWithProperty.group("DATABASEGROUP")); + Matcher matcherWithoutPort = + EXTERNAL_HOST_URL_PATTERN.matcher( + "jdbc:cloudspanner://localhost/instances/default/databases/test-db"); + assertTrue(matcherWithoutPort.matches()); + assertEquals("default", matcherWithoutPort.group("INSTANCEGROUP")); + assertEquals("test-db", matcherWithoutPort.group("DATABASEGROUP")); + Matcher matcherWithProject = + EXTERNAL_HOST_URL_PATTERN.matcher( + "jdbc:cloudspanner://localhost:15000/projects/default/instances/default/databases/singers-db"); + assertFalse(matcherWithProject.matches()); + Matcher matcherWithoutHost = + EXTERNAL_HOST_URL_PATTERN.matcher( + "jdbc:cloudspanner:/instances/default/databases/singers-db"); + assertFalse(matcherWithoutHost.matches()); + } }