From a79af61882f1ff696d46f612a5b3a8ce50ee75d6 Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Tue, 10 Feb 2026 15:08:52 +0900 Subject: [PATCH v8 1/5] Refactor partition pruning initialization for clarity and modularity Move the creation of PartitionPruneState structures out of ExecDoInitialPruning() into a new ExecCreatePartitionPruneStates() function. This separates the setup of pruning state from the execution of initial pruning logic, making the code clearer and easier to maintain. Simplify handling of unpruned relids by moving responsibility for recording them in EState into CreatePartitionPruneState(), avoiding the need to pass all_leafpart_rtis as an out parameter. Also move the setting of ecxt_param_exec_vals from ExecCreatePartitionPruneState() to InitExecPartitionPruneContexts(), to allow the former to be called at a time when the PARAM_EXEC parameters have not yet been set up. This refactoring allows callers to reuse the pruning setup logic without always triggering pruning, a capability useful for future use cases that may only need metadata initialization. --- src/backend/executor/execMain.c | 1 + src/backend/executor/execPartition.c | 103 +++++++++++++++++++-------- src/include/executor/execPartition.h | 1 + 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 58b84955c2b..c58a2abe9a7 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -870,6 +870,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) * to each PartitionPruneInfo entry, and the es_part_prune_results list is * parallel to es_part_prune_infos. */ + ExecCreatePartitionPruneStates(estate); ExecDoInitialPruning(estate); /* diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index d96d4f9947b..feea9fdfde0 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -185,8 +185,7 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel, static List *adjust_partition_colnos(List *colnos, ResultRelInfo *leaf_part_rri); static List *adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap); static PartitionPruneState *CreatePartitionPruneState(EState *estate, - PartitionPruneInfo *pruneinfo, - Bitmapset **all_leafpart_rtis); + PartitionPruneInfo *pruneinfo); static void InitPartitionPruneContext(PartitionPruneContext *context, List *pruning_steps, PartitionDesc partdesc, @@ -1943,6 +1942,9 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap) * * Functions: * + * ExecCreatePartitionPruneStates + * Create PartitionPruneState for all PartitionPruneInfos in the EState + * * ExecDoInitialPruning: * Perform runtime "initial" pruning, if necessary, to determine the set * of child subnodes that need to be initialized during ExecInitNode() for @@ -1967,6 +1969,29 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap) *------------------------------------------------------------------------- */ +/* + * ExecCreatePartitionPruneStates + * + * Create a PartitionPruneState for each PartitionPruneInfo in the estate, + * and save them in estate->es_part_prune_states. This setup is required + * before any initial or runtime pruning can occur. + */ +void +ExecCreatePartitionPruneStates(EState *estate) +{ + ListCell *lc; + + foreach(lc, estate->es_part_prune_infos) + { + PartitionPruneInfo *pruneinfo = lfirst_node(PartitionPruneInfo, lc); + PartitionPruneState *prunestate; + + /* Create and save the PartitionPruneState. */ + prunestate = CreatePartitionPruneState(estate, pruneinfo); + estate->es_part_prune_states = lappend(estate->es_part_prune_states, + prunestate); + } +} /* * ExecDoInitialPruning @@ -1974,11 +1999,11 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap) * of child subnodes that need to be initialized during ExecInitNode() for * plan nodes that support partition pruning. * - * This function iterates over each PartitionPruneInfo entry in - * estate->es_part_prune_infos. For each entry, it creates a PartitionPruneState - * and adds it to es_part_prune_states. ExecInitPartitionExecPruning() accesses + * This function iterates over each PartitionPruneState in + * estate->es_part_prune_states, which must have been populated earlier by + * ExecCreatePartitionPruneStates(). ExecInitPartitionExecPruning() accesses * these states through their corresponding indexes in es_part_prune_states and - * assign each state to the parent node's PlanState, from where it will be used + * assigns each state to the parent node's PlanState, from where it will be used * for "exec" pruning. * * If initial pruning steps exist for a PartitionPruneInfo entry, this function @@ -1996,20 +2021,13 @@ ExecDoInitialPruning(EState *estate) { ListCell *lc; - foreach(lc, estate->es_part_prune_infos) + Assert(estate->es_part_prune_results == NULL); + foreach(lc, estate->es_part_prune_states) { - PartitionPruneInfo *pruneinfo = lfirst_node(PartitionPruneInfo, lc); - PartitionPruneState *prunestate; + PartitionPruneState *prunestate = (PartitionPruneState *) lfirst(lc); Bitmapset *validsubplans = NULL; - Bitmapset *all_leafpart_rtis = NULL; Bitmapset *validsubplan_rtis = NULL; - /* Create and save the PartitionPruneState. */ - prunestate = CreatePartitionPruneState(estate, pruneinfo, - &all_leafpart_rtis); - estate->es_part_prune_states = lappend(estate->es_part_prune_states, - prunestate); - /* * Perform initial pruning steps, if any, and save the result * bitmapset or NULL as described in the header comment. @@ -2017,8 +2035,6 @@ ExecDoInitialPruning(EState *estate) if (prunestate->do_initial_prune) validsubplans = ExecFindMatchingSubPlans(prunestate, true, &validsubplan_rtis); - else - validsubplan_rtis = all_leafpart_rtis; estate->es_unpruned_relids = bms_add_members(estate->es_unpruned_relids, validsubplan_rtis); @@ -2136,14 +2152,12 @@ ExecInitPartitionExecPruning(PlanState *planstate, * parent plan node's PlanState. * * If initial pruning steps are to be skipped (e.g., during EXPLAIN - * (GENERIC_PLAN)), *all_leafpart_rtis will be populated with the RT indexes of - * all leaf partitions whose scanning subnode is included in the parent plan - * node's list of child plans. The caller must add these RT indexes to - * estate->es_unpruned_relids. + * (GENERIC_PLAN)), the RT indexes of all leaf partitions whose scanning + * subnode is included in the parent plan node's list of child plans are + * added to estate->es_unpruned_relids. */ static PartitionPruneState * -CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo, - Bitmapset **all_leafpart_rtis) +CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo) { PartitionPruneState *prunestate; int n_part_hierarchies; @@ -2377,8 +2391,8 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo, pinfo->execparamids); /* - * Return all leaf partition indexes if we're skipping pruning in - * the EXPLAIN (GENERIC_PLAN) case. + * Add all leaf partition indexes to es_unpruned_relids if we're + * skipping pruning in the EXPLAIN (GENERIC_PLAN) case. */ if (pinfo->initial_pruning_steps && !prunestate->do_initial_prune) { @@ -2390,10 +2404,29 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo, Index rtindex = pprune->leafpart_rti_map[part_index]; if (rtindex) - *all_leafpart_rtis = bms_add_member(*all_leafpart_rtis, - rtindex); + estate->es_unpruned_relids = + bms_add_member(estate->es_unpruned_relids, rtindex); } } + else if (pinfo->initial_pruning_steps == NIL) + { + /* + * All partitions better be present in es_unpruned_relids when + * none are initially prunable. + */ +#ifdef USE_ASSERT_CHECKING + int part_index = -1; + + while ((part_index = bms_next_member(pprune->present_parts, + part_index)) >= 0) + { + Index rtindex = pprune->leafpart_rti_map[part_index]; + + if (rtindex) + Assert(bms_is_member(rtindex, estate->es_unpruned_relids)); + } +#endif + } j++; } @@ -2490,9 +2523,10 @@ InitPartitionPruneContext(PartitionPruneContext *context, * Initialize exec pruning contexts deferred by CreatePartitionPruneState() * * This function finalizes exec pruning setup for a PartitionPruneState by - * initializing contexts for pruning steps that require the parent plan's - * PlanState. It iterates over PartitionPruningData entries and sets up the - * necessary execution contexts for pruning during query execution. + * initializing contexts for pruning steps that require PARAM_EXEC parameters + * and the parent plan's PlanState. It iterates over PartitionPruningData + * entries and sets up the necessary execution contexts for pruning during + * query execution. * * Also fix the mapping of partition indexes to subplan indexes contained in * prunestate by considering the new list of subplans that survived initial @@ -2520,9 +2554,16 @@ InitExecPartitionPruneContexts(PartitionPruneState *prunestate, bool fix_subplan_map = false; Assert(prunestate->do_exec_prune); + Assert(prunestate->econtext); Assert(parent_plan != NULL); estate = parent_plan->state; + /* + * These might not be available when ExecCreatePartitionPruneState() is + * called. + */ + prunestate->econtext->ecxt_param_exec_vals = estate->es_param_exec_vals; + /* * No need to fix subplans maps if initial pruning didn't eliminate any * subplans. diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h index 82063ec2a16..4c96808c376 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -130,6 +130,7 @@ typedef struct PartitionPruneState PartitionPruningData *partprunedata[FLEXIBLE_ARRAY_MEMBER]; } PartitionPruneState; +extern void ExecCreatePartitionPruneStates(EState *estate); extern void ExecDoInitialPruning(EState *estate); extern PartitionPruneState *ExecInitPartitionExecPruning(PlanState *planstate, int n_total_subplans, -- 2.47.3