Skip to content

fix(jdbc): coerce numeric getters like sqlite-jdbc - #55

Merged
magnusp merged 2 commits into
mainfrom
fix/31-numeric-coercion
Oct 21, 2026
Merged

magnusp merged 2 commits into
mainfrom
fix/31-numeric-coercion

Conversation

@magnusp

@magnusp magnusp commented Oct 21, 2026

Copy link
Copy Markdown
Owner

Closes #31. Part of #54.

What changed

  • getLong and getDouble now apply SQLite's text-to-number conversion instead of strict Long.parseLong/Double.parseDouble parsing.
  • Blob values are decoded as UTF-8 text and then converted through the same path, matching sqlite-jdbc's handling of blob storage classes in numeric getters.
  • getInt, getByte, and getShort inherit the conversion via getLong; getFloat inherits it via getDouble, so all numeric getters agree.
  • Added LibsqlResultSetTest fixtures covering non-numeric text, numeric text, REAL text, exponent text, leading whitespace/trailing garbage, numeric blobs, non-numeric blobs, REAL storage, and INTEGER storage. Each case asserts getInt, getLong, getFloat, and getDouble.

Contract decision

Match xerial 3.53.4.0 (JDBC3ResultSet.java:304-350, backed by sqlite3_column_int64/sqlite3_column_double) as required by #54's drop-in-replacement goal:

  • Text integral getters use sqlite3Atoi64 semantics: leading whitespace and sign, decimal prefix only, saturation on overflow, 0 when no digits. Thus '1.9' -> 1, '1.5e2' -> 1, 'abc' -> 0.
  • Text floating getters use sqlite3AtoF semantics: leading whitespace and sign, decimal prefix with optional exponent, 0 when no mantissa digits.
  • Blob bytes are interpreted as text and converted the same way: x'313233' -> 123, x'616263' -> 0.
  • NULL remains 0 for numeric getters, with wasNull() still reporting true.

Evidence

Before the fix (new tests only):

./mvnw -pl libsql-jdbc -am test
...
[ERROR] Tests run: 13, Failures: 5, Errors: 0, Skipped: 0
[ERROR]   LibsqlResultSetTest.numericBlobIsInterpretedAsText:57->assertNumeric:90 expected: 123 but was: 0
[ERROR]   LibsqlResultSetTest.realTextBlobIsInterpretedAsText:64->assertNumeric:90 expected: 1 but was: 0
[ERROR]   LibsqlResultSetTest.realTextTruncatesForIntegralGettersAndKeepsFractionForFloatingGetters:36->assertNumeric:90 expected: 1 but was: 0
[ERROR]   LibsqlResultSetTest.textWithExponentUsesIntegerPrefixForIntegralGetters:43->assertNumeric:90 expected: 1 but was: 0
[ERROR]   LibsqlResultSetTest.textWithLeadingWhitespaceAndTrailingGarbageUsesNumericPrefix:50->assertNumeric:90 expected: 42 but was: 0

After the fix:

./mvnw -pl libsql-jdbc -am test
...
Tests run: 13, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
./mvnw spotless:check
BUILD SUCCESS

Additional verification: an ad-hoc probe of the same conversion cases against xerial 3.53.4.0 produced identical getInt/getLong/getFloat/getDouble output for 29 inputs, including overflow, exponent, whitespace, and negative-zero cases.

Deviations

None.

@magnusp
magnusp force-pushed the fix/31-numeric-coercion branch from 0baf822 to 9fae229 Compare October 21, 2026 21:38
Route getObject(int, Class) numeric targets through strict TEXT parsing instead of the relaxed public getters. Public getInt/getLong/getFloat/getDouble keep SQLite coercion.
@magnusp
magnusp force-pushed the fix/31-numeric-coercion branch from e45dd39 to ac5a238 Compare October 21, 2026 21:45
@magnusp
magnusp merged commit 2dd0db9 into main Oct 21, 2026
5 checks passed
@magnusp
magnusp deleted the fix/31-numeric-coercion branch October 21, 2026 21:51
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.

Numeric getters do not follow SQLite text and blob coercion

1 participant