Skip to content

Commit 3e55124

Browse files
committed
Merge branch 'main' into cb2
2 parents fb91c97 + f10f15e commit 3e55124

53 files changed

Lines changed: 3162 additions & 296 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
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: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,18 @@
44

55
### Added
66

7+
- **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`.
8+
- **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.
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.
12+
- Implement multi-row INSERT batching optimization for prepared statements to improve performance when executing large batches of INSERT operations.
13+
714
### Updated
15+
- Databricks SDK dependency upgraded to latest version 0.60.0
816

917
### Fixed
10-
18+
- Integrated Azure U2M flow into driver for improved stability.
19+
- Fixed `ResultSet.getString` for Boolean columns in Metadata result set.
1120
---
1221
*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+
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
<httpclient.version>4.5.14</httpclient.version>
5656
<commons-configuration.version>2.10.1</commons-configuration.version>
5757
<commons-io.version>2.14.0</commons-io.version>
58-
<databricks-sdk.version>0.52.0</databricks-sdk.version>
58+
<databricks-sdk.version>0.60.0</databricks-sdk.version>
5959
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
6060
<sql-logic-test.version>0.3</sql-logic-test.version>
6161
<lz4-compression.version>1.8.0</lz4-compression.version>

scripts/githooks/post-commit

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,23 @@ if ! git diff --quiet; then
1212
echo "Please 'git add' and 'git commit' these to include formatting changes."
1313
echo "========================================================================"
1414
echo
15-
# Optional: show the changed files
1615
git status --short
1716
else
1817
echo
1918
echo "✓ Spotless checked: No further formatting changes needed after commit."
2019
echo
20+
fi
21+
22+
# Check if the latest commit message contains a Signed-off-by: line
23+
if ! git log -1 --pretty=%B | grep -q "Signed-off-by:"; then
24+
echo
25+
echo "========================================================================"
26+
echo "❗ WARNING: Your last commit is missing a Signed-off-by line."
27+
echo "Please amend your commit with 'git commit -s --amend' to add it."
28+
echo "========================================================================"
29+
echo
30+
else
31+
echo
32+
echo "✓ DCO check: Last commit includes a Signed-off-by line."
33+
echo
2134
fi

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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ public String getHostUrl() throws DatabricksParsingException {
215215
}
216216
}
217217

218+
@Override
219+
public String getHost() {
220+
return this.host;
221+
}
222+
218223
@Override
219224
public IDatabricksComputeResource getComputeResource() {
220225
return computeResource;
@@ -225,6 +230,12 @@ public String getHttpPath() {
225230
return getParameter(DatabricksJdbcUrlParams.HTTP_PATH);
226231
}
227232

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+
228239
@Override
229240
public String getHostForOAuth() {
230241
return this.host;
@@ -1019,4 +1030,9 @@ public int getTelemetryFlushIntervalInMilliseconds() {
10191030
return Math.max(
10201031
1000, Integer.parseInt(getParameter(DatabricksJdbcUrlParams.TELEMETRY_FLUSH_INTERVAL)));
10211032
}
1033+
1034+
@Override
1035+
public boolean isBatchedInsertsEnabled() {
1036+
return getParameter(DatabricksJdbcUrlParams.ENABLE_BATCHED_INSERTS).equals("1");
1037+
}
10221038
}

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()) {

0 commit comments

Comments
 (0)