Skip to content

Commit 4a49cda

Browse files
jackcclaude
andcommitted
Merge pull request #2591 from AlisinaDevelo/test/tx-rollback-conn-closed
tx: regression test for Rollback after mid-query connection close (#2557) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2 parents 53acbaf + d64ab64 commit 4a49cda

2 files changed

Lines changed: 33 additions & 0 deletions

File tree

conn.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,9 @@ func (c *Conn) Exec(ctx context.Context, sql string, arguments ...any) (pgconn.C
475475
}
476476

477477
if err := c.deallocateInvalidatedCachedStatements(ctx); err != nil {
478+
if c.queryTracer != nil {
479+
c.queryTracer.TraceQueryEnd(ctx, c, TraceQueryEndData{Err: err})
480+
}
478481
return pgconn.CommandTag{}, err
479482
}
480483

tx_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,36 @@ func TestTxSendBatchClosed(t *testing.T) {
644644
require.Error(t, err)
645645
}
646646

647+
// When a query is cancelled mid-flight the underlying connection is closed, but
648+
// the Tx handle has not been finalized. The first Rollback then fails to send
649+
// ROLLBACK over the dead connection. That error must be matchable as
650+
// pgconn.ErrConnClosed (transport gone) rather than ErrTxClosed (handle already
651+
// finalized), so callers can tell the two apart. A second Rollback returns
652+
// ErrTxClosed. See https://github.com/jackc/pgx/issues/2557.
653+
func TestTxRollbackOnClosedConnReturnsErrConnClosed(t *testing.T) {
654+
t.Parallel()
655+
656+
conn := mustConnectString(t, os.Getenv("PGX_TEST_DATABASE"))
657+
defer closeConn(t, conn)
658+
659+
tx, err := conn.Begin(context.Background())
660+
require.NoError(t, err)
661+
662+
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
663+
defer cancel()
664+
665+
_, err = tx.Exec(ctx, "select pg_sleep(5)")
666+
require.Error(t, err)
667+
require.True(t, conn.IsClosed())
668+
669+
err = tx.Rollback(context.Background())
670+
require.ErrorIs(t, err, pgconn.ErrConnClosed)
671+
require.NotErrorIs(t, err, pgx.ErrTxClosed)
672+
673+
err = tx.Rollback(context.Background())
674+
require.ErrorIs(t, err, pgx.ErrTxClosed)
675+
}
676+
647677
func TestBeginTxNonFatalErrorKeepsConnAlive(t *testing.T) {
648678
t.Parallel()
649679

0 commit comments

Comments
 (0)