From eee68a884d848eaf7e97e36a04192a594f88e3ad Mon Sep 17 00:00:00 2001
From: Shihao <zhong950419@gmail.com>
Date: Tue, 29 Sep 2026 21:27:11 -0600
Subject: [PATCH v1 2/2] Forget a statement timeout that fires after the
 statement is done

A statement timeout can fire after the statement's last
CHECK_FOR_INTERRUPTS(), for example while interrupts are held in
dsm_detach() during parallel query cleanup.  disable_statement_timeout()
then does nothing because the timer is no longer active, so the fired
indicator and the cancel request it queued stay set.  The next statement
fails on its first CHECK_FOR_INTERRUPTS(), even if it is a COMMIT.
Clear both when the timer has fired but was not serviced.
---
 src/backend/tcop/postgres.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index b6bdfe213fe..c7b0b972954 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -5407,4 +5407,14 @@ disable_statement_timeout(void)
 {
 	if (get_timeout_active(STATEMENT_TIMEOUT))
 		disable_timeout(STATEMENT_TIMEOUT, false);
+	else if (get_timeout_indicator(STATEMENT_TIMEOUT, true))
+	{
+		/*
+		 * The timeout fired after the statement's last
+		 * CHECK_FOR_INTERRUPTS(), for instance while interrupts were held
+		 * during cleanup.  The statement is over, so drop the cancel request
+		 * it queued rather than let the next statement fail on it.
+		 */
+		QueryCancelPending = false;
+	}
 }
-- 
2.37.1 (Apple Git-137.1)

