From ab67b9f7caf85b5de6e66783636903a896994f10 Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Sun, 25 Oct 2026 04:10:31 +0100 Subject: [PATCH 1/6] fix(itests): supply real rowid and sqlxml fixtures The RowId and SQLXML stubs returned null bytes and null text, so the B-2 rows bound null. Return the rowid-1 bytes and the text. Read the NClob wrapper directly so the B-5 row proves the wrapper round trip. --- .../itest/Jdbc4AppendixBTypeMappingIT.java | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java b/libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java index 49ab0c5..2933d69 100644 --- a/libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java +++ b/libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java @@ -415,11 +415,11 @@ static Expected any(Class type) { TEXT, ResultSet::getURL, Expected.any(URL.class)), new WriteRow("Java class", new Marker("abc"), "JAVA_OBJECT", Types.JAVA_OBJECT, UNSPECIFIED, (rs, i) -> rs.getObject(i), Expected.of(new Marker("abc"))), - new WriteRow("java.sql.RowId", stub(RowId.class), "ROWID", Types.ROWID, UNSPECIFIED, + new WriteRow("java.sql.RowId", rowId(TEXT_ROWID), "ROWID", Types.ROWID, UNSPECIFIED, ResultSet::getRowId, Expected.any(RowId.class)), new WriteRow("java.sql.NClob", nclob("abc"), "NCLOB", Types.NCLOB, TEXT, ResultSet::getNClob, Expected.any(NClob.class)), - new WriteRow("java.sql.SQLXML", stub(SQLXML.class), "SQLXML", Types.SQLXML, UNSPECIFIED, + new WriteRow("java.sql.SQLXML", sqlxml(TEXT_XML), "SQLXML", Types.SQLXML, UNSPECIFIED, ResultSet::getSQLXML, Expected.any(SQLXML.class))); @ParameterizedTest(name = "B-2 {0} -> {2}") @@ -881,10 +881,7 @@ private static SqlRead readFor(Target target) { case "TIMESTAMP" -> ResultSet::getTimestamp; case "CLOB" -> Jdbc4AppendixBTypeMappingIT::clobText; case "BLOB" -> Jdbc4AppendixBTypeMappingIT::blobBytes; - case "NCLOB" -> (rs, i) -> { - NClob nclob = rs.getNClob(i); - return nclob == null ? null : nclob.getSubString(1, (int) nclob.length()); - }; + case "NCLOB" -> ResultSet::getNClob; case "ARRAY" -> ResultSet::getArray; case "STRUCT" -> (rs, i) -> rs.getObject(i); case "REF" -> ResultSet::getRef; @@ -1219,6 +1216,36 @@ private static NClob nclob(String text) { }); } + private static RowId rowId(String text) { + byte[] bytes = text.getBytes(StandardCharsets.UTF_8); + return (RowId) Proxy.newProxyInstance( + RowId.class.getClassLoader(), + new Class[] {RowId.class}, + (proxy, method, args) -> switch (method.getName()) { + case "toString" -> text; + case "hashCode" -> System.identityHashCode(proxy); + case "equals" -> proxy == args[0]; + case "getBytes" -> bytes; + default -> defaultValue(method.getReturnType()); + }); + } + + private static SQLXML sqlxml(String text) { + return (SQLXML) Proxy.newProxyInstance( + SQLXML.class.getClassLoader(), + new Class[] {SQLXML.class}, + (proxy, method, args) -> switch (method.getName()) { + case "toString" -> text; + case "hashCode" -> System.identityHashCode(proxy); + case "equals" -> proxy == args[0]; + case "getString" -> text; + case "getCharacterStream" -> new StringReader(text); + case "getBinaryStream" -> + new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + default -> defaultValue(method.getReturnType()); + }); + } + private static URL url(String value) { try { return URI.create(value).toURL(); From 6da78cb24a4fce3dd226ad4be3271437baaeba40 Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Sun, 25 Oct 2026 04:10:31 +0100 Subject: [PATCH 2/6] test(conformance): quarantine xerial tests replaced by appendix b Four selected xerial methods assert behavior that Appendix B replaces. Exclude them from the libSQL run without editing the vendored tree. The xerial-control profile still runs them. --- libsql-conformance/README.md | 20 +++++- .../libsql/conformance/XerialHarnessTest.java | 63 +++++++++++++++++++ .../libsql/conformance/XerialQuarantine.java | 59 +++++++++++++++++ ...unit.platform.launcher.PostDiscoveryFilter | 1 + 4 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialQuarantine.java create mode 100644 libsql-conformance/src/test/resources/META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter diff --git a/libsql-conformance/README.md b/libsql-conformance/README.md index d079b32..cf14eb5 100644 --- a/libsql-conformance/README.md +++ b/libsql-conformance/README.md @@ -47,8 +47,24 @@ with: ./mvnw -pl libsql-conformance -am verify ``` -Last green result: 272 tests, 7 skipped, with `SavepointTest` included. The -parity queue (#54) closed at 268 tests, 7 skipped. +Last green result: 270 tests, 7 skipped, with `SavepointTest` included. The +count includes the four Appendix B quarantines below and two harness tests for +the quarantine. + +### Appendix B quarantines + +JDBC 4.3 Appendix B is the oracle. Four selected xerial test methods assert +behavior that Appendix B replaces. They stay in the vendored tree and still +run in the `xerial-control` profile, but `XerialQuarantine` excludes them from +the libSQL run. The full type profile is in +[`../docs/jdbc-appendix-b-compliance.md`](../docs/jdbc-appendix-b-compliance.md). + +| Test | Why the xerial expectation is quarantined | +|---|---| +| `org.sqlite.StatementTest#bytesTest` | xerial allows `getBytes` on a declared `BLOB`. Table B-6 lists `getBytes` only for `BINARY`, `VARBINARY`, and `LONGVARBINARY`. | +| `org.sqlite.RSMetaDataTest#columnTypes` | xerial reports a declared `NCHAR` as `Types.CHAR`. Appendix B defines `NCHAR` as its own JDBC type, so the driver reports `Types.NCHAR`. | +| `org.sqlite.RSMetaDataTest#testGetColumnClassName` | xerial reports a declared `BLOB` as `java.lang.Object`. Table B-3 maps `BLOB` to `java.sql.Blob`. | +| `org.sqlite.PrepStmtTest#getObject` | xerial returns an `Integer` for `getObject` on a declared `BIT`. Table B-3 maps `BIT` to `Boolean`. | ### Three-layer contract diff --git a/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialHarnessTest.java b/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialHarnessTest.java index 5714051..50fdf88 100644 --- a/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialHarnessTest.java +++ b/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialHarnessTest.java @@ -16,6 +16,8 @@ import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.descriptor.MethodSource; /** * Exercises the conformance harness itself, without a running sqld container where possible. @@ -63,6 +65,54 @@ void fileMemoryUriIsNotRetained() { assertThat(memoryMode.retained()).isFalse(); } + @Test + void quarantineExcludesOnlyTheAppendixBConflicts() { + XerialQuarantine quarantine = new XerialQuarantine(); + + for (XerialQuarantine.Quarantined quarantined : XerialQuarantine.QUARANTINED) { + assertThat( + quarantine + .apply( + descriptor( + quarantined.className(), + quarantined.methodName())) + .excluded()) + .as("%s#%s", quarantined.className(), quarantined.methodName()) + .isTrue(); + } + + assertThat(quarantine.apply(descriptor("org.sqlite.ResultSetTest", "next")).included()) + .as("an unconflicted xerial test") + .isTrue(); + } + + @Test + void quarantineIsInactiveDuringTheXerialControlRun() { + String previous = System.getProperty(XerialControl.ENABLED_PROPERTY); + System.setProperty(XerialControl.ENABLED_PROPERTY, "xerial"); + try { + XerialQuarantine quarantine = new XerialQuarantine(); + for (XerialQuarantine.Quarantined quarantined : XerialQuarantine.QUARANTINED) { + assertThat( + quarantine + .apply( + descriptor( + quarantined.className(), + quarantined.methodName())) + .included()) + .as("control run keeps %s#%s", quarantined.className(), + quarantined.methodName()) + .isTrue(); + } + } finally { + if (previous == null) { + System.clearProperty(XerialControl.ENABLED_PROPERTY); + } else { + System.setProperty(XerialControl.ENABLED_PROPERTY, previous); + } + } + } + @Test void queryStringIsPartOfTheFileNamespace() { XerialConformanceDriver.Target readOnly = @@ -163,6 +213,19 @@ void stopReportsASwallowedCleanupFailure() { } } + private static TestDescriptor descriptor(String className, String methodName) { + MethodSource source = MethodSource.from(className, methodName); + return (TestDescriptor) + Proxy.newProxyInstance( + TestDescriptor.class.getClassLoader(), + new Class[] {TestDescriptor.class}, + (proxy, method, args) -> + switch (method.getName()) { + case "getSource" -> java.util.Optional.of(source); + default -> null; + }); + } + private static Connection wrap(Connection connection, String namespace) { return wrap(connection, namespace, ignored -> {}); } diff --git a/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialQuarantine.java b/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialQuarantine.java new file mode 100644 index 0000000..88d64f2 --- /dev/null +++ b/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialQuarantine.java @@ -0,0 +1,59 @@ +package com.github.magnusp.libsql.conformance; + +import java.util.List; +import org.junit.platform.engine.FilterResult; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.support.descriptor.MethodSource; +import org.junit.platform.launcher.PostDiscoveryFilter; + +/** + * Quarantines the xerial tests whose expectations Appendix B replaces. + * + *

These tests assert sqlite-jdbc behavior that JDBC 4.3 Appendix B defines differently. They + * stay in the vendored tree and still run in the {@code xerial-control} profile, where the + * reference driver is the subject. They are excluded only from the libSQL run, and the reason is + * kept here so the exclusion cannot become an unexplained skip. + */ +public final class XerialQuarantine implements PostDiscoveryFilter { + + /** One upstream test method whose xerial expectation conflicts with Appendix B. */ + record Quarantined(String className, String methodName, String reason) {} + + static final List QUARANTINED = + List.of( + new Quarantined( + "org.sqlite.StatementTest", + "bytesTest", + "xerial allows getBytes on a declared BLOB; Table B-6 lists getBytes" + + " only for BINARY, VARBINARY and LONGVARBINARY"), + new Quarantined( + "org.sqlite.RSMetaDataTest", + "columnTypes", + "xerial reports a declared NCHAR as Types.CHAR; Appendix B defines" + + " NCHAR as its own JDBC type, so the driver reports Types.NCHAR"), + new Quarantined( + "org.sqlite.RSMetaDataTest", + "testGetColumnClassName", + "xerial reports a declared BLOB as java.lang.Object; Table B-3 maps" + + " BLOB to java.sql.Blob"), + new Quarantined( + "org.sqlite.PrepStmtTest", + "getObject", + "xerial returns an Integer for getObject on a declared BIT; Table B-3" + + " maps BIT to Boolean")); + + @Override + public FilterResult apply(TestDescriptor descriptor) { + if (XerialControl.isEnabled() + || !(descriptor.getSource().orElse(null) instanceof MethodSource source)) { + return FilterResult.included("Appendix B quarantine is inactive for this run"); + } + for (Quarantined quarantined : QUARANTINED) { + if (quarantined.className().equals(source.getClassName()) + && quarantined.methodName().equals(source.getMethodName())) { + return FilterResult.excluded(quarantined.reason()); + } + } + return FilterResult.included("not quarantined"); + } +} diff --git a/libsql-conformance/src/test/resources/META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter b/libsql-conformance/src/test/resources/META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter new file mode 100644 index 0000000..c1e5331 --- /dev/null +++ b/libsql-conformance/src/test/resources/META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter @@ -0,0 +1 @@ +com.github.magnusp.libsql.conformance.XerialQuarantine From 234186d45c68cd8932006594b4b706f57303214c Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Sun, 25 Oct 2026 04:10:31 +0100 Subject: [PATCH 3/6] docs(jdbc): publish the appendix b compliance profile Give every Appendix B row a status, a reason, and the test that proves it. Record the expression fallback as an exception and the policy in AGENTS.md. Add the verification commands to README.md. --- AGENTS.md | 11 ++ README.md | 35 +++++ docs/jdbc-appendix-b-compliance.md | 245 +++++++++++++++++++++++++++++ 3 files changed, 291 insertions(+) create mode 100644 docs/jdbc-appendix-b-compliance.md diff --git a/AGENTS.md b/AGENTS.md index 014dd81..b4964c4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -134,6 +134,17 @@ DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" \ Use the absolute path shown. A relative `DOCKER_CONFIG` is resolved against the fork's working directory, not the shell's. +### JDBC 4.3 Appendix B policy + +JDBC 4.3 Appendix B is the oracle for type mapping. The source is [`vendor/JDBC4-TYPE-MAPPING.md`](vendor/JDBC4-TYPE-MAPPING.md). + +- When Appendix B and sqlite-jdbc disagree, Appendix B wins. A conformance test that encodes the xerial behavior is quarantined in `libsql-conformance`, not copied. +- Keep sqlite-jdbc parity only where Appendix B is silent. Parity never overrides a defined Appendix B conversion. +- `ARRAY`, `STRUCT`, `REF`, `JAVA_OBJECT`, and `DISTINCT` are N/A. The driver throws `SQLFeatureNotSupportedException` and does not emulate them. +- An expression column has no declared type. Its storage-class fallback is a documented exception in [`docs/jdbc-appendix-b-compliance.md`](docs/jdbc-appendix-b-compliance.md), not a supported Appendix B row. + +The compliance profile is [`docs/jdbc-appendix-b-compliance.md`](docs/jdbc-appendix-b-compliance.md). Run the commands in [`README.md`](README.md) before changing a type mapping. + --- ## 5. Coding Standards & Conventions diff --git a/README.md b/README.md index e785563..7dc663e 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,41 @@ mise exec -- ./mvnw clean verify mise exec -- ./mvnw spotless:apply ``` +### JDBC 4.3 Appendix B checks + +Run the Appendix B unit suite. + +```bash +./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixB*' -Dsurefire.failIfNoSpecifiedTests=false test +``` + +Run the full `libsql-jdbc` unit suite. + +```bash +./mvnw -q -pl libsql-jdbc test +``` + +Run the Appendix B server suite. The install step puts the current driver in the local repository. Under the nono sandbox, the Docker config path is required. + +```bash +./mvnw -q -DskipTests install -pl libsql-hrana-codec,libsql-client,libsql-jdbc +DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" ./mvnw -pl libsql-itests -Dit.test=Jdbc4AppendixBTypeMappingIT -Dtest=NoSuchTest -Dsurefire.failIfNoSpecifiedTests=false verify +``` + +Run the xerial conformance suite. + +```bash +./mvnw -pl libsql-conformance -am verify +``` + +Run the full gate. + +```bash +DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" ./mvnw clean verify +``` + +The compliance profile is in [`docs/jdbc-appendix-b-compliance.md`](docs/jdbc-appendix-b-compliance.md). + ## Contributing We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines and development workflow, and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for community standards. diff --git a/docs/jdbc-appendix-b-compliance.md b/docs/jdbc-appendix-b-compliance.md new file mode 100644 index 0000000..bbb702a --- /dev/null +++ b/docs/jdbc-appendix-b-compliance.md @@ -0,0 +1,245 @@ +# JDBC 4.3 Appendix B compliance profile + +This page records the JDBC 4.3 Appendix B status of `libsql-jdbc`. The oracle is the specification in [`../vendor/JDBC4-TYPE-MAPPING.md`](../vendor/JDBC4-TYPE-MAPPING.md), not sqlite-jdbc. Every row below names the test that proves it. + +## How to read this profile + +- `supported` means the driver maps the row to a Hrana value kind and its declared type directly. +- `emulated` means SQLite has no distinct storage for the JDBC type. The driver supplies the Java type through a wrapper or a text or integer codec, and the observable Java type matches the appendix. +- `N/A` means SQLite has no interoperable representation. The driver throws `SQLFeatureNotSupportedException`. + +Five types are N/A. They are `ARRAY`, `STRUCT`, `REF`, `JAVA_OBJECT`, and `DISTINCT`. + +The unit suites are `Jdbc4AppendixBReadTest`, `Jdbc4AppendixBSetObjectTest`, and `Jdbc4AppendixBProfileTest`. The server suite is `Jdbc4AppendixBTypeMappingIT`. Both run from a clean checkout with the commands in the root [`README.md`](../README.md). + +## Table B-1, JDBC types mapped to Java types + +Table B-1 is observed through the natural ResultSet getter for each JDBC type. + +| Appendix B row | Status | Reason | Test | +|---|---|---|---| +| `CHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `VARCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `LONGVARCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `NUMERIC` | emulated | SQLite has no decimal type. The driver reads the stored value as BigDecimal. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `DECIMAL` | emulated | SQLite has no decimal type. The driver reads the stored value as BigDecimal. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BIT` | emulated | SQLite has no boolean type. The driver reads integer 0 or 1 as Boolean. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BOOLEAN` | emulated | SQLite has no boolean type. The driver reads integer 0 or 1 as Boolean. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `TINYINT` | supported | A narrowed Hrana integer maps directly to byte. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `SMALLINT` | supported | A narrowed Hrana integer maps directly to short. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `INTEGER` | supported | A Hrana integer maps directly to int. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BIGINT` | supported | A Hrana integer maps directly to long. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `REAL` | supported | A Hrana real maps directly to float. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `FLOAT` | supported | A Hrana real maps directly to double. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `DOUBLE` | supported | A Hrana real maps directly to double. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BINARY` | supported | A Hrana blob maps directly to byte[]. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `VARBINARY` | supported | A Hrana blob maps directly to byte[]. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `LONGVARBINARY` | supported | A Hrana blob maps directly to byte[]. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `DATE` | emulated | SQLite has no date type. The driver parses ISO text into java.sql.Date. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `TIME` | emulated | SQLite has no time type. The driver parses text into java.sql.Time. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `TIMESTAMP` | emulated | SQLite has no timestamp type. The driver parses text into java.sql.Timestamp. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `CLOB` | emulated | The driver wraps stored text in java.sql.Clob. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BLOB` | supported | A Hrana blob maps directly to java.sql.Blob. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `ARRAY` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `DISTINCT` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `STRUCT` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `REF` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `DATALINK` | emulated | The driver parses stored text into java.net.URL. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `JAVA_OBJECT` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `ROWID` | emulated | The driver wraps stored text or blob bytes in java.sql.RowId. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `NCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `NVARCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `LONGNVARCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `NCLOB` | emulated | The driver wraps stored text in java.sql.NClob. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `SQLXML` | emulated | The driver wraps stored text in java.sql.SQLXML. | `Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | + +## Table B-2, Java types mapped to JDBC types + +Table B-2 is observed through the standard setter for each Java type. + +| Appendix B row | Status | Reason | Test | +|---|---|---|---| +| `String` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.math.BigDecimal` | emulated | Binds decimal text. SQLite has no decimal type. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `boolean` | emulated | Binds integer 0 or 1. SQLite has no boolean type. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `byte` | supported | Binds a narrowed Hrana integer. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `short` | supported | Binds a narrowed Hrana integer. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `int` | supported | Binds a Hrana integer. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `long` | supported | Binds a Hrana integer. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `float` | supported | Binds a Hrana real. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `double` | supported | Binds a Hrana real. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `byte[]` | supported | Binds a Hrana blob. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.Date` | emulated | Binds SQLite date text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.Time` | emulated | Binds SQLite time text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.Timestamp` | emulated | Binds SQLite timestamp text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.Clob` | emulated | Reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.Blob` | supported | Reads the binary stream and binds a blob. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.net.URL` | emulated | Binds the URL as text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.RowId` | emulated | Binds the RowId bytes as a Hrana blob. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.NClob` | emulated | Reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.SQLXML` | emulated | Reads the SQLXML text and binds it. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | + +## Table B-3, JDBC types mapped to Java object types + +Table B-3 is observed through `getObject(int)` for each declared type. + +| Appendix B row | Status | Reason | Test | +|---|---|---|---| +| `CHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `VARCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `LONGVARCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `NUMERIC` | emulated | SQLite has no decimal type. The driver reads the stored value as BigDecimal. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `DECIMAL` | emulated | SQLite has no decimal type. The driver reads the stored value as BigDecimal. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BIT` | emulated | SQLite has no boolean type. The driver reads integer 0 or 1 as Boolean. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BOOLEAN` | emulated | SQLite has no boolean type. The driver reads integer 0 or 1 as Boolean. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `TINYINT` | supported | A narrowed Hrana integer maps directly to byte. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `SMALLINT` | supported | A narrowed Hrana integer maps directly to short. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `INTEGER` | supported | A Hrana integer maps directly to int. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BIGINT` | supported | A Hrana integer maps directly to long. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `REAL` | supported | A Hrana real maps directly to float. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `FLOAT` | supported | A Hrana real maps directly to double. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `DOUBLE` | supported | A Hrana real maps directly to double. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BINARY` | supported | A Hrana blob maps directly to byte[]. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `VARBINARY` | supported | A Hrana blob maps directly to byte[]. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `LONGVARBINARY` | supported | A Hrana blob maps directly to byte[]. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `DATE` | emulated | SQLite has no date type. The driver parses ISO text into java.sql.Date. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `TIME` | emulated | SQLite has no time type. The driver parses text into java.sql.Time. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `TIMESTAMP` | emulated | SQLite has no timestamp type. The driver parses text into java.sql.Timestamp. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `DISTINCT` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `CLOB` | emulated | The driver wraps stored text in java.sql.Clob. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `BLOB` | supported | A Hrana blob maps directly to java.sql.Blob. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `ARRAY` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `STRUCT` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `REF` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `DATALINK` | emulated | The driver parses stored text into java.net.URL. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `JAVA_OBJECT` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `ROWID` | emulated | The driver wraps stored text or blob bytes in java.sql.RowId. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `NCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `NVARCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `LONGNVARCHAR` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `NCLOB` | emulated | The driver wraps stored text in java.sql.NClob. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | +| `SQLXML` | emulated | The driver wraps stored text in java.sql.SQLXML. | `Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType`, `Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl` | + +## Table B-4, Java object types mapped to JDBC types + +Table B-4 is observed through `setObject(int, Object)` with no target type. + +| Appendix B row | Status | Reason | Test | +|---|---|---|---| +| `String` | supported | SQLite text maps directly to String. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.math.BigDecimal` | emulated | Binds decimal text. SQLite has no decimal type. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `Boolean` | emulated | Binds integer 0 or 1. SQLite has no boolean type. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `Byte` | supported | Binds a narrowed Hrana integer. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `Short` | supported | Binds a narrowed Hrana integer. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `Integer` | supported | Binds a Hrana integer. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `Long` | supported | Binds a Hrana integer. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `Float` | supported | Binds a Hrana real. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `Double` | supported | Binds a Hrana real. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `byte[]` | supported | Binds a Hrana blob. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.math.BigInteger` | supported | Binds a Hrana integer after an exact long range check. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.Date` | emulated | Binds SQLite date text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.Time` | emulated | Binds SQLite time text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.Timestamp` | emulated | Binds SQLite timestamp text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.Clob` | emulated | Reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.Blob` | supported | Reads the binary stream and binds a blob. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.net.URL` | emulated | Binds the URL as text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.RowId` | emulated | Binds the RowId bytes as a Hrana blob. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.NClob` | emulated | Reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.SQLXML` | emulated | Reads the SQLXML text and binds it. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.util.Calendar` | emulated | Binds SQLite timestamp text from the calendar instant. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.util.Date` | emulated | Binds SQLite timestamp text from the date instant. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.time.LocalDate` | emulated | Binds SQLite date text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.time.LocalTime` | emulated | Binds SQLite time text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.time.LocalDateTime` | emulated | Binds SQLite timestamp text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.time.OffsetTime` | emulated | Binds ISO-8601 text with an offset. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.time.OffsetDateTime` | emulated | Binds ISO-8601 text with an offset. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | + +## Table B-5, conversions by setObject and setNull + +Table B-5 is observed through `setObject(int, Object, int)`. A listed pair must convert. An unlisted pair must throw. + +| Appendix B row | Status | Reason | Test | +|---|---|---|---| +| `String` | supported | Every listed target is a defined conversion. Binary targets bind text bytes. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.math.BigDecimal` | emulated | Numeric targets narrow through BigDecimal. DECIMAL and NUMERIC bind decimal text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `Boolean` | emulated | Binds integer 0 or 1 for numeric and boolean targets. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `Byte` | supported | Every listed target is a defined numeric or text conversion. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `Short` | supported | Every listed target is a defined numeric or text conversion. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `Integer` | supported | Every listed target is a defined numeric or text conversion. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `Long` | supported | Every listed target is a defined numeric or text conversion. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `Float` | supported | Every listed target is a defined numeric or text conversion. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `Double` | supported | Every listed target is a defined numeric or text conversion. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `byte[]` | supported | BINARY, VARBINARY and LONGVARBINARY bind the blob bytes. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.math.BigInteger` | supported | BIGINT binds an integer. Text targets bind the decimal form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.sql.Date` | emulated | DATE and TIMESTAMP bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.sql.Time` | emulated | TIME and TIMESTAMP bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.sql.Timestamp` | emulated | DATE, TIME and TIMESTAMP bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Blob` | supported | BLOB binds the blob bytes. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.sql.Clob` | emulated | CLOB reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.net.URL` | emulated | DATALINK binds the URL text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.RowId` | emulated | ROWID binds the RowId bytes. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.sql.NClob` | emulated | NCLOB reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.sql.SQLXML` | emulated | SQLXML binds the XML text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.util.Calendar` | emulated | Temporal targets bind text. The ARRAY target is N/A. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.util.Date` | emulated | Temporal targets bind text. The ARRAY target is N/A. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.time.LocalDate` | emulated | DATE and text targets bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.time.LocalTime` | emulated | TIME and text targets bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.time.LocalDateTime` | emulated | DATE, TIME, TIMESTAMP and text targets bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.time.OffsetTime` | emulated | TIME_WITH_TIMEZONE and text targets bind ISO-8601 text with an offset. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | +| `java.time.OffsetDateTime` | emulated | TIME_WITH_TIMEZONE, TIMESTAMP_WITH_TIMEZONE and text targets bind ISO-8601 text with an offset. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | + +## Table B-6, ResultSet getter conversions + +Table B-6 is observed through each getter against its recommended declared type. + +| Appendix B row | Status | Reason | Test | +|---|---|---|---| +| `getByte` | supported | Reads a numeric, boolean or text value as a byte. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getShort` | supported | Reads a numeric, boolean or text value as a short. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getInt` | supported | Reads a numeric, boolean or text value as an int. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getLong` | supported | Reads a numeric, boolean or text value as a long. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getFloat` | supported | Reads a numeric, boolean or text value as a float. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getDouble` | supported | Reads a numeric, boolean or text value as a double. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getBigDecimal` | supported | Reads a numeric, boolean or text value as BigDecimal. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getBoolean` | emulated | Reads integer 0 or 1, and the text true or false, as Boolean. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getString` | supported | Reads text and the listed scalar types as String. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getNString` | supported | Reads text and the listed scalar types as String. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getBytes` | supported | Reads binary values and the listed types as byte[]. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getDate` | emulated | Parses the supported text forms into java.sql.Date. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getTime` | emulated | Parses the supported text forms into java.sql.Time. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getTimestamp` | emulated | Parses the supported text forms into java.sql.Timestamp. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getAsciiStream` | emulated | Returns the text bytes as a US-ASCII stream. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getBinaryStream` | supported | Returns the blob bytes as a stream. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getCharacterStream` | emulated | Returns a reader over the stored text or bytes. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getNCharacterStream` | emulated | Returns a reader over the stored text or bytes. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getClob` | emulated | Wraps stored text in java.sql.Clob. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getNClob` | emulated | Wraps stored text in java.sql.NClob. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getBlob` | supported | Wraps stored bytes in java.sql.Blob. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getArray` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `getRef` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `getURL` | emulated | Parses stored text into java.net.URL. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getObject` | supported | Returns the Table B-3 object type for each supported declared type. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getRowId` | emulated | Wraps stored text or bytes in java.sql.RowId. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | +| `getSQLXML` | emulated | Wraps stored text in java.sql.SQLXML. | `Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes`, `Jdbc4AppendixBTypeMappingIT#b6GetterReadsRecommendedTypeFromRealDdl` | + +## Documented exception + +An expression column has no declared type. `SELECT 1 + 1` reports a null `decltype`, so the driver cannot resolve a JDBC type before it sees the value. The driver falls back to the storage class of the value and stays permissive. This fallback is an exception, not a supported Appendix B row, because the appendix assumes a declared JDBC type. + +The fallback is covered by `Jdbc4AppendixBProfileTest#expressionFallbackStaysPermissive`. The same exception is recorded in `JdbcTypeMapping.Support.FALLBACK`. + +## Conformance quarantines + +The xerial conformance suite keeps its selected tests except for four methods whose expectations Appendix B replaces. The list and the reason for each one are in [`../libsql-conformance/README.md`](../libsql-conformance/README.md). They still run in the `xerial-control` profile. From 0a8ec03256ddb1098538053df7f04692cab8a209 Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Sun, 25 Oct 2026 04:32:09 +0100 Subject: [PATCH 4/6] test(itests): assert the nclob wrapper and its content The B-5 reader returned the NClob wrapper while the expectation checked only the type, so the stored text was no longer verified. Read the wrapper, assert its type, and compare getSubString(1, length) with the source text in B-2, B-4, and B-5. --- .../itest/Jdbc4AppendixBTypeMappingIT.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java b/libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java index 2933d69..2e5c094 100644 --- a/libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java +++ b/libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java @@ -418,7 +418,7 @@ static Expected any(Class type) { new WriteRow("java.sql.RowId", rowId(TEXT_ROWID), "ROWID", Types.ROWID, UNSPECIFIED, ResultSet::getRowId, Expected.any(RowId.class)), new WriteRow("java.sql.NClob", nclob("abc"), "NCLOB", Types.NCLOB, TEXT, - ResultSet::getNClob, Expected.any(NClob.class)), + Jdbc4AppendixBTypeMappingIT::nclobText, Expected.of("abc")), new WriteRow("java.sql.SQLXML", sqlxml(TEXT_XML), "SQLXML", Types.SQLXML, UNSPECIFIED, ResultSet::getSQLXML, Expected.any(SQLXML.class))); @@ -542,7 +542,7 @@ private static Calendar calendar2024() { new WriteRow("java.sql.RowId", stub(RowId.class), "ROWID", Types.ROWID, UNSPECIFIED, ResultSet::getRowId, Expected.any(RowId.class)), new WriteRow("java.sql.NClob", nclob("abc"), "NCLOB", Types.NCLOB, TEXT, - ResultSet::getNClob, Expected.any(NClob.class)), + Jdbc4AppendixBTypeMappingIT::nclobText, Expected.of("abc")), new WriteRow("java.sql.SQLXML", stub(SQLXML.class), "SQLXML", Types.SQLXML, UNSPECIFIED, ResultSet::getSQLXML, Expected.any(SQLXML.class)), new WriteRow("java.util.Calendar", CALENDAR, "TIMESTAMP", Types.TIMESTAMP, TEXT, @@ -881,7 +881,7 @@ private static SqlRead readFor(Target target) { case "TIMESTAMP" -> ResultSet::getTimestamp; case "CLOB" -> Jdbc4AppendixBTypeMappingIT::clobText; case "BLOB" -> Jdbc4AppendixBTypeMappingIT::blobBytes; - case "NCLOB" -> ResultSet::getNClob; + case "NCLOB" -> Jdbc4AppendixBTypeMappingIT::nclobText; case "ARRAY" -> ResultSet::getArray; case "STRUCT" -> (rs, i) -> rs.getObject(i); case "REF" -> ResultSet::getRef; @@ -926,7 +926,7 @@ private static Expected expectedFor(JavaRow row, Target target) { case "TIME" -> timeExpected(source); case "TIMESTAMP" -> timestampExpected(source); case "CLOB" -> Expected.of(clobTextValue(source)); - case "NCLOB" -> Expected.any(NClob.class); + case "NCLOB" -> Expected.of(clobTextValue(source)); case "BLOB" -> Expected.of(bytesForm(source)); case "BINARY", "VARBINARY", "LONGVARBINARY" -> Expected.of(bytesForm(source)); case "DATALINK" -> Expected.any(URL.class); @@ -1127,6 +1127,14 @@ private static String clobText(ResultSet resultSet, int column) throws SQLExcept return clob == null ? null : clob.getSubString(1, (int) clob.length()); } + private static String nclobText(ResultSet resultSet, int column) throws SQLException { + NClob nclob = resultSet.getNClob(column); + assertThat(nclob) + .as("NCLOB column must read as an NClob wrapper") + .isInstanceOf(NClob.class); + return nclob.getSubString(1, (int) nclob.length()); + } + private static byte[] blobBytes(ResultSet resultSet, int column) throws SQLException { Blob blob = resultSet.getBlob(column); if (blob == null) { From c3190ff4f82ec319c59f0eed2c6c192f152735aa Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Sun, 25 Oct 2026 04:32:12 +0100 Subject: [PATCH 5/6] docs(conformance): note the checks the method quarantines drop The quarantine table names the conflicting assertion for each method but not the non-conflicting checks the method-level exclusion also removes. List those checks per method and correct the count note: 270 excludes the four quarantines. --- libsql-conformance/README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libsql-conformance/README.md b/libsql-conformance/README.md index cf14eb5..8546c45 100644 --- a/libsql-conformance/README.md +++ b/libsql-conformance/README.md @@ -48,8 +48,8 @@ with: ``` Last green result: 270 tests, 7 skipped, with `SavepointTest` included. The -count includes the four Appendix B quarantines below and two harness tests for -the quarantine. +count excludes the four Appendix B quarantines below and includes the two +harness tests for the quarantine. ### Appendix B quarantines @@ -66,6 +66,14 @@ the libSQL run. The full type profile is in | `org.sqlite.RSMetaDataTest#testGetColumnClassName` | xerial reports a declared `BLOB` as `java.lang.Object`. Table B-3 maps `BLOB` to `java.sql.Blob`. | | `org.sqlite.PrepStmtTest#getObject` | xerial returns an `Integer` for `getObject` on a declared `BIT`. Table B-3 maps `BIT` to `Boolean`. | +The exclusion is method-level, so each method also loses checks that do not +conflict with Appendix B: + +- `StatementTest#bytesTest` also loses its BLOB `setBytes`/`getBytes` round trip. +- `RSMetaDataTest#columnTypes` also checks other column types that do not conflict, including the INTEGER family, text, numeric, boolean, date and timestamp types, plus DECIMAL precision and scale. +- `RSMetaDataTest#testGetColumnClassName` also checks the INTEGER, VARCHAR, and DOUBLE class names. +- `PrepStmtTest#getObject` also checks other `getObject` rows (INTEGER, FLOAT, untyped, VARCHAR and BLOB columns) and the typed getters above them. + ### Three-layer contract When the layers disagree, the contract is: From 0861960e4fab7f48e74868af7e3f0b086675b6da Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Sun, 25 Oct 2026 04:32:16 +0100 Subject: [PATCH 6/6] docs(jdbc): point setter n/a rows at setter tests The profile test only exercises getObject, getArray, and getRef on declared columns, so it cannot prove the B-2, B-4, or B-5 setter rows. Cite the integration rows and the setObject rejection test instead, and note that the timezone types belong to B-5 and B-6 rather than B-1 or B-3. --- docs/jdbc-appendix-b-compliance.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/jdbc-appendix-b-compliance.md b/docs/jdbc-appendix-b-compliance.md index bbb702a..e24bcc4 100644 --- a/docs/jdbc-appendix-b-compliance.md +++ b/docs/jdbc-appendix-b-compliance.md @@ -14,7 +14,7 @@ The unit suites are `Jdbc4AppendixBReadTest`, `Jdbc4AppendixBSetObjectTest`, and ## Table B-1, JDBC types mapped to Java types -Table B-1 is observed through the natural ResultSet getter for each JDBC type. +Table B-1 is observed through the natural ResultSet getter for each JDBC type. `TIME_WITH_TIMEZONE` and `TIMESTAMP_WITH_TIMEZONE` are not Table B-1 rows; Tables B-5 and B-6 cover them, so the profile test listing them as supported does not conflict with this table. | Appendix B row | Status | Reason | Test | |---|---|---|---| @@ -74,18 +74,18 @@ Table B-2 is observed through the standard setter for each Java type. | `java.sql.Timestamp` | emulated | Binds SQLite timestamp text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | | `java.sql.Clob` | emulated | Reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | | `java.sql.Blob` | supported | Reads the binary stream and binds a blob. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | -| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | -| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | -| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | +| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | | `java.net.URL` | emulated | Binds the URL as text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | -| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | | `java.sql.RowId` | emulated | Binds the RowId bytes as a Hrana blob. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | | `java.sql.NClob` | emulated | Reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | | `java.sql.SQLXML` | emulated | Reads the SQLXML text and binds it. | `Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType` | ## Table B-3, JDBC types mapped to Java object types -Table B-3 is observed through `getObject(int)` for each declared type. +Table B-3 is observed through `getObject(int)` for each declared type. `TIME_WITH_TIMEZONE` and `TIMESTAMP_WITH_TIMEZONE` are not Table B-3 rows; Tables B-5 and B-6 cover them, so the profile test listing them as supported does not conflict with this table. | Appendix B row | Status | Reason | Test | |---|---|---|---| @@ -146,11 +146,11 @@ Table B-4 is observed through `setObject(int, Object)` with no target type. | `java.sql.Timestamp` | emulated | Binds SQLite timestamp text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | | `java.sql.Clob` | emulated | Reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | | `java.sql.Blob` | supported | Reads the binary stream and binds a blob. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | -| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | -| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | -| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | +| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | | `java.net.URL` | emulated | Binds the URL as text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | -| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | | `java.sql.RowId` | emulated | Binds the RowId bytes as a Hrana blob. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | | `java.sql.NClob` | emulated | Reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | | `java.sql.SQLXML` | emulated | Reads the SQLXML text and binds it. | `Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType` | @@ -182,13 +182,13 @@ Table B-5 is observed through `setObject(int, Object, int)`. A listed pair must | `java.sql.Date` | emulated | DATE and TIMESTAMP bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | | `java.sql.Time` | emulated | TIME and TIMESTAMP bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | | `java.sql.Timestamp` | emulated | DATE, TIME and TIMESTAMP bind the SQLite text form. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | -| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Array` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnsupportedTypesAndValues` | | `java.sql.Blob` | supported | BLOB binds the blob bytes. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | | `java.sql.Clob` | emulated | CLOB reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | -| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | -| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `java.sql.Struct` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnsupportedTypesAndValues` | +| `java.sql.Ref` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnsupportedTypesAndValues` | | `java.net.URL` | emulated | DATALINK binds the URL text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | -| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBProfileTest#everyUnsupportedDeclaredTypeThrowsFeatureNotSupported` | +| `Java class` | N/A | SQLite has no interoperable representation. The driver throws SQLFeatureNotSupportedException. | `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnsupportedTypesAndValues` | | `java.sql.RowId` | emulated | ROWID binds the RowId bytes. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | | `java.sql.NClob` | emulated | NCLOB reads the character stream and binds text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` | | `java.sql.SQLXML` | emulated | SQLXML binds the XML text. | `Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType`, `Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes` |