Skip to content

docs(jdbc): document last_insert_rowid under the remote model (#83) - #126

Merged
magnusp merged 1 commit into
mainfrom
fix/i83-last-insert-rowid
Oct 22, 2026
Merged

magnusp merged 1 commit into
mainfrom
fix/i83-last-insert-rowid

Conversation

@magnusp

@magnusp magnusp commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Summary

Statement.getGeneratedKeys() after an auto-commit insert already reports the rowid from StmtResult.last_insert_rowid. This PR pins that protocol linkage in LibsqlGeneratedKeysTest and documents why a direct SELECT last_insert_rowid() cannot return the same value.

No production code changes.

Contract

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

Divergence

A null baton opens a new Hrana stream, and StmtResult.last_insert_rowid is a per-statement result on one stream. Auto-commit is one-shot, so a later direct SELECT last_insert_rowid() runs on a fresh stream and returns 0. xerial returns the connection's last rowid because it owns a single SQLite connection.

The driver holds no session stream in auto-commit because Hrana over HTTP expires idle streams, and #99 removed the last eager stream of that kind. A hidden stream is not an option. The supported ways to read the rowid are getGeneratedKeys() and running the query inside an explicit transaction, where the connection holds the baton and both statements share one stream. Section 8 of IMPLEMENTATION_BUGS_AND_RESOLUTIONS.md records this.

Live evidence

Throwaway itest against real sqld (ghcr.io/tursodatabase/libsql-server:latest), one connection, each mode inserting then selecting last_insert_rowid():

PROBE in-transaction generatedKey=1 directQuery=1
PROBE auto-commit generatedKey=2 directQuery=0

The throwaway probe was removed after the run. The retained contract is the unit test plus the doc section; the probe asserted no behavior the unit test does not already pin, and adding it would have added a second sqld container lane for one already-covered fact.

Verification

Lane Command Result
Unit ./mvnw -pl libsql-jdbc test -Dtest=LibsqlGeneratedKeysTest 11 tests pass
Module ./mvnw -pl libsql-jdbc test 211 tests pass, BUILD SUCCESS
Integration ./mvnw -pl libsql-itests -am verify BUILD SUCCESS
Conformance ./mvnw -pl libsql-conformance -am verify 115 tests, 1 skipped, BUILD SUCCESS
Control ./mvnw -pl libsql-conformance -am -Pxerial-control verify BUILD SUCCESS
Format ./mvnw spotless:check No violations
Reactor ./mvnw test BUILD SUCCESS
Package ./mvnw -pl libsql-jdbc -am package -DskipTests BUILD SUCCESS
Trunk probe strengthened test against 37a86a0 Passes at trunk too; expected because this PR changes no production code, so there is no new failing case

Perf lane skipped. The change touches one test and one Markdown file, so no hot path changed and no timing comparison is meaningful.

Logs are under /tmp/xerial-parity-i83/. The itests lane used the readable empty Docker config copy at /tmp/docker-config via DOCKER_CONFIG.

Base 37a86a0, head 333af86.

Fixes #83

@magnusp
magnusp merged commit 766e4c5 into main Oct 22, 2026
5 checks passed
@magnusp
magnusp deleted the fix/i83-last-insert-rowid branch October 22, 2026 20:50
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.

last_insert_rowid() in auto-commit reads a fresh Hrana session

1 participant