Skip to content

getBoolean uses custom truthiness instead of numeric conversion #32

Closed

Description

@magnusp

Problem

Boolean reads disagree with sqlite-jdbc and with SQLite numeric semantics. Code that stores flags as text or REAL gets different answers after a migration.

Actual behavior

libSQL treats text "true" and "1" as true and tests REAL directly (LibsqlResultSet.java:126-136). xerial 3.53.4.0 implements getBoolean as getInt(col) != 0 (JDBC3ResultSet.java:180-182). As a result, xerial returns false for "true", true for "2", and false for REAL 0.5. libSQL returns true, true, and true.

Expected behavior

The driver chooses one contract for boolean conversion. Matching sqlite-jdbc means converting through the integer getter. A stricter documented contract is also acceptable if tests define every storage class.

Reproduction

try (ResultSet rs = s.executeQuery("select 'true', '2', 0.5, x'313233'")) {
    rs.next();
    System.out.println(rs.getBoolean(1)); // libSQL true, xerial false
    System.out.println(rs.getBoolean(2)); // true in both
    System.out.println(rs.getBoolean(3)); // libSQL true, xerial false
    System.out.println(rs.getBoolean(4)); // libSQL true, xerial true
}

Compatibility decision

sqlite-jdbc reduces every value through integer conversion, so any nonzero prefix is true. libSQL adds string truthiness and a nonzero REAL test. Matching sqlite-jdbc keeps results predictable for code that already uses it. The libSQL rules are friendlier for "true" text but diverge from SQLite's own numeric behavior. Which contract wins?

Acceptance criteria

  • A documented decision covers each storage class.
  • Tests cover "true", "0", "2", REAL fractions, blobs, and NULL.
  • getBoolean and getInt agree wherever the decision says they should.

References

  • libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java:126-136 (getBoolean)
  • xerial 3.53.4.0 JDBC3ResultSet.java:180-182 (getBoolean)

Steering

Lane A (LibsqlResultSet.java), position 2 of 5. Depends on #31, whose integer coercion is the parity target. Lands in wave 2.

Corrections from the #28 review. The body misstates current libSQL behavior. Probed results: libSQL returns true, false, true for 'true', '2', and 0.5; xerial returns false, true, false. The reproduction comment "true in both" for '2' is wrong. Restate the reproduction with these values when editing.

Contract. Match xerial 3.53.4.0: getBoolean is getInt(col) != 0 (JDBC3ResultSet.java:180-182). Parity is the default under #54, which settles the compatibility decision above.

Evidence. New tests fail on the current code and pass after the fix. Storage-class matrix test: 'true', '0', '2', REAL 0.5, REAL 2.0, blob x'313233', and NULL. getBoolean and getInt agree everywhere. Run ./mvnw -pl libsql-jdbc -am test and ./mvnw spotless:apply before push.

PR shape. One PR, Closes #32. Part of #54.

Activity

  1. added
    bugSomething isn't working
    P1High priority: significant correctness or compatibility gap
    on Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High priority: significant correctness or compatibility gapbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions