-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix(bigquery-jdbc): add proper version to BigQueryDriver #13294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| /* | ||
| * 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.utils; | ||
|
|
||
| import com.google.cloud.bigquery.jdbc.BigQueryJdbcCustomLogger; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.util.Properties; | ||
| import java.util.concurrent.atomic.AtomicReference; | ||
|
|
||
| /** Utility class to load and parse the JDBC driver version from dependencies.properties. */ | ||
| public final class BigQueryJdbcVersionUtility { | ||
|
|
||
| private static final BigQueryJdbcCustomLogger LOG = | ||
| new BigQueryJdbcCustomLogger(BigQueryJdbcVersionUtility.class.getName()); | ||
|
|
||
| private static final AtomicReference<String> parsedDriverVersion = new AtomicReference<>(null); | ||
| private static final AtomicReference<Integer> parsedDriverMajorVersion = | ||
| new AtomicReference<>(null); | ||
| private static final AtomicReference<Integer> parsedDriverMinorVersion = | ||
| new AtomicReference<>(null); | ||
|
|
||
| private BigQueryJdbcVersionUtility() { | ||
| // Utility class, static methods only. | ||
| } | ||
|
|
||
| /** | ||
| * Gets the full driver version string. | ||
| * | ||
| * @return the driver version string, e.g., "1.0.0-SNAPSHOT" | ||
| */ | ||
| public static String getDriverVersion() { | ||
| ensureLoaded(); | ||
| return parsedDriverVersion.get(); | ||
| } | ||
|
|
||
| /** | ||
| * Gets the driver major version. | ||
| * | ||
| * @return the major version number | ||
| */ | ||
| public static int getDriverMajorVersion() { | ||
| ensureLoaded(); | ||
| return parsedDriverMajorVersion.get() != null ? parsedDriverMajorVersion.get() : 0; | ||
| } | ||
|
|
||
| /** | ||
| * Gets the driver minor version. | ||
| * | ||
| * @return the minor version number | ||
| */ | ||
| public static int getDriverMinorVersion() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above |
||
| ensureLoaded(); | ||
| return parsedDriverMinorVersion.get() != null ? parsedDriverMinorVersion.get() : 0; | ||
| } | ||
|
|
||
| private static void ensureLoaded() { | ||
| if (parsedDriverVersion.get() != null) { | ||
| return; | ||
| } | ||
| Properties props = new Properties(); | ||
| try (InputStream input = | ||
| BigQueryJdbcVersionUtility.class.getResourceAsStream( | ||
| "/com/google/cloud/bigquery/jdbc/dependencies.properties")) { | ||
| if (input == null) { | ||
| String errorMessage = | ||
| "Could not find dependencies.properties. Driver version information is unavailable."; | ||
| IllegalStateException ex = new IllegalStateException(errorMessage); | ||
| LOG.severe(errorMessage, ex); | ||
| throw ex; | ||
| } | ||
| props.load(input); | ||
| String versionString = props.getProperty("version.jdbc"); | ||
| if (versionString == null || versionString.trim().isEmpty()) { | ||
| String errorMessage = | ||
| "The property version.jdbc not found or empty in dependencies.properties."; | ||
| IllegalStateException ex = new IllegalStateException(errorMessage); | ||
| LOG.severe(errorMessage, ex); | ||
| throw ex; | ||
| } | ||
| parsedDriverVersion.compareAndSet(null, versionString.trim()); | ||
| String[] parts = versionString.split("\\."); | ||
| if (parts.length < 2) { | ||
| return; | ||
| } | ||
| parsedDriverMajorVersion.compareAndSet(null, Integer.parseInt(parts[0])); | ||
| String minorPart = parts[1]; | ||
| String numericMinor = minorPart.replaceAll("[^0-9].*", ""); | ||
| if (!numericMinor.isEmpty()) { | ||
| parsedDriverMinorVersion.compareAndSet(null, Integer.parseInt(numericMinor)); | ||
| } | ||
| } catch (IOException | NumberFormatException e) { | ||
| String errorMessage = | ||
| "Error reading dependencies.properties. Driver version information is" | ||
| + " unavailable. Error: " | ||
| + e.getMessage(); | ||
| IllegalStateException ex = new IllegalStateException(errorMessage, e); | ||
| LOG.severe(errorMessage, ex); | ||
| throw ex; | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+17
to
+116
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Concurrency Race Condition & Robustness IssueThere is a race condition in the lazy initialization logic of Additionally, if the version string has only one part (e.g., SolutionSince this is a utility class loading static classpath resources, using a package com.google.cloud.bigquery.jdbc.utils;
import com.google.cloud.bigquery.jdbc.BigQueryJdbcCustomLogger;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/** Utility class to load and parse the JDBC driver version from dependencies.properties. */
public final class BigQueryJdbcVersionUtility {
private static final BigQueryJdbcCustomLogger LOG =
new BigQueryJdbcCustomLogger(BigQueryJdbcVersionUtility.class.getName());
private static final String driverVersion;
private static final int driverMajorVersion;
private static final int driverMinorVersion;
static {
String version = "0.0.0";
int major = 0;
int minor = 0;
try (InputStream input =
BigQueryJdbcVersionUtility.class.getResourceAsStream(
"/com/google/cloud/bigquery/jdbc/dependencies.properties")) {
if (input == null) {
String errorMessage =
"Could not find dependencies.properties. Driver version information is unavailable.";
IllegalStateException ex = new IllegalStateException(errorMessage);
LOG.severe(errorMessage, ex);
throw ex;
}
Properties props = new Properties();
props.load(input);
String versionString = props.getProperty("version.jdbc");
if (versionString == null || versionString.trim().isEmpty()) {
String errorMessage =
"The property version.jdbc not found or empty in dependencies.properties.";
IllegalStateException ex = new IllegalStateException(errorMessage);
LOG.severe(errorMessage, ex);
throw ex;
}
version = versionString.trim();
String[] parts = version.split("\\.");
if (parts.length > 0) {
major = Integer.parseInt(parts[0]);
}
if (parts.length > 1) {
String minorPart = parts[1];
String numericMinor = minorPart.replaceAll("[^0-9].*", "");
if (!numericMinor.isEmpty()) {
minor = Integer.parseInt(numericMinor);
}
}
} catch (IOException | NumberFormatException e) {
String errorMessage =
"Error reading dependencies.properties. Driver version information is"
+ " unavailable. Error: "
+ e.getMessage();
IllegalStateException ex = new IllegalStateException(errorMessage, e);
LOG.severe(errorMessage, ex);
throw ex;
}
driverVersion = version;
driverMajorVersion = major;
driverMinorVersion = minor;
}
private BigQueryJdbcVersionUtility() {
// Utility class, static methods only.
}
/**
* Gets the full driver version string.
*
* @return the driver version string, e.g., "1.0.0-SNAPSHOT"
*/
public static String getDriverVersion() {
return driverVersion;
}
/**
* Gets the driver major version.
*
* @return the major version number
*/
public static int getDriverMajorVersion() {
return driverMajorVersion;
}
/**
* Gets the driver minor version.
*
* @return the minor version number
*/
public static int getDriverMinorVersion() {
return driverMinorVersion;
}
}
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree with gemini, we should address concurrency issue here |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this and the minorVersion function with this new impl could throw
IllegalStateExceptionforBigQueryDriver.getMajorVersion()andgetMinorVersion(), right?I think we need to confirm JDBC spec if that's okay or should it throw SQL exception or should it default to something and not throw error at all