Skip to content

Commit 0e7d912

Browse files
feat: Avatical Removal Part 3/3 - Remove Avatica dependency completely (#166)
Completes the removal of Apache Calcite Avatica from jdbc-core. The driver no longer depends on Avatica for result set handling, cursor management, type accessors - Remove Avatica from StreamingResultSet: no longer extends AvaticaResultSet. Implements DataCloudResultSet directly with all JDBC ResultSet methods delegating to QueryJDBCAccessor instances. Adds proper checkClosed() guards on all methods. - Remove Avatica cursor layer: delete MetadataCursor (extended AbstractCursor) and MetadataResultSet (extended AvaticaResultSet). Replace with DataCloudMetadataResultSet, a standalone metadata result set implementation. - Extract DataCloudQueryAccessor interface: defines the accessor contract (all typed getters) that QueryJDBCAccessor implements, replacing the dependency on Avatica's AbstractCursor.Accessor. - Rename for clarity: SimpleResultSetMetaData → DataCloudResultSetMetaData, SimpleMetadataResultSet → DataCloudMetadataResultSet, DataCloudAccessor → DataCloudQueryAccessor.
1 parent d0301f5 commit 0e7d912

62 files changed

Lines changed: 1355 additions & 1772 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.

buildSrc/src/main/kotlin/shading.gradle.kts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ abstract class ShadingExtension @Inject constructor(
3838
"META-INF/LICENSE*", "META-INF/NOTICE*",
3939
"META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "META-INF/*.xml",
4040
"**/*.proto", "org.slf4j",
41-
"META-INF/services/com.fasterxml.*", "org.apache.calcite.avatica.remote.Driver",
41+
"META-INF/services/com.fasterxml.*",
4242
".netbeans_automatic_build", "git.properties", "google-http-client.properties",
4343
"storage.v1.json", "pipes-fork-server-default-log4j2.xml",
4444
"dependencies.properties", "arrow-git.properties"
@@ -73,9 +73,6 @@ abstract class ShadingExtension @Inject constructor(
7373
relocate("okhttp3", "$shadeBase.okhttp3")
7474
relocate("okio", "$shadeBase.okio")
7575
relocate("org.apache.arrow", "$shadeBase.org.apache.arrow")
76-
relocate("org.apache.calcite", "$shadeBase.org.apache.calcite") {
77-
exclude("org.apache.calcite.avatica.remote.Driver")
78-
}
7976
relocate("org.apache.commons", "$shadeBase.org.apache.commons")
8077
relocate("org.apache.hc", "$shadeBase.org.apache.hc")
8178

gradle/libs.versions.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ net-jodah-failsafe = "3.3.2"
2020
netty = "4.1.132.Final"
2121
# This is soft pinned to 4.* (as we didn't invest in the upgrade yet) in `buildSrc/src/main/kotlin/version-updates.gradle.kts`
2222
okhttp3 = "4.12.0"
23-
# @pin this version as the following versions have a breaking Cursor change, that - with the upcoming Avactica removal - we currently don't want to invest in
24-
org-apache-calcite-avatica-core = "1.26.0"
2523
org-apache-commons-commons-lang3 = "3.20.0"
2624
# This is soft pinned to 3.* (as the driver is targetting in Spark 3) in `buildSrc/src/main/kotlin/version-updates.gradle.kts`
2725
org-apache-spark = "3.5.8"
@@ -43,7 +41,6 @@ slf4j = "2.0.17"
4341
[libraries]
4442
apache-arrow-memory-netty = { module = "org.apache.arrow:arrow-memory-netty", version.ref = "arrow" }
4543
apache-arrow-vector = { module = "org.apache.arrow:arrow-vector", version.ref = "arrow" }
46-
apache-calcite-avatica = { module = "org.apache.calcite.avatica:avatica-core", version.ref = "org-apache-calcite-avatica-core" }
4744
apache-commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "org-apache-commons-commons-lang3" }
4845
apache-httpcomponents-httpclient = { module = "org.apache.httpcomponents.client5:httpclient5", version.ref = "apache-httpcomponents-httpclient" }
4946
assertj = { module = "org.assertj:assertj-core", version.ref = "org-assertj-assertj-core" }

jdbc-core/build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ dependencies {
1818
implementation(project(":jdbc-util"))
1919
implementation(libs.slf4j.api)
2020
implementation(libs.bundles.arrow)
21-
implementation(libs.apache.calcite.avatica)
2221
implementation(libs.guava)
2322
implementation(libs.jackson.databind)
2423
implementation(libs.failsafe)

jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/ArrowStreamReaderCursor.java

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
import static com.salesforce.datacloud.jdbc.util.ThrowingFunction.rethrowFunction;
88

9+
import com.salesforce.datacloud.jdbc.core.accessor.QueryJDBCAccessor;
910
import com.salesforce.datacloud.jdbc.core.accessor.QueryJDBCAccessorFactory;
1011
import java.io.IOException;
1112
import java.sql.SQLException;
1213
import java.time.ZoneId;
13-
import java.util.Calendar;
1414
import java.util.List;
1515
import java.util.concurrent.atomic.AtomicInteger;
1616
import java.util.stream.Collectors;
@@ -20,12 +20,9 @@
2020
import org.apache.arrow.vector.FieldVector;
2121
import org.apache.arrow.vector.VectorSchemaRoot;
2222
import org.apache.arrow.vector.ipc.ArrowStreamReader;
23-
import org.apache.calcite.avatica.ColumnMetaData;
24-
import org.apache.calcite.avatica.util.AbstractCursor;
25-
import org.apache.calcite.avatica.util.ArrayImpl;
2623

2724
@Slf4j
28-
class ArrowStreamReaderCursor extends AbstractCursor {
25+
class ArrowStreamReaderCursor implements AutoCloseable {
2926

3027
private static final int INIT_ROW_NUMBER = -1;
3128

@@ -42,26 +39,19 @@ class ArrowStreamReaderCursor extends AbstractCursor {
4239
this.sessionZone = sessionZone;
4340
}
4441

45-
private void wasNullConsumer(boolean wasNull) {
46-
this.wasNull[0] = wasNull;
47-
}
48-
4942
@SneakyThrows
5043
private VectorSchemaRoot getSchemaRoot() {
5144
return reader.getVectorSchemaRoot();
5245
}
5346

54-
@Override
55-
@SneakyThrows
56-
public List<Accessor> createAccessors(
57-
List<ColumnMetaData> types, Calendar localCalendar, ArrayImpl.Factory factory) {
47+
List<QueryJDBCAccessor> createAccessors() {
5848
return getSchemaRoot().getFieldVectors().stream()
5949
.map(rethrowFunction(this::createAccessor))
6050
.collect(Collectors.toList());
6151
}
6252

63-
private Accessor createAccessor(FieldVector vector) throws SQLException {
64-
return QueryJDBCAccessorFactory.createAccessor(vector, currentIndex::get, this::wasNullConsumer, sessionZone);
53+
private QueryJDBCAccessor createAccessor(FieldVector vector) throws SQLException {
54+
return QueryJDBCAccessorFactory.createAccessor(vector, currentIndex::get, sessionZone);
6555
}
6656

6757
private boolean loadNextBatch() throws IOException {
@@ -73,7 +63,6 @@ private boolean loadNextBatch() throws IOException {
7363
}
7464

7565
@SneakyThrows
76-
@Override
7766
public boolean next() {
7867
val current = currentIndex.incrementAndGet();
7968
val total = getSchemaRoot().getRowCount();
@@ -94,11 +83,6 @@ public boolean next() {
9483
}
9584
}
9685

97-
@Override
98-
protected Getter createGetter(int i) {
99-
throw new UnsupportedOperationException();
100-
}
101-
10286
@SneakyThrows
10387
@Override
10488
public void close() {

jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/ColumnNameResolver.java

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
*/
55
package com.salesforce.datacloud.jdbc.core;
66

7+
import com.salesforce.datacloud.jdbc.core.metadata.ColumnMetadata;
78
import java.sql.SQLException;
89
import java.util.HashMap;
910
import java.util.List;
1011
import java.util.Map;
11-
import org.apache.calcite.avatica.ColumnMetaData;
1212

1313
/**
1414
* Resolves column names to their JDBC indices using fast HashMap lookups.
@@ -35,25 +35,19 @@ public final class ColumnNameResolver {
3535
*
3636
* @param columns the column metadata list
3737
*/
38-
public ColumnNameResolver(List<ColumnMetaData> columns) {
38+
public ColumnNameResolver(List<ColumnMetadata> columns) {
3939
this.exactColumnLabelMap = new HashMap<>(columns.size());
4040
this.lowercaseColumnLabelMap = new HashMap<>(columns.size());
41-
42-
// First pass: index exact labels to ordinals
43-
for (ColumnMetaData columnMetaData : columns) {
44-
if (columnMetaData.label != null) {
45-
// Use putIfAbsent to ensure first occurrence (lowest ordinal) wins for duplicates
46-
exactColumnLabelMap.putIfAbsent(columnMetaData.label, columnMetaData.ordinal);
47-
}
48-
}
49-
50-
// Second pass: index lowercase labels to ordinals, but only if the lowercase key doesn't exist yet
41+
// Index lowercase labels to ordinals, but only if the lowercase key doesn't exist yet
5142
// This ensures the first column with a given lowercase name wins (lowest ordinal)
52-
for (ColumnMetaData columnMetaData : columns) {
53-
if (columnMetaData.label != null) {
54-
String lowerLabel = columnMetaData.label.toLowerCase();
43+
for (int i = 0; i < columns.size(); i++) {
44+
ColumnMetadata col = columns.get(i);
45+
String label = col.getName();
46+
if (label != null) {
47+
// Use putIfAbsent to ensure first occurrence (lowest ordinal) wins for duplicates
48+
exactColumnLabelMap.putIfAbsent(label, i);
5549
// Only add if this lowercase key hasn't been seen yet (preserves first occurrence)
56-
lowercaseColumnLabelMap.putIfAbsent(lowerLabel, columnMetaData.ordinal);
50+
lowercaseColumnLabelMap.putIfAbsent(label.toLowerCase(), i);
5751
}
5852
}
5953
}
@@ -71,14 +65,13 @@ public int findColumn(String columnLabel) throws SQLException {
7165
// First try exact match (case-sensitive)
7266
Integer index = exactColumnLabelMap.get(columnLabel);
7367
if (index != null) {
74-
// Avatica uses 0-based ordinals, but JDBC uses 1-based indices
68+
// Internal ordinals are 0-based, but JDBC uses 1-based indices
7569
return index + 1;
7670
}
7771

7872
// Fallback to lowercase match (case-insensitive)
7973
index = lowercaseColumnLabelMap.get(columnLabel.toLowerCase());
8074
if (index != null) {
81-
// Avatica uses 0-based ordinals, but JDBC uses 1-based indices
8275
return index + 1;
8376
}
8477

jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/DataCloudConnection.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import static com.salesforce.datacloud.jdbc.util.ArrowUtils.toColumnMetaData;
1111

1212
import com.google.protobuf.Empty;
13+
import com.salesforce.datacloud.jdbc.core.metadata.ColumnMetadata;
14+
import com.salesforce.datacloud.jdbc.core.metadata.DataCloudResultSetMetaData;
1315
import com.salesforce.datacloud.jdbc.core.partial.DataCloudQueryPolling;
1416
import com.salesforce.datacloud.jdbc.exception.DataCloudJDBCException;
1517
import com.salesforce.datacloud.jdbc.exception.QueryExceptionHandler;
@@ -47,7 +49,6 @@
4749
import java.sql.Struct;
4850
import java.time.Duration;
4951
import java.util.Arrays;
50-
import java.util.Collections;
5152
import java.util.List;
5253
import java.util.Map;
5354
import java.util.Properties;
@@ -61,9 +62,6 @@
6162
import lombok.NonNull;
6263
import lombok.extern.slf4j.Slf4j;
6364
import lombok.val;
64-
import org.apache.calcite.avatica.AvaticaResultSetMetaData;
65-
import org.apache.calcite.avatica.ColumnMetaData;
66-
import org.apache.calcite.avatica.Meta;
6765
import salesforce.cdp.hyperdb.v1.CancelQueryParam;
6866
import salesforce.cdp.hyperdb.v1.HyperServiceGrpc;
6967

@@ -279,11 +277,8 @@ public DataCloudResultSet getChunkBasedResultSet(String queryId, long chunkId) t
279277
public ResultSetMetaData getSchemaForQueryId(String queryId) throws SQLException {
280278
try {
281279
val schema = QuerySchemaAccessor.getArrowSchema(QueryAccessGrpcClient.of(queryId, getStub()));
282-
List<ColumnMetaData> columns = toColumnMetaData(schema.getFields());
283-
// Create metadata directly without full ResultSet infrastructure
284-
Meta.Signature signature = new Meta.Signature(
285-
columns, null, Collections.emptyList(), Collections.emptyMap(), null, Meta.StatementType.SELECT);
286-
return new AvaticaResultSetMetaData(null, null, signature);
280+
List<ColumnMetadata> columns = toColumnMetaData(schema.getFields());
281+
return new DataCloudResultSetMetaData(columns);
287282
} catch (StatusRuntimeException ex) {
288283
throw createException(connectionProperties.isIncludeCustomerDetailInReason(), null, queryId, ex);
289284
}

jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/DataCloudDatabaseMetadata.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import static com.salesforce.datacloud.jdbc.core.QueryMetadataUtil.createSchemaResultSet;
1111
import static com.salesforce.datacloud.jdbc.core.QueryMetadataUtil.createTableResultSet;
1212
import static com.salesforce.datacloud.jdbc.core.QueryMetadataUtil.createTableTypesResultSet;
13-
import static com.salesforce.datacloud.jdbc.util.Constants.*;
1413

1514
import com.google.common.collect.ImmutableList;
1615
import com.salesforce.datacloud.jdbc.config.DriverVersion;
@@ -688,39 +687,39 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
688687
@Override
689688
public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern)
690689
throws SQLException {
691-
return MetadataResultSet.of();
690+
return DataCloudMetadataResultSet.empty();
692691
}
693692

694693
@Override
695694
public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern)
696695
throws SQLException {
697-
return MetadataResultSet.of();
696+
return DataCloudMetadataResultSet.empty();
698697
}
699698

700699
@Override
701700
public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable)
702701
throws SQLException {
703-
return MetadataResultSet.of();
702+
return DataCloudMetadataResultSet.empty();
704703
}
705704

706705
@Override
707706
public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException {
708-
return MetadataResultSet.of();
707+
return DataCloudMetadataResultSet.empty();
709708
}
710709

711710
@Override
712711
public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
713-
return MetadataResultSet.of();
712+
return DataCloudMetadataResultSet.empty();
714713
}
715714

716715
@Override
717716
public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException {
718-
return MetadataResultSet.of();
717+
return DataCloudMetadataResultSet.empty();
719718
}
720719

721720
@Override
722721
public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException {
723-
return MetadataResultSet.of();
722+
return DataCloudMetadataResultSet.empty();
724723
}
725724

726725
@Override
@@ -732,18 +731,18 @@ public ResultSet getCrossReference(
732731
String foreignSchema,
733732
String foreignTable)
734733
throws SQLException {
735-
return MetadataResultSet.of();
734+
return DataCloudMetadataResultSet.empty();
736735
}
737736

738737
@Override
739738
public ResultSet getTypeInfo() throws SQLException {
740-
return MetadataResultSet.of();
739+
return DataCloudMetadataResultSet.empty();
741740
}
742741

743742
@Override
744743
public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate)
745744
throws SQLException {
746-
return MetadataResultSet.of();
745+
return DataCloudMetadataResultSet.empty();
747746
}
748747

749748
@Override

jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/SimpleMetadataResultSet.java renamed to jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/DataCloudMetadataResultSet.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,55 @@
55
package com.salesforce.datacloud.jdbc.core;
66

77
import com.salesforce.datacloud.jdbc.core.metadata.ColumnMetadata;
8-
import com.salesforce.datacloud.jdbc.core.metadata.SimpleResultSetMetaData;
8+
import com.salesforce.datacloud.jdbc.core.metadata.DataCloudResultSetMetaData;
99
import com.salesforce.datacloud.jdbc.core.resultset.ColumnAccessor;
1010
import com.salesforce.datacloud.jdbc.core.resultset.SimpleResultSet;
1111
import java.sql.SQLException;
1212
import java.sql.Statement;
13+
import java.util.Collections;
1314
import java.util.List;
1415
import java.util.OptionalLong;
1516

1617
/**
1718
* Custom ResultSet implementation for metadata queries
1819
*/
19-
public class SimpleMetadataResultSet extends SimpleResultSet<SimpleMetadataResultSet> {
20+
public class DataCloudMetadataResultSet extends SimpleResultSet<DataCloudMetadataResultSet> {
2021

2122
private final List<Object> data;
2223
private int currentRow = -1;
2324
private boolean closed = false;
2425

25-
private SimpleMetadataResultSet(
26-
SimpleResultSetMetaData metadata, ColumnAccessor<SimpleMetadataResultSet>[] accessors, List<Object> data) {
26+
private DataCloudMetadataResultSet(
27+
DataCloudResultSetMetaData metadata,
28+
ColumnAccessor<DataCloudMetadataResultSet>[] accessors,
29+
List<Object> data) {
2730
super(metadata, accessors, false);
2831
this.data = data;
2932
}
3033

31-
public static SimpleMetadataResultSet of(SimpleResultSetMetaData metadata, List<Object> data) throws SQLException {
34+
public static DataCloudMetadataResultSet empty() throws SQLException {
35+
return of(new DataCloudResultSetMetaData(Collections.emptyList()), Collections.emptyList());
36+
}
37+
38+
public static DataCloudMetadataResultSet of(DataCloudResultSetMetaData metadata, List<Object> data)
39+
throws SQLException {
3240
@SuppressWarnings("unchecked")
33-
ColumnAccessor<SimpleMetadataResultSet>[] accessors = new ColumnAccessor[metadata.getColumnCount()];
41+
ColumnAccessor<DataCloudMetadataResultSet>[] accessors = new ColumnAccessor[metadata.getColumnCount()];
3442
for (int i = 0; i < metadata.getColumnCount(); i++) {
3543
final int columnIndex = i;
3644
accessors[i] = createAccessor(metadata.getColumn(i + 1), columnIndex);
3745
}
3846

39-
return new SimpleMetadataResultSet(metadata, accessors, data);
47+
return new DataCloudMetadataResultSet(metadata, accessors, data);
4048
}
4149

4250
/**
4351
* Creates a ColumnAccessor for a specific column.
4452
*/
45-
private static ColumnAccessor<SimpleMetadataResultSet> createAccessor(ColumnMetadata column, int columnIndex) {
46-
return new ColumnAccessor<SimpleMetadataResultSet>() {
53+
private static ColumnAccessor<DataCloudMetadataResultSet> createAccessor(ColumnMetadata column, int columnIndex) {
54+
return new ColumnAccessor<DataCloudMetadataResultSet>() {
4755
@Override
48-
public String getString(SimpleMetadataResultSet resultSet) throws SQLException {
56+
public String getString(DataCloudMetadataResultSet resultSet) throws SQLException {
4957
Object value = getValue(resultSet, columnIndex);
5058
if (value == null) {
5159
return null;
@@ -54,7 +62,7 @@ public String getString(SimpleMetadataResultSet resultSet) throws SQLException {
5462
}
5563

5664
@Override
57-
public Boolean getBoolean(SimpleMetadataResultSet resultSet) throws SQLException {
65+
public Boolean getBoolean(DataCloudMetadataResultSet resultSet) throws SQLException {
5866
Object value = getValue(resultSet, columnIndex);
5967
if (value == null) {
6068
return null;
@@ -66,7 +74,7 @@ public Boolean getBoolean(SimpleMetadataResultSet resultSet) throws SQLException
6674
}
6775

6876
@Override
69-
public OptionalLong getAnyInteger(SimpleMetadataResultSet resultSet) throws SQLException {
77+
public OptionalLong getAnyInteger(DataCloudMetadataResultSet resultSet) throws SQLException {
7078
Object value = getValue(resultSet, columnIndex);
7179
if (value == null) {
7280
return OptionalLong.empty();
@@ -81,7 +89,7 @@ public OptionalLong getAnyInteger(SimpleMetadataResultSet resultSet) throws SQLE
8189
/**
8290
* Helper method to get the value for the current row and column.
8391
*/
84-
private Object getValue(SimpleMetadataResultSet resultSet, int columnIndex) throws SQLException {
92+
private Object getValue(DataCloudMetadataResultSet resultSet, int columnIndex) throws SQLException {
8593
if (resultSet.closed) {
8694
throw new SQLException("ResultSet is closed");
8795
}

0 commit comments

Comments
 (0)