Stmt timeout error can be sent after a CommandComplete
Hi,
At the end of a command, disable_statement_timeout is called as the
timeout applies to a specific command and a CommandComplete message is
sent.
However, it's possible for the stmt timeout to have been fired between
the last message and the call to disable_statement_timeout. The
timeout won't be active anymore, so disable_timeout will be skipped.
However, the timeout is still queued, and the next call to
CHECK_FOR_INTERRUPTS will process and generate a stmt timeout error.
This leads to the confusing situation where we can have a
CompleteCommand message followed by a stmt timeout error for the same
command.
This patch fixes this issue by resetting the timeout indicator if the
timeout is inactive, relying on get_timeout_indicator to reset the
timeout indicator.
Regards,
Anthonin Bonnefoy
Attachments:
v1-0001-Reset-stmt-timeout-indicator-on-disable_statement.patchapplication/octet-stream; name=v1-0001-Reset-stmt-timeout-indicator-on-disable_statement.patchDownload
From fde0f84597c824da977e906853fea75835c1626f Mon Sep 17 00:00:00 2001
From: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Date: Tue, 13 Jan 2026 08:49:23 +0100
Subject: Reset stmt timeout indicator on disable_statement_timeout
At the end of a command, disable_statement_timeout is called as the
timeout applies to a specific command and a CommandComplete message is
sent.
However, it's possible for the stmt timeout to have been fired between
the last message and the call to disable_statement_timeout. The timeout
won't be active anymore, so disable_timeout will be skipped. However,
the timeout is still queued, and the next call to CHECK_FOR_INTERRUPTS
will process and generate a stmt_timeout error.
This leads to the confusing situation where we can have a
CompleteCommand message followed by a StmtTimeout error for the same
command.
This patch fixes this issue by resetting the timeout indicator if the
timeout is inactive.
---
src/backend/tcop/postgres.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index e54bf1e760f..aa9be553fb9 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -5229,11 +5229,15 @@ enable_statement_timeout(void)
}
/*
- * Disable statement timeout, if active.
+ * Disable statement timeout, if active. If not active, the I've-been-fired
+ * indicator is reset.
*/
static void
disable_statement_timeout(void)
{
if (get_timeout_active(STATEMENT_TIMEOUT))
disable_timeout(STATEMENT_TIMEOUT, false);
+ else
+ /* The timeout may have been fired, reset the timeout indicator */
+ get_timeout_indicator(STATEMENT_TIMEOUT, true);
}
--
2.51.0