From 69ccdab98144d841845b0d3cd9be95ba644c3d98 Mon Sep 17 00:00:00 2001 From: Jiaming Date: Thu, 6 Aug 2026 16:44:10 -0400 Subject: [PATCH] fix(postgres): queue ROLLBACK when begin() is cancelled before BEGIN response A future dropped between queueing BEGIN and reading its response left the server session inside a transaction that the client no longer tracked (transaction_depth is only incremented after the response is read, so the Rollback drop guard was a no-op at depth 0). The connection then returned to the pool and subsequent checkouts silently ran inside the leaked transaction. Queue an explicit ROLLBACK in the guard for the depth-0 case; if the BEGIN never reached the server the paired ROLLBACK is a harmless warning. --- sqlx-postgres/src/transaction.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sqlx-postgres/src/transaction.rs b/sqlx-postgres/src/transaction.rs index 3f4122ea82..896e456dd4 100644 --- a/sqlx-postgres/src/transaction.rs +++ b/sqlx-postgres/src/transaction.rs @@ -82,7 +82,14 @@ struct Rollback<'c> { impl Drop for Rollback<'_> { fn drop(&mut self) { - if !self.defuse { + if self.defuse { + return; + } + if self.conn.inner.transaction_depth == 0 { + self.conn + .queue_simple_query("ROLLBACK") + .expect("BUG: ROLLBACK somehow too large for protocol"); + } else { PgTransactionManager::start_rollback(self.conn) } }