Skip to content

fix(jdbc): decide and pin every silent statement setter (#97) - #151

Merged
magnusp merged 2 commits into
mainfrom
fix/i97-statement-setters
Oct 23, 2026
Merged

magnusp merged 2 commits into
mainfrom
fix/i97-statement-setters

Conversation

@magnusp

@magnusp magnusp commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Fixes #97.

Hrana 3 is the source of truth for transport, values, metadata, batching, transactions, and error reporting. java.sql is the source of truth for the JDBC surface. xerial/sqlite-jdbc 3.53.4.0 is a behavioral reference, never a copy target.

Decisions

Setter Behavior xerial reference
setMaxRows(int) Implemented for plain and prepared statements. Stores the limit under the statement lock and drops excess rows when the result set is built, including LibsqlPreparedStatement.executeQuery(). getMaxRows() reads it back. Negative throws SQLException("max row count must be >= 0"). Stores rs.maxRows and truncates; probed setMaxRows(2) returns 2 rows. Parity.
setQueryTimeout(int) 0 (no limit) accepted; positive throws SQLFeatureNotSupportedException("Query timeouts are not supported"); negative throws SQLException. Stores the value and uses it as SQLite's busy timeout, not a query deadline.
setMaxFieldSize(int) 0 (no limit) accepted; positive throws SQLFeatureNotSupportedException("Column size limits are not supported"); negative throws SQLException. Validates negative, then ignores any positive value; getter stays 0.
setEscapeProcessing(boolean) Implemented as the java.sql flag, initially on, for plain and prepared SQL. While on, SQL containing a JDBC escape sequence throws SQLFeatureNotSupportedException before it is sent; when off, the SQL is sent verbatim. Braces in literals, quoted identifiers, and comments do not count. Silently ignores both values.
setCursorName(String) Always throws SQLFeatureNotSupportedException("Cursor names are not supported"). Silently ignores the name.

The zero-valued defaults on setQueryTimeout and setMaxFieldSize are accepted because zero means "no limit", which is exactly what the driver does. This also keeps the selected upstream CachedRowSetTest (gh_224) green: the JDK CachedRowSetReader calls setMaxRows(0), setMaxFieldSize(0), setQueryTimeout(0), and setEscapeProcessing(true) on every PreparedStatement it populates. Throwing at set time for those values would make a selected conformance test fail.

Divergences

  • setQueryTimeout throws for a positive timeout instead of storing it. Honoring it needs a per-request HTTP deadline and cancel in libsql-client, outside this PR's Files block. xerial's mapping to the SQLite busy timeout is a lock wait, not the SQLTimeoutException deadline java.sql defines.
  • setMaxFieldSize throws for a positive limit instead of ignoring it. Column value truncation lives in LibsqlResultSet, outside this PR's Files block, and xerial's silent ignore is a bug rather than a behavior to copy.
  • setEscapeProcessing rejects escape-bearing SQL while enabled instead of rounding. The driver has no escape translator, and java.sql does not list SQLFeatureNotSupportedException for this setter, so rejecting the call itself would break generic JDBC tooling. Rejecting at execution is explicit and names the real gap.
  • setCursorName always throws. java.sql allows a no-op when positioned update/delete is unsupported, but Hrana has no positioned cursor at all, so an explicit throw is honest. Nothing in the selected conformance suite calls it.

Evidence

Base ffe6f1932aa62af1063ef5de36aaad0d278900a1, head 2c301f6d4be1d80e6adb42d36db4f491ab772c7f.

Red, trunk plus the new LibsqlStatementTest: Tests run: 9, Failures: 6. The truncation test reads getMaxRows() as 0, and the negative, query-timeout, field-size, escape-enabled, and cursor-name cases all find no exception. Logs in /tmp/xerial-parity-i97/lane-1-trunk.log.

Green at head:

  • ./mvnw -pl libsql-jdbc test -Dtest=LibsqlStatementTest: 9/9.
  • ./mvnw -pl libsql-jdbc test -Dtest=LibsqlPreparedStatementTest: 8/8, including the prepared setMaxRows limit and escape checks.
  • ./mvnw -pl libsql-jdbc test: 304/304.
  • ./mvnw -pl libsql-conformance -am verify: 123 run, 0 failures, 1 skipped, BUILD SUCCESS.
  • ./mvnw -pl libsql-conformance -am -Pxerial-control verify: 100 run, 0 failures, 1 skipped.
  • ./mvnw spotless:check, ./mvnw test, and ./mvnw -pl libsql-jdbc -am package -DskipTests: BUILD SUCCESS.
  • ./mvnw -pl libsql-jdbc test -Dtest='LibsqlStatement*': 33/33.
  • Perf, ./mvnw -pl libsql-jdbc test wall clock, trunk median 2.65 s of three runs, head median 2.17 s, inside the ten percent rule.

All lane logs are under /tmp/xerial-parity-i97/.

@magnusp
magnusp merged commit c496e38 into main Oct 23, 2026
6 checks passed
@magnusp
magnusp deleted the fix/i97-statement-setters branch October 23, 2026 02:15
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.

Statement setters remain silent no-ops

1 participant