Repository navigation
Expose the transaction status the server reports (Postgres, MySQL, SQLite) - #4512
Open
alandariva wants to merge 1 commit into
Open
alandariva wants to merge 1 commit into
alandariva wants to merge 1 commit into
Conversation
- `PgConnection::transaction_status()` returns the status of the last `ReadyForQuery` message, after reading responses still pending; the status type is now public as `PgTransactionStatus`. - `MySqlConnection::server_in_transaction()` and `server_autocommit()` read the status flags of the last OK or EOF packet. `ping()` now refreshes them (ERR packets carry none), and a new connection takes them from the handshake instead of starting empty. - `LockedSqliteHandle::is_autocommit()` wraps `sqlite3_get_autocommit`. Unlike `Connection::is_in_transaction()`, which counts the transactions begun through SQLx, these reflect transactions begun or ended by statements sent as queries, inside stored procedures, or by the server itself (a deadlock, `INSERT OR ROLLBACK`, an interrupted write).
alandariva
added a commit
to alandariva/jykre-studio
that referenced
this pull request
Nov 8, 2026
- ADR-0030 (transaction state through a pinned SQLx fork) is accepted and implemented; the references no longer call it proposed. - ADR-0027 notes that SQLite now reports its transaction state through the fork, so only whether a transaction wrote is inferred. - TD-001 and ADR-0030 link transact-rs/sqlx#4512, which proposes the same readers upstream, rebased on its main. cargo xtask check passed.
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.
Each database already tells the client whether a session is in a transaction, and SQLx reads it, but keeps it private (
pub(crate) fn in_transaction). The publicConnection::is_in_transaction()counts the transactions begun through SQLx (transaction_depth), so it cannot see aBEGINsent as a query, a transaction begun inside a MySQL stored procedure, a rollback after a deadlock, or one SQLite ended on its own. Tools that run user-written SQL (SQL editors, REPLs) need that state to show it and to avoid committing or rolling back work silently; today they have to probe with extra queries, which can change what the session sees (a PostgreSQLSELECTtakes the transaction's snapshot, so a laterSET TRANSACTION ISOLATION LEVELfails).This adds read-only accessors and changes nothing else:
PgConnection::transaction_status()returns the status of the lastReadyForQuery(Idle,Transaction,Error). It first reads responses still pending (wait_until_ready), so it is current after a failed statement or a dropped stream; no query is sent. The existing private enum becomes public asPgTransactionStatus(renamed fromTransactionStatus, withClone, Copy, PartialEq, Eq).MySqlConnection::server_in_transaction()andserver_autocommit()readSERVER_STATUS_IN_TRANS/SERVER_STATUS_AUTOCOMMITfrom the last OK or EOF packet. Two small fixes make them reliable:ping()now stores the status of its OK packet. ERR packets carry no status, so after a failed statement (for example a deadlock victim, whose transaction the server rolled back) a ping reads it again without running a statement.server_autocommit()is right before the first query even whenset_names,timezoneand thesql_modeoptions are all off.LockedSqliteHandle::is_autocommit()wrapssqlite3_get_autocommit, so callers do not needunsafeand the semver-exemptlibsqlite3-systype.Tests (
tests/postgres,tests/mysql,tests/sqlite) coverBEGINsent as a query, a partly read result, a failed statement,COMMIT AND CHAIN, a transaction begun inside a procedure, autocommit, the status before the first query, a deadlock between two connections andINSERT OR ROLLBACK. Each was checked to fail without its fix (PostgreSQL 18, MySQL 8.4, bundled SQLite); the SQLite suite passes with--test-threads=1.Related: #4469 asks the pool to use the same
ReadyForQuerystate internally to skip the release ping; this PR only exposes it to callers.We have been running this on top of 0.9.0 in a desktop SQL client to show the session's real transaction state.
Does your PR solve an issue?
No existing issue. It relates to #4469 (same protocol state, used internally by the pool).
Is this a breaking change?
No. It only adds public methods and a public type. The type was private before, so the rename breaks nothing. The MySQL status flags now start from the handshake and are refreshed by
ping(). The only internal reader of those flags isMySqlTransactionManager::begin, which checks them right after its ownBEGIN, so its behaviour does not change.