Avatical Removal Part 3/3: Remove Avatica dependency completely#166
Avatical Removal Part 3/3: Remove Avatica dependency completely#166
Conversation
Codecov Report❌ Patch coverage is
❌ Your patch check has failed because the patch coverage (83.79%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #166 +/- ##
============================================
- Coverage 82.40% 81.94% -0.47%
- Complexity 1568 1585 +17
============================================
Files 119 116 -3
Lines 4422 4464 +42
Branches 457 450 -7
============================================
+ Hits 3644 3658 +14
- Misses 556 587 +31
+ Partials 222 219 -3
🚀 New features to boost your workflow:
|
...e/src/test/java/com/salesforce/datacloud/jdbc/core/metadata/SimpleResultSetMetaDataTest.java
Outdated
Show resolved
Hide resolved
| public void testCursorNextAndRowCount() { | ||
| List<Object> data = new ArrayList<>(); | ||
| data.add("Account_home_dll"); | ||
| cursor = new MetadataCursor(data); | ||
| cursor.next(); | ||
| assertThat(cursor.next()).isFalse(); | ||
| } |
There was a problem hiding this comment.
Do we have test coverage for cursor somewhere else?
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/accessor/DataCloudAccessor.java
Outdated
Show resolved
Hide resolved
| // Arrow timestamps with timezone map to JDBC TIMESTAMP, not TIMESTAMP_WITH_TIMEZONE | ||
| if (typeId == Types.TIMESTAMP_WITH_TIMEZONE) { | ||
| return Types.TIMESTAMP; | ||
| } |
There was a problem hiding this comment.
Why do we need to adjust that here? Feels wrong to me to override the column type
There was a problem hiding this comment.
It does feel wrong, however the reason for this right now is that Arrow's TIMESTAMPSECTZ / TIMESTAMPMILLITZ / etc. store an epoch value + a timezone string, but the TimeStampVectorAccessor already normalizes these to UTC LocalDateTime / Timestamp values before returning them. By the time the JDBC caller gets the value via getTimestamp(), the timezone has already been folded into the instant — the returned java.sql.Timestamp doesn't carry timezone info.
If we remove the override, and TimeStampVectorAccessor remains as is, JDBCReferenceTest fails because it expects select timestamptz '1000-01-01 01:00:00+0100' to map to columnType=93 and className java.sql.TimeStamp
My view is that this is a symptom of the fact we don't currently correctly handle timestamp/timezone types in the JDBC driver, and that this should go away once #158 gets in
There was a problem hiding this comment.
@KaviarasuSakthivadivel / @carsheng let's discuss on how we want to sequence the two PRs.
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/ArrowStreamReaderCursor.java
Show resolved
Hide resolved
| for (int i = 0; i < columns.size(); i++) { | ||
| ColumnMetadata col = columns.get(i); | ||
| String label = col.getName(); | ||
| if (label != null) { | ||
| // Use putIfAbsent to ensure first occurrence (lowest ordinal) wins for duplicates | ||
| exactColumnLabelMap.putIfAbsent(columnMetaData.label, columnMetaData.ordinal); | ||
| } | ||
| } | ||
|
|
||
| // Second pass: index lowercase labels to ordinals, but only if the lowercase key doesn't exist yet | ||
| // This ensures the first column with a given lowercase name wins (lowest ordinal) | ||
| for (ColumnMetaData columnMetaData : columns) { | ||
| if (columnMetaData.label != null) { | ||
| String lowerLabel = columnMetaData.label.toLowerCase(); | ||
| // Only add if this lowercase key hasn't been seen yet (preserves first occurrence) | ||
| lowercaseColumnLabelMap.putIfAbsent(lowerLabel, columnMetaData.ordinal); | ||
| exactColumnLabelMap.putIfAbsent(label, i); | ||
| lowercaseColumnLabelMap.putIfAbsent(label.toLowerCase(), i); |
There was a problem hiding this comment.
Doesn#t this change behavior? I think this should break a test case
There was a problem hiding this comment.
Do we need to change this behaviour?
There was a problem hiding this comment.
Actually taking a second look I think the new logic is correct. On the lookup side we always first check exact and then lower case. Having a single pass is more efficient than interating twice.
Please keep the documentation on the semantics of the two maps and how this is working.
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/accessor/DataCloudAccessor.java
Outdated
Show resolved
Hide resolved
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/accessor/QueryJDBCAccessor.java
Outdated
Show resolved
Hide resolved
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/StreamingResultSet.java
Outdated
Show resolved
Hide resolved
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/ArrowStreamReaderCursor.java
Outdated
Show resolved
Hide resolved
| // Match standard JDBC behavior: readOnly=false does not mean the column is writable, | ||
| // it means we don't know. isWritable() and isDefinitelyWritable() still return false. | ||
| return false; |
There was a problem hiding this comment.
I think the old behavior was correct because we know that this column can't be written through SQL as DC only supports SELECT clauses
There was a problem hiding this comment.
At first i thought so too, but i've since realized the following the "old behavior" was actually incorrect.
According to QueryJDBCReferenceTest, which compares behavior against the Postgres driver, isReadOnly=false for a column is in line w/ what Postgres driver does.
So the correct behavior should be:
Generally:
ResultSet.isReadonly=true // the resultset itself isReadonly, we don't support write operations
For this line:
ResultSet.getMetadata.isReadOnly(1)=false //a column is technically not readonly
Why was this not caught earlier?
SimpleResultSetMetadata in the earlier avatica PR (aka, "old behavior") were limited to only the metadata flow. Now that that SimpleResultSetMetadata is now incorporated into the normal ResultSet flow (i.e. u make a query, then look at the metadata), QueryJDBCReferenceTest fails b/c it expects column.isReadonly=false. See here in reference.json: https://github.com/forcedotcom/datacloud-jdbc/blob/main/jdbc-reference/src/main/resources/reference.json#L19
There was a problem hiding this comment.
isReadOnly=false for a column is in line w/ what Postgres driver does.
Postgres driver is setting this to falser because one can do insert / update statements in Postgres. In Data Cloud that doesn't work so for us it would be correct to set isReadOnly true AFAIK
| for (int i = 0; i < columns.size(); i++) { | ||
| ColumnMetadata col = columns.get(i); | ||
| String label = col.getName(); | ||
| if (label != null) { | ||
| // Use putIfAbsent to ensure first occurrence (lowest ordinal) wins for duplicates | ||
| exactColumnLabelMap.putIfAbsent(columnMetaData.label, columnMetaData.ordinal); | ||
| } | ||
| } | ||
|
|
||
| // Second pass: index lowercase labels to ordinals, but only if the lowercase key doesn't exist yet | ||
| // This ensures the first column with a given lowercase name wins (lowest ordinal) | ||
| for (ColumnMetaData columnMetaData : columns) { | ||
| if (columnMetaData.label != null) { | ||
| String lowerLabel = columnMetaData.label.toLowerCase(); | ||
| // Only add if this lowercase key hasn't been seen yet (preserves first occurrence) | ||
| lowercaseColumnLabelMap.putIfAbsent(lowerLabel, columnMetaData.ordinal); | ||
| exactColumnLabelMap.putIfAbsent(label, i); | ||
| lowercaseColumnLabelMap.putIfAbsent(label.toLowerCase(), i); |
There was a problem hiding this comment.
Actually taking a second look I think the new logic is correct. On the lookup side we always first check exact and then lower case. Having a single pass is more efficient than interating twice.
Please keep the documentation on the semantics of the two maps and how this is working.
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/StreamingResultSet.java
Show resolved
Hide resolved
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/StreamingResultSet.java
Show resolved
Hide resolved
jdbc-core/src/main/java/com/salesforce/datacloud/jdbc/core/StreamingResultSet.java
Show resolved
Hide resolved
…& SimpleMetadataResultSet-->DataCloudMetadataResultSet
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