From 6148c0cd16d4dc39d514d1911fc84402df1721e2 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Mon, 1 Jun 2026 16:13:03 -0400 Subject: [PATCH 1/4] fix(bigquery-jdbc): configure logging early to capture URL parsing warnings and errors --- .../cloud/bigquery/jdbc/BigQueryDriver.java | 23 ++++++---- .../bigquery/jdbc/BigQueryJdbcUrlUtility.java | 24 ++++++++++ .../bigquery/jdbc/BigQueryDriverTest.java | 44 ++++++++++++++++++- 3 files changed, 81 insertions(+), 10 deletions(-) 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 5b138873b399..5a76382fd6e8 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 @@ -130,22 +130,19 @@ public Connection connect(String url, Properties info) throws SQLException { // strip 'jdbc:' from the URL, add any extra properties String connectionUri = BigQueryJdbcUrlUtility.appendPropertiesToURL(url.substring(5), this.toString(), info); - DataSource ds; - try { - ds = DataSource.fromUrl(connectionUri); - } catch (BigQueryJdbcRuntimeException e) { - throw new BigQueryJdbcException("Failed to parse connection URL", e); - } - // LogLevel - String logLevelStr = ds.getLogLevel(); + String logLevelStr = + BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation( + connectionUri, BigQueryJdbcUrlUtility.LOG_LEVEL_PROPERTY_NAME); if (logLevelStr == null) { logLevelStr = System.getenv(BigQueryJdbcUrlUtility.LOG_LEVEL_ENV_VAR); } Level logLevel = BigQueryJdbcUrlUtility.parseLogLevel(logLevelStr); // LogPath - String logPath = ds.getLogPath(); + String logPath = + BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation( + connectionUri, BigQueryJdbcUrlUtility.LOG_PATH_PROPERTY_NAME); if (logPath == null) { logPath = System.getenv(BigQueryJdbcUrlUtility.LOG_PATH_ENV_VAR); } @@ -155,6 +152,14 @@ public Connection connect(String url, Properties info) throws SQLException { BigQueryJdbcRootLogger.setLevel(logLevel, logPath); + DataSource ds; + try { + ds = DataSource.fromUrl(connectionUri); + } catch (BigQueryJdbcRuntimeException e) { + LOG.severe("Failed to parse connection URL", e); + throw new BigQueryJdbcException("Failed to parse connection URL", e); + } + // Logging starts from here. BigQueryConnection connection = new BigQueryConnection(connectionUri, ds); LOG.info( 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 c0dfcbd1f4aa..6afdae5bd8c0 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 @@ -662,6 +662,30 @@ static String parseUriProperty(String uri, String property) { return map.get(property); } + /** + * Parses a URI property from the given URI without validating any other properties. + * + * @param uri The URI to parse. + * @param property The name of the property to parse. + * @return The String value of the property, or null if the property is not found. + */ + static String parseUriPropertyWithoutValidation(String uri, String property) { + if (uri == null) { + return null; + } + String searchKey = ";" + property.toUpperCase() + "="; + String upperUri = uri.toUpperCase(); + int index = upperUri.indexOf(searchKey); + if (index == -1) { + return null; + } + int valueStart = index + searchKey.length(); + int valueEnd = uri.indexOf(';', valueStart); + String value = + (valueEnd == -1) ? uri.substring(valueStart) : uri.substring(valueStart, valueEnd); + return CharEscapers.decodeUriPath(value.replace("+", "%2B")); + } + /** * Parses the URL into a map of key-value pairs, validating that all keys are known properties. * diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java index 85eb254038f3..8258f76fc170 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java @@ -21,11 +21,13 @@ import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.util.Properties; +import java.util.logging.Level; import java.util.logging.Logger; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class BigQueryDriverTest { +public class BigQueryDriverTest extends BigQueryJdbcLoggingBaseTest { static BigQueryDriver bigQueryDriver; @@ -104,4 +106,44 @@ public void testConnectWithInvalidUrlChainsNoException() throws SQLException { new Properties()); assertThat(connection.isClosed()).isFalse(); } + + @Test + public void testUnknownPropertyWarningIsLogged() throws SQLException { + Connection connection = + bigQueryDriver.connect( + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;LogLevel=3;" + + "MyUnknownSetting=Value", + new Properties()); + assertThat(connection.isClosed()).isFalse(); + + boolean foundWarning = + capturedLogs.stream() + .anyMatch( + r -> + r.getLevel() == Level.WARNING + && r.getMessage() + .contains("Wrong value or unknown setting: MYUNKNOWNSETTING")); + assertThat(foundWarning).isTrue(); + } + + @Test + public void testMalformedUrlExceptionIsLogged() { + try { + bigQueryDriver.connect( + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;LogLevel=3;" + + "MalformedPropertyWithoutEquals", + new Properties()); + Assertions.fail("Should have thrown BigQueryJdbcException"); + } catch (SQLException e) { + boolean foundSevere = + capturedLogs.stream() + .anyMatch( + r -> + r.getLevel() == Level.SEVERE + && r.getMessage().contains("Failed to parse connection URL")); + assertThat(foundSevere).isTrue(); + } + } } From 9116a0e86d6ccafb2d53e6a4138c0bc9a7c13aca Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Mon, 1 Jun 2026 16:13:03 -0400 Subject: [PATCH 2/4] fix(bigquery-jdbc): configure logging early to capture URL parsing warnings and errors --- .../cloud/bigquery/jdbc/BigQueryDriver.java | 23 ++++++---- .../bigquery/jdbc/BigQueryJdbcUrlUtility.java | 31 +++++++++++++ .../bigquery/jdbc/BigQueryDriverTest.java | 44 ++++++++++++++++++- 3 files changed, 88 insertions(+), 10 deletions(-) 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 5b138873b399..5a76382fd6e8 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 @@ -130,22 +130,19 @@ public Connection connect(String url, Properties info) throws SQLException { // strip 'jdbc:' from the URL, add any extra properties String connectionUri = BigQueryJdbcUrlUtility.appendPropertiesToURL(url.substring(5), this.toString(), info); - DataSource ds; - try { - ds = DataSource.fromUrl(connectionUri); - } catch (BigQueryJdbcRuntimeException e) { - throw new BigQueryJdbcException("Failed to parse connection URL", e); - } - // LogLevel - String logLevelStr = ds.getLogLevel(); + String logLevelStr = + BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation( + connectionUri, BigQueryJdbcUrlUtility.LOG_LEVEL_PROPERTY_NAME); if (logLevelStr == null) { logLevelStr = System.getenv(BigQueryJdbcUrlUtility.LOG_LEVEL_ENV_VAR); } Level logLevel = BigQueryJdbcUrlUtility.parseLogLevel(logLevelStr); // LogPath - String logPath = ds.getLogPath(); + String logPath = + BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation( + connectionUri, BigQueryJdbcUrlUtility.LOG_PATH_PROPERTY_NAME); if (logPath == null) { logPath = System.getenv(BigQueryJdbcUrlUtility.LOG_PATH_ENV_VAR); } @@ -155,6 +152,14 @@ public Connection connect(String url, Properties info) throws SQLException { BigQueryJdbcRootLogger.setLevel(logLevel, logPath); + DataSource ds; + try { + ds = DataSource.fromUrl(connectionUri); + } catch (BigQueryJdbcRuntimeException e) { + LOG.severe("Failed to parse connection URL", e); + throw new BigQueryJdbcException("Failed to parse connection URL", e); + } + // Logging starts from here. BigQueryConnection connection = new BigQueryConnection(connectionUri, ds); LOG.info( 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 c0dfcbd1f4aa..0a19bed7a2c8 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 @@ -662,6 +662,37 @@ static String parseUriProperty(String uri, String property) { return map.get(property); } + /** + * Parses a URI property from the given URI without validating any other properties. + * + * @param uri The URI to parse. + * @param property The name of the property to parse. + * @return The String value of the property, or null if the property is not found. + */ + static String parseUriPropertyWithoutValidation(String uri, String property) { + if (uri == null) { + return null; + } + int start = 0; + int len = uri.length(); + while (start < len) { + int nextSemi = uri.indexOf(';', start); + int end = (nextSemi == -1) ? len : nextSemi; + + int eqIndex = uri.indexOf('=', start); + if (eqIndex > start && eqIndex < end) { + String key = uri.substring(start, eqIndex).trim(); + if (key.equalsIgnoreCase(property)) { + String value = uri.substring(eqIndex + 1, end); + return CharEscapers.decodeUriPath(value.replace("+", "%2B")); + } + } + + start = end + 1; + } + return null; + } + /** * Parses the URL into a map of key-value pairs, validating that all keys are known properties. * diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java index 85eb254038f3..8258f76fc170 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java @@ -21,11 +21,13 @@ import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.util.Properties; +import java.util.logging.Level; import java.util.logging.Logger; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class BigQueryDriverTest { +public class BigQueryDriverTest extends BigQueryJdbcLoggingBaseTest { static BigQueryDriver bigQueryDriver; @@ -104,4 +106,44 @@ public void testConnectWithInvalidUrlChainsNoException() throws SQLException { new Properties()); assertThat(connection.isClosed()).isFalse(); } + + @Test + public void testUnknownPropertyWarningIsLogged() throws SQLException { + Connection connection = + bigQueryDriver.connect( + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;LogLevel=3;" + + "MyUnknownSetting=Value", + new Properties()); + assertThat(connection.isClosed()).isFalse(); + + boolean foundWarning = + capturedLogs.stream() + .anyMatch( + r -> + r.getLevel() == Level.WARNING + && r.getMessage() + .contains("Wrong value or unknown setting: MYUNKNOWNSETTING")); + assertThat(foundWarning).isTrue(); + } + + @Test + public void testMalformedUrlExceptionIsLogged() { + try { + bigQueryDriver.connect( + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;LogLevel=3;" + + "MalformedPropertyWithoutEquals", + new Properties()); + Assertions.fail("Should have thrown BigQueryJdbcException"); + } catch (SQLException e) { + boolean foundSevere = + capturedLogs.stream() + .anyMatch( + r -> + r.getLevel() == Level.SEVERE + && r.getMessage().contains("Failed to parse connection URL")); + assertThat(foundSevere).isTrue(); + } + } } From 1ae6b5f3a979c395c4a6138491fa8d7e82ef38d8 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Mon, 1 Jun 2026 16:34:21 -0400 Subject: [PATCH 3/4] nit --- .../java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 5a76382fd6e8..f5c020d6ca8e 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 @@ -151,7 +151,7 @@ public Connection connect(String url, Properties info) throws SQLException { } BigQueryJdbcRootLogger.setLevel(logLevel, logPath); - + // Logging starts from here. DataSource ds; try { ds = DataSource.fromUrl(connectionUri); @@ -160,7 +160,6 @@ public Connection connect(String url, Properties info) throws SQLException { throw new BigQueryJdbcException("Failed to parse connection URL", e); } - // Logging starts from here. BigQueryConnection connection = new BigQueryConnection(connectionUri, ds); LOG.info( "Driver info : { {Database Product Name : %s}, " From 7b13442ebe1b37c2d8bad9655da29932ffc0c976 Mon Sep 17 00:00:00 2001 From: Neenu1995 Date: Tue, 2 Jun 2026 10:45:12 -0400 Subject: [PATCH 4/4] throw exception --- .../cloud/bigquery/jdbc/BigQueryDriver.java | 45 +++++++++++-------- .../bigquery/jdbc/BigQueryDriverTest.java | 19 ++++++++ 2 files changed, 45 insertions(+), 19 deletions(-) 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 b3a16ae829c8..15058ff01bd9 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 @@ -129,27 +129,34 @@ public Connection connect(String url, Properties info) throws SQLException { if (acceptsURL(url)) { String connectionUri = BigQueryJdbcUrlUtility.appendPropertiesToURL(url.substring(5), this.toString(), info); - // LogLevel - String logLevelStr = - BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation( - connectionUri, BigQueryJdbcUrlUtility.LOG_LEVEL_PROPERTY_NAME); - if (logLevelStr == null) { - logLevelStr = System.getenv(BigQueryJdbcUrlUtility.LOG_LEVEL_ENV_VAR); - } - Level logLevel = BigQueryJdbcUrlUtility.parseLogLevel(logLevelStr); + Level logLevel; + String logPath; + try { + // LogLevel + String logLevelStr = + BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation( + connectionUri, BigQueryJdbcUrlUtility.LOG_LEVEL_PROPERTY_NAME); + if (logLevelStr == null) { + logLevelStr = System.getenv(BigQueryJdbcUrlUtility.LOG_LEVEL_ENV_VAR); + } + logLevel = BigQueryJdbcUrlUtility.parseLogLevel(logLevelStr); - // LogPath - String logPath = - BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation( - connectionUri, BigQueryJdbcUrlUtility.LOG_PATH_PROPERTY_NAME); - if (logPath == null) { - logPath = System.getenv(BigQueryJdbcUrlUtility.LOG_PATH_ENV_VAR); - } - if (logPath == null) { - logPath = BigQueryJdbcUrlUtility.DEFAULT_LOG_PATH; - } + // LogPath + logPath = + BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation( + connectionUri, BigQueryJdbcUrlUtility.LOG_PATH_PROPERTY_NAME); + if (logPath == null) { + logPath = System.getenv(BigQueryJdbcUrlUtility.LOG_PATH_ENV_VAR); + } + if (logPath == null) { + logPath = BigQueryJdbcUrlUtility.DEFAULT_LOG_PATH; + } - BigQueryJdbcRootLogger.setLevel(logLevel, logPath); + BigQueryJdbcRootLogger.setLevel(logLevel, logPath); + } catch (RuntimeException e) { + LOG.log(Level.SEVERE, "Failed to parse connection URL properties", e); + throw new BigQueryJdbcException("Failed to parse connection URL properties", e); + } // Logging starts from here. DataSource ds; diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java index 8a8d91da11da..8a637ac1e3be 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java @@ -146,4 +146,23 @@ public void testMalformedUrlExceptionIsLogged() { && r.getMessage().contains("Failed to parse connection URL")); assertThat(foundSevere).isTrue(); } + + @Test + public void testInvalidLogLevelExceptionIsLogged() { + Assertions.assertThrows( + SQLException.class, + () -> + bigQueryDriver.connect( + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;LogLevel=invalidInt;", + new Properties())); + + boolean foundSevere = + capturedLogs.stream() + .anyMatch( + r -> + r.getLevel() == Level.SEVERE + && r.getMessage().contains("Failed to parse connection URL properties")); + assertThat(foundSevere).isTrue(); + } }