From 82d31451606348955e2bf1d9c6ef2426153ecaee Mon Sep 17 00:00:00 2001
From: Manu <manuelreyesbravo@gmail.com>
Date: Thu, 17 Sep 2026 19:10:53 -0300
Subject: [PATCH] Make partition pruning step generation interruptible

get_steps_using_prefix_recurse() generates one pruning step for each combination of the clauses matched to the partition keys, so the number of recursive calls is the product of the number of clauses matched to each key.  For a range-partitioned table with 18 partition keys and two clauses per key that is about 520k calls taking ~120ms, none of which check for interrupts, so statement_timeout is not honored until the whole step list has been built.

Add a CHECK_FOR_INTERRUPTS() to the recursion, for the same reason commit 35313832248 added one to the planner.

Reported-by: Qifan Liu <imchifan@163.com>
---
 src/backend/partitioning/partprune.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 5e98f503244..0083bb7858f 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -2553,6 +2553,13 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
 	/* Actually, recursion would be limited by PARTITION_MAX_KEYS. */
 	check_stack_depth();
 
+	/*
+	 * The number of combinations generated here is the product of the number
+	 * of clauses matched to each partition key, so it can grow large enough
+	 * that the statement becomes uncancellable for a noticeable time.
+	 */
+	CHECK_FOR_INTERRUPTS();
+
 	Assert(start != NULL);
 	cur_keyno = ((PartClauseInfo *) lfirst(start))->keyno;
 	final_keyno = ((PartClauseInfo *) llast(prefix))->keyno;
-- 
2.55.0

