From 7a7974979158bedb57cb9eb6bfab3d9d447ace35 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Wed, 28 Oct 2026 16:30:11 -0400 Subject: [PATCH 01/11] feat(bigquery-jdbc): add enableGraphMetadata connection property --- .../bigquery/jdbc/BigQueryConnection.java | 6 +++++ .../bigquery/jdbc/BigQueryJdbcUrlUtility.java | 8 +++++++ .../cloud/bigquery/jdbc/DataSource.java | 22 ++++++++++++++++++ .../jdbc/BigQueryJdbcUrlUtilityTest.java | 23 +++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java index 6189f7ea75be..a80457d93e05 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java @@ -240,6 +240,7 @@ public class BigQueryConnection extends BigQueryNoOpsConnection { boolean enableGcpLogExporter; OpenTelemetry customOpenTelemetry; boolean useGlobalOpenTelemetry; + boolean enableGraphMetadata; private OpenTelemetry openTelemetry; private Context otelContext; Tracer tracer = @@ -397,6 +398,7 @@ public class BigQueryConnection extends BigQueryNoOpsConnection { this.connectionPoolSize = ds.getConnectionPoolSize(); this.listenerPoolSize = ds.getListenerPoolSize(); this.partnerToken = ds.getPartnerToken(); + this.enableGraphMetadata = ds.getEnableGraphMetadata(); this.headerProvider = createHeaderProvider(); this.enableGcpTraceExporter = ds.getEnableGcpTraceExporter(); @@ -867,6 +869,10 @@ Long getListenerPoolSize() { return listenerPoolSize; } + boolean isEnableGraphMetadata() { + return this.enableGraphMetadata; + } + @Override public boolean isValid(int timeout) throws SQLException { if (timeout < 0) { diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java index ef7c9363c68d..9755a26a421d 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java @@ -193,6 +193,8 @@ protected boolean removeEldestEntry(Map.Entry> eldes static final String MAX_BYTES_BILLED_PROPERTY_NAME = "MaximumBytesBilled"; static final Long DEFAULT_MAX_BYTES_BILLED_VALUE = 0L; static final String LABELS_PROPERTY_NAME = "Labels"; + static final String ENABLE_GRAPH_PROPERTY_NAME = "EnablePropertyGraphMetadata"; + static final boolean DEFAULT_ENABLE_GRAPH_VALUE = false; static final List OVERRIDE_PROPERTIES = Arrays.asList( BIGQUERY_ENDPOINT_OVERRIDE_PROPERTY_NAME, @@ -691,6 +693,12 @@ protected boolean removeEldestEntry(Map.Entry> eldes .setDefaultValue( String.valueOf( TelemetryPropertyUtility.DEFAULT_ENABLE_DIAGNOSTIC_TELEMETRY_VALUE)) + .build(), + BigQueryConnectionProperty.newBuilder() + .setName(ENABLE_GRAPH_PROPERTY_NAME) + .setDescription( + "Enables or disables discovery of Property Graphs and related metadata in DatabaseMetaData methods.") + .setDefaultValue(String.valueOf(DEFAULT_ENABLE_GRAPH_VALUE)) .build()))); private static final List NETWORK_PROPERTIES = diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java index 66034dc1a35d..440549c1e6b6 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java @@ -131,6 +131,7 @@ public class DataSource implements javax.sql.DataSource { private OpenTelemetry customOpenTelemetry; private boolean useGlobalOpenTelemetry = BigQueryJdbcUrlUtility.DEFAULT_USE_GLOBAL_OTEL_VALUE; private Boolean enableDiagnosticTelemetry; + private Boolean enableGraphMetadata; // Make sure the JDBC driver class is loaded. static { @@ -396,6 +397,12 @@ public class DataSource implements javax.sql.DataSource { ds.setEnableDiagnosticTelemetry( BigQueryJdbcUrlUtility.convertIntToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_DIAGNOSTIC_TELEMETRY_PROPERTY_NAME))) + .put( + BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME, + (ds, val) -> + ds.setEnableGraphMetadata( + BigQueryJdbcUrlUtility.convertIntToBoolean( + val, BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME))) .build(); public static DataSource fromUrl(String url) { @@ -738,6 +745,11 @@ Properties createProperties() { BigQueryJdbcUrlUtility.USE_GLOBAL_OTEL_PROPERTY_NAME, String.valueOf(this.useGlobalOpenTelemetry)); } + if (this.enableGraphMetadata != null) { + connectionProperties.setProperty( + BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME, + String.valueOf(this.enableGraphMetadata)); + } connectionProperties.setProperty( BigQueryJdbcUrlUtility.ENABLE_DIAGNOSTIC_TELEMETRY_PROPERTY_NAME, String.valueOf(getEnableDiagnosticTelemetry())); @@ -1537,6 +1549,16 @@ public void setPrivateServiceConnect(String privateServiceConnect) { this.privateServiceConnect = privateServiceConnect; } + public Boolean getEnableGraphMetadata() { + return enableGraphMetadata != null + ? enableGraphMetadata + : BigQueryJdbcUrlUtility.DEFAULT_ENABLE_GRAPH_VALUE; + } + + public void setEnableGraphMetadata(Boolean enableGraphMetadata) { + this.enableGraphMetadata = enableGraphMetadata; + } + @Override public PrintWriter getLogWriter() { return null; diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java index 55d9d4bde62b..c9e13aaab567 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java @@ -391,4 +391,27 @@ public void testParseDiagnosticTelemetryProperties() { assertThat(defaultDs.getEnableDiagnosticTelemetry()) .isEqualTo(TelemetryPropertyUtility.DEFAULT_ENABLE_DIAGNOSTIC_TELEMETRY_VALUE); } + + @Test + public void testEnableGraphMetadataProperties() { + String url = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "ProjectId=MyBigQueryProject;" + + "EnablePropertyGraphMetadata=1"; + + assertThat(BigQueryJdbcUrlUtility.parseUriProperty(url, "EnablePropertyGraphMetadata")) + .isEqualTo("1"); + + DataSource ds = DataSource.fromUrl(url); + assertThat(ds.getEnableGraphMetadata()).isTrue(); + + Properties props = ds.createProperties(); + assertThat(props.getProperty("EnablePropertyGraphMetadata")).isEqualTo("true"); + + String urlWithoutGraph = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;ProjectId=MyBigQueryProject"; + DataSource defaultDs = DataSource.fromUrl(urlWithoutGraph); + assertThat(defaultDs.getEnableGraphMetadata()) + .isEqualTo(BigQueryJdbcUrlUtility.DEFAULT_ENABLE_GRAPH_VALUE); + } } From c430c6b79b3e018367ccf24b6da5b7aba9bf6973 Mon Sep 17 00:00:00 2001 From: Neenu Shaji Date: Thu, 29 Oct 2026 10:31:13 -0400 Subject: [PATCH 02/11] Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../main/java/com/google/cloud/bigquery/jdbc/DataSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java index 440549c1e6b6..1dfbe2d3c68c 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java @@ -1549,7 +1549,7 @@ public void setPrivateServiceConnect(String privateServiceConnect) { this.privateServiceConnect = privateServiceConnect; } - public Boolean getEnableGraphMetadata() { + public boolean getEnableGraphMetadata() { return enableGraphMetadata != null ? enableGraphMetadata : BigQueryJdbcUrlUtility.DEFAULT_ENABLE_GRAPH_VALUE; From a285b57d599eb0137c1928d33b6f9c88b9e4d755 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Thu, 29 Oct 2026 10:54:11 -0400 Subject: [PATCH 03/11] address comments --- .../bigquery/jdbc/BigQueryConnection.java | 8 +++-- .../cloud/bigquery/jdbc/BigQueryDriver.java | 2 +- .../bigquery/jdbc/BigQueryJdbcUrlUtility.java | 7 ++-- .../cloud/bigquery/jdbc/DataSource.java | 36 +++++++++---------- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java index a80457d93e05..02f518a16ff4 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java @@ -164,7 +164,9 @@ public class BigQueryConnection extends BigQueryNoOpsConnection { BigQueryJdbcUrlUtility.OAUTH_SA_IMPERSONATION_TOKEN_LIFETIME_PROPERTY_NAME, BigQueryJdbcUrlUtility.OAUTH_SA_EMAIL_PROPERTY_NAME, BigQueryJdbcUrlUtility.OAUTH_PVT_KEY_PATH_PROPERTY_NAME, - BigQueryJdbcUrlUtility.OAUTH_CLIENT_ID_PROPERTY_NAME) + BigQueryJdbcUrlUtility.OAUTH_CLIENT_ID_PROPERTY_NAME, + BigQueryJdbcUrlUtility.ENABLE_DIAGNOSTIC_TELEMETRY_PROPERTY_NAME, + BigQueryJdbcUrlUtility.ENABLE_GRAPH_METADATA_PROPERTY_NAME) .build(); private HeaderProvider headerProvider; BigQueryReadClient bigQueryReadClient = null; @@ -315,7 +317,7 @@ public class BigQueryConnection extends BigQueryNoOpsConnection { } this.reqGoogleDriveScope = - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( String.valueOf(ds.getRequestGoogleDriveScope()), BigQueryJdbcUrlUtility.REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME); @@ -1650,7 +1652,7 @@ private boolean checkIsReadOnlyTokenUsed(Map authProps) { String readonlyValue = authProps.get(BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_READONLY_PROPERTY_NAME); if (readonlyValue != null) { - return BigQueryJdbcUrlUtility.convertIntToBoolean( + return BigQueryJdbcUrlUtility.convertToBoolean( readonlyValue, BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_READONLY_PROPERTY_NAME); } return false; diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java index 140636632316..204d3fc4e2ee 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java @@ -174,7 +174,7 @@ public Connection connect(String url, Properties info) throws SQLException { boolean enableGcpLogExporter = false; if (enableGcpLogExporterStr != null) { enableGcpLogExporter = - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( enableGcpLogExporterStr, BigQueryJdbcUrlUtility.ENABLE_GCP_LOG_EXPORTER_PROPERTY_NAME); } diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java index 9755a26a421d..bd00e7b945c2 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java @@ -193,7 +193,7 @@ protected boolean removeEldestEntry(Map.Entry> eldes static final String MAX_BYTES_BILLED_PROPERTY_NAME = "MaximumBytesBilled"; static final Long DEFAULT_MAX_BYTES_BILLED_VALUE = 0L; static final String LABELS_PROPERTY_NAME = "Labels"; - static final String ENABLE_GRAPH_PROPERTY_NAME = "EnablePropertyGraphMetadata"; + static final String ENABLE_GRAPH_METADATA_PROPERTY_NAME = "EnablePropertyGraphMetadata"; static final boolean DEFAULT_ENABLE_GRAPH_VALUE = false; static final List OVERRIDE_PROPERTIES = Arrays.asList( @@ -695,10 +695,9 @@ protected boolean removeEldestEntry(Map.Entry> eldes TelemetryPropertyUtility.DEFAULT_ENABLE_DIAGNOSTIC_TELEMETRY_VALUE)) .build(), BigQueryConnectionProperty.newBuilder() - .setName(ENABLE_GRAPH_PROPERTY_NAME) + .setName(ENABLE_GRAPH_METADATA_PROPERTY_NAME) .setDescription( "Enables or disables discovery of Property Graphs and related metadata in DatabaseMetaData methods.") - .setDefaultValue(String.valueOf(DEFAULT_ENABLE_GRAPH_VALUE)) .build()))); private static final List NETWORK_PROPERTIES = @@ -869,7 +868,7 @@ static String appendPropertiesToURL(String url, String callerClassName, Properti return urlBuilder.toString(); } - static boolean convertIntToBoolean(String value, String propertyName) { + static boolean convertToBoolean(String value, String propertyName) { int integerValue; try { diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java index 1dfbe2d3c68c..3152fb07f0f5 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java @@ -158,13 +158,13 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.ENABLE_HTAPI_PROPERTY_NAME, (ds, val) -> ds.setEnableHighThroughputAPI( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_HTAPI_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.UNSUPPORTED_HTAPI_FALLBACK_PROPERTY_NAME, (ds, val) -> ds.setUnsupportedHTAPIFallback( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.UNSUPPORTED_HTAPI_FALLBACK_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.HTAPI_MIN_TABLE_SIZE_PROPERTY_NAME, @@ -183,13 +183,13 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.ENABLE_SESSION_PROPERTY_NAME, (ds, val) -> ds.setEnableSession( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_SESSION_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ENABLE_TIMESTAMP_PICOS_PROPERTY_NAME, (ds, val) -> ds.setEnableTimestampPicos( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_TIMESTAMP_PICOS_PROPERTY_NAME))) .put(BigQueryJdbcUrlUtility.LOG_LEVEL_PROPERTY_NAME, DataSource::setLogLevel) .put(BigQueryJdbcUrlUtility.LOG_PATH_PROPERTY_NAME, DataSource::setLogPath) @@ -210,7 +210,7 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_READONLY_PROPERTY_NAME, (ds, val) -> ds.setOAuthAccessTokenReadonly( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_READONLY_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.OAUTH_REFRESH_TOKEN_PROPERTY_NAME, @@ -219,14 +219,14 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.USE_QUERY_CACHE_PROPERTY_NAME, (ds, val) -> ds.setUseQueryCache( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.USE_QUERY_CACHE_PROPERTY_NAME))) .put(BigQueryJdbcUrlUtility.QUERY_DIALECT_PROPERTY_NAME, DataSource::setQueryDialect) .put( BigQueryJdbcUrlUtility.ALLOW_LARGE_RESULTS_PROPERTY_NAME, (ds, val) -> ds.setAllowLargeResults( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ALLOW_LARGE_RESULTS_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.LARGE_RESULTS_TABLE_PROPERTY_NAME, @@ -259,7 +259,7 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.ENABLE_WRITE_API_PROPERTY_NAME, (ds, val) -> ds.setEnableWriteAPI( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_WRITE_API_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ADDITIONAL_PROJECTS_PROPERTY_NAME, @@ -268,14 +268,14 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.FILTER_TABLES_ON_DEFAULT_DATASET_PROPERTY_NAME, (ds, val) -> ds.setFilterTablesOnDefaultDataset( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.FILTER_TABLES_ON_DEFAULT_DATASET_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ENABLE_PROJECT_DISCOVERY_PROPERTY_NAME, (ds, val) -> ds.setEnableProjectDiscovery( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_PROJECT_DISCOVERY_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME, @@ -377,32 +377,32 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.ENABLE_GCP_TRACE_EXPORTER_PROPERTY_NAME, (ds, val) -> ds.setEnableGcpTraceExporter( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_GCP_TRACE_EXPORTER_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ENABLE_GCP_LOG_EXPORTER_PROPERTY_NAME, (ds, val) -> ds.setEnableGcpLogExporter( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_GCP_LOG_EXPORTER_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.USE_GLOBAL_OTEL_PROPERTY_NAME, (ds, val) -> ds.setUseGlobalOpenTelemetry( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.USE_GLOBAL_OTEL_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ENABLE_DIAGNOSTIC_TELEMETRY_PROPERTY_NAME, (ds, val) -> ds.setEnableDiagnosticTelemetry( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_DIAGNOSTIC_TELEMETRY_PROPERTY_NAME))) .put( - BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME, + BigQueryJdbcUrlUtility.ENABLE_GRAPH_METADATA_PROPERTY_NAME, (ds, val) -> ds.setEnableGraphMetadata( - BigQueryJdbcUrlUtility.convertIntToBoolean( - val, BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME))) + BigQueryJdbcUrlUtility.convertToBoolean( + val, BigQueryJdbcUrlUtility.ENABLE_GRAPH_METADATA_PROPERTY_NAME))) .build(); public static DataSource fromUrl(String url) { @@ -747,7 +747,7 @@ Properties createProperties() { } if (this.enableGraphMetadata != null) { connectionProperties.setProperty( - BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME, + BigQueryJdbcUrlUtility.ENABLE_GRAPH_METADATA_PROPERTY_NAME, String.valueOf(this.enableGraphMetadata)); } connectionProperties.setProperty( From c8c84678f8ec714b2203af2e34e97e50397d5f21 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Thu, 29 Oct 2026 11:38:33 -0400 Subject: [PATCH 04/11] address comments --- .../bigquery/jdbc/BigQueryConnection.java | 4 +- .../cloud/bigquery/jdbc/BigQueryDriver.java | 2 +- .../bigquery/jdbc/BigQueryJdbcUrlUtility.java | 9 ++--- .../cloud/bigquery/jdbc/DataSource.java | 38 +++++++++---------- .../jdbc/BigQueryJdbcUrlUtilityTest.java | 2 +- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java index a80457d93e05..7124cc4c4ff7 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java @@ -315,7 +315,7 @@ public class BigQueryConnection extends BigQueryNoOpsConnection { } this.reqGoogleDriveScope = - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( String.valueOf(ds.getRequestGoogleDriveScope()), BigQueryJdbcUrlUtility.REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME); @@ -1650,7 +1650,7 @@ private boolean checkIsReadOnlyTokenUsed(Map authProps) { String readonlyValue = authProps.get(BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_READONLY_PROPERTY_NAME); if (readonlyValue != null) { - return BigQueryJdbcUrlUtility.convertIntToBoolean( + return BigQueryJdbcUrlUtility.convertToBoolean( readonlyValue, BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_READONLY_PROPERTY_NAME); } return false; diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java index 140636632316..204d3fc4e2ee 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java @@ -174,7 +174,7 @@ public Connection connect(String url, Properties info) throws SQLException { boolean enableGcpLogExporter = false; if (enableGcpLogExporterStr != null) { enableGcpLogExporter = - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( enableGcpLogExporterStr, BigQueryJdbcUrlUtility.ENABLE_GCP_LOG_EXPORTER_PROPERTY_NAME); } diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java index 9755a26a421d..d22846470081 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java @@ -193,8 +193,8 @@ protected boolean removeEldestEntry(Map.Entry> eldes static final String MAX_BYTES_BILLED_PROPERTY_NAME = "MaximumBytesBilled"; static final Long DEFAULT_MAX_BYTES_BILLED_VALUE = 0L; static final String LABELS_PROPERTY_NAME = "Labels"; - static final String ENABLE_GRAPH_PROPERTY_NAME = "EnablePropertyGraphMetadata"; - static final boolean DEFAULT_ENABLE_GRAPH_VALUE = false; + static final String ENABLE_GRAPH_METADATA_PROPERTY_NAME = "EnableGraphMetadata"; + static final boolean DEFAULT_ENABLE_GRAPH_METADATA_VALUE = false; static final List OVERRIDE_PROPERTIES = Arrays.asList( BIGQUERY_ENDPOINT_OVERRIDE_PROPERTY_NAME, @@ -695,10 +695,9 @@ protected boolean removeEldestEntry(Map.Entry> eldes TelemetryPropertyUtility.DEFAULT_ENABLE_DIAGNOSTIC_TELEMETRY_VALUE)) .build(), BigQueryConnectionProperty.newBuilder() - .setName(ENABLE_GRAPH_PROPERTY_NAME) + .setName(ENABLE_GRAPH_METADATA_PROPERTY_NAME) .setDescription( "Enables or disables discovery of Property Graphs and related metadata in DatabaseMetaData methods.") - .setDefaultValue(String.valueOf(DEFAULT_ENABLE_GRAPH_VALUE)) .build()))); private static final List NETWORK_PROPERTIES = @@ -869,7 +868,7 @@ static String appendPropertiesToURL(String url, String callerClassName, Properti return urlBuilder.toString(); } - static boolean convertIntToBoolean(String value, String propertyName) { + static boolean convertToBoolean(String value, String propertyName) { int integerValue; try { diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java index 1dfbe2d3c68c..7d91c128d9a7 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java @@ -158,13 +158,13 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.ENABLE_HTAPI_PROPERTY_NAME, (ds, val) -> ds.setEnableHighThroughputAPI( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_HTAPI_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.UNSUPPORTED_HTAPI_FALLBACK_PROPERTY_NAME, (ds, val) -> ds.setUnsupportedHTAPIFallback( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.UNSUPPORTED_HTAPI_FALLBACK_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.HTAPI_MIN_TABLE_SIZE_PROPERTY_NAME, @@ -183,13 +183,13 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.ENABLE_SESSION_PROPERTY_NAME, (ds, val) -> ds.setEnableSession( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_SESSION_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ENABLE_TIMESTAMP_PICOS_PROPERTY_NAME, (ds, val) -> ds.setEnableTimestampPicos( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_TIMESTAMP_PICOS_PROPERTY_NAME))) .put(BigQueryJdbcUrlUtility.LOG_LEVEL_PROPERTY_NAME, DataSource::setLogLevel) .put(BigQueryJdbcUrlUtility.LOG_PATH_PROPERTY_NAME, DataSource::setLogPath) @@ -210,7 +210,7 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_READONLY_PROPERTY_NAME, (ds, val) -> ds.setOAuthAccessTokenReadonly( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_READONLY_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.OAUTH_REFRESH_TOKEN_PROPERTY_NAME, @@ -219,14 +219,14 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.USE_QUERY_CACHE_PROPERTY_NAME, (ds, val) -> ds.setUseQueryCache( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.USE_QUERY_CACHE_PROPERTY_NAME))) .put(BigQueryJdbcUrlUtility.QUERY_DIALECT_PROPERTY_NAME, DataSource::setQueryDialect) .put( BigQueryJdbcUrlUtility.ALLOW_LARGE_RESULTS_PROPERTY_NAME, (ds, val) -> ds.setAllowLargeResults( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ALLOW_LARGE_RESULTS_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.LARGE_RESULTS_TABLE_PROPERTY_NAME, @@ -259,7 +259,7 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.ENABLE_WRITE_API_PROPERTY_NAME, (ds, val) -> ds.setEnableWriteAPI( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_WRITE_API_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ADDITIONAL_PROJECTS_PROPERTY_NAME, @@ -268,14 +268,14 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.FILTER_TABLES_ON_DEFAULT_DATASET_PROPERTY_NAME, (ds, val) -> ds.setFilterTablesOnDefaultDataset( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.FILTER_TABLES_ON_DEFAULT_DATASET_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ENABLE_PROJECT_DISCOVERY_PROPERTY_NAME, (ds, val) -> ds.setEnableProjectDiscovery( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_PROJECT_DISCOVERY_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME, @@ -377,32 +377,32 @@ public class DataSource implements javax.sql.DataSource { BigQueryJdbcUrlUtility.ENABLE_GCP_TRACE_EXPORTER_PROPERTY_NAME, (ds, val) -> ds.setEnableGcpTraceExporter( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_GCP_TRACE_EXPORTER_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ENABLE_GCP_LOG_EXPORTER_PROPERTY_NAME, (ds, val) -> ds.setEnableGcpLogExporter( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_GCP_LOG_EXPORTER_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.USE_GLOBAL_OTEL_PROPERTY_NAME, (ds, val) -> ds.setUseGlobalOpenTelemetry( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.USE_GLOBAL_OTEL_PROPERTY_NAME))) .put( BigQueryJdbcUrlUtility.ENABLE_DIAGNOSTIC_TELEMETRY_PROPERTY_NAME, (ds, val) -> ds.setEnableDiagnosticTelemetry( - BigQueryJdbcUrlUtility.convertIntToBoolean( + BigQueryJdbcUrlUtility.convertToBoolean( val, BigQueryJdbcUrlUtility.ENABLE_DIAGNOSTIC_TELEMETRY_PROPERTY_NAME))) .put( - BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME, + BigQueryJdbcUrlUtility.ENABLE_GRAPH_METADATA_PROPERTY_NAME, (ds, val) -> ds.setEnableGraphMetadata( - BigQueryJdbcUrlUtility.convertIntToBoolean( - val, BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME))) + BigQueryJdbcUrlUtility.convertToBoolean( + val, BigQueryJdbcUrlUtility.ENABLE_GRAPH_METADATA_PROPERTY_NAME))) .build(); public static DataSource fromUrl(String url) { @@ -747,7 +747,7 @@ Properties createProperties() { } if (this.enableGraphMetadata != null) { connectionProperties.setProperty( - BigQueryJdbcUrlUtility.ENABLE_GRAPH_PROPERTY_NAME, + BigQueryJdbcUrlUtility.ENABLE_GRAPH_METADATA_PROPERTY_NAME, String.valueOf(this.enableGraphMetadata)); } connectionProperties.setProperty( @@ -1552,7 +1552,7 @@ public void setPrivateServiceConnect(String privateServiceConnect) { public boolean getEnableGraphMetadata() { return enableGraphMetadata != null ? enableGraphMetadata - : BigQueryJdbcUrlUtility.DEFAULT_ENABLE_GRAPH_VALUE; + : BigQueryJdbcUrlUtility.DEFAULT_ENABLE_GRAPH_METADATA_VALUE; } public void setEnableGraphMetadata(Boolean enableGraphMetadata) { diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java index c9e13aaab567..9d115d4a1c22 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java @@ -412,6 +412,6 @@ public void testEnableGraphMetadataProperties() { "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;ProjectId=MyBigQueryProject"; DataSource defaultDs = DataSource.fromUrl(urlWithoutGraph); assertThat(defaultDs.getEnableGraphMetadata()) - .isEqualTo(BigQueryJdbcUrlUtility.DEFAULT_ENABLE_GRAPH_VALUE); + .isEqualTo(BigQueryJdbcUrlUtility.DEFAULT_ENABLE_GRAPH_METADATA_VALUE); } } From b30489f57aad15210b462361fac1b6a044e1836a Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Thu, 29 Oct 2026 12:11:34 -0400 Subject: [PATCH 05/11] fix test --- .../cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java index 9d115d4a1c22..daf938657196 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java @@ -397,16 +397,15 @@ public void testEnableGraphMetadataProperties() { String url = "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + "ProjectId=MyBigQueryProject;" - + "EnablePropertyGraphMetadata=1"; + + "EnableGraphMetadata=1"; - assertThat(BigQueryJdbcUrlUtility.parseUriProperty(url, "EnablePropertyGraphMetadata")) - .isEqualTo("1"); + assertThat(BigQueryJdbcUrlUtility.parseUriProperty(url, "EnableGraphMetadata")).isEqualTo("1"); DataSource ds = DataSource.fromUrl(url); assertThat(ds.getEnableGraphMetadata()).isTrue(); Properties props = ds.createProperties(); - assertThat(props.getProperty("EnablePropertyGraphMetadata")).isEqualTo("true"); + assertThat(props.getProperty("EnableGraphMetadata")).isEqualTo("true"); String urlWithoutGraph = "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;ProjectId=MyBigQueryProject"; From 2eb99b703ababbeec3a2329e4a3e44e292399151 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Mon, 2 Nov 2026 14:44:32 -0500 Subject: [PATCH 06/11] address comments --- .../jdbc/BigQueryDatabaseMetaData.java | 15 +- .../jdbc/BigQueryDatabaseMetaDataTest.java | 135 ++++++++++++++---- 2 files changed, 119 insertions(+), 31 deletions(-) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java index 54d9991997e8..b0fa063ac674 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java @@ -1330,7 +1330,7 @@ private ResultSet getTablesImpl( && requestedTypes.contains(GRAPH_TABLE_TYPE); boolean isExactGraphTableName = tableNamePattern != null - && !needsListing(tableNamePattern) + && !tableNamePattern.contains("%") && tableNamePattern.contains("."); if (!isExactGraphTableName && !onlyGraphTablesRequested) { processTargetTablesConcurrently( @@ -1475,7 +1475,7 @@ Comparator defineGetTablesComparator(FieldList resultSchemaField Comparator.nullsFirst(String::compareTo)); } - private static String quoteIdentifier(String identifier) throws SQLException { + static String quoteIdentifier(String identifier) throws SQLException { if (identifier == null || !VALID_IDENTIFIER_PATTERN.matcher(identifier).matches()) { throw new BigQueryJdbcException( String.format("Invalid BigQuery identifier: '%s'", identifier)); @@ -1491,17 +1491,18 @@ boolean shouldSkipGraphTables(String tableNamePattern, Set requestedType return true; } if (tableNamePattern != null - && !needsListing(tableNamePattern) + && !tableNamePattern.contains("%") && !tableNamePattern.contains(".")) { return true; } return false; } - private String resolveGraphRegion() throws SQLException { + String resolveGraphRegion() throws SQLException { String location = this.connection != null ? this.connection.getLocation() : null; if (location == null || location.trim().isEmpty()) { location = DEFAULT_GRAPH_REGION; + LOG.info(String.format("Deafulting to Graph Location %s", DEFAULT_GRAPH_REGION)); } String normalized = location.trim().toLowerCase(Locale.US); return normalized.startsWith("region-") ? normalized : "region-" + normalized; @@ -1519,6 +1520,8 @@ void appendGraphTableRows( return; } + LOG.info("Appending Graph table rows"); + List targetCatalogs = effectiveCatalog != null ? Collections.singletonList(effectiveCatalog) @@ -5003,14 +5006,14 @@ private static synchronized String getExportedKeysSqlContent() { return exportedKeysSqlContent; } - private static synchronized String getGraphTablesDatasetSqlContent() { + static synchronized String getGraphTablesDatasetSqlContent() { if (graphTablesDatasetSqlContent == null) { graphTablesDatasetSqlContent = readSqlFromFile(GET_GRAPH_TABLES_DATASET_SQL); } return graphTablesDatasetSqlContent; } - private static synchronized String getGraphTablesRegionSqlContent() { + static synchronized String getGraphTablesRegionSqlContent() { if (graphTablesRegionSqlContent == null) { graphTablesRegionSqlContent = readSqlFromFile(GET_GRAPH_TABLES_REGION_SQL); } diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java index 9c9e5f10b77e..0f316af47cd7 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java @@ -726,6 +726,8 @@ public void testSortResults_Tables() { // Add rows in unsorted order (based on TYPE, CAT, SCHEM, NAME) results.add(createTableRow("cat_a", "sch_z", "table_1", "TABLE", schemaFields)); results.add(createTableRow("cat_b", "sch_a", "view_1", "VIEW", schemaFields)); + results.add( + createTableRow("cat_a", "sch_a", "RetailGraph.Product", "GRAPH TABLE", schemaFields)); results.add(createTableRow("cat_a", "sch_c", "table_2", "TABLE", schemaFields)); results.add(createTableRow(null, "sch_b", "table_0", "TABLE", schemaFields)); results.add(createTableRow("cat_a", "sch_z", "table_0", "TABLE", schemaFields)); @@ -734,44 +736,51 @@ public void testSortResults_Tables() { Comparator comparator = dbMetadata.defineGetTablesComparator(schemaFields); dbMetadata.sortResults(results, comparator, "getTables", dbMetadata.LOG); - // Expected order: TABLEs first, then VIEWs. Within type, sort by CAT, SCHEM, NAME - assertEquals(6, results.size()); + // Expected order: GRAPH TABLE first, then TABLEs, then VIEWs. Within type, sort by CAT, SCHEM, + // NAME + assertEquals(7, results.size()); - // 1. Null cat, sch_b, table_0, TABLE - assertTrue(results.get(0).get("TABLE_CAT").isNull(), "Row 0 TABLE_CAT should be null"); - assertEquals("sch_b", results.get(0).get("TABLE_SCHEM").getStringValue()); - assertEquals("table_0", results.get(0).get("TABLE_NAME").getStringValue()); - assertEquals("TABLE", results.get(0).get("TABLE_TYPE").getStringValue()); + // 1. cat_a, sch_a, RetailGraph.Product, GRAPH TABLE + assertEquals("cat_a", results.get(0).get("TABLE_CAT").getStringValue()); + assertEquals("sch_a", results.get(0).get("TABLE_SCHEM").getStringValue()); + assertEquals("RetailGraph.Product", results.get(0).get("TABLE_NAME").getStringValue()); + assertEquals("GRAPH TABLE", results.get(0).get("TABLE_TYPE").getStringValue()); - // 2. cat_a, sch_c, table_2, TABLE - assertEquals("cat_a", results.get(1).get("TABLE_CAT").getStringValue()); - assertEquals("sch_c", results.get(1).get("TABLE_SCHEM").getStringValue()); - assertEquals("table_2", results.get(1).get("TABLE_NAME").getStringValue()); + // 2. Null cat, sch_b, table_0, TABLE + assertTrue(results.get(1).get("TABLE_CAT").isNull(), "Row 1 TABLE_CAT should be null"); + assertEquals("sch_b", results.get(1).get("TABLE_SCHEM").getStringValue()); + assertEquals("table_0", results.get(1).get("TABLE_NAME").getStringValue()); assertEquals("TABLE", results.get(1).get("TABLE_TYPE").getStringValue()); - // 3. cat_a, sch_z, table_0, TABLE + // 3. cat_a, sch_c, table_2, TABLE assertEquals("cat_a", results.get(2).get("TABLE_CAT").getStringValue()); - assertEquals("sch_z", results.get(2).get("TABLE_SCHEM").getStringValue()); - assertEquals("table_0", results.get(2).get("TABLE_NAME").getStringValue()); + assertEquals("sch_c", results.get(2).get("TABLE_SCHEM").getStringValue()); + assertEquals("table_2", results.get(2).get("TABLE_NAME").getStringValue()); assertEquals("TABLE", results.get(2).get("TABLE_TYPE").getStringValue()); - // 4. cat_a, sch_z, table_1, TABLE + // 4. cat_a, sch_z, table_0, TABLE assertEquals("cat_a", results.get(3).get("TABLE_CAT").getStringValue()); assertEquals("sch_z", results.get(3).get("TABLE_SCHEM").getStringValue()); - assertEquals("table_1", results.get(3).get("TABLE_NAME").getStringValue()); + assertEquals("table_0", results.get(3).get("TABLE_NAME").getStringValue()); assertEquals("TABLE", results.get(3).get("TABLE_TYPE").getStringValue()); - // 5. cat_a, null, view_0, VIEW + // 5. cat_a, sch_z, table_1, TABLE assertEquals("cat_a", results.get(4).get("TABLE_CAT").getStringValue()); - assertTrue(results.get(4).get("TABLE_SCHEM").isNull(), "Row 4 TABLE_SCHEM should be null"); - assertEquals("view_0", results.get(4).get("TABLE_NAME").getStringValue()); - assertEquals("VIEW", results.get(4).get("TABLE_TYPE").getStringValue()); - - // 6. cat_b, sch_a, view_1, VIEW - assertEquals("cat_b", results.get(5).get("TABLE_CAT").getStringValue()); - assertEquals("sch_a", results.get(5).get("TABLE_SCHEM").getStringValue()); - assertEquals("view_1", results.get(5).get("TABLE_NAME").getStringValue()); + assertEquals("sch_z", results.get(4).get("TABLE_SCHEM").getStringValue()); + assertEquals("table_1", results.get(4).get("TABLE_NAME").getStringValue()); + assertEquals("TABLE", results.get(4).get("TABLE_TYPE").getStringValue()); + + // 6. cat_a, null, view_0, VIEW + assertEquals("cat_a", results.get(5).get("TABLE_CAT").getStringValue()); + assertTrue(results.get(5).get("TABLE_SCHEM").isNull(), "Row 5 TABLE_SCHEM should be null"); + assertEquals("view_0", results.get(5).get("TABLE_NAME").getStringValue()); assertEquals("VIEW", results.get(5).get("TABLE_TYPE").getStringValue()); + + // 7. cat_b, sch_a, view_1, VIEW + assertEquals("cat_b", results.get(6).get("TABLE_CAT").getStringValue()); + assertEquals("sch_a", results.get(6).get("TABLE_SCHEM").getStringValue()); + assertEquals("view_1", results.get(6).get("TABLE_NAME").getStringValue()); + assertEquals("VIEW", results.get(6).get("TABLE_TYPE").getStringValue()); } @Test @@ -3835,6 +3844,82 @@ public void testGetTableTypes_withGraphTablesEnabled() throws SQLException { } } + @Test + public void testShouldSkipGraphTables() { + Set tableOnly = Collections.singleton("TABLE"); + Set graphIncluded = new HashSet<>(Arrays.asList("TABLE", "GRAPH TABLE")); + + // Disabled connection property -> always skip + when(bigQueryConnection.isEnableGraphMetadata()).thenReturn(false); + assertTrue(dbMetadata.shouldSkipGraphTables(null, null)); + assertTrue(dbMetadata.shouldSkipGraphTables("%", graphIncluded)); + assertTrue(dbMetadata.shouldSkipGraphTables("RetailGraph.Product", graphIncluded)); + + // Enabled connection property + when(bigQueryConnection.isEnableGraphMetadata()).thenReturn(true); + // Requested types exclude GRAPH TABLE -> skip + assertTrue(dbMetadata.shouldSkipGraphTables("%", tableOnly)); + // Plain table names without '%' or '.' (including snake_case with '_') -> skip + assertTrue(dbMetadata.shouldSkipGraphTables("my_normal_table", null)); + assertTrue(dbMetadata.shouldSkipGraphTables("plain_table", graphIncluded)); + + // Wildcard '%', null pattern, or dot-qualified graph table names -> do not skip + assertFalse(dbMetadata.shouldSkipGraphTables(null, null)); + assertFalse(dbMetadata.shouldSkipGraphTables("%", null)); + assertFalse(dbMetadata.shouldSkipGraphTables("RetailGraph.Product", null)); + assertFalse(dbMetadata.shouldSkipGraphTables("Graph_.Person", graphIncluded)); + assertFalse(dbMetadata.shouldSkipGraphTables("my_graph.%", graphIncluded)); + } + + @Test + public void testResolveGraphRegion() throws SQLException { + when(bigQueryConnection.getLocation()).thenReturn(null); + assertEquals("region-us", dbMetadata.resolveGraphRegion()); + + when(bigQueryConnection.getLocation()).thenReturn(" "); + assertEquals("region-us", dbMetadata.resolveGraphRegion()); + + when(bigQueryConnection.getLocation()).thenReturn("US"); + assertEquals("region-us", dbMetadata.resolveGraphRegion()); + + when(bigQueryConnection.getLocation()).thenReturn("us-central1"); + assertEquals("region-us-central1", dbMetadata.resolveGraphRegion()); + + when(bigQueryConnection.getLocation()).thenReturn("region-eu"); + assertEquals("region-eu", dbMetadata.resolveGraphRegion()); + } + + @Test + public void testQuoteIdentifier() throws SQLException { + assertEquals("`my-project_1`", BigQueryDatabaseMetaData.quoteIdentifier("my-project_1")); + assertEquals("`my_dataset`", BigQueryDatabaseMetaData.quoteIdentifier("my_dataset")); + assertEquals("`region-us`", BigQueryDatabaseMetaData.quoteIdentifier("region-us")); + + assertThrows(BigQueryJdbcException.class, () -> BigQueryDatabaseMetaData.quoteIdentifier(null)); + assertThrows(BigQueryJdbcException.class, () -> BigQueryDatabaseMetaData.quoteIdentifier("")); + assertThrows( + BigQueryJdbcException.class, () -> BigQueryDatabaseMetaData.quoteIdentifier("bad`id")); + assertThrows( + BigQueryJdbcException.class, () -> BigQueryDatabaseMetaData.quoteIdentifier("drop;table")); + } + + @Test + public void testGraphTablesSqlContent() throws SQLException { + String datasetSql = + dbMetadata.replaceSqlParameters( + BigQueryDatabaseMetaData.getGraphTablesDatasetSqlContent(), + BigQueryDatabaseMetaData.quoteIdentifier("my-project"), + BigQueryDatabaseMetaData.quoteIdentifier("my_dataset")); + assertThat(datasetSql).contains("`my-project`.`my_dataset`.INFORMATION_SCHEMA.PROPERTY_GRAPHS"); + + String regionSql = + dbMetadata.replaceSqlParameters( + BigQueryDatabaseMetaData.getGraphTablesRegionSqlContent(), + BigQueryDatabaseMetaData.quoteIdentifier("my-project"), + BigQueryDatabaseMetaData.quoteIdentifier("region-us")); + assertThat(regionSql).contains("`my-project`.`region-us`.INFORMATION_SCHEMA.PROPERTY_GRAPHS"); + } + @FunctionalInterface private interface MetadataResultSetSupplier { ResultSet get(BigQueryDatabaseMetaData metadata) throws SQLException; From a831f43676fae7897e98f75853e31da7b2b874d7 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Mon, 2 Nov 2026 14:51:00 -0500 Subject: [PATCH 07/11] add test tag --- .../google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java index 98f675e16e05..a75a6e293497 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java @@ -823,6 +823,7 @@ public void testDatabaseMetadataGetTables() throws SQLException { @Test @Tag("disable_tpc") + @Tag("advanced) public void testDatabaseMetadataGetTables_PropertyGraph() throws SQLException { String nodeTable = "GRAPH_NODE_TABLE_" + randomNumber; String edgeTable = "GRAPH_EDGE_TABLE_" + randomNumber; From ff49045a9ec44f8a307225bad4566e995fce3d19 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Mon, 2 Nov 2026 15:04:07 -0500 Subject: [PATCH 08/11] use test helper --- .../cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java index a75a6e293497..94822b4e09bb 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java @@ -823,7 +823,7 @@ public void testDatabaseMetadataGetTables() throws SQLException { @Test @Tag("disable_tpc") - @Tag("advanced) + @Tag("advanced") public void testDatabaseMetadataGetTables_PropertyGraph() throws SQLException { String nodeTable = "GRAPH_NODE_TABLE_" + randomNumber; String edgeTable = "GRAPH_EDGE_TABLE_" + randomNumber; @@ -860,13 +860,7 @@ public void testDatabaseMetadataGetTables_PropertyGraph() throws SQLException { DatabaseMetaData metaData = conn.getMetaData(); // 1. Verify getTableTypes() includes "GRAPH TABLE" - Set tableTypes = new HashSet<>(); - try (ResultSet rsTypes = metaData.getTableTypes()) { - while (rsTypes.next()) { - tableTypes.add(rsTypes.getString("TABLE_TYPE")); - } - } - Assertions.assertTrue(tableTypes.contains("GRAPH TABLE")); + verifyTableTypes(metaData, Arrays.asList("EXTERNAL", "GRAPH TABLE", "TABLE", "VIEW")); // 2. Verify getTables() with wildcard pattern returns both node and edge elements Set graphTables = new HashSet<>(); From 788982bc9f0d4d381e173824b57c11f452ec1a30 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Tue, 3 Nov 2026 12:25:01 -0500 Subject: [PATCH 09/11] address comments --- .../jdbc/BigQueryDatabaseMetaData.java | 83 ++++++------------- ...ql => DatabaseMetaData_GetGraphTables.sql} | 2 +- ...atabaseMetaData_GetGraphTables_Dataset.sql | 29 ------- .../jdbc/BigQueryDatabaseMetaDataTest.java | 30 ++----- .../jdbc/it/ITDatabaseMetadataTest.java | 11 --- 5 files changed, 33 insertions(+), 122 deletions(-) rename java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/{DatabaseMetaData_GetGraphTables_Region.sql => DatabaseMetaData_GetGraphTables.sql} (95%) delete mode 100644 java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables_Dataset.sql diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java index b0fa063ac674..3996a9bf74c4 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java @@ -104,12 +104,8 @@ class BigQueryDatabaseMetaData implements DatabaseMetaData { private static final int DEFAULT_QUEUE_CAPACITY = 5000; private static final String GET_EXPORTED_KEYS_SQL = "DatabaseMetaData_GetExportedKeys.sql"; private static String exportedKeysSqlContent; - private static final String GET_GRAPH_TABLES_REGION_SQL = - "DatabaseMetaData_GetGraphTables_Region.sql"; - private static String graphTablesRegionSqlContent; - private static final String GET_GRAPH_TABLES_DATASET_SQL = - "DatabaseMetaData_GetGraphTables_Dataset.sql"; - private static String graphTablesDatasetSqlContent; + private static final String GET_GRAPH_TABLES_SQL = "DatabaseMetaData_GetGraphTables.sql"; + private static String graphTablesSqlContent; // Declared package-private for testing. static final String GOOGLE_SQL_QUOTED_IDENTIFIER = "`"; // Does not include SQL:2003 Keywords as per JDBC spec. @@ -153,7 +149,6 @@ class BigQueryDatabaseMetaData implements DatabaseMetaData { }; static final String GRAPH_TABLE_TYPE = "GRAPH TABLE"; private static final String DEFAULT_GRAPH_REGION = "us"; - private static final Pattern VALID_IDENTIFIER_PATTERN = Pattern.compile("^[A-Za-z0-9_\\-:.]+$"); String URL; BigQueryConnection connection; @@ -1331,6 +1326,7 @@ private ResultSet getTablesImpl( boolean isExactGraphTableName = tableNamePattern != null && !tableNamePattern.contains("%") + // If table name has a dot it is expected to be a graph table name. && tableNamePattern.contains("."); if (!isExactGraphTableName && !onlyGraphTablesRequested) { processTargetTablesConcurrently( @@ -1475,14 +1471,6 @@ Comparator defineGetTablesComparator(FieldList resultSchemaField Comparator.nullsFirst(String::compareTo)); } - static String quoteIdentifier(String identifier) throws SQLException { - if (identifier == null || !VALID_IDENTIFIER_PATTERN.matcher(identifier).matches()) { - throw new BigQueryJdbcException( - String.format("Invalid BigQuery identifier: '%s'", identifier)); - } - return GOOGLE_SQL_QUOTED_IDENTIFIER + identifier + GOOGLE_SQL_QUOTED_IDENTIFIER; - } - boolean shouldSkipGraphTables(String tableNamePattern, Set requestedTypes) { if (this.connection == null || !this.connection.isEnableGraphMetadata()) { return true; @@ -1527,32 +1515,20 @@ void appendGraphTableRows( ? Collections.singletonList(effectiveCatalog) : getAccessibleCatalogNames(); boolean isExactDataset = - effectiveSchemaPattern != null && !needsListing(effectiveSchemaPattern); + effectiveSchemaPattern != null && !effectiveSchemaPattern.contains("%"); String effectiveTablePattern = (tableNamePattern == null) ? "%" : tableNamePattern; for (String project : targetCatalogs) { - String formattedSql; - if (isExactDataset) { - formattedSql = - replaceSqlParameters( - getGraphTablesDatasetSqlContent(), - quoteIdentifier(project), - quoteIdentifier(effectiveSchemaPattern)); - } else { - formattedSql = - replaceSqlParameters( - getGraphTablesRegionSqlContent(), - quoteIdentifier(project), - quoteIdentifier(resolveGraphRegion())); - } + + String formattedSql = + replaceSqlParameters( + getGraphTablesSqlContent(), + project, + isExactDataset ? effectiveSchemaPattern : resolveGraphRegion()); try (PreparedStatement statement = this.connection.prepareStatement(formattedSql)) { - if (isExactDataset) { - statement.setString(1, effectiveTablePattern); - } else { - statement.setString(1, effectiveSchemaPattern == null ? "%" : effectiveSchemaPattern); - statement.setString(2, effectiveTablePattern); - } + statement.setString(1, effectiveSchemaPattern == null ? "%" : effectiveSchemaPattern); + statement.setString(2, effectiveTablePattern); try (ResultSet rs = statement.executeQuery()) { while (rs.next()) { @@ -1563,16 +1539,16 @@ void appendGraphTableRows( String remarks = sourceTable != null ? "Source: " + sourceTable : null; List values = new ArrayList<>(resultSchemaResults.size()); - values.add(createStringFieldValue(tableCat)); - values.add(createStringFieldValue(tableSchem)); - values.add(createStringFieldValue(tableName)); - values.add(createStringFieldValue(GRAPH_TABLE_TYPE)); - values.add(createStringFieldValue(remarks)); - values.add(createNullFieldValue()); - values.add(createNullFieldValue()); - values.add(createNullFieldValue()); - values.add(createNullFieldValue()); - values.add(createNullFieldValue()); + values.add(createStringFieldValue(tableCat)); // 1. TABLE_CAT + values.add(createStringFieldValue(tableSchem)); // 2. TABLE_SCHEM + values.add(createStringFieldValue(tableName)); // 3. TABLE_NAME + values.add(createStringFieldValue(GRAPH_TABLE_TYPE)); // 4. TABLE_TYPE + values.add(createStringFieldValue(remarks)); // 5. REMARKS + values.add(createNullFieldValue()); // 6. TYPE_CAT (always null) + values.add(createNullFieldValue()); // 7. TYPE_SCHEM (always null) + values.add(createNullFieldValue()); // 8. TYPE_NAME (always null) + values.add(createNullFieldValue()); // 9. SELF_REFERENCING_COL_NAME (always null) + values.add(createNullFieldValue()); // 10. REF_GENERATION (always null) collectedResults.add(FieldValueList.of(values, resultSchemaResults)); } } @@ -5006,18 +4982,11 @@ private static synchronized String getExportedKeysSqlContent() { return exportedKeysSqlContent; } - static synchronized String getGraphTablesDatasetSqlContent() { - if (graphTablesDatasetSqlContent == null) { - graphTablesDatasetSqlContent = readSqlFromFile(GET_GRAPH_TABLES_DATASET_SQL); - } - return graphTablesDatasetSqlContent; - } - - static synchronized String getGraphTablesRegionSqlContent() { - if (graphTablesRegionSqlContent == null) { - graphTablesRegionSqlContent = readSqlFromFile(GET_GRAPH_TABLES_REGION_SQL); + static synchronized String getGraphTablesSqlContent() { + if (graphTablesSqlContent == null) { + graphTablesSqlContent = readSqlFromFile(GET_GRAPH_TABLES_SQL); } - return graphTablesRegionSqlContent; + return graphTablesSqlContent; } static String readSqlFromFile(String filename) { diff --git a/java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables_Region.sql b/java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables.sql similarity index 95% rename from java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables_Region.sql rename to java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables.sql index a6ec6e197846..3bfdd4ea528c 100644 --- a/java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables_Region.sql +++ b/java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables.sql @@ -22,7 +22,7 @@ SELECT JSON_VALUE(t, '$.dataSourceTable.projectId'), '.', JSON_VALUE(t, '$.dataSourceTable.datasetId'), '.', JSON_VALUE(t, '$.dataSourceTable.tableId')) AS SOURCE_TABLE -FROM %1$s.%2$s.INFORMATION_SCHEMA.PROPERTY_GRAPHS, +FROM `%1$s.%2$s.INFORMATION_SCHEMA.PROPERTY_GRAPHS`, UNNEST(ARRAY_CONCAT( IFNULL(JSON_QUERY_ARRAY(property_graph_metadata_json, '$.nodeTables'), []), IFNULL(JSON_QUERY_ARRAY(property_graph_metadata_json, '$.edgeTables'), []))) AS t diff --git a/java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables_Dataset.sql b/java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables_Dataset.sql deleted file mode 100644 index 499a5b9fd608..000000000000 --- a/java-bigquery-jdbc/src/main/resources/com/google/cloud/bigquery/jdbc/DatabaseMetaData_GetGraphTables_Dataset.sql +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2026 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 - * - * https://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. - */ - -SELECT - property_graph_catalog AS TABLE_CAT, - property_graph_schema AS TABLE_SCHEM, - CONCAT(property_graph_name, '.', JSON_VALUE(t, '$.name')) AS TABLE_NAME, - CONCAT( - JSON_VALUE(t, '$.dataSourceTable.projectId'), '.', - JSON_VALUE(t, '$.dataSourceTable.datasetId'), '.', - JSON_VALUE(t, '$.dataSourceTable.tableId')) AS SOURCE_TABLE -FROM %1$s.%2$s.INFORMATION_SCHEMA.PROPERTY_GRAPHS, -UNNEST(ARRAY_CONCAT( - IFNULL(JSON_QUERY_ARRAY(property_graph_metadata_json, '$.nodeTables'), []), - IFNULL(JSON_QUERY_ARRAY(property_graph_metadata_json, '$.edgeTables'), []))) AS t -WHERE LOWER(CONCAT(property_graph_name, '.', JSON_VALUE(t, '$.name'))) LIKE LOWER(?) \ No newline at end of file diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java index 0f316af47cd7..d24a763ab03b 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java @@ -726,12 +726,12 @@ public void testSortResults_Tables() { // Add rows in unsorted order (based on TYPE, CAT, SCHEM, NAME) results.add(createTableRow("cat_a", "sch_z", "table_1", "TABLE", schemaFields)); results.add(createTableRow("cat_b", "sch_a", "view_1", "VIEW", schemaFields)); - results.add( - createTableRow("cat_a", "sch_a", "RetailGraph.Product", "GRAPH TABLE", schemaFields)); results.add(createTableRow("cat_a", "sch_c", "table_2", "TABLE", schemaFields)); results.add(createTableRow(null, "sch_b", "table_0", "TABLE", schemaFields)); results.add(createTableRow("cat_a", "sch_z", "table_0", "TABLE", schemaFields)); results.add(createTableRow("cat_a", null, "view_0", "VIEW", schemaFields)); + results.add( + createTableRow("cat_a", "sch_a", "RetailGraph.Product", "GRAPH TABLE", schemaFields)); Comparator comparator = dbMetadata.defineGetTablesComparator(schemaFields); dbMetadata.sortResults(results, comparator, "getTables", dbMetadata.LOG); @@ -3889,35 +3889,17 @@ public void testResolveGraphRegion() throws SQLException { assertEquals("region-eu", dbMetadata.resolveGraphRegion()); } - @Test - public void testQuoteIdentifier() throws SQLException { - assertEquals("`my-project_1`", BigQueryDatabaseMetaData.quoteIdentifier("my-project_1")); - assertEquals("`my_dataset`", BigQueryDatabaseMetaData.quoteIdentifier("my_dataset")); - assertEquals("`region-us`", BigQueryDatabaseMetaData.quoteIdentifier("region-us")); - - assertThrows(BigQueryJdbcException.class, () -> BigQueryDatabaseMetaData.quoteIdentifier(null)); - assertThrows(BigQueryJdbcException.class, () -> BigQueryDatabaseMetaData.quoteIdentifier("")); - assertThrows( - BigQueryJdbcException.class, () -> BigQueryDatabaseMetaData.quoteIdentifier("bad`id")); - assertThrows( - BigQueryJdbcException.class, () -> BigQueryDatabaseMetaData.quoteIdentifier("drop;table")); - } - @Test public void testGraphTablesSqlContent() throws SQLException { String datasetSql = dbMetadata.replaceSqlParameters( - BigQueryDatabaseMetaData.getGraphTablesDatasetSqlContent(), - BigQueryDatabaseMetaData.quoteIdentifier("my-project"), - BigQueryDatabaseMetaData.quoteIdentifier("my_dataset")); - assertThat(datasetSql).contains("`my-project`.`my_dataset`.INFORMATION_SCHEMA.PROPERTY_GRAPHS"); + BigQueryDatabaseMetaData.getGraphTablesSqlContent(), "my-project", "my_dataset"); + assertThat(datasetSql).contains("`my-project.my_dataset.INFORMATION_SCHEMA.PROPERTY_GRAPHS`"); String regionSql = dbMetadata.replaceSqlParameters( - BigQueryDatabaseMetaData.getGraphTablesRegionSqlContent(), - BigQueryDatabaseMetaData.quoteIdentifier("my-project"), - BigQueryDatabaseMetaData.quoteIdentifier("region-us")); - assertThat(regionSql).contains("`my-project`.`region-us`.INFORMATION_SCHEMA.PROPERTY_GRAPHS"); + BigQueryDatabaseMetaData.getGraphTablesSqlContent(), "my-project", "region-us"); + assertThat(regionSql).contains("`my-project.region-us.INFORMATION_SCHEMA.PROPERTY_GRAPHS`"); } @FunctionalInterface diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java index 94822b4e09bb..c52fa73dfcb2 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITDatabaseMetadataTest.java @@ -877,17 +877,6 @@ public void testDatabaseMetadataGetTables_PropertyGraph() throws SQLException { Assertions.assertTrue(graphTables.contains(graphName + ".Person")); Assertions.assertTrue(graphTables.contains(graphName + ".Knows")); Assertions.assertEquals(2, graphTables.size()); - } finally { - try (Connection cleanupConn = DriverManager.getConnection(ITBase.connectionUrl); - Statement cleanupStmt = cleanupConn.createStatement()) { - cleanupStmt.execute( - String.format( - "DROP PROPERTY GRAPH IF EXISTS `%s.%s.%s`", PROJECT_ID, DATASET, graphName)); - cleanupStmt.execute( - String.format("DROP TABLE IF EXISTS `%s.%s.%s`", PROJECT_ID, DATASET, edgeTable)); - cleanupStmt.execute( - String.format("DROP TABLE IF EXISTS `%s.%s.%s`", PROJECT_ID, DATASET, nodeTable)); - } } } From 4c6740d08ef48017a9030cd3312d24df59cf8226 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Tue, 3 Nov 2026 12:27:53 -0500 Subject: [PATCH 10/11] fix comment --- .../google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java index 3996a9bf74c4..87b563ed54cd 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java @@ -1326,7 +1326,6 @@ private ResultSet getTablesImpl( boolean isExactGraphTableName = tableNamePattern != null && !tableNamePattern.contains("%") - // If table name has a dot it is expected to be a graph table name. && tableNamePattern.contains("."); if (!isExactGraphTableName && !onlyGraphTablesRequested) { processTargetTablesConcurrently( @@ -1480,6 +1479,7 @@ boolean shouldSkipGraphTables(String tableNamePattern, Set requestedType } if (tableNamePattern != null && !tableNamePattern.contains("%") + // If table name has a dot it is expected to be a graph table name. && !tableNamePattern.contains(".")) { return true; } From 190783abd17531609cb6e53166bc83b21afc74e9 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Tue, 3 Nov 2026 15:54:03 -0500 Subject: [PATCH 11/11] Add identifier validation --- .../jdbc/BigQueryDatabaseMetaData.java | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java index 87b563ed54cd..075fe4f2a373 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java @@ -149,6 +149,16 @@ class BigQueryDatabaseMetaData implements DatabaseMetaData { }; static final String GRAPH_TABLE_TYPE = "GRAPH TABLE"; private static final String DEFAULT_GRAPH_REGION = "us"; + // Google Cloud project IDs: letters, digits, hyphens, and optional domain prefix (e.g. + // domain.com:proj-1) + private static final Pattern VALID_CATALOG_PATTERN = + Pattern.compile("^[A-Za-z0-9][A-Za-z0-9:._-]*$"); + // BigQuery dataset IDs: letters, digits, and underscores only + private static final Pattern VALID_SCHEMA_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$"); + // BigQuery region qualifier for regional INFORMATION_SCHEMA queries (e.g. region-us, + // region-us-central1) + private static final Pattern VALID_REGION_SCOPE_PATTERN = + Pattern.compile("^region-[A-Za-z0-9-]+$"); String URL; BigQueryConnection connection; @@ -1470,6 +1480,27 @@ Comparator defineGetTablesComparator(FieldList resultSchemaField Comparator.nullsFirst(String::compareTo)); } + static void validateCatalogIdentifier(String catalog) throws SQLException { + if (catalog == null || !VALID_CATALOG_PATTERN.matcher(catalog).matches()) { + throw new BigQueryJdbcException( + String.format("Invalid catalog (project ID) identifier: '%s'", catalog)); + } + } + + static void validateSchemaIdentifier(String schema) throws SQLException { + if (schema == null || !VALID_SCHEMA_PATTERN.matcher(schema).matches()) { + throw new BigQueryJdbcException( + String.format("Invalid schema (dataset ID) identifier: '%s'", schema)); + } + } + + static void validateRegionScopeIdentifier(String regionScope) throws SQLException { + if (regionScope == null || !VALID_REGION_SCOPE_PATTERN.matcher(regionScope).matches()) { + throw new BigQueryJdbcException( + String.format("Invalid region scope identifier: '%s'", regionScope)); + } + } + boolean shouldSkipGraphTables(String tableNamePattern, Set requestedTypes) { if (this.connection == null || !this.connection.isEnableGraphMetadata()) { return true; @@ -1517,14 +1548,15 @@ void appendGraphTableRows( boolean isExactDataset = effectiveSchemaPattern != null && !effectiveSchemaPattern.contains("%"); String effectiveTablePattern = (tableNamePattern == null) ? "%" : tableNamePattern; - + String scope = isExactDataset ? effectiveSchemaPattern : resolveGraphRegion(); + if (isExactDataset) { + validateSchemaIdentifier(scope); + } else { + validateRegionScopeIdentifier(scope); + } for (String project : targetCatalogs) { - - String formattedSql = - replaceSqlParameters( - getGraphTablesSqlContent(), - project, - isExactDataset ? effectiveSchemaPattern : resolveGraphRegion()); + validateCatalogIdentifier(project); + String formattedSql = replaceSqlParameters(getGraphTablesSqlContent(), project, scope); try (PreparedStatement statement = this.connection.prepareStatement(formattedSql)) { statement.setString(1, effectiveSchemaPattern == null ? "%" : effectiveSchemaPattern); @@ -2324,6 +2356,8 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) return BigQueryJsonResultSet.of(resultSchema, -1, queue, null); } + validateCatalogIdentifier(catalog); + validateSchemaIdentifier(schema); String sql = getExportedKeysSqlContent(); String formattedSql = replaceSqlParameters(sql, catalog, schema, table); PreparedStatement stmt = this.connection.prepareStatement(formattedSql);