Skip to content

ResultSet navigation differs on duplicate labels and cursor state #45

Closed

Description

@magnusp

Problem

findColumn, cursor state, getRow, isLast, and wasNull differ from sqlite-jdbc. Applications that share result sets, read metadata before the first row, or compute pagination see different results.

Actual behavior

findColumn uses a map and returns the last duplicate label (LibsqlResultSet.java:307-324). xerial 3.53.4.0 returns the first. Getters throw before the first row and after the last row (:74-86). xerial returns row 1 before next() and null or zero after the end. getRow returns 0 after the end (:432-435), isLast returns a real boolean (:452-455), and wasNull returns false before any getter (:108-112). xerial throws SQLFeatureNotSupportedException from isLast.

Expected behavior

The driver chooses the JDBC-correct contract or matches xerial, documents it, and tests navigation boundaries.

Reproduction

try (ResultSet rs = s.executeQuery("select 1 as a, 2 as a")) {
    rs.findColumn("a"); // 1 in xerial, 2 in libSQL
    rs.getRow();        // 1 in xerial, 0 in libSQL
    rs.wasNull();       // throws in xerial, false in libSQL
}

Compatibility decision

Strict JDBC says a getter outside a valid row throws, and several xerial behaviors are not strict JDBC. xerial returns a synthetic row before next(), returns null after the end, and throws from isLast. Matching xerial helps migrations but keeps non-standard cursor semantics. Following JDBC makes boundary behavior predictable but differs from the reference driver. Which contract wins for each method?

Acceptance criteria

  • A documented contract covers duplicate labels and cursor boundaries.
  • Tests cover duplicate labels, getter before next(), getter after the end, getRow, isLast, and wasNull.
  • Tests pin the behavior before the first row and after the last row.

References

  • libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java:74-86 (getCurrentValue)
  • libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java:108-112 (wasNull)
  • libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java:307-324 (findColumn)
  • libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java:432-435 (getRow)
  • libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java:452-455 (isLast)
  • xerial 3.53.4.0 JDBC3ResultSet.java:139-153 (isLast, getRow, wasNull) and :40-52 (findColumn)

Steering

Lane A (LibsqlResultSet.java), position 5 of 5. Depends on #34 (lane order; P2 lands after the lane's P1s). Lands in wave 5.

Corrections from the #28 review. xerial getRow() returns 0 before next(), not 1, and returns the last row number after the end (1 for a one-row result), not 0. The body's "xerial returns row 1 before next()" claim and its reproduction comment are wrong. It is the column getters that return the first row before next() (probed: getInt returns 1 before next() and 0 after the end). Only getRow and getInt were re-verified in #28. Re-probe every other claimed xerial boundary (findColumn duplicate-label order, isLast throwing SQLFeatureNotSupportedException, wasNull before any getter) against the pinned 3.53.4.0 jar before pinning tests.

Contract. Default parity under #54. This issue holds the most contested quirks, so the PR body must list the chosen target per method: findColumn, getters before next(), getters after the end, getRow, isLast, and wasNull.

Evidence. New tests fail on the current code and pass after the fix, covering duplicate labels and every cursor boundary in the acceptance criteria. Run ./mvnw -pl libsql-jdbc -am test and ./mvnw spotless:apply before push.

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

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

    P2Normal priority: edge case, feature gap, or test/process improvementbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions