Skip to content

Fix connection left in broken state when BEGIN fails or ROLLBACK errors#457

Merged
isoos merged 4 commits into
isoos:masterfrom
kartikey321:fix/transaction-cleanup-on-failure
Jun 7, 2026
Merged

Fix connection left in broken state when BEGIN fails or ROLLBACK errors#457
isoos merged 4 commits into
isoos:masterfrom
kartikey321:fix/transaction-cleanup-on-failure

Conversation

@kartikey321

Copy link
Copy Markdown
Contributor

Fixes #456

Problem

Two cleanup gaps in runTx leave the connection in an unusable or undefined state after failure scenarios.

Bug 1 — Connection permanently blocked when BEGIN fails

_activeTransaction was assigned before BEGIN entered the try block. If PostgreSQL rejected BEGIN (e.g. the connection
was already in a failed transaction state), the assignment was never unwound. Every subsequent conn.execute() call then threw:

Attempting to execute query on connection while inside a runTx call.

Bug 2 — Failed ROLLBACK leaves connection in undefined state

When ROLLBACK itself failed and the original exception was a PgException, the rollback failure was silently swallowed and
the connection was returned to the pool with the PostgreSQL backend potentially still mid-transaction. Subsequent queries on
that connection would execute inside a ghost transaction.

Fix

Bug 1: Move BEGIN inside the try block so a failed BEGIN goes through the same cleanup path (_activeTransaction = null, session closed) as any other error.

Bug 2: Call _closeAfterError() on both ROLLBACK call sites when ROLLBACK itself fails, matching the behaviour of
pgx which explicitly kills the connection in this case.

Testing

Added a regression test in test/transaction_test.dart covering the failed BEGIN scenario — manually starting a transaction,
triggering an error to put the connection in a failed state, then calling runTx and verifying the connection remains usable
afterwards.

Two cleanup gaps in runTx:

1. _activeTransaction was assigned before BEGIN entered the try block.
   If BEGIN was rejected by PostgreSQL the assignment was never unwound,
   permanently blocking the connection with "inside a runTx call" on
   every subsequent execute() call. Fix: move BEGIN inside the try block
   so a failed BEGIN goes through the same cleanup path as any other error.

2. When ROLLBACK itself failed and the original exception was a PgException,
   the rollback failure was silently swallowed and the connection was
   returned to the pool in an undefined PostgreSQL transaction state.
   Fix: call _closeAfterError() on both ROLLBACK call sites when ROLLBACK
   fails, matching pgx which explicitly kills the connection in this case.
@isoos

isoos commented Jun 6, 2026

Copy link
Copy Markdown
Owner

@kartikey321: could you please update the changelog too (for the other PR too)?

@kartikey321

Copy link
Copy Markdown
Contributor Author

Hi @isoos, working on the changelog update now. Quick question — would you prefer #455 and #457 kept as separate
PRs or merged into one? Also, should the changelog entry use a proposed 3.5.12 version heading, or would you prefer
an unreleased/## [next] section that you can rename when cutting the release?

@isoos

isoos commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Can be merged, and yes, bump the version to 3.5.12

When any PgException occurred inside runTx, _transactionException was set
and never cleared — even after a successful ROLLBACK TO SAVEPOINT restored
PostgreSQL to a healthy state. mayCommit therefore returned false and the
driver sent ROLLBACK instead of COMMIT, silently discarding all subsequent
work that completed successfully at the PostgreSQL level.

Fix: clear _transactionException in _handleMessage whenever PostgreSQL
sends ReadyForQuery with state='T' (InTransaction), which is the
authoritative signal that the connection is in a clean, committable state.
Comment thread .gitignore Outdated
@isoos isoos merged commit 8655bfb into isoos:master Jun 7, 2026
1 check passed
@isoos

isoos commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Thanks! I'll release the new version probably tomorrow the latest.

@kartikey321

Copy link
Copy Markdown
Contributor Author

Thank you for the quick action

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.

Bug: connection left in broken state when BEGIN fails or ROLLBACK errors in runTx

2 participants