@@ -143,6 +143,11 @@ static bool DoingCommandRead = false;
143143static bool doing_extended_query_message = false;
144144static bool ignore_till_sync = false;
145145
146+ /*
147+ * Flag to keep track of whether statement timeout timer is active.
148+ */
149+ static bool stmt_timeout_active = false;
150+
146151/*
147152 * If an unnamed prepared statement exists, it's stored here.
148153 * We keep it separate from the hashtable kept by commands/prepare.c
@@ -182,6 +187,8 @@ static bool IsTransactionExitStmtList(List *pstmts);
182187static bool IsTransactionStmtList (List * pstmts );
183188static void drop_unnamed_stmt (void );
184189static void log_disconnections (int code , Datum arg );
190+ static void enable_statement_timeout (void );
191+ static void disable_statement_timeout (void );
185192
186193
187194/* ----------------------------------------------------------------
@@ -1241,7 +1248,8 @@ exec_parse_message(const char *query_string, /* string to execute */
12411248 /*
12421249 * Start up a transaction command so we can run parse analysis etc. (Note
12431250 * that this will normally change current memory context.) Nothing happens
1244- * if we are already in one.
1251+ * if we are already in one. This also arms the statement timeout if
1252+ * necessary.
12451253 */
12461254 start_xact_command ();
12471255
@@ -1529,7 +1537,8 @@ exec_bind_message(StringInfo input_message)
15291537 /*
15301538 * Start up a transaction command so we can call functions etc. (Note that
15311539 * this will normally change current memory context.) Nothing happens if
1532- * we are already in one.
1540+ * we are already in one. This also arms the statement timeout if
1541+ * necessary.
15331542 */
15341543 start_xact_command ();
15351544
@@ -2021,6 +2030,9 @@ exec_execute_message(const char *portal_name, long max_rows)
20212030 * those that start or end a transaction block.
20222031 */
20232032 CommandCounterIncrement ();
2033+
2034+ /* full command has been executed, reset timeout */
2035+ disable_statement_timeout ();
20242036 }
20252037
20262038 /* Send appropriate CommandComplete to client */
@@ -2450,25 +2462,27 @@ start_xact_command(void)
24502462 {
24512463 StartTransactionCommand ();
24522464
2453- /* Set statement timeout running, if any */
2454- /* NB: this mustn't be enabled until we are within an xact */
2455- if (StatementTimeout > 0 )
2456- enable_timeout_after (STATEMENT_TIMEOUT , StatementTimeout );
2457- else
2458- disable_timeout (STATEMENT_TIMEOUT , false);
2459-
24602465 xact_started = true;
24612466 }
2467+
2468+ /*
2469+ * Start statement timeout if necessary. Note that this'll intentionally
2470+ * not reset the clock on an already started timeout, to avoid the timing
2471+ * overhead when start_xact_command() is invoked repeatedly, without an
2472+ * interceding finish_xact_command() (e.g. parse/bind/execute). If that's
2473+ * not desired, the timeout has to be disabled explicitly.
2474+ */
2475+ enable_statement_timeout ();
24622476}
24632477
24642478static void
24652479finish_xact_command (void )
24662480{
2481+ /* cancel active statement timeout after each command */
2482+ disable_statement_timeout ();
2483+
24672484 if (xact_started )
24682485 {
2469- /* Cancel any active statement timeout before committing */
2470- disable_timeout (STATEMENT_TIMEOUT , false);
2471-
24722486 CommitTransactionCommand ();
24732487
24742488#ifdef MEMORY_CONTEXT_CHECKING
@@ -4537,3 +4551,42 @@ log_disconnections(int code, Datum arg)
45374551 port -> user_name , port -> database_name , port -> remote_host ,
45384552 port -> remote_port [0 ] ? " port=" : "" , port -> remote_port )));
45394553}
4554+
4555+ /*
4556+ * Start statement timeout timer, if enabled.
4557+ *
4558+ * If there's already a timeout running, don't restart the timer. That
4559+ * enables compromises between accuracy of timeouts and cost of starting a
4560+ * timeout.
4561+ */
4562+ static void
4563+ enable_statement_timeout (void )
4564+ {
4565+ /* must be within an xact */
4566+ Assert (xact_started );
4567+
4568+ if (StatementTimeout > 0 )
4569+ {
4570+ if (!stmt_timeout_active )
4571+ {
4572+ enable_timeout_after (STATEMENT_TIMEOUT , StatementTimeout );
4573+ stmt_timeout_active = true;
4574+ }
4575+ }
4576+ else
4577+ disable_timeout (STATEMENT_TIMEOUT , false);
4578+ }
4579+
4580+ /*
4581+ * Disable statement timeout, if active.
4582+ */
4583+ static void
4584+ disable_statement_timeout (void )
4585+ {
4586+ if (stmt_timeout_active )
4587+ {
4588+ disable_timeout (STATEMENT_TIMEOUT , false);
4589+
4590+ stmt_timeout_active = false;
4591+ }
4592+ }
0 commit comments