Expose PG-compatible status/transaction_status/async_exec on the JDBC connection (+ CI Postgres 14)#1220
Open
skunkworker wants to merge 2 commits into
Open
Conversation
…nection ActiveRecord's native PostgreSQL reconnect/retry machinery (e.g. #retryable_query_error? checks transaction_status against PQTRANS_INERROR) and the Rails test-suite helper #remote_disconnect call PG::Connection methods on the raw connection, which under JRuby is a PostgreSQLJdbcConnection - not a PG::Connection. They raised NoMethodError / 'uninitialized constant PG'. Implement #status, #transaction_status (read from the driver's protocol-level BaseConnection#getTransactionState) and #async_exec on the JDBC connection, and define the libpq ::PG::PQTRANS_* / ::PG::CONNECTION_* constants AR references (only when the real pg gem is absent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PostgreSQL 11 is EOL and lacks pg_current_xact_id() (added in PG 13), which AR 7.2's test suite uses - causing a cascade of 'function does not exist' / 'current transaction is aborted' errors in the Postgres jobs. Move to a supported release. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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.
Summary
Under JRuby the PostgreSQL raw connection is a
PostgreSQLJdbcConnection, not aPG::Connection. ActiveRecord 7.2's PostgreSQL reconnection test suite callsPG::Connectionmethods and::PG::*constants directly on that raw connection, so they blew up withNoMethodError/uninitialized constant PGand aborted those tests.This PR makes the JDBC connection answer the small libpq-compatible API those paths invoke, and bumps the CI Postgres image to a supported release.
Changes
status,transaction_status,async_execonPostgreSQLRubyJdbcConnection(Java).::PG::PQTRANS_*/::PG::CONNECTION_*constants (lib/arjdbc/postgresql/pg_compat.rb), defined only when the realpggem is absent.11→14(separate commit) — PG 11 is EOL and lackspg_current_xact_id()(PG 13+), which the AR 7.2 suite uses.Why the
PGmodule shim is necessaryThe real
pggem is a C extension and is unavailable under JRuby — the entire reason AR-JDBC exists — so the top-level::PGnamespace and its libpq constants are simply not defined.AR-JDBC's own production code never references
::PG. Verified by runtime method resolution:It is AR's native PostgreSQL adapter that compares
transaction_statusto::PG::PQTRANS_INERROR, but AR-JDBC isclass PostgreSQLAdapter < AbstractAdapter(it does not subclass AR's native PG adapter), so that method is never in the ancestry. The other native::PGsites are bypassed the same way:#retryable_query_error?resolves toAbstractAdapter(no::PG), notpostgresql_adapter.rb#L826-L831.#reset!is overridden by AR-JDBC, sopostgresql_adapter.rb#L367-L372is never reached.#cancel_any_running_query/IDLE_TRANSACTION_STATUSESlive in AR's nativepostgresql/database_statements.rb, which AR-JDBC never loads (it ships its own):database_statements.rb#L162-L166.So the shim's only consumer is the Rails test suite. Rails'
remote_disconnecthelper hard-codes::PG::*on the raw connection, in files this gem cannot edit:test/cases/adapter_test.rb#L913-L921—.status == ::PG::CONNECTION_BAD(L917),.transaction_status == ::PG::PQTRANS_INTRANS(L918),.async_exec("begin")(L919)test/cases/adapter_test.rb#L885-L893—.transaction_status == ::PG::PQTRANS_INTRANS(L891)Because those constants are resolved on the caller's side (
== ::PG::PQTRANS_INTRANS), nothing our methods return can satisfy them — a top-level::PGmust exist or the tests raiseuninitialized constant PG.Why shim rather than exclude these tests? They exercise behavior AR-JDBC genuinely supports and cares about — reconnect/retry after a dropped backend, the same scenario as the connection-loss work in the sibling PRs. The
::PGreferences are only test scaffolding used to induce the disconnect, not the behavior under test. With the shim in place these tests run and drop from 26 errors → 3 errors / 4 failures; the remaining 7 are real reconnect-recovery and transaction-state gaps. Excluding the tests would throw away that coverage and mask those genuine gaps. Exclusions are for things that cannot work under JRuby; these can. Hence the shim — an ~8-line, version-stable libpq constants module guarded byunless defined?(PG)— is the correct minimal solution.Why the constant values / state mapping are correct
ConnStatusType(CONNECTION_OK = 0,CONNECTION_BAD = 1) andPGTransactionStatusType(PQTRANS_IDLE = 0,ACTIVE = 1,INTRANS = 2,INERROR = 3,UNKNOWN = 4) — PostgreSQL source:libpq-fe.h#L56-L59andlibpq-fe.h#L114-L120transaction_statusreads the driver's protocol-level state viaBaseConnection#getTransactionState()and mapsIDLE/OPEN/FAILED→PQTRANS_IDLE/INTRANS/INERROR. Driver enum:pgjdbc TransactionState.java#L8-L11(
PGConnectionexposes no transaction state, hence the unwrap toBaseConnection.)Verification
Local run of
test/cases/adapter_test.rb(jruby-9.4.14.0, AR 7-2-stable,--seed=12345):transaction_status, 13×statusNoMethodError)The remaining 3 errors / 4 failures are deeper reconnect-recovery and transaction-state-tracking gaps, tracked separately. This PR does not target the
too many clientsconnection-leak cascade — that is a distinct issue.🤖 Generated with Claude Code