diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 8bf2ba1c04a..b6751da5743 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -825,6 +825,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) ExecInitRangeTable(estate, rangeTable); estate->es_plannedstmt = plannedstmt; + estate->es_part_prune_infos = plannedstmt->partPruneInfos; /* * Next, build the ExecRowMark array from the PlanRowMark(s), if any. diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 99512826c54..aca0c6f323f 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -183,6 +183,7 @@ ExecSerializePlan(Plan *plan, EState *estate) pstmt->dependsOnRole = false; pstmt->parallelModeNeeded = false; pstmt->planTree = plan; + pstmt->partPruneInfos = estate->es_part_prune_infos; pstmt->rtable = estate->es_range_table; pstmt->resultRelations = NIL; pstmt->appendRelations = NIL; diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index e85f9b8f5a0..8e6453aec2a 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1791,6 +1791,9 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap) * Initialize data structure needed for run-time partition pruning and * do initial pruning if needed * + * 'root_parent_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 @@ -1803,11 +1806,24 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap) PartitionPruneState * ExecInitPartitionPruning(PlanState *planstate, int n_total_subplans, - PartitionPruneInfo *pruneinfo, + int part_prune_index, + Bitmapset *root_parent_relids, Bitmapset **initially_valid_subplans) { PartitionPruneState *prunestate; EState *estate = planstate->state; + PartitionPruneInfo *pruneinfo; + + /* Obtain the pruneinfo we need, and make sure it's the right one */ + pruneinfo = list_nth(estate->es_part_prune_infos, part_prune_index); + if (!bms_equal(root_parent_relids, pruneinfo->root_parent_relids)) + ereport(ERROR, + errcode(ERRCODE_INTERNAL_ERROR), + errmsg_internal("mismatching PartitionPruneInfo found at part_prune_index %d", + part_prune_index), + errdetail_internal("plan node relids %s, pruneinfo relids %s", + bmsToString(root_parent_relids), + bmsToString(pruneinfo->root_parent_relids))); /* We may need an expression context to evaluate partition exprs */ ExecAssignExprContext(estate, planstate); diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 0e595ffa6e5..9695de85b9a 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -119,6 +119,7 @@ CreateExecutorState(void) estate->es_relations = NULL; estate->es_rowmarks = NULL; estate->es_plannedstmt = NULL; + estate->es_part_prune_infos = NIL; estate->es_junkFilter = NULL; diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 357e10a1d7b..99830198bdb 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -134,7 +134,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags) appendstate->as_begun = false; /* If run-time partition pruning is enabled, then set that up now */ - if (node->part_prune_info != NULL) + if (node->part_prune_index >= 0) { PartitionPruneState *prunestate; @@ -145,7 +145,8 @@ ExecInitAppend(Append *node, EState *estate, int eflags) */ prunestate = ExecInitPartitionPruning(&appendstate->ps, list_length(node->appendplans), - node->part_prune_info, + node->part_prune_index, + node->apprelids, &validsubplans); appendstate->as_prune_state = prunestate; nplans = bms_num_members(validsubplans); diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index c5c62fa5c78..f370f9f2877 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -82,7 +82,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) mergestate->ps.ExecProcNode = ExecMergeAppend; /* If run-time partition pruning is enabled, then set that up now */ - if (node->part_prune_info != NULL) + if (node->part_prune_index >= 0) { PartitionPruneState *prunestate; @@ -93,7 +93,8 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) */ prunestate = ExecInitPartitionPruning(&mergestate->ps, list_length(node->mergeplans), - node->part_prune_info, + node->part_prune_index, + node->apprelids, &validsubplans); mergestate->ms_prune_state = prunestate; nplans = bms_num_members(validsubplans); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 5013ac3377f..66139928e81 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1203,7 +1203,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) ListCell *subpaths; int nasyncplans = 0; RelOptInfo *rel = best_path->path.parent; - PartitionPruneInfo *partpruneinfo = NULL; int nodenumsortkeys = 0; AttrNumber *nodeSortColIdx = NULL; Oid *nodeSortOperators = NULL; @@ -1354,6 +1353,9 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) subplans = lappend(subplans, subplan); } + /* Set below if we find quals that we can use to run-time prune */ + plan->part_prune_index = -1; + /* * If any quals exist, they may be useful to perform further partition * pruning during execution. Gather information needed by the executor to @@ -1377,16 +1379,14 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) } if (prunequal != NIL) - partpruneinfo = - make_partition_pruneinfo(root, rel, - best_path->subpaths, - prunequal); + plan->part_prune_index = make_partition_pruneinfo(root, rel, + best_path->subpaths, + prunequal); } plan->appendplans = subplans; plan->nasyncplans = nasyncplans; plan->first_partial_plan = best_path->first_partial_path; - plan->part_prune_info = partpruneinfo; copy_generic_path_info(&plan->plan, (Path *) best_path); @@ -1425,7 +1425,6 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, List *subplans = NIL; ListCell *subpaths; RelOptInfo *rel = best_path->path.parent; - PartitionPruneInfo *partpruneinfo = NULL; /* * We don't have the actual creation of the MergeAppend node split out @@ -1518,6 +1517,9 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, subplans = lappend(subplans, subplan); } + /* Set below if we find quals that we can use to run-time prune */ + node->part_prune_index = -1; + /* * If any quals exist, they may be useful to perform further partition * pruning during execution. Gather information needed by the executor to @@ -1541,13 +1543,13 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, } if (prunequal != NIL) - partpruneinfo = make_partition_pruneinfo(root, rel, - best_path->subpaths, - prunequal); + node->part_prune_index = make_partition_pruneinfo(root, rel, + best_path->subpaths, + prunequal); } node->mergeplans = subplans; - node->part_prune_info = partpruneinfo; + /* * If prepare_sort_from_pathkeys added sort columns, but we were told to diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 493a3af0fa3..799602f5ea5 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -519,6 +519,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions, result->dependsOnRole = glob->dependsOnRole; result->parallelModeNeeded = glob->parallelModeNeeded; result->planTree = top_plan; + result->partPruneInfos = glob->partPruneInfos; result->rtable = glob->finalrtable; result->resultRelations = glob->resultRelations; result->appendRelations = glob->appendRelations; diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 1cb0abdbc1f..e67f0e3509b 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -348,6 +348,31 @@ set_plan_references(PlannerInfo *root, Plan *plan) } } + /* Also fix up the information in PartitionPruneInfos. */ + foreach (lc, root->partPruneInfos) + { + PartitionPruneInfo *pruneinfo = lfirst(lc); + ListCell *l; + + pruneinfo->root_parent_relids = + offset_relid_set(pruneinfo->root_parent_relids, rtoffset); + foreach(l, pruneinfo->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *pinfo = lfirst(l2); + + /* RT index of the table to which the pinfo belongs. */ + pinfo->rtindex += rtoffset; + } + } + + glob->partPruneInfos = lappend(glob->partPruneInfos, pruneinfo); + } + return result; } @@ -1658,21 +1683,12 @@ set_append_references(PlannerInfo *root, aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset); - if (aplan->part_prune_info) - { - foreach(l, aplan->part_prune_info->prune_infos) - { - List *prune_infos = lfirst(l); - ListCell *l2; - - foreach(l2, prune_infos) - { - PartitionedRelPruneInfo *pinfo = lfirst(l2); - - pinfo->rtindex += rtoffset; - } - } - } + /* + * PartitionPruneInfos will be added to a list in PlannerGlobal, so update + * the index. + */ + if (aplan->part_prune_index >= 0) + aplan->part_prune_index += list_length(root->glob->partPruneInfos); /* We don't need to recurse to lefttree or righttree ... */ Assert(aplan->plan.lefttree == NULL); @@ -1734,21 +1750,12 @@ set_mergeappend_references(PlannerInfo *root, mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset); - if (mplan->part_prune_info) - { - foreach(l, mplan->part_prune_info->prune_infos) - { - List *prune_infos = lfirst(l); - ListCell *l2; - - foreach(l2, prune_infos) - { - PartitionedRelPruneInfo *pinfo = lfirst(l2); - - pinfo->rtindex += rtoffset; - } - } - } + /* + * PartitionPruneInfos will be added to a list in PlannerGlobal, so update + * the index. + */ + if (mplan->part_prune_index >= 0) + mplan->part_prune_index += list_length(root->glob->partPruneInfos); /* We don't need to recurse to lefttree or righttree ... */ Assert(mplan->plan.lefttree == NULL); diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 6188bf69cbd..d48f6784c1d 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -209,16 +209,20 @@ static void partkey_datum_from_expr(PartitionPruneContext *context, /* * make_partition_pruneinfo - * Builds a PartitionPruneInfo which can be used in the executor to allow - * additional partition pruning to take place. Returns NULL when - * partition pruning would be useless. + * Checks if the given set of quals can be used to build pruning steps + * that the executor can use to prune away unneeded partitions. If + * suitable quals are found then a PartitionPruneInfo is built and tagged + * onto the PlannerInfo's partPruneInfos list. + * + * The return value is the 0-based index of the item added to the + * partPruneInfos list or -1 if nothing was added. * * 'parentrel' is the RelOptInfo for an appendrel, and 'subpaths' is the list * of scan paths for its child rels. * 'prunequal' is a list of potential pruning quals (i.e., restriction * clauses that are applicable to the appendrel). */ -PartitionPruneInfo * +int make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, List *subpaths, List *prunequal) @@ -332,10 +336,11 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, * quals, then we can just not bother with run-time pruning. */ if (prunerelinfos == NIL) - return NULL; + return -1; /* Else build the result data structure */ pruneinfo = makeNode(PartitionPruneInfo); + pruneinfo->root_parent_relids = parentrel->relids; pruneinfo->prune_infos = prunerelinfos; /* @@ -358,7 +363,9 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, else pruneinfo->other_subplans = NULL; - return pruneinfo; + root->partPruneInfos = lappend(root->partPruneInfos, pruneinfo); + + return list_length(root->partPruneInfos) - 1; } /* diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 4e74aba1e98..8e80a075a27 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202211301 +#define CATALOG_VERSION_NO 202212011 #endif diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h index 708435e9528..17fabc18c9f 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -123,9 +123,9 @@ typedef struct PartitionPruneState extern PartitionPruneState *ExecInitPartitionPruning(PlanState *planstate, int n_total_subplans, - PartitionPruneInfo *pruneinfo, + int part_prune_index, + Bitmapset *root_parent_relids, Bitmapset **initially_valid_subplans); extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate, bool initial_prune); - #endif /* EXECPARTITION_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 18e572f1712..a2008846c63 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -614,6 +614,7 @@ typedef struct EState struct ExecRowMark **es_rowmarks; /* Array of per-range-table-entry * ExecRowMarks, or NULL if none */ PlannedStmt *es_plannedstmt; /* link to top of plan tree */ + List *es_part_prune_infos; /* PlannedStmt.partPruneInfos */ const char *es_sourceText; /* Source text from QueryDesc */ JunkFilter *es_junkFilter; /* top-level junk filter, if any */ diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index ef95429a0d0..dd4eb8679df 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -122,6 +122,9 @@ typedef struct PlannerGlobal /* "flat" list of AppendRelInfos */ List *appendRelations; + /* List of PartitionPruneInfo contained in the plan */ + List *partPruneInfos; + /* OIDs of relations the plan depends on */ List *relationOids; @@ -503,6 +506,9 @@ struct PlannerInfo /* Does this query modify any partition key columns? */ bool partColsUpdated; + + /* PartitionPruneInfos added in this query's plan. */ + List *partPruneInfos; }; diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 61cae463fb3..2e202892a71 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -70,6 +70,9 @@ typedef struct PlannedStmt struct Plan *planTree; /* tree of Plan nodes */ + List *partPruneInfos; /* List of PartitionPruneInfo contained in + * the plan */ + List *rtable; /* list of RangeTblEntry nodes */ /* rtable indexes of target relations for INSERT/UPDATE/DELETE/MERGE */ @@ -270,8 +273,8 @@ typedef struct Append */ int first_partial_plan; - /* Info for run-time subplan pruning; NULL if we're not doing that */ - struct PartitionPruneInfo *part_prune_info; + /* Index to PlannerInfo.partPruneInfos or -1 if no run-time pruning */ + int part_prune_index; } Append; /* ---------------- @@ -305,8 +308,8 @@ typedef struct MergeAppend /* NULLS FIRST/LAST directions */ bool *nullsFirst pg_node_attr(array_size(numCols)); - /* Info for run-time subplan pruning; NULL if we're not doing that */ - struct PartitionPruneInfo *part_prune_info; + /* Index to PlannerInfo.partPruneInfos or -1 if no run-time pruning */ + int part_prune_index; } MergeAppend; /* ---------------- @@ -1406,6 +1409,8 @@ typedef struct PlanRowMark * Then, since an Append-type node could have multiple partitioning * hierarchies among its children, we have an unordered List of those Lists. * + * root_parent_relids RelOptInfo.relids of the relation to which the parent + * plan node and this PartitionPruneInfo node belong * prune_infos List of Lists containing PartitionedRelPruneInfo nodes, * one sublist per run-time-prunable partition hierarchy * appearing in the parent plan node's subplans. @@ -1418,6 +1423,7 @@ typedef struct PartitionPruneInfo pg_node_attr(no_equal) NodeTag type; + Bitmapset *root_parent_relids; List *prune_infos; Bitmapset *other_subplans; } PartitionPruneInfo; diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h index 90684efa253..ebf0dcff8cc 100644 --- a/src/include/partitioning/partprune.h +++ b/src/include/partitioning/partprune.h @@ -70,10 +70,10 @@ typedef struct PartitionPruneContext #define PruneCxtStateIdx(partnatts, step_id, keyno) \ ((partnatts) * (step_id) + (keyno)) -extern PartitionPruneInfo *make_partition_pruneinfo(struct PlannerInfo *root, - struct RelOptInfo *parentrel, - List *subpaths, - List *prunequal); +extern int make_partition_pruneinfo(struct PlannerInfo *root, + struct RelOptInfo *parentrel, + List *subpaths, + List *prunequal); extern Bitmapset *prune_append_rel_partitions(struct RelOptInfo *rel); extern Bitmapset *get_matching_partitions(PartitionPruneContext *context, List *pruning_steps);