Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
public class BigQueryConversionException extends SQLException {

public BigQueryConversionException(String message, Throwable cause) {
super(BigQueryJdbcExceptionUtils.formatMessage(message, cause), cause);
super(
BigQueryJdbcExceptionUtils.formatMessage(message, cause),
BigQueryJdbcSqlStates.DATA_EXCEPTION,
cause);
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class BigQueryJdbcException extends SQLException {
* @param message The detail message.
*/
public BigQueryJdbcException(String message) {
super(message);
super(message, BigQueryJdbcSqlStates.GENERAL_ERROR);
}

/**
Expand All @@ -37,7 +37,7 @@ public BigQueryJdbcException(String message) {
* @param ex The InterruptedException to be thrown.
*/
public BigQueryJdbcException(InterruptedException ex) {
super(ex);
super(ex.getMessage(), BigQueryJdbcSqlStates.QUERY_CANCELED, ex);
}

/**
Expand All @@ -47,7 +47,10 @@ public BigQueryJdbcException(InterruptedException ex) {
* @param ex The BigQueryException to be thrown.
*/
public BigQueryJdbcException(String message, BigQueryException ex) {
super(BigQueryJdbcExceptionUtils.formatMessage(message, ex), ex);
super(
BigQueryJdbcExceptionUtils.formatMessage(message, ex),
BigQueryJdbcExceptionUtils.sqlStateForCause(ex),
ex);
this.bigQueryException = ex;
}

Expand All @@ -58,7 +61,10 @@ public BigQueryJdbcException(String message, BigQueryException ex) {
* @param cause Throwable that is being converted.
*/
public BigQueryJdbcException(String message, Throwable cause) {
super(BigQueryJdbcExceptionUtils.formatMessage(message, cause), cause);
super(
BigQueryJdbcExceptionUtils.formatMessage(message, cause),
BigQueryJdbcExceptionUtils.sqlStateForCause(cause),
cause);
}

/**
Expand All @@ -68,7 +74,10 @@ public BigQueryJdbcException(String message, Throwable cause) {
* @param cause Throwable that is being converted.
*/
public BigQueryJdbcException(Throwable cause) {
super(cause);
super(
cause == null ? null : cause.getMessage(),
BigQueryJdbcExceptionUtils.sqlStateForCause(cause),
cause);
}

public BigQueryException getBigQueryException() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.google.cloud.bigquery.exception;

import com.google.cloud.bigquery.BigQueryException;

/** Utility class for JDBC exceptions. */
final class BigQueryJdbcExceptionUtils {

Expand All @@ -37,4 +39,49 @@ public static String formatMessage(String message, Throwable cause) {
? "\n" + (cause.getMessage() != null ? cause.getMessage() : cause.toString())
: "");
}

/**
* Maps a cause to a standard SQL:2003 SQLState.
*
* <p>Returns {@code HY000} (general error) for anything unrecognised, so the result is always a
* valid 5-character state and never null.
*
* @param cause the underlying cause, may be null.
* @return a 5-character SQLState.
*/
static String sqlStateForCause(Throwable cause) {
if (!(cause instanceof BigQueryException)) {
return BigQueryJdbcSqlStates.GENERAL_ERROR;
}
String reason = ((BigQueryException) cause).getReason();
if (reason == null) {
return BigQueryJdbcSqlStates.GENERAL_ERROR;
}
switch (reason) {
case "invalidQuery":
case "invalid":
case "badRequest":
return BigQueryJdbcSqlStates.SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION;
case "accessDenied":
return BigQueryJdbcSqlStates.INSUFFICIENT_PRIVILEGE;
case "invalidUser":
return BigQueryJdbcSqlStates.INVALID_AUTHORIZATION;
case "quotaExceeded":
case "rateLimitExceeded":
case "resourcesExceeded":
return BigQueryJdbcSqlStates.INSUFFICIENT_RESOURCES;
case "responseTooLarge":
return BigQueryJdbcSqlStates.PROGRAM_LIMIT_EXCEEDED;
case "stopped":
return BigQueryJdbcSqlStates.QUERY_CANCELED;
case "backendError":
case "internalError":
case "jobInternalError":
return BigQueryJdbcSqlStates.SYSTEM_ERROR;
case "notImplemented":
return BigQueryJdbcSqlStates.FEATURE_NOT_SUPPORTED;
default:
return BigQueryJdbcSqlStates.GENERAL_ERROR;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class BigQueryJdbcSqlFeatureNotSupportedException extends SQLFeatureNotSu
* @param message The detail message.
*/
public BigQueryJdbcSqlFeatureNotSupportedException(String message) {
super(message);
super(message, BigQueryJdbcSqlStates.FEATURE_NOT_SUPPORTED);
}

/**
Expand All @@ -36,6 +36,6 @@ public BigQueryJdbcSqlFeatureNotSupportedException(String message) {
* @param ex The BigQueryException to be thrown.
*/
public BigQueryJdbcSqlFeatureNotSupportedException(BigQueryException ex) {
super(ex);
super(ex.getMessage(), BigQueryJdbcSqlStates.FEATURE_NOT_SUPPORTED, ex);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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.exception;

/**
* Standard SQL:2003 SQLState codes used by the driver.
*
* <p>A SQLState is a 5-character code: a 2-character class followed by a 3-character subclass.
* These values are defined by the SQL standard and are portable across databases; nothing here is
* BigQuery-specific. {@code BigQueryDatabaseMetaData.getSQLStateType()} declares that the driver
* emits SQL:2003 states, so do not mix in X/Open or ODBC-only codes.
*/
final class BigQueryJdbcSqlStates {

/** 08 — connection exception. */
static final String CONNECTION_EXCEPTION = "08006";

/** 0A — feature not supported. */
static final String FEATURE_NOT_SUPPORTED = "0A000";

/** 22 — data exception (bad value, failed conversion). */
static final String DATA_EXCEPTION = "22000";

/** 28 — invalid authorization specification (authentication failed). */
static final String INVALID_AUTHORIZATION = "28000";

/** 42 — syntax error or access rule violation. */
static final String SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION = "42000";

static final String INSUFFICIENT_PRIVILEGE = "42501";

/** 53 — insufficient resources. */
static final String INSUFFICIENT_RESOURCES = "53000";

/** 54 — program limit exceeded. */
static final String PROGRAM_LIMIT_EXCEEDED = "54000";

/** 57 — operator intervention. */
static final String QUERY_CANCELED = "57014";

/** 58 — system error. */
static final String SYSTEM_ERROR = "58000";

/** HY — general error; the fallback when nothing more specific applies. */
static final String GENERAL_ERROR = "HY000";

private BigQueryJdbcSqlStates() {
// Utility class, prevent instantiation
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@ public class BigQueryJdbcSqlSyntaxErrorException extends SQLSyntaxErrorException
* @param ex The BigQueryException to be thrown.
*/
public BigQueryJdbcSqlSyntaxErrorException(BigQueryException ex) {
super(ex.getMessage(), "Incorrect SQL syntax.");
super(ex.getMessage(), BigQueryJdbcSqlStates.SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION, ex);
}

public BigQueryJdbcSqlSyntaxErrorException(String message, BigQueryException ex) {
super(BigQueryJdbcExceptionUtils.formatMessage(message, ex), ex);
super(
BigQueryJdbcExceptionUtils.formatMessage(message, ex),
BigQueryJdbcSqlStates.SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION,
ex);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.google.cloud.bigquery.jdbc;

import com.google.cloud.bigquery.jdbc.telemetry.v1.TelemetryManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -177,6 +178,11 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
LOG.severe("Exception occurred during " + methodName + ": " + errMsg, cause);
}

TelemetryManager.recordError(
TelemetryManager.extractErrorCode(cause),
TelemetryManager.extractXdbcCode(cause),
methodName);

throw cause;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@
import java.util.logging.Logger;

/** Utility builder for constructing {@link DriverEnvironment} telemetry protos. */
final class DriverEnvironmentBuilder {
private static final Logger logger = Logger.getLogger(DriverEnvironmentBuilder.class.getName());
final class DriverEnvironmentDetector {
private static final Logger logger = Logger.getLogger(DriverEnvironmentDetector.class.getName());

static final String DRIVER_NAME = "google-bigquery-jdbc-driver";
static final String DRIVER_NAME = "Google-BigQuery-JDBC-Driver";
static final String CLIENT_LANGUAGE = "java";
static final String DEFAULT_TELEMETRY_TAG_DIR = ".bigquery-jdbc";
static final String DEFAULT_TELEMETRY_TAG_FILE = "telemetry-tag";
static final String UNKNOWN = "unknown";
static final String RESTRICTED = "restricted";

private DriverEnvironmentBuilder() {}
private DriverEnvironmentDetector() {}

static DriverEnvironment build() {
return build(null);
Expand Down Expand Up @@ -171,7 +171,7 @@ static String getOrCreateTelemetryTag(Path customFilePath) {
logger.log(Level.WARNING, "Failed to persist telemetry tag to file", e);
}
return newId;
} catch (SecurityException e) {
} catch (RuntimeException e) {
return UUID.randomUUID().toString();
}
}
Expand Down
Loading
Loading