|
|
|
@ -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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|