Skip to content

Fix stale _transactionException after ROLLBACK TO SAVEPOINT - #455

Closed
kartikey321 wants to merge 1 commit into
isoos:masterfrom
kartikey321:fix/savepoint-transaction-exception
Closed

Fix stale _transactionException after ROLLBACK TO SAVEPOINT#455
kartikey321 wants to merge 1 commit into
isoos:masterfrom
kartikey321:fix/savepoint-transaction-exception

Conversation

@kartikey321

Copy link
Copy Markdown
Contributor

Fixes #454

Problem

When any PgException occurred inside runTx, the internal _transactionException field 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.

Root cause

_handleMessage sets _transactionException on every ErrorResponseMessage (line 531) but has no path to clear
it. After ROLLBACK TO SAVEPOINT, PostgreSQL sends ReadyForQuery(state='T') — the authoritative signal that the
connection is in a clean, committable state — which the driver was ignoring for this purpose.

Fix

Clear _transactionException in _handleMessage when a ReadyForQuery with state='T' is received. This matches
the approach taken by asyncpg and pgx,
both of which treat ReadyForQuery('T') as the signal that the connection is healthy.

Testing

Added a regression test in test/transaction_test.dart that:

  1. Triggers a 42P01 error inside runTx
  2. Recovers via ROLLBACK TO SAVEPOINT / RELEASE SAVEPOINT
  3. Inserts a row and expects it to be committed

The test fails on the original code and passes with this fix.

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.
@kartikey321

Copy link
Copy Markdown
Contributor Author

This pr changes are merged in another pr #457

Closing this one

@kartikey321 kartikey321 closed this Jun 7, 2026
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: _transactionException not cleared after ROLLBACK TO SAVEPOINT, causing silent rollback of recovered transactions

1 participant