Skip to content

Commit 64e8c67

Browse files
authored
Merge branch 'main' into samikshya-chand_data/u2m
2 parents da32910 + 0e10d04 commit 64e8c67

28 files changed

Lines changed: 566 additions & 125 deletions
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Enforce Release Freeze
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
7+
jobs:
8+
freeze-check:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Check out repository
13+
uses: actions/checkout@v4
14+
15+
- name: Set up jq
16+
run: sudo apt-get update && sudo apt-get install -y jq
17+
18+
- name: Enforce branch freeze logic
19+
shell: bash
20+
env:
21+
# GITHUB_HEAD_REF: Source branch name for PRs
22+
PR_BRANCH: ${{ github.head_ref }}
23+
run: |
24+
CONFIG_FILE="development/.release-config.json"
25+
26+
if [[ ! -f "$CONFIG_FILE" ]]; then
27+
echo "✅ No release config file - passing check."
28+
exit 0
29+
fi
30+
31+
FREEZE=$(jq '.freeze' "$CONFIG_FILE")
32+
33+
if [[ "$FREEZE" != "true" ]]; then
34+
echo "✅ Freeze is off - passing check."
35+
exit 0
36+
fi
37+
38+
ALLOW_LIST=( $(jq -r '.allow_list[]' "$CONFIG_FILE") )
39+
40+
BRANCH="$PR_BRANCH"
41+
ALLOWED=0
42+
43+
# Check for exact branch name in allow_list
44+
for ENTRY in $(jq -r '.allow_list[]' "$CONFIG_FILE"); do
45+
if [[ "$BRANCH" == "$ENTRY" ]]; then
46+
ALLOWED=1
47+
break
48+
fi
49+
done
50+
51+
if [[ "$ALLOWED" == "1" ]]; then
52+
echo "✅ Branch '$BRANCH' is in allow_list. Passing check."
53+
exit 0
54+
else
55+
echo "❌ Release freeze is ACTIVE!"
56+
REASON=$(jq -r '.reason' "$CONFIG_FILE")
57+
echo "Reason: $REASON"
58+
echo "Branch '$BRANCH' is NOT permitted to merge under current freeze rules."
59+
exit 1
60+
fi

NEXT_CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66

77
- **Query Tags support**: Added ability to attach key-value tags to SQL queries for analytical purposes that would appear in `system.query.history` table. Example: `jdbc:databricks://host;QUERY_TAGS=team:marketing,dashboard:abc123`.
88
- **SQL Scripting support**: Added support for [SQL Scripting](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-scripting)
9-
- 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.
9+
- 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.
10+
- Support for fetching schemas across all catalogs (when catalog is specified as null or a wildcard) in `DatabaseMetaData#getSchemas` API in SQL Execution mode.
11+
- **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.
1012

1113
### Updated
1214
- Databricks SDK dependency upgraded to latest version 0.60.0
1315

1416
### Fixed
1517
- Integrated Azure U2M flow into driver for improved stability.
18+
- Fixed `ResultSet.getString` for Boolean columns in Metadata result set.
1619
---
1720
*Note: When making changes, please add your change under the appropriate section with a brief description.*

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ Optional parameters:
9191
- `OAuth2RedirectUrlPort` - Ports for redirect URL (default: 8020)
9292
- `EnableOIDCDiscovery` - Enable OIDC discovery (default: 1)
9393
- `OAuthDiscoveryURL` - OIDC discovery endpoint (default: /oidc/.well-known/oauth-authorization-server)
94+
- `EnableSQLValidationForIsValid` - Enable SQL query based validation in `isValid()` connection checks (default: 0)
9495

9596
### Logging
9697

development/.release-freeze.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"freeze": false,
3+
"reason": "Release description",
4+
"allow_list": []
5+
}

src/main/java/com/databricks/jdbc/api/impl/DatabricksConnection.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,21 @@ public SQLXML createSQLXML() throws SQLException {
414414
@Override
415415
public boolean isValid(int timeout) throws SQLException {
416416
ValidationUtil.checkIfNonNegative(timeout, "timeout");
417-
return !isClosed();
417+
if (isClosed()) {
418+
return false;
419+
}
420+
if (connectionContext.getEnableSQLValidationForIsValid()) {
421+
try (Statement stmt = createStatement()) {
422+
stmt.setQueryTimeout(timeout);
423+
// This is a lightweight query to check if the connection is valid
424+
stmt.execute("SELECT VERSION()");
425+
return true;
426+
} catch (Exception e) {
427+
LOGGER.debug("Validation failed for isValid(): {}", e.getMessage());
428+
return false;
429+
}
430+
}
431+
return true;
418432
}
419433

420434
/**

src/main/java/com/databricks/jdbc/api/impl/DatabricksConnectionContext.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,12 @@ public String getHttpPath() {
230230
return getParameter(DatabricksJdbcUrlParams.HTTP_PATH);
231231
}
232232

233+
public boolean getEnableSQLValidationForIsValid() {
234+
LOGGER.debug("String getEnableSQLValidationForIsValid()");
235+
return getParameter(DatabricksJdbcUrlParams.ENABLE_SQL_VALIDATION_FOR_IS_VALID, "0")
236+
.equals("1");
237+
}
238+
233239
@Override
234240
public String getHostForOAuth() {
235241
return this.host;

src/main/java/com/databricks/jdbc/api/impl/DatabricksDatabaseMetaData.java

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import com.databricks.jdbc.api.internal.IDatabricksSession;
1010
import com.databricks.jdbc.common.*;
1111
import com.databricks.jdbc.common.util.DriverUtil;
12-
import com.databricks.jdbc.common.util.JdbcThreadUtils;
1312
import com.databricks.jdbc.dbclient.impl.common.MetadataResultSetBuilder;
1413
import com.databricks.jdbc.dbclient.impl.common.StatementId;
1514
import com.databricks.jdbc.exception.DatabricksSQLException;
@@ -20,8 +19,6 @@
2019
import com.databricks.sdk.service.sql.StatementState;
2120
import java.sql.*;
2221
import java.util.*;
23-
import java.util.concurrent.ExecutorService;
24-
import java.util.concurrent.Executors;
2522

2623
public class DatabricksDatabaseMetaData implements DatabaseMetaData {
2724

@@ -40,9 +37,6 @@ public class DatabricksDatabaseMetaData implements DatabaseMetaData {
4037
public static final String SYSTEM_FUNCTIONS = "DATABASE,IFNULL,USER";
4138
public static final String TIME_DATE_FUNCTIONS =
4239
"CURDATE,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURTIME,DAYNAME,DAYOFMONTH,DAYOFWEEK,DAYOFYEAR,HOUR,MINUTE,MONTH,MONTHNAME,NOW,QUARTER,SECOND,TIMESTAMPADD,TIMESTAMPDIFF,WEEK,YEAR";
43-
private static final Object THREAD_POOL_LOCK = new Object();
44-
private static ExecutorService schemasThreadPool = null;
45-
private static final int DEFAULT_MAX_THREADS = 10;
4640
private final IDatabricksConnectionInternal connection;
4741
private final IDatabricksSession session;
4842
private final MetadataResultSetBuilder metadataResultSetBuilder;
@@ -1505,48 +1499,6 @@ public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLExce
15051499
catalog, schemaPattern);
15061500
throwExceptionIfConnectionIsClosed();
15071501

1508-
if (session.getConnectionContext().getClientType() == DatabricksClientType.SEA
1509-
&& (catalog == null || catalog.equals("*") || catalog.equals("%"))) {
1510-
// Fetch catalogs from the metadata client
1511-
List<String> catalogList = new ArrayList<>();
1512-
try (ResultSet catalogs = getCatalogs()) {
1513-
while (catalogs.next()) {
1514-
String c = catalogs.getString(1);
1515-
if (c != null && !c.isEmpty()) {
1516-
catalogList.add(c);
1517-
}
1518-
}
1519-
}
1520-
1521-
// Process catalogs in parallel, gathering schema information
1522-
List<List<Object>> schemaRows =
1523-
JdbcThreadUtils.parallelFlatMap(
1524-
catalogList,
1525-
session.getConnectionContext(),
1526-
DEFAULT_MAX_THREADS, // Not significant since the executor is provided as a parameter
1527-
90, // 90 seconds timeout
1528-
c -> {
1529-
List<List<Object>> rows = new ArrayList<>();
1530-
try (ResultSet catalogSchemas =
1531-
session.getDatabricksMetadataClient().listSchemas(session, c, schemaPattern)) {
1532-
while (catalogSchemas.next()) {
1533-
List<Object> schemaRow = new ArrayList<>();
1534-
schemaRow.add(catalogSchemas.getString(1)); // TABLE_SCHEM
1535-
schemaRow.add(catalogSchemas.getString(2)); // TABLE_CATALOG
1536-
rows.add(schemaRow);
1537-
}
1538-
} catch (SQLException e) {
1539-
LOGGER.warn("Error fetching schemas for catalog %s %s", c, e.getMessage());
1540-
}
1541-
return rows;
1542-
},
1543-
getOrCreateSchemasThreadPool());
1544-
1545-
// Convert combined data into a result set
1546-
return metadataResultSetBuilder.getResultSetWithGivenRowsAndColumns(
1547-
SCHEMA_COLUMNS, schemaRows, METADATA_STATEMENT_ID, CommandName.LIST_SCHEMAS);
1548-
}
1549-
15501502
return session.getDatabricksMetadataClient().listSchemas(session, catalog, schemaPattern);
15511503
}
15521504

@@ -1659,23 +1611,6 @@ public boolean isWrapperFor(Class<?> iface) throws SQLException {
16591611
return iface != null && iface.isAssignableFrom(this.getClass());
16601612
}
16611613

1662-
private static ExecutorService getOrCreateSchemasThreadPool() {
1663-
synchronized (THREAD_POOL_LOCK) {
1664-
if (schemasThreadPool == null || schemasThreadPool.isShutdown()) {
1665-
// Could read max threads from a configuration property
1666-
schemasThreadPool =
1667-
Executors.newFixedThreadPool(
1668-
DEFAULT_MAX_THREADS,
1669-
r -> {
1670-
Thread t = new Thread(r, "jdbc-schemas-fetcher");
1671-
t.setDaemon(true);
1672-
return t;
1673-
});
1674-
}
1675-
return schemasThreadPool;
1676-
}
1677-
}
1678-
16791614
private void throwExceptionIfConnectionIsClosed() throws SQLException {
16801615
LOGGER.debug("private void throwExceptionIfConnectionIsClosed()");
16811616
if (!connection.getSession().isOpen()) {

src/main/java/com/databricks/jdbc/api/impl/converters/BitConverter.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,18 @@ public boolean toBoolean(Object object) throws DatabricksSQLException {
1717
return Boolean.parseBoolean((String) object);
1818
}
1919
throw new DatabricksSQLException(
20-
"Unsupported type for conversion to BIT: " + object.getClass(),
20+
"Unsupported type for conversion to BIT: " + (object == null ? "null" : object.getClass()),
21+
DatabricksDriverErrorCode.UNSUPPORTED_OPERATION);
22+
}
23+
24+
@Override
25+
public String toString(Object object) throws DatabricksSQLException {
26+
if (object instanceof Boolean) {
27+
return object.toString();
28+
}
29+
throw new DatabricksSQLException(
30+
"Unsupported type for conversion to String: "
31+
+ (object == null ? "null" : object.getClass()),
2132
DatabricksDriverErrorCode.UNSUPPORTED_OPERATION);
2233
}
2334
}

src/main/java/com/databricks/jdbc/api/internal/IDatabricksConnectionContext.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ public interface IDatabricksConnectionContext {
9696

9797
String getHttpPath();
9898

99+
/** Returns the value of the EnableSQLValidationForIsValid connection property. */
100+
boolean getEnableSQLValidationForIsValid();
101+
99102
String getProxyHost();
100103

101104
int getProxyPort();

src/main/java/com/databricks/jdbc/common/DatabricksJdbcUrlParams.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ public enum DatabricksJdbcUrlParams {
153153
HTTP_CONNECTION_REQUEST_TIMEOUT(
154154
"HttpConnectionRequestTimeout", "HTTP connection request timeout in seconds"),
155155
CLOUD_FETCH_SPEED_THRESHOLD(
156-
"CloudFetchSpeedThreshold", "Minimum expected download speed in MB/s", "0.1");
156+
"CloudFetchSpeedThreshold", "Minimum expected download speed in MB/s", "0.1"),
157+
ENABLE_SQL_VALIDATION_FOR_IS_VALID(
158+
"EnableSQLValidationForIsValid",
159+
"Enable SQL query execution for connection validation in isValid() method",
160+
"0");
157161

158162
private final String paramName;
159163
private final String defaultValue;

0 commit comments

Comments
 (0)