diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java b/java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java index 5b89cf27eecf..f03f8279ca6b 100644 --- a/java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java @@ -706,10 +706,16 @@ private static Map parseUrlInternal(String url) { if (kv.length != 2 || !PROPERTY_NAME_MAP.containsKey(key)) { String ref = (kv.length == 2) ? key : part; String safeRef = ref.length() > 32 ? ref.substring(0, 32) + "..." : ref; - throw new BigQueryJdbcRuntimeException( - String.format("Wrong value or unknown setting: %s", safeRef)); + // Some tools can pass unknown keys. In order not to break compatibility, throw + // an exception only with incorrect format, otherwise log an error. + if (kv.length != 2) { + throw new BigQueryJdbcRuntimeException( + String.format("Wrong value or unknown setting: %s", safeRef)); + } else { + LOG.warning("Wrong value or unknown setting: %s", safeRef); + continue; + } } - map.put(PROPERTY_NAME_MAP.get(key), CharEscapers.decodeUriPath(kv[1].replace("+", "%2B"))); } return Collections.unmodifiableMap(map); diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java index 03e4ea3fb605..85eb254038f3 100644 --- a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java @@ -16,10 +16,7 @@ package com.google.cloud.bigquery.jdbc; import static com.google.common.truth.Truth.assertThat; -import static org.junit.jupiter.api.Assertions.fail; -import com.google.cloud.bigquery.exception.BigQueryJdbcException; -import com.google.cloud.bigquery.exception.BigQueryJdbcRuntimeException; import java.sql.Connection; import java.sql.DriverPropertyInfo; import java.sql.SQLException; @@ -98,15 +95,13 @@ public void testJDBCCompliantReturnsFalse() { } @Test - public void testConnectWithInvalidUrlChainsException() { - try { - bigQueryDriver.connect( - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;InvalidProperty=Value", - new Properties()); - fail("Expected SQLException"); - } catch (SQLException e) { - assertThat((Throwable) e).isInstanceOf(BigQueryJdbcException.class); - assertThat(e.getCause()).isInstanceOf(BigQueryJdbcRuntimeException.class); - } + public void testConnectWithInvalidUrlChainsNoException() throws SQLException { + Connection connection = + bigQueryDriver.connect( + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;" + + "InvalidProperty=Value", + new Properties()); + assertThat(connection.isClosed()).isFalse(); } } diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcLoggingBaseTest.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcLoggingBaseTest.java new file mode 100644 index 000000000000..b97a7bd1e0f4 --- /dev/null +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcLoggingBaseTest.java @@ -0,0 +1,67 @@ +/* + * 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 + * + * http://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. + */ + +package com.google.cloud.bigquery.jdbc; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +public abstract class BigQueryJdbcLoggingBaseTest extends BigQueryJdbcBaseTest { + + protected List capturedLogs = new ArrayList<>(); + private Handler handler; + private Logger logger; + private long threadId; + + @BeforeEach + public void setUpLogValidator() { + logger = BigQueryJdbcRootLogger.getRootLogger(); + capturedLogs.clear(); + threadId = Thread.currentThread().getId(); + handler = + new Handler() { + @Override + public void publish(LogRecord record) { + if (record.getThreadID() == threadId) { + capturedLogs.add(record); + } + } + + @Override + public void flush() {} + + @Override + public void close() throws SecurityException {} + }; + logger.addHandler(handler); + } + + @AfterEach + public void tearDownLogValidator() { + if (logger != null && handler != null) { + logger.removeHandler(handler); + } + } + + protected boolean assertLogContains(String snippet) { + return capturedLogs.stream().anyMatch(r -> r.getMessage().contains(snippet)); + } +} diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java index 99a013ddd76f..4f6769fc97f7 100644 --- a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtilityTest.java @@ -17,17 +17,16 @@ package com.google.cloud.bigquery.jdbc; import static com.google.common.truth.Truth.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import com.google.cloud.bigquery.exception.BigQueryJdbcRuntimeException; import java.util.Collections; import java.util.Map; import java.util.Properties; import org.junit.jupiter.api.Test; -public class BigQueryJdbcUrlUtilityTest { +public class BigQueryJdbcUrlUtilityTest extends BigQueryJdbcLoggingBaseTest { @Test public void testParsePropertyWithNoDefault() { @@ -41,27 +40,25 @@ public void testParsePropertyWithNoDefault() { } @Test - public void testParseUrlWithUnknownProperty_throwsException() { + public void testParseUrlWithUnknownProperty_no_exception() { String url = "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + "ProjectId=MyBigQueryProject;" + "UnknownProperty=SomeValue"; - assertThrows( - BigQueryJdbcRuntimeException.class, - () -> BigQueryJdbcUrlUtility.parseUriProperty(url, "ProjectId")); + BigQueryJdbcUrlUtility.parseUriProperty(url, "ProjectId"); + assertThat(assertLogContains("Wrong value or unknown setting")).isTrue(); } @Test - public void testParseUrlWithTypo_throwsException() { + public void testParseUrlWithTypo_no_exception() { String url = "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + "ProjectId=MyBigQueryProject;" + "ProjeectId=TypoValue"; - assertThrows( - BigQueryJdbcRuntimeException.class, - () -> BigQueryJdbcUrlUtility.parseUriProperty(url, "ProjectId")); + assertDoesNotThrow(() -> BigQueryJdbcUrlUtility.parseUriProperty(url, "ProjectId")); + assertThat(assertLogContains("Wrong value or unknown setting")).isTrue(); } @Test @@ -72,7 +69,7 @@ public void testParsePropertyWithDefault() { + "OAuthAccessToken=RedactedToken"; String result = BigQueryJdbcUrlUtility.parseUriProperty(url, "OAuthType"); - assertThat(result).isEqualTo(null); + assertThat(result).isNull(); } @Test @@ -143,14 +140,12 @@ public void testParseUrl_longUnknownProperty_sanitized() { String longKey = String.join("", Collections.nCopies(50, "a")); String url = "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + longKey + "=value"; - BigQueryJdbcRuntimeException e = - assertThrows( - BigQueryJdbcRuntimeException.class, () -> BigQueryJdbcUrlUtility.parseUrl(url)); - - assertThat(e.getMessage()).contains("Wrong value or unknown setting: "); - assertThat(e.getMessage()).contains("..."); - assertThat(e.getMessage()).doesNotContain(longKey); - assertThat(e.getMessage().length()).isLessThan(100); + assertDoesNotThrow(() -> BigQueryJdbcUrlUtility.parseUrl(url)); + String message = capturedLogs.get(0).getMessage(); + assertThat(message).contains("Wrong value or unknown setting: "); + assertThat(message).contains("..."); + assertThat(message).doesNotContain(longKey); + assertThat(message.length()).isLessThan(100); } @Test