From ad97128f8e2fd441f21fd6ba6dd6710e6789a12e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 11 Aug 2026 16:59:22 +0200 Subject: [PATCH] perf(spanner-jdbc): cache JDBC metadata query strings Cache the SQL strings that are loaded from disk for the standard JDBC metadata queries. --- .../spanner/jdbc/JdbcDatabaseMetaData.java | 25 +++++++++++-------- .../jdbc/JdbcDatabaseMetaDataTest.java | 9 +++++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/java-spanner-jdbc/src/main/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaData.java b/java-spanner-jdbc/src/main/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaData.java index 7168e2f9204b..f4418b09148f 100644 --- a/java-spanner-jdbc/src/main/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaData.java +++ b/java-spanner-jdbc/src/main/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaData.java @@ -26,10 +26,12 @@ import com.google.cloud.spanner.Type.StructField; import com.google.cloud.spanner.connection.Connection.InternalMetadataQuery; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; @@ -40,6 +42,8 @@ import java.util.Collections; import java.util.Properties; import java.util.Scanner; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** {@link DatabaseMetaData} implementation for Cloud Spanner */ class JdbcDatabaseMetaData extends AbstractJdbcWrapper implements DatabaseMetaData { @@ -50,18 +54,19 @@ class JdbcDatabaseMetaData extends AbstractJdbcWrapper implements DatabaseMetaDa private static final String PRODUCT_NAME = "Google Cloud Spanner"; private static final String POSTGRESQL_PRODUCT_NAME = PRODUCT_NAME + " PostgreSQL"; + private static final ConcurrentMap SQL_CACHE = new ConcurrentHashMap<>(); + @VisibleForTesting static String readSqlFromFile(String filename, Dialect dialect) { - InputStream in; - switch (dialect) { - case POSTGRESQL: - in = JdbcDatabaseMetaData.class.getResourceAsStream("postgresql/" + filename); - break; - case GOOGLE_STANDARD_SQL: - default: - in = JdbcDatabaseMetaData.class.getResourceAsStream(filename); - } - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + return SQL_CACHE.computeIfAbsent( + filename + "/" + dialect, (key) -> loadSqlFromFile(filename, dialect)); + } + + private static String loadSqlFromFile(String filename, Dialect dialect) { + String resourcePath = dialect == Dialect.POSTGRESQL ? "postgresql/" + filename : filename; + InputStream in = JdbcDatabaseMetaData.class.getResourceAsStream(resourcePath); + Preconditions.checkNotNull(in, "Resource not found: " + resourcePath); + BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); StringBuilder builder = new StringBuilder(); try (Scanner scanner = new Scanner(reader)) { while (scanner.hasNextLine()) { diff --git a/java-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaDataTest.java b/java-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaDataTest.java index fc3168ab4f0a..f6e4bd7948d4 100644 --- a/java-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaDataTest.java +++ b/java-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaDataTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -574,4 +575,12 @@ public void testGetUserName() throws SQLException, IOException { DatabaseMetaData meta = new JdbcDatabaseMetaData(connection); assertEquals("test@test-project.iam.gserviceaccount.com", meta.getUserName()); } + + @Test + public void testReadSqlFromFileCaching() { + String sql1 = JdbcDatabaseMetaData.readSqlFromFile("DatabaseMetaData_GetTables.sql", dialect); + String sql2 = JdbcDatabaseMetaData.readSqlFromFile("DatabaseMetaData_GetTables.sql", dialect); + assertNotNull(sql1); + assertSame(sql1, sql2); + } }