From bf58589444d954071e0ac168f0815ea3503c373b Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Thu, 22 Oct 2026 23:53:42 +0200 Subject: [PATCH] fix(jdbc): wrap REAL to int like SQLite getInt cast a REAL straight to int, which clamps. SQLite converts through int64 and keeps the low 32 bits. Route REAL through long and round INTEGER through double before narrowing to float, matching SQLite's numeric conversion. Fixes #101 --- .../magnusp/libsql/jdbc/LibsqlResultSet.java | 4 ++-- .../libsql/jdbc/LibsqlResultSetTest.java | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java b/libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java index a567f41..44b3247 100644 --- a/libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java +++ b/libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java @@ -458,7 +458,7 @@ public int getInt(int columnIndex) throws SQLException { return switch (val) { case Value.Null n -> 0; case Value.Integer i -> (int) i.value(); - case Value.Float f -> (int) f.value(); + case Value.Float f -> (int) (long) f.value(); case Value.Text t -> (int) parseSqliteLong(t.value()); case Value.Blob b -> (int) parseSqliteLong(blobAsText(b)); }; @@ -474,7 +474,7 @@ public float getFloat(int columnIndex) throws SQLException { Value val = getCurrentValue(columnIndex); return switch (val) { case Value.Null n -> 0.0F; - case Value.Integer i -> (float) i.value(); + case Value.Integer i -> (float) (double) i.value(); case Value.Float f -> (float) f.value(); case Value.Text t -> (float) parseSqliteDouble(t.value()); case Value.Blob b -> (float) parseSqliteDouble(blobAsText(b)); diff --git a/libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/LibsqlResultSetTest.java b/libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/LibsqlResultSetTest.java index 8e556db..1eeec5d 100644 --- a/libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/LibsqlResultSetTest.java +++ b/libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/LibsqlResultSetTest.java @@ -148,6 +148,30 @@ void realStorageTruncatesForIntegralGettersAndKeepsFractionForFloatingGetters() assertNumeric(rs, 1, 1, 1L, 1.9f, 1.9); } + @Test + void realStorageWrapsToIntThroughInt64LikeSqlite() throws SQLException { + LibsqlResultSet rs = resultSet(new Value.Float(3e9), new Value.Float(-3e9)); + + assertThat(rs.next()).isTrue(); + assertThat(rs.getInt(1)).isEqualTo(-1294967296); + assertThat(rs.getObject(1, Integer.class)).isEqualTo(-1294967296); + assertThat(rs.getInt(2)).isEqualTo(1294967296); + } + + @Test + void getBooleanOnWrappingRealIsFalse() throws SQLException { + LibsqlResultSet rs = resultSet(new Value.Float(4294967296.0)); + assertThat(rs.next()).isTrue(); + assertThat(rs.getBoolean(1)).isFalse(); + } + + @Test + void getFloatOnLargeIntegerRoundsThroughDouble() throws SQLException { + LibsqlResultSet rs = resultSet(new Value.Integer(1152921573326323713L)); + assertThat(rs.next()).isTrue(); + assertThat(rs.getFloat(1)).isEqualTo(1.1529215E18f); + } + @Test void integerStorageIsReturnedUnchanged() throws SQLException { LibsqlResultSet rs = resultSet(new Value.Integer(42));