Skip to content

fix(jdbc): stringify REAL values with SQLite canonical text - #68

Merged
magnusp merged 1 commit into
mainfrom
fix/33-real-canonical-text
Oct 21, 2026
Merged

magnusp merged 1 commit into
mainfrom
fix/33-real-canonical-text

Conversation

@magnusp

@magnusp magnusp commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

What changed

ResultSet.getString now renders REAL values with SQLite's canonical text instead of Double.toString. getBigDecimal inherits the fix because it parses getString, so scale is stable for a given REAL value.

  • Added a port of the SQLite 3.53.4 fixed-point REAL conversion used by printf("%!.17g") (sqlite3FpDecode, sqlite3Fp2Convert10, and the power-of-ten tables). It produces up to 17 significant digits, trims trailing zeros, uses fixed notation for decimal exponents from -4 through 16, and scientific notation with a signed, at least two-digit exponent otherwise. The output always keeps one digit after the decimal point.
  • Documented the rule on LibsqlResultSet.getString.
  • Added LibsqlResultSetRealTextTest covering the three pinned values, BigDecimal scale and equals stability, negatives, and the notation boundaries at 1e16/1e17 and 1e-4/1e-5.

Contract decision

Match xerial/sqlite-jdbc 3.53.4.0. There is no transport obstacle: Hrana delivers REAL as a JSON number, which the driver parses to the same IEEE-754 double that SQLite formats. Parity, not a deviation.

Evidence

Failing before the fix:

$ ./mvnw -q -pl libsql-jdbc -am -Dtest=LibsqlResultSetRealTextTest -Dsurefire.failIfNoSpecifiedTests=false test
Tests run: 14, Failures: 12, Errors: 0, Skipped: 0
expected: "0.0001"
 but was: "1.0E-4"
expected: 0.0001
 but was: 0.00010

Passing after the fix:

$ ./mvnw -q -pl libsql-jdbc -am -Dtest=LibsqlResultSetRealTextTest -Dsurefire.failIfNoSpecifiedTests=false test
(no output, exit 0)

$ ./mvnw -pl libsql-jdbc -am test
Tests run: 94, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

$ ./mvnw spotless:check
BUILD SUCCESS

As an additional differential check, the internal formatter was compared against xerial 3.53.4.0's cast(? as text) for 1,299,525 values (random 64-bit patterns plus random magnitudes across the full double range): 0 mismatches.

Deviations

None.

Out of scope

getBytes for a REAL still builds bytes from Double.toString, while xerial returns the canonical text bytes. This is outside this issue's String/BigDecimal scope and was left unchanged.

Closes #33

@magnusp
magnusp merged commit 486a6f4 into main Oct 21, 2026
5 checks passed
@magnusp
magnusp deleted the fix/33-real-canonical-text branch October 21, 2026 22:34
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.

REAL values stringify with Double.toString instead of SQLite canonical text

1 participant