aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execPartition.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execPartition.c')
-rw-r--r--src/backend/executor/execPartition.c314
1 files changed, 223 insertions, 91 deletions
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 16aec59d0ec..4e9c32cef16 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -181,7 +181,7 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
int maxfieldlen);
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(PlanState *planstate,
+static PartitionPruneState *CreatePartitionPruneState(EState *estate,
PartitionPruneInfo *pruneinfo);
static void InitPartitionPruneContext(PartitionPruneContext *context,
List *pruning_steps,
@@ -189,9 +189,10 @@ static void InitPartitionPruneContext(PartitionPruneContext *context,
PartitionKey partkey,
PlanState *planstate,
ExprContext *econtext);
-static void PartitionPruneFixSubPlanMap(PartitionPruneState *prunestate,
- Bitmapset *initially_valid_subplans,
- int n_total_subplans);
+static void InitExecPartitionPruneContexts(PartitionPruneState *prunstate,
+ PlanState *parent_plan,
+ Bitmapset *initially_valid_subplans,
+ int n_total_subplans);
static void find_matching_subplans_recurse(PartitionPruningData *prunedata,
PartitionedRelPruningData *pprune,
bool initial_prune,
@@ -1762,48 +1763,106 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap)
*
* Functions:
*
- * ExecInitPartitionPruning:
- * Creates the PartitionPruneState required by ExecFindMatchingSubPlans.
- * Details stored include how to map the partition index returned by the
- * partition pruning code into subplan indexes. Also determines the set
- * of subplans to initialize considering the result of performing initial
- * pruning steps if any. Maps in PartitionPruneState are updated to
+ * ExecDoInitialPruning:
+ * Perform runtime "initial" pruning, if necessary, to determine the set
+ * of child subnodes that need to be initialized during ExecInitNode() for
+ * all plan nodes that contain a PartitionPruneInfo.
+ *
+ * ExecInitPartitionExecPruning:
+ * Updates the PartitionPruneState found at given part_prune_index in
+ * EState.es_part_prune_states for use during "exec" pruning if required.
+ * Also returns the set of subplans to initialize that would be stored at
+ * part_prune_index in EState.es_part_prune_result by
+ * ExecDoInitialPruning(). Maps in PartitionPruneState are updated to
* account for initial pruning possibly having eliminated some of the
* subplans.
*
* ExecFindMatchingSubPlans:
* Returns indexes of matching subplans after evaluating the expressions
* that are safe to evaluate at a given point. This function is first
- * called during ExecInitPartitionPruning() to find the initially
- * matching subplans based on performing the initial pruning steps and
- * then must be called again each time the value of a Param listed in
+ * called during ExecDoInitialPruning() to find the initially matching
+ * subplans based on performing the initial pruning steps and then must be
+ * called again each time the value of a Param listed in
* PartitionPruneState's 'execparamids' changes.
*-------------------------------------------------------------------------
*/
/*
- * ExecInitPartitionPruning
- * Initialize data structure needed for run-time partition pruning and
- * do initial pruning if needed
+ * ExecDoInitialPruning
+ * Perform runtime "initial" pruning, if necessary, to determine the set
+ * 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
+ * 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
+ * for "exec" pruning.
+ *
+ * If initial pruning steps exist for a PartitionPruneInfo entry, this function
+ * executes those pruning steps and stores the result as a bitmapset of valid
+ * child subplans, identifying which subplans should be initialized for
+ * execution. The results are saved in estate->es_part_prune_results.
+ *
+ * If no initial pruning is performed for a given PartitionPruneInfo, a NULL
+ * entry is still added to es_part_prune_results to maintain alignment with
+ * es_part_prune_infos. This ensures that ExecInitPartitionExecPruning() can
+ * use the same index to retrieve the pruning results.
+ */
+void
+ExecDoInitialPruning(EState *estate)
+{
+ ListCell *lc;
+
+ foreach(lc, estate->es_part_prune_infos)
+ {
+ PartitionPruneInfo *pruneinfo = lfirst_node(PartitionPruneInfo, lc);
+ PartitionPruneState *prunestate;
+ Bitmapset *validsubplans = NULL;
+
+ /* Create and save the PartitionPruneState. */
+ prunestate = CreatePartitionPruneState(estate, pruneinfo);
+ 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.
+ */
+ if (prunestate->do_initial_prune)
+ validsubplans = ExecFindMatchingSubPlans(prunestate, true);
+ estate->es_part_prune_results = lappend(estate->es_part_prune_results,
+ validsubplans);
+ }
+}
+
+/*
+ * ExecInitPartitionExecPruning
+ * Initialize the data structures needed for runtime "exec" partition
+ * pruning and return the result of initial pruning, if available.
*
* 'relids' identifies the relation to which both the parent plan and the
* PartitionPruneInfo given by 'part_prune_index' belong.
*
* On return, *initially_valid_subplans is assigned the set of indexes of
* child subplans that must be initialized along with the parent plan node.
- * Initial pruning is performed here if needed and in that case only the
- * surviving subplans' indexes are added.
+ * Initial pruning would have been performed by ExecDoInitialPruning(), if
+ * necessary, and the bitmapset of surviving subplans' indexes would have
+ * been stored as the part_prune_index'th element of
+ * EState.es_part_prune_results.
*
- * If subplans are indeed pruned, subplan_map arrays contained in the returned
- * PartitionPruneState are re-sequenced to not count those, though only if the
- * maps will be needed for subsequent execution pruning passes.
+ * If subplans were indeed pruned during initial pruning, the subplan_map
+ * arrays in the returned PartitionPruneState are re-sequenced to exclude those
+ * subplans, but only if the maps will be needed for subsequent execution
+ * pruning passes.
*/
PartitionPruneState *
-ExecInitPartitionPruning(PlanState *planstate,
- int n_total_subplans,
- int part_prune_index,
- Bitmapset *relids,
- Bitmapset **initially_valid_subplans)
+ExecInitPartitionExecPruning(PlanState *planstate,
+ int n_total_subplans,
+ int part_prune_index,
+ Bitmapset *relids,
+ Bitmapset **initially_valid_subplans)
{
PartitionPruneState *prunestate;
EState *estate = planstate->state;
@@ -1819,17 +1878,19 @@ ExecInitPartitionPruning(PlanState *planstate,
bmsToString(pruneinfo->relids), part_prune_index,
bmsToString(relids));
- /* We may need an expression context to evaluate partition exprs */
- ExecAssignExprContext(estate, planstate);
-
- /* Create the working data structure for pruning */
- prunestate = CreatePartitionPruneState(planstate, pruneinfo);
-
/*
- * Perform an initial partition prune pass, if required.
+ * The PartitionPruneState would have been created by
+ * ExecDoInitialPruning() and stored as the part_prune_index'th element of
+ * EState.es_part_prune_states.
*/
+ prunestate = list_nth(estate->es_part_prune_states, part_prune_index);
+ Assert(prunestate != NULL);
+
+ /* Use the result of initial pruning done by ExecDoInitialPruning(). */
if (prunestate->do_initial_prune)
- *initially_valid_subplans = ExecFindMatchingSubPlans(prunestate, true);
+ *initially_valid_subplans = list_nth_node(Bitmapset,
+ estate->es_part_prune_results,
+ part_prune_index);
else
{
/* No pruning, so we'll need to initialize all subplans */
@@ -1839,22 +1900,21 @@ ExecInitPartitionPruning(PlanState *planstate,
}
/*
- * Re-sequence subplan indexes contained in prunestate to account for any
- * that were removed above due to initial pruning. No need to do this if
- * no steps were removed.
+ * The exec pruning state must also be initialized, if needed, before it
+ * can be used for pruning during execution.
+ *
+ * This also re-sequences subplan indexes contained in prunestate to
+ * account for any that were removed due to initial pruning; refer to the
+ * condition in InitExecPartitionPruneContexts() that is used to determine
+ * whether to do this. If no exec pruning needs to be done, we would thus
+ * leave the maps to be in an invalid invalid state, but that's ok since
+ * that data won't be consulted again (cf initial Assert in
+ * ExecFindMatchingSubPlans).
*/
- if (bms_num_members(*initially_valid_subplans) < n_total_subplans)
- {
- /*
- * We can safely skip this when !do_exec_prune, even though that
- * leaves invalid data in prunestate, because that data won't be
- * consulted again (cf initial Assert in ExecFindMatchingSubPlans).
- */
- if (prunestate->do_exec_prune)
- PartitionPruneFixSubPlanMap(prunestate,
- *initially_valid_subplans,
- n_total_subplans);
- }
+ if (prunestate->do_exec_prune)
+ InitExecPartitionPruneContexts(prunestate, planstate,
+ *initially_valid_subplans,
+ n_total_subplans);
return prunestate;
}
@@ -1863,7 +1923,11 @@ ExecInitPartitionPruning(PlanState *planstate,
* CreatePartitionPruneState
* Build the data structure required for calling ExecFindMatchingSubPlans
*
- * 'planstate' is the parent plan node's execution state.
+ * This includes PartitionPruneContexts (stored in each
+ * PartitionedRelPruningData corresponding to a PartitionedRelPruneInfo),
+ * which hold the ExprStates needed to evaluate pruning expressions, and
+ * mapping arrays to convert partition indexes from the pruning logic
+ * into subplan indexes in the parent plan node's list of child subplans.
*
* 'pruneinfo' is a PartitionPruneInfo as generated by
* make_partition_pruneinfo. Here we build a PartitionPruneState containing a
@@ -1875,16 +1939,25 @@ ExecInitPartitionPruning(PlanState *planstate,
* stored in each PartitionedRelPruningData can be re-used each time we
* re-evaluate which partitions match the pruning steps provided in each
* PartitionedRelPruneInfo.
+ *
+ * Note that only the PartitionPruneContexts for initial pruning are
+ * initialized here. Those required for exec pruning are initialized later in
+ * ExecInitPartitionExecPruning(), as they depend on the availability of the
+ * parent plan node's PlanState.
*/
static PartitionPruneState *
-CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo)
+CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo)
{
- EState *estate = planstate->state;
PartitionPruneState *prunestate;
int n_part_hierarchies;
ListCell *lc;
int i;
- ExprContext *econtext = planstate->ps_ExprContext;
+
+ /*
+ * Expression context that will be used by partkey_datum_from_expr() to
+ * evaluate expressions for comparison against partition bounds.
+ */
+ ExprContext *econtext = CreateExprContext(estate);
/* For data reading, executor always includes detached partitions */
if (estate->es_partition_directory == NULL)
@@ -1901,6 +1974,8 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo)
palloc(offsetof(PartitionPruneState, partprunedata) +
sizeof(PartitionPruningData *) * n_part_hierarchies);
+ /* Save ExprContext for use during InitExecPartitionPruneContexts(). */
+ prunestate->econtext = econtext;
prunestate->execparamids = NULL;
/* other_subplans can change at runtime, so we need our own copy */
prunestate->other_subplans = bms_copy(pruneinfo->other_subplans);
@@ -1950,6 +2025,10 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo)
* duration of this executor run.
*/
partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex);
+
+ /* Remember for InitExecPartitionPruneContext(). */
+ pprune->partrel = partrel;
+
partkey = RelationGetPartitionKey(partrel);
partdesc = PartitionDirectoryLookup(estate->es_partition_directory,
partrel);
@@ -2061,17 +2140,21 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo)
pprune->present_parts = bms_copy(pinfo->present_parts);
/*
- * Initialize pruning contexts as needed. Note that we must skip
- * execution-time partition pruning in EXPLAIN (GENERIC_PLAN),
- * since parameter values may be missing.
+ * Only initial_context is initialized here. exec_context is
+ * initialized during ExecInitPartitionExecPruning() when the
+ * parent plan's PlanState is available.
+ *
+ * Note that we must skip execution-time (both "init" and "exec")
+ * partition pruning in EXPLAIN (GENERIC_PLAN), since parameter
+ * values may be missing.
*/
pprune->initial_pruning_steps = pinfo->initial_pruning_steps;
if (pinfo->initial_pruning_steps &&
!(econtext->ecxt_estate->es_top_eflags & EXEC_FLAG_EXPLAIN_GENERIC))
{
InitPartitionPruneContext(&pprune->initial_context,
- pinfo->initial_pruning_steps,
- partdesc, partkey, planstate,
+ pprune->initial_pruning_steps,
+ partdesc, partkey, NULL,
econtext);
/* Record whether initial pruning is needed at any level */
prunestate->do_initial_prune = true;
@@ -2080,10 +2163,6 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo)
if (pinfo->exec_pruning_steps &&
!(econtext->ecxt_estate->es_top_eflags & EXEC_FLAG_EXPLAIN_GENERIC))
{
- InitPartitionPruneContext(&pprune->exec_context,
- pinfo->exec_pruning_steps,
- partdesc, partkey, planstate,
- econtext);
/* Record whether exec pruning is needed at any level */
prunestate->do_exec_prune = true;
}
@@ -2188,10 +2267,17 @@ InitPartitionPruneContext(PartitionPruneContext *context,
}
/*
- * PartitionPruneFixSubPlanMap
- * Fix mapping of partition indexes to subplan indexes contained in
- * prunestate by considering the new list of subplans that survived
- * initial pruning
+ * InitExecPartitionPruneContexts
+ * 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.
+ *
+ * Also fix the mapping of partition indexes to subplan indexes contained in
+ * prunestate by considering the new list of subplans that survived initial
+ * pruning.
*
* Current values of the indexes present in PartitionPruneState count all the
* subplans that would be present before initial pruning was done. If initial
@@ -2202,27 +2288,43 @@ InitPartitionPruneContext(PartitionPruneContext *context,
* subplans in the post-initial-pruning set.
*/
static void
-PartitionPruneFixSubPlanMap(PartitionPruneState *prunestate,
- Bitmapset *initially_valid_subplans,
- int n_total_subplans)
+InitExecPartitionPruneContexts(PartitionPruneState *prunestate,
+ PlanState *parent_plan,
+ Bitmapset *initially_valid_subplans,
+ int n_total_subplans)
{
- int *new_subplan_indexes;
+ EState *estate;
+ int *new_subplan_indexes = NULL;
Bitmapset *new_other_subplans;
int i;
int newidx;
+ bool fix_subplan_map = false;
+
+ Assert(prunestate->do_exec_prune);
+ Assert(parent_plan != NULL);
+ estate = parent_plan->state;
/*
- * First we must build a temporary array which maps old subplan indexes to
- * new ones. For convenience of initialization, we use 1-based indexes in
- * this array and leave pruned items as 0.
+ * No need to fix subplans maps if initial pruning didn't eliminate any
+ * subplans.
*/
- new_subplan_indexes = (int *) palloc0(sizeof(int) * n_total_subplans);
- newidx = 1;
- i = -1;
- while ((i = bms_next_member(initially_valid_subplans, i)) >= 0)
+ if (bms_num_members(initially_valid_subplans) < n_total_subplans)
{
- Assert(i < n_total_subplans);
- new_subplan_indexes[i] = newidx++;
+ fix_subplan_map = true;
+
+ /*
+ * First we must build a temporary array which maps old subplan
+ * indexes to new ones. For convenience of initialization, we use
+ * 1-based indexes in this array and leave pruned items as 0.
+ */
+ new_subplan_indexes = (int *) palloc0(sizeof(int) * n_total_subplans);
+ newidx = 1;
+ i = -1;
+ while ((i = bms_next_member(initially_valid_subplans, i)) >= 0)
+ {
+ Assert(i < n_total_subplans);
+ new_subplan_indexes[i] = newidx++;
+ }
}
/*
@@ -2247,6 +2349,29 @@ PartitionPruneFixSubPlanMap(PartitionPruneState *prunestate,
int nparts = pprune->nparts;
int k;
+ /* Initialize PartitionPruneContext for exec pruning, if needed. */
+ if (pprune->exec_pruning_steps != NIL)
+ {
+ PartitionKey partkey;
+ PartitionDesc partdesc;
+
+ /*
+ * See the comment in CreatePartitionPruneState() regarding
+ * the usage of partdesc and partkey.
+ */
+ partkey = RelationGetPartitionKey(pprune->partrel);
+ partdesc = PartitionDirectoryLookup(estate->es_partition_directory,
+ pprune->partrel);
+
+ InitPartitionPruneContext(&pprune->exec_context,
+ pprune->exec_pruning_steps,
+ partdesc, partkey, parent_plan,
+ prunestate->econtext);
+ }
+
+ if (!fix_subplan_map)
+ continue;
+
/* We just rebuild present_parts from scratch */
bms_free(pprune->present_parts);
pprune->present_parts = NULL;
@@ -2288,19 +2413,22 @@ PartitionPruneFixSubPlanMap(PartitionPruneState *prunestate,
}
/*
- * We must also recompute the other_subplans set, since indexes in it may
- * change.
+ * If we fixed subplan maps, we must also recompute the other_subplans
+ * set, since indexes in it may change.
*/
- new_other_subplans = NULL;
- i = -1;
- while ((i = bms_next_member(prunestate->other_subplans, i)) >= 0)
- new_other_subplans = bms_add_member(new_other_subplans,
- new_subplan_indexes[i] - 1);
+ if (fix_subplan_map)
+ {
+ new_other_subplans = NULL;
+ i = -1;
+ while ((i = bms_next_member(prunestate->other_subplans, i)) >= 0)
+ new_other_subplans = bms_add_member(new_other_subplans,
+ new_subplan_indexes[i] - 1);
- bms_free(prunestate->other_subplans);
- prunestate->other_subplans = new_other_subplans;
+ bms_free(prunestate->other_subplans);
+ prunestate->other_subplans = new_other_subplans;
- pfree(new_subplan_indexes);
+ pfree(new_subplan_indexes);
+ }
}
/*
@@ -2351,8 +2479,12 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate,
find_matching_subplans_recurse(prunedata, pprune, initial_prune,
&result);
- /* Expression eval may have used space in ExprContext too */
- if (pprune->exec_pruning_steps)
+ /*
+ * Expression eval may have used space in ExprContext too.
+ * Avoid accessing exec_context during initial pruning, as it is not
+ * valid at that stage.
+ */
+ if (!initial_prune && pprune->exec_pruning_steps)
ResetExprContext(pprune->exec_context.exprcontext);
}