Skip to content

fix(jdbc): make getColumnClassName follow the current row - #66

Merged
magnusp merged 1 commit into
mainfrom
fix/36-column-classname
Oct 21, 2026
Merged

magnusp merged 1 commit into
mainfrom
fix/36-column-classname

Conversation

@magnusp

@magnusp magnusp commented Oct 21, 2026

Copy link
Copy Markdown
Owner

Closes #36. Part of #54.

What changed

  • LibsqlResultSetMetaData.getColumnClassName now reads the value at the metadata cursor through the shared LibsqlResultSet.valueForMetadata accessor added by getColumnType ignores runtime storage class #35, instead of scanning every row for a column-wide class.
  • A valid current row reports the current storage class: INTEGER in the int range is java.lang.Integer, INTEGER outside it is java.lang.Long, FLOAT is java.lang.Double, TEXT is java.lang.String, and BLOB/NULL are java.lang.Object.
  • Empty results and positions after the last row report java.lang.Object.
  • Removed the now-unused cross-row integerClassName and isIntInRange helpers.
  • Added behavior tests for an empty result and for a mixed-type column (select 1 union all select 'a') before cursor movement, on each row, and after the last row, plus a current-row Integer-to-Long range check.

Contract decision

Class metadata is cursor-local, matching xerial 3.53.4.0 JDBC3ResultSet.getColumnClassName (JDBC3ResultSet.java:579-597). Empty results and end-of-results report java.lang.Object; otherwise the class describes the value on the current row. Parity wins under #54.

One Steering detail does not match the pinned xerial behavior. Steering says positions before the first row report java.lang.Object. I probed xerial 3.53.4.0 directly: it preloads the first row during execute, so before the first next() it reports that row's class (Integer/String in a newly executed result set), not Object. The vendored RSMetaDataTest.testGetColumnClassName asserts that preloaded behavior, so returning Object before the first row would break the conformance suite. This PR therefore follows the actual pinned xerial behavior, which is the primary contract, and keeps conformance green.

Evidence

Failing before the fix:

$ ./mvnw -q -pl libsql-jdbc -am -Dtest=LibsqlResultSetMetaDataTest -Dsurefire.failIfNoSpecifiedTests=false test
[ERROR] Tests run: 16, Failures: 3, Errors: 0, Skipped: 0
[ERROR] LibsqlResultSetMetaDataTest.reportsObjectClassNameForEmptyResultSet:229
[column 1 before the first row] expected: "java.lang.Object" but was: "java.lang.Integer"
[ERROR] LibsqlResultSetMetaDataTest.reportsCurrentRowClassNameForMixedTypeColumn:253
[before the first row] expected: "java.lang.Integer" but was: "java.lang.String"
[ERROR] LibsqlResultSetMetaDataTest.reportsClassNameForCurrentRowOutsideIntRange:282
expected: "java.lang.Integer" but was: "java.lang.Long"

Passing after the fix:

$ ./mvnw -pl libsql-jdbc -am test
Tests run: 83, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
$ ./mvnw -pl libsql-conformance -am verify
Tests run: 115, Failures: 0, Errors: 0, Skipped: 1
BUILD SUCCESS

The conformance run includes the vendored xerial RSMetaDataTest (13 tests, all passed), confirming the before-first-row and mixed-column behavior against live sqld.

$ ./mvnw spotless:apply
BUILD SUCCESS (no formatting changes)

Deviations

None from xerial 3.53.4.0. The literal Steering sentence about Object before the first row is not what the pinned xerial does; see Contract decision. Following it would regress the vendored conformance test, so the PR keeps actual xerial parity instead.

Closes #36. Part of #54.

getColumnClassName now reads the value at the metadata cursor, the same
runtime accessor #35 introduced, instead of scanning every row for a
column-wide class. Empty results and positions after the last row report
java.lang.Object; a valid row reports the current storage class, with
integers outside the int range reporting java.lang.Long. Before the first
next() the cursor is the preloaded first row, matching xerial 3.53.4.0
JDBC3ResultSet.getColumnClassName.
@magnusp
magnusp force-pushed the fix/36-column-classname branch from af34f44 to d0bad84 Compare October 21, 2026 22:34
@magnusp
magnusp merged commit bdff98b into main Oct 21, 2026
5 checks passed
@magnusp
magnusp deleted the fix/36-column-classname branch October 21, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

getColumnClassName is wrong for empty and mixed-type result sets

1 participant