Serve the java.sql surface clojure.jdbc actually reaches for - #15
Merged
Merged
Conversation
Running clojure.jdbc's own test suite against this shim for the first time
turned up five gaps. Upstream's suite could not even load before; it now
passes whole — 25 tests, 78 assertions, 0 failures.
- DriverManager/getConnection. clojure.jdbc's dbspec->connection ends there,
which is where a JVM driver is reached once it has registered itself. Serving
it is what lets a program that only requires jdbc.core work: extending
proto/IConnection cannot, because that extension has to load AFTER
clojure.jdbc's own to win while this namespace has to load BEFORE them.
- Class/forName on a driver classname. A dbspec may carry
{:classname "org.sqlite.JDBC"}, and clojure.jdbc loads it before connecting.
The two drivers this library backs are registered so the class resolves; one
it does not back still throws ClassNotFoundException.
- The default transaction isolation is the driver's, not a constant. SQLite
serializes by nature and its JDBC driver answers SERIALIZABLE; postgres
starts at READ_COMMITTED. Reporting 2 for both said sqlite was weaker.
- executeBatch raises BatchUpdateException, the class the JVM throws and the
one a caller catches to tell a failed batch entry from any other SQL error.
- PreparedStatement answers getConnection, which java.sql.Statement declares
and clojure.jdbc's lazy cursor calls.
The last one needed the hierarchy too. jdbc.impl imports the class and extends
protocols to the bare name:
(:import java.sql.PreparedStatement)
(extend-protocol proto/IFetch PreparedStatement (fetch [stmt conn opts] …))
An extension written against a SIMPLE name is filed under that name only when
jolt models the class; otherwise it is localized to the extending namespace, as
"jdbc.impl.PreparedStatement" — a tag no value can carry — and the arm silently
never fires while the fully-qualified arms beside it work. So the java.sql
names are grafted onto the modeled hierarchy through
jolt.host/register-class-supers!, and values report the simple spelling
alongside the qualified one. (jdbc/fetch conn stmt) was failing with "No method
fetch in jdbc.proto/IFetch".
Verified against the released jolt v0.8.0: upstream clojure.jdbc's suite, this
library's own suite, and examples/ring-app end to end over the wire.
This was referenced Sep 1, 2026
yogthos
added a commit
that referenced
this pull request
Sep 1, 2026
This library's job is to run the published clojure.jdbc unmodified on a java.sql shim. Only upstream's tests can say whether it still does: the suite in clj-test is ours, so it agrees with our own idea of the API and kept passing while five real gaps sat behind it — the ones #15 fixed once upstream's suite was pointed at the shim for the first time. The tests come from upstream's tree at the sha deps.edn already pins, read out of deps.edn rather than repeated in the script, so a bump to the clojure.jdbc pin moves this gate with it instead of leaving it on an older tree that still passes. Copying the test files in here would drift the other way: they would go on agreeing with whatever the shim had become. Upstream ships its tests outside :paths, so they cannot be reached by an alias in our deps.edn. The script assembles a throwaway project with db as a :local/root and the checkout's test/ on the source roots. The namespaces are the sqlite-only set upstream nominates in its own tests-jolt.edn; jdbc.postgres-test needs a live postgres and hikari-cp, and db's own suite covers the postgres driver. Verified both ways: green as it stands (25 tests, 78 assertions), and exit 1 naming the regression when PreparedStatement's getConnection is removed. Co-authored-by: Yogthos <yogthos@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Running clojure.jdbc's own test suite against this shim for the first time turned up five gaps. Upstream's suite could not previously load at all; it now passes whole.
DriverManagerDriverManager/getConnection— where a JVM driver is reached once registered{:classname "org.sqlite.JDBC"}threwClassNotFoundExceptionREAD_COMMITTEDSERIALIZABLE; postgres staysREAD_COMMITTEDexecuteBatchthrew a bareSQLExceptionBatchUpdateException, the class the JVM throwsPreparedStatementhad nogetConnectionjava.sql.Statementdeclares it; clojure.jdbc's lazy cursor calls itThe one worth reading
jdbc.implimports the class and extends protocols to the bare name:An extension written against a simple name is filed under that name only when jolt models the class. Otherwise it is localized to the extending namespace —
jdbc.impl.PreparedStatement, a tag no value can carry — and the arm silently never fires, while the fully-qualified arms beside it work.(jdbc/fetch conn stmt)was dying withNo method fetch in jdbc.proto/IFetcheven thoughclassandinstance?were both correct.Fixed by grafting the java.sql names onto the modeled hierarchy via the existing
jolt.host/register-class-supers!seam, and reporting the simple spelling alongside the qualified one.Verified
Against the released jolt v0.8.0 (no unreleased runtime changes needed):
all checks passedexamples/ring-append to end, live server over the wire —all passedNote for consumers
A consumer must still
(require '[db.jdbc])beforejdbc.core, as the README says. A jolt-side change to make that require optional is written but deliberately not part of this PR.Upstream's suite is not yet wired in as a gate here — worth doing so these do not regress.