Skip to content

Commit fcb4fbb

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/callable-statement-in-params
2 parents 5f2833e + 72636bf commit fcb4fbb

File tree

24 files changed

+424
-548
lines changed

24 files changed

+424
-548
lines changed

.github/workflows/release-thin.yml

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,102 @@ permissions:
2020
contents: write
2121

2222
jobs:
23+
# Gate: Vulnerability scan must pass before publishing.
24+
# Runs OWASP Dependency Check against NVD and fails on CVSS >= 7.
25+
vulnerability-scan:
26+
if: false
27+
runs-on:
28+
group: databricks-protected-runner-group
29+
labels: linux-ubuntu-latest
30+
steps:
31+
- name: Checkout
32+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
33+
with:
34+
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.event.workflow_run.head_sha }}
35+
fetch-tags: true
36+
fetch-depth: 0
37+
38+
- name: Set up JDK
39+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
40+
with:
41+
java-version: 21
42+
distribution: 'adopt'
43+
44+
- name: Get JFrog OIDC token
45+
run: |
46+
set -euo pipefail
47+
48+
ID_TOKEN=$(curl -sLS \
49+
-H "User-Agent: actions/oidc-client" \
50+
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
51+
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=jfrog-github" | jq .value | tr -d '"')
52+
echo "::add-mask::${ID_TOKEN}"
53+
54+
ACCESS_TOKEN=$(curl -sLS -XPOST -H "Content-Type: application/json" \
55+
"https://databricks.jfrog.io/access/api/v1/oidc/token" \
56+
-d "{\"grant_type\": \"urn:ietf:params:oauth:grant-type:token-exchange\", \"subject_token_type\":\"urn:ietf:params:oauth:token-type:id_token\", \"subject_token\": \"${ID_TOKEN}\", \"provider_name\": \"github-actions\"}" | jq .access_token | tr -d '"')
57+
echo "::add-mask::${ACCESS_TOKEN}"
58+
59+
if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then
60+
echo "FAIL: Could not extract JFrog access token"
61+
exit 1
62+
fi
63+
64+
echo "JFROG_ACCESS_TOKEN=${ACCESS_TOKEN}" >> "$GITHUB_ENV"
65+
66+
- name: Configure maven
67+
run: |
68+
set -euo pipefail
69+
70+
mkdir -p ~/.m2
71+
cat > ~/.m2/settings.xml << EOF
72+
<settings>
73+
<mirrors>
74+
<mirror>
75+
<id>jfrog-central</id>
76+
<mirrorOf>*</mirrorOf>
77+
<url>https://databricks.jfrog.io/artifactory/db-maven/</url>
78+
</mirror>
79+
</mirrors>
80+
<servers>
81+
<server>
82+
<id>jfrog-central</id>
83+
<username>gha-service-account</username>
84+
<password>${JFROG_ACCESS_TOKEN}</password>
85+
</server>
86+
</servers>
87+
</settings>
88+
EOF
89+
90+
- name: Run OWASP Dependency Check
91+
run: |
92+
mvn -pl jdbc-core org.owasp:dependency-check-maven:check \
93+
-Dnvd.api.key=${{ secrets.NVD_API_KEY }} \
94+
-DfailBuildOnCVSS=7
95+
96+
- name: Upload scan reports
97+
if: always()
98+
uses: actions/upload-artifact@ea165f8d65b6db9b8a1f7b0951caef032b8f2f72 # v4
99+
with:
100+
name: release-thin-vulnerability-scan
101+
path: |
102+
jdbc-core/target/dependency-check-report.html
103+
jdbc-core/target/dependency-check-report.json
104+
23105
publish-thin:
24106
# DISABLED: Third-party package publishing frozen per company-wide policy.
25107
# To re-enable, replace 'false' below with the original condition:
26108
# github.event_name == 'workflow_dispatch' ||
27109
# (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
28110
if: false
111+
needs: vulnerability-scan
29112
runs-on:
30113
group: databricks-protected-runner-group
31114
labels: linux-ubuntu-latest
32115
steps:
33116
- name: Checkout
34117
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
35118
with:
36-
# If manual trigger: use input tag, else use the SHA from the completed workflow run
37119
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.event.workflow_run.head_sha }}
38120
fetch-tags: true
39121
fetch-depth: 0
@@ -55,14 +137,12 @@ jobs:
55137
run: |
56138
set -euo pipefail
57139
58-
# Get GitHub OIDC ID token
59140
ID_TOKEN=$(curl -sLS \
60141
-H "User-Agent: actions/oidc-client" \
61142
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
62143
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=jfrog-github" | jq .value | tr -d '"')
63144
echo "::add-mask::${ID_TOKEN}"
64145
65-
# Exchange for JFrog access token
66146
ACCESS_TOKEN=$(curl -sLS -XPOST -H "Content-Type: application/json" \
67147
"https://databricks.jfrog.io/access/api/v1/oidc/token" \
68148
-d "{\"grant_type\": \"urn:ietf:params:oauth:grant-type:token-exchange\", \"subject_token_type\":\"urn:ietf:params:oauth:token-type:id_token\", \"subject_token\": \"${ID_TOKEN}\", \"provider_name\": \"github-actions\"}" | jq .access_token | tr -d '"')
@@ -103,23 +183,13 @@ jobs:
103183
104184
echo "Maven configured to use JFrog registry"
105185
106-
# Step 1: Build and install dependencies to local Maven repository
107-
# This builds jdbc-core (and parent) without publishing them.
108-
# The -am flag builds all dependencies needed by assembly-thin.
109-
# We use -Prelease here to generate sources/javadoc JARs for jdbc-core,
110-
# which assembly-thin needs for its own sources/javadoc artifacts.
111-
# GPG signing is skipped since we're only installing locally, not publishing.
112186
- name: Build dependencies
113187
run: |
114188
mvn -Prelease clean install --batch-mode -pl jdbc-core -am -Dgpg.skip=true \
115189
-Dnvd.api.key=${{ secrets.NVD_API_KEY }} \
116190
-Dossindex.username=${{ secrets.OSSINDEX_USERNAME }} \
117191
-Dossindex.password=${{ secrets.OSSINDEX_PASSWORD }}
118192
119-
# Step 2: Deploy only the thin JAR module to Maven Central
120-
# We don't use -am here to avoid the central-publishing-maven-plugin
121-
# from collecting parent/jdbc-core artifacts into the deployment bundle.
122-
# The jdbc-core dependency is already available from Step 1.
123193
- name: Publish thin JAR to Maven Central
124194
run: |
125195
mvn -Prelease deploy --batch-mode -pl assembly-thin \
@@ -135,10 +205,8 @@ jobs:
135205
id: get_tag
136206
run: |
137207
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
138-
# For manual trigger, use the input tag directly
139208
TAG="${{ inputs.tag }}"
140209
else
141-
# For workflow_run, find the tag pointing to the current commit
142210
TAG=$(git tag --points-at HEAD | grep "^v" | head -1)
143211
if [ -z "$TAG" ]; then
144212
echo "Error: No tag found for current commit"
@@ -171,4 +239,4 @@ jobs:
171239
with:
172240
tag_name: ${{ steps.get_tag.outputs.tag }}
173241
files: |
174-
assembly-thin/target/databricks-jdbc-thin-*.jar
242+
assembly-thin/target/databricks-jdbc-thin-*.jar

.github/workflows/release.yml

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,89 @@ permissions:
1414
contents: write
1515

1616
jobs:
17+
# Gate: Vulnerability scan must pass before publishing.
18+
# Runs OWASP Dependency Check against NVD and fails on CVSS >= 7.
19+
vulnerability-scan:
20+
if: false
21+
runs-on:
22+
group: databricks-protected-runner-group
23+
labels: linux-ubuntu-latest
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
27+
28+
- name: Set up JDK
29+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
30+
with:
31+
java-version: 21
32+
distribution: 'adopt'
33+
34+
- name: Get JFrog OIDC token
35+
run: |
36+
set -euo pipefail
37+
38+
ID_TOKEN=$(curl -sLS \
39+
-H "User-Agent: actions/oidc-client" \
40+
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
41+
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=jfrog-github" | jq .value | tr -d '"')
42+
echo "::add-mask::${ID_TOKEN}"
43+
44+
ACCESS_TOKEN=$(curl -sLS -XPOST -H "Content-Type: application/json" \
45+
"https://databricks.jfrog.io/access/api/v1/oidc/token" \
46+
-d "{\"grant_type\": \"urn:ietf:params:oauth:grant-type:token-exchange\", \"subject_token_type\":\"urn:ietf:params:oauth:token-type:id_token\", \"subject_token\": \"${ID_TOKEN}\", \"provider_name\": \"github-actions\"}" | jq .access_token | tr -d '"')
47+
echo "::add-mask::${ACCESS_TOKEN}"
48+
49+
if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then
50+
echo "FAIL: Could not extract JFrog access token"
51+
exit 1
52+
fi
53+
54+
echo "JFROG_ACCESS_TOKEN=${ACCESS_TOKEN}" >> "$GITHUB_ENV"
55+
56+
- name: Configure maven
57+
run: |
58+
set -euo pipefail
59+
60+
mkdir -p ~/.m2
61+
cat > ~/.m2/settings.xml << EOF
62+
<settings>
63+
<mirrors>
64+
<mirror>
65+
<id>jfrog-central</id>
66+
<mirrorOf>*</mirrorOf>
67+
<url>https://databricks.jfrog.io/artifactory/db-maven/</url>
68+
</mirror>
69+
</mirrors>
70+
<servers>
71+
<server>
72+
<id>jfrog-central</id>
73+
<username>gha-service-account</username>
74+
<password>${JFROG_ACCESS_TOKEN}</password>
75+
</server>
76+
</servers>
77+
</settings>
78+
EOF
79+
80+
- name: Run OWASP Dependency Check
81+
run: |
82+
mvn -pl jdbc-core org.owasp:dependency-check-maven:check \
83+
-Dnvd.api.key=${{ secrets.NVD_API_KEY }} \
84+
-DfailBuildOnCVSS=7
85+
86+
- name: Upload scan reports
87+
if: always()
88+
uses: actions/upload-artifact@ea165f8d65b6db9b8a1f7b0951caef032b8f2f72 # v4
89+
with:
90+
name: release-vulnerability-scan
91+
path: |
92+
jdbc-core/target/dependency-check-report.html
93+
jdbc-core/target/dependency-check-report.json
94+
1795
publish:
1896
# DISABLED: Third-party package publishing frozen per company-wide policy.
1997
# Remove this line to re-enable publishing.
2098
if: false
99+
needs: vulnerability-scan
21100
runs-on:
22101
group: databricks-protected-runner-group
23102
labels: linux-ubuntu-latest
@@ -42,14 +121,12 @@ jobs:
42121
run: |
43122
set -euo pipefail
44123
45-
# Get GitHub OIDC ID token
46124
ID_TOKEN=$(curl -sLS \
47125
-H "User-Agent: actions/oidc-client" \
48126
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
49127
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=jfrog-github" | jq .value | tr -d '"')
50128
echo "::add-mask::${ID_TOKEN}"
51129
52-
# Exchange for JFrog access token
53130
ACCESS_TOKEN=$(curl -sLS -XPOST -H "Content-Type: application/json" \
54131
"https://databricks.jfrog.io/access/api/v1/oidc/token" \
55132
-d "{\"grant_type\": \"urn:ietf:params:oauth:grant-type:token-exchange\", \"subject_token_type\":\"urn:ietf:params:oauth:token-type:id_token\", \"subject_token\": \"${ID_TOKEN}\", \"provider_name\": \"github-actions\"}" | jq .access_token | tr -d '"')
@@ -123,4 +200,3 @@ jobs:
123200
with:
124201
files: |
125202
assembly-uber/target/databricks-jdbc-*.jar
126-

NEXT_CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
- Fixed `PARSE_SYNTAX_ERROR` for column names containing special characters (e.g., dots) when `EnableBatchedInserts` is enabled, by re-quoting column names with backticks in reconstructed multi-row INSERT statements.
1313
- Fixed Volume ingestion for SEA mode, which was broken due to statement being closed prematurely.
1414
- Fixed escaped pattern characters in catalogName for `getSchemas`, as returned catalogName should be unescaped.
15+
- Fixed `getColumnClassName()` returning null for VARIANT columns in SEA mode by adding VARIANT to the type system.
16+
- Fixed `getColumns()` returning `DATA_TYPE=0` (NULL) for GEOMETRY/GEOGRAPHY columns in Thrift mode. Now returns `Types.VARCHAR` (12) when geospatial is disabled and `Types.OTHER` (1111) when enabled, consistent with SEA mode.
1517

1618
---
1719
*Note: When making changes, please add your change under the appropriate section

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,9 +1132,18 @@ public ResultSet getCrossReference(
11321132
foreignTable));
11331133

11341134
throwExceptionIfConnectionIsClosed();
1135-
if (parentTable == null && foreignTable == null) {
1135+
// Thrift requires parentTable — null or empty parentTable is invalid
1136+
if (parentTable == null || parentTable.isEmpty()) {
1137+
LOGGER.debug("getCrossReference: parentTable is null or empty, throwing");
11361138
throw new DatabricksSQLException(
1137-
"Invalid argument: foreignTable and parentTableName are both null",
1139+
"Invalid argument: parentTable may not be null or empty",
1140+
DatabricksDriverErrorCode.INVALID_STATE);
1141+
}
1142+
// Empty foreign table is also invalid — Thrift server rejects it
1143+
if (foreignTable != null && foreignTable.isEmpty()) {
1144+
LOGGER.debug("getCrossReference: foreignTable is empty string, throwing");
1145+
throw new DatabricksSQLException(
1146+
"Invalid argument: foreignTable may not be empty",
11381147
DatabricksDriverErrorCode.INVALID_STATE);
11391148
}
11401149

src/main/java/com/databricks/jdbc/common/util/DatabricksTypeUtil.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ public static ColumnInfoTypeName getColumnInfoType(String typeName) {
116116
return ColumnInfoTypeName.MAP;
117117
case DatabricksTypeUtil.INTERVAL:
118118
return ColumnInfoTypeName.INTERVAL;
119+
case DatabricksTypeUtil.VARIANT:
120+
return ColumnInfoTypeName.VARIANT;
119121
}
120122
return ColumnInfoTypeName.USER_DEFINED_TYPE;
121123
}
@@ -163,6 +165,7 @@ public static int getColumnType(ColumnInfoTypeName typeName) {
163165
return Types.STRUCT;
164166
case ARRAY:
165167
return Types.ARRAY;
168+
case VARIANT:
166169
case GEOMETRY:
167170
case GEOGRAPHY:
168171
case USER_DEFINED_TYPE:
@@ -203,6 +206,7 @@ public static String getColumnTypeClassName(ColumnInfoTypeName typeName) {
203206
case CHAR:
204207
case STRING:
205208
case INTERVAL:
209+
case VARIANT:
206210
case USER_DEFINED_TYPE:
207211
return "java.lang.String";
208212
case TIMESTAMP:

src/main/java/com/databricks/jdbc/dbclient/impl/common/MetadataResultSetBuilder.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,8 @@ int getCode(String s) {
11311131
case "CHARACTER":
11321132
return 1;
11331133
case "VARIANT":
1134+
case "GEOMETRY":
1135+
case "GEOGRAPHY":
11341136
return 1111;
11351137
}
11361138
if (s.startsWith(INTERVAL)) {
@@ -1626,8 +1628,10 @@ List<List<Object>> getThriftRows(List<List<Object>> rows, List<ResultColumn> col
16261628
}
16271629
}
16281630
if (column.getColumnName().equals(DATA_TYPE_COLUMN.getColumnName())) {
1629-
// Check if complex datatype support is disabled and this is a complex type
1630-
if (!ctx.isComplexDatatypeSupportEnabled() && isComplexType(typeVal)) {
1631+
// Check if geospatial support is disabled and this is a geospatial type
1632+
if (!ctx.isGeoSpatialSupportEnabled() && isGeospatialType(typeVal)) {
1633+
object = Types.VARCHAR;
1634+
} else if (!ctx.isComplexDatatypeSupportEnabled() && isComplexType(typeVal)) {
16311635
object = Types.VARCHAR;
16321636
} else {
16331637
object = getCode(stripBaseTypeName(typeVal));

0 commit comments

Comments
 (0)