Skip to content

fix(jdbc): read declared columns through implemented getters - #251

Merged
magnusp merged 1 commit into
mainfrom
fix/jdbc-declared-blob-reads
Oct 25, 2026
Merged

magnusp merged 1 commit into
mainfrom
fix/jdbc-declared-blob-reads

Conversation

@magnusp

@magnusp magnusp commented Oct 25, 2026

Copy link
Copy Markdown
Owner

Why

A declared BLOB column rejected getBytes. The driver treated JDBC 4.3 Appendix B Table B-6 as a rejection list instead of the set of conversions a driver must support, so a getter that was not listed for the declared type threw SQLFeatureNotSupportedException. xerial reads these columns, and users reported the error.

What changed

  • LibsqlResultSet now rejects only the five N/A declared types. A representable column reads through every implemented getter, and the stored value decides the conversion.
  • Removed the getter matrix, Getter enum, and getterMask field that only served the rejection.
  • Un-quarantined xerial StatementTest#bytesTest and added a real-DDL regression for a declared BLOB.

Scope

Leaves setObject Table B-5 strictness unchanged. Opens follow-up issues for the label overloads of getArray and getRef (#250) and the unused JdbcType.storage component (#249).

Blast Radius

Read behavior changes for declared columns that were previously rejected. Rejection now comes only from the stored value, so a bad conversion still throws SQLException. The five N/A types behave as before.

Verification

  • ./mvnw test runs 1511 JDBC tests with no failures.
  • ./mvnw -pl libsql-conformance -am verify runs 271 tests with 7 skipped and no failures.
  • Jdbc4AppendixBTypeMappingIT#b6DeclaredBlobReadsThroughByteAndTextGetters passes against the pinned sqld image.

Table B-6 was enforced as a rejection list, so getBytes on a declared BLOB
threw SQLFeatureNotSupportedException. Treat the table as the required
support matrix and let the stored value decide the conversion, matching
sqlite-jdbc. Only the five N/A declared types remain rejected.

The getter mask, Getter enum, and getterMask field were used only by the
rejection, so remove them.
@magnusp

magnusp commented Oct 25, 2026

Copy link
Copy Markdown
Owner Author

PASS+NOTES

Independent shipping verification of PR #251, parent vs head, using a fresh JUnit IT written as a JDBC user would use the driver.

Revisions

  • Head SHA: 4a359b0149e602db585b73d99cff53ca2496cc57
  • Base branch: main at 8e5cd4ea0d4f37aa4913612fb1cd689e9f51a421 (matches origin/main)
  • Patch-id: cf0eec3faee836f24095b1b890d045229b7d47ef (git diff origin/main...HEAD | git patch-id --stable) — matches the expected patch-id.
  • PR state at verification: OPEN, not draft, base 8e5cd4e, head 4a359b0.

Repro test

Temporary untracked test libsql-itests/src/test/java/io/github/magnusp/libsql/itest/BlobReadReproIT.java, extending SqldContainerBase:

statement.execute("CREATE TABLE blob_read_repro (v BLOB)");
// INSERT ... VALUES (?) with setBytes(1, "abc".getBytes(UTF_8))
assertThat(resultSet.next()).isTrue();
assertThat(resultSet.getBytes(1)).isEqualTo(BYTES_ABC);
assertThat(resultSet.getString(1)).isEqualTo("abc");

Not committed. It remained untracked across both checkouts.

Parent (main @ 8e5cd4e): fails as expected

BUILD FAILURE; failsafe report:

Test set: io.github.magnusp.libsql.itest.BlobReadReproIT
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0
io.github.magnusp.libsql.itest.BlobReadReproIT.declaredBlobReadsThroughBytesAndString:33 » SQLFeatureNotSupported getBytes does not support declared BLOB
java.sql.SQLFeatureNotSupportedException: getBytes does not support declared BLOB
	at io.github.magnusp.libsql.jdbc.LibsqlResultSet.checkGetter(LibsqlResultSet.java:144)
	at io.github.magnusp.libsql.jdbc.LibsqlResultSet.getBytes(LibsqlResultSet.java:373)
	at io.github.magnusp.libsql.itest.BlobReadReproIT.declaredBlobReadsThroughBytesAndString(BlobReadReproIT.java:33)

Fails on getBytes, at the exact line, with SQLFeatureNotSupportedException naming declared BLOB.

Head (@ 4a359b0): passes

Same repro test, same command:

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.289 s -- in io.github.magnusp.libsql.itest.BlobReadReproIT
BUILD SUCCESS

Unit suite built by -am: Tests run: 1511, Failures: 0, Errors: 0, Skipped: 0.

PR's own targeted regression test:

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.325 s -- in io.github.magnusp.libsql.itest.Jdbc4AppendixBTypeMappingIT
BUILD SUCCESS

That test asserts getBytes, getString, getBinaryStream, and getBlob on a real v BLOB column against sqld.

Commands run

git fetch origin
git checkout --detach origin/main
DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" ./mvnw -pl libsql-itests -am -Dit.test=BlobReadReproIT -DfailIfNoTests=false verify
git checkout --detach 4a359b0149e602db585b73d99cff53ca2496cc57
DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" ./mvnw -pl libsql-itests -am -Dit.test=BlobReadReproIT -DfailIfNoTests=false verify
DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" ./mvnw -pl libsql-itests -am -Dit.test=Jdbc4AppendixBTypeMappingIT#b6DeclaredBlobReadsThroughByteAndTextGetters -DfailIfNoTests=false verify
git diff origin/main...HEAD | git patch-id --stable

Notes (non-blocking)

  1. The change is broader than the repro: LibsqlResultSet.checkGetter is replaced by checkReadable, so getter-specific Table B-6 gating is removed for every declared type, and the stored value's conversion decides success. This is deliberate and traceable in this PR: Jdbc4AppendixBReadTest was rewritten to assert required cells plus permissive reads, the B-6 docs were updated, and the matching XerialQuarantine entry (StatementTest.bytesTest) was removed. getArray/getRef still throw SQLFeatureNotSupportedException, and unrepresentable declared types are still rejected. I did not find a behavior contradiction in the updated expectations.
  2. Scope of this verification: the two focused integration tests above plus the full unit suite compiled with -am. I did not run the entire libsql-itests or libsql-conformance suites, so regressions outside these tests would not have been observed here.

@magnusp
magnusp merged commit 47f9ebb into main Oct 25, 2026
6 checks passed
@magnusp
magnusp deleted the fix/jdbc-declared-blob-reads branch October 25, 2026 21:51
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.

1 participant