Skip to content
Merged
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
1 change: 1 addition & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- **SQL Scripting support**: Added support for [SQL Scripting](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-scripting)
- Added a client property `enableVolumeOperations` to enable GET/PUT/REMOVE volume operations on a stream. For backward compatibility, allowedVolumeIngestionPaths can also be used for REMOVE operation.
- Support for fetching schemas across all catalogs (when catalog is specified as null or a wildcard) in `DatabaseMetaData#getSchemas` API in SQL Execution mode.
- **Configurable SQL validation in isValid()**: Added `EnableSQLValidationForIsValid` connection property to control whether `isValid()` method executes an actual SQL query for server-side validation. Default value is 0.

### Updated
- Databricks SDK dependency upgraded to latest version 0.60.0
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ Optional parameters:
- `OAuth2RedirectUrlPort` - Ports for redirect URL (default: 8020)
- `EnableOIDCDiscovery` - Enable OIDC discovery (default: 1)
- `OAuthDiscoveryURL` - OIDC discovery endpoint (default: /oidc/.well-known/oauth-authorization-server)
- `EnableSQLValidationForIsValid` - Enable SQL query based validation in `isValid()` connection checks (default: 0)
Comment thread
msrathore-db marked this conversation as resolved.

### Logging

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,21 @@ public SQLXML createSQLXML() throws SQLException {
@Override
public boolean isValid(int timeout) throws SQLException {
ValidationUtil.checkIfNonNegative(timeout, "timeout");
return !isClosed();
if (isClosed()) {
return false;
Comment thread
msrathore-db marked this conversation as resolved.
}
if (connectionContext.getEnableSQLValidationForIsValid()) {
try (Statement stmt = createStatement()) {
stmt.setQueryTimeout(timeout);
// This is a lightweight query to check if the connection is valid
stmt.execute("SELECT VERSION()");
Comment thread
msrathore-db marked this conversation as resolved.
return true;
} catch (Exception e) {
LOGGER.debug("Validation failed for isValid(): {}", e.getMessage());
return false;
}
}
return true;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ public String getHttpPath() {
return getParameter(DatabricksJdbcUrlParams.HTTP_PATH);
}

public boolean getEnableSQLValidationForIsValid() {
LOGGER.debug("String getEnableSQLValidationForIsValid()");
return getParameter(DatabricksJdbcUrlParams.ENABLE_SQL_VALIDATION_FOR_IS_VALID, "0")
.equals("1");
}

@Override
public String getHostForOAuth() {
return this.host;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ public interface IDatabricksConnectionContext {

String getHttpPath();

/** Returns the value of the EnableSQLValidationForIsValid connection property. */
boolean getEnableSQLValidationForIsValid();

String getProxyHost();

int getProxyPort();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,11 @@ public enum DatabricksJdbcUrlParams {
HTTP_CONNECTION_REQUEST_TIMEOUT(
"HttpConnectionRequestTimeout", "HTTP connection request timeout in seconds"),
CLOUD_FETCH_SPEED_THRESHOLD(
"CloudFetchSpeedThreshold", "Minimum expected download speed in MB/s", "0.1");
"CloudFetchSpeedThreshold", "Minimum expected download speed in MB/s", "0.1"),
ENABLE_SQL_VALIDATION_FOR_IS_VALID(
"EnableSQLValidationForIsValid",
"Enable SQL query execution for connection validation in isValid() method",
"0");

private final String paramName;
private final String defaultValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public class DatabricksDriverPropertyUtil {
DatabricksJdbcUrlParams.ROWS_FETCHED_PER_BLOCK,
DatabricksJdbcUrlParams.DEFAULT_STRING_COLUMN_LENGTH,
DatabricksJdbcUrlParams.SOCKET_TIMEOUT,
DatabricksJdbcUrlParams.ENABLE_TOKEN_CACHE);
DatabricksJdbcUrlParams.ENABLE_TOKEN_CACHE,
DatabricksJdbcUrlParams.ENABLE_SQL_VALIDATION_FOR_IS_VALID);

public static List<DriverPropertyInfo> getMissingProperties(String url, Properties info)
throws DatabricksParsingException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,4 +483,38 @@ public void testQueryTagsInSessionConfigs() throws SQLException {
assertTrue(sessionConfigs.containsKey("query_tags"));
assertEquals("team:marketing,dashboard:abc123", sessionConfigs.get("query_tags"));
}

@Test
public void testIsValidWithSQLValidationEnabled() throws SQLException {
String jdbcUrlWithValidation = CATALOG_SCHEMA_JDBC_URL + ";EnableSQLValidationForIsValid=1";
IDatabricksConnectionContext connectionContextWithValidation =
DatabricksConnectionContext.parse(jdbcUrlWithValidation, new Properties());
when(databricksClient.createSession(
new Warehouse(WAREHOUSE_ID), CATALOG, SCHEMA, new HashMap<>()))
.thenReturn(IMMUTABLE_SESSION_INFO);
connection = new DatabricksConnection(connectionContextWithValidation, databricksClient);
connection.open();
DatabricksConnection spyConnection = spy(connection);
DatabricksStatement mockStatement = mock(DatabricksStatement.class);
doReturn(mockStatement).when(spyConnection).createStatement();
doNothing().when(mockStatement).setQueryTimeout(anyInt());
when(mockStatement.execute("SELECT VERSION()")).thenReturn(true);

assertTrue(spyConnection.isValid(5));
verify(spyConnection).createStatement();
verify(mockStatement).setQueryTimeout(5);
verify(mockStatement).execute("SELECT VERSION()");

DatabricksStatement mockStatementFail = mock(DatabricksStatement.class);
doReturn(mockStatementFail).when(spyConnection).createStatement();
doNothing().when(mockStatementFail).setQueryTimeout(anyInt());
when(mockStatementFail.execute("SELECT VERSION()"))
.thenThrow(new SQLException("Connection lost"));

assertFalse(spyConnection.isValid(5));
verify(mockStatementFail).setQueryTimeout(5);
verify(mockStatementFail).execute("SELECT VERSION()");

connection.close();
}
}
Loading