diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index fb8dba3ab2c..1d27b840ca9 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -853,6 +853,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos); 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 ff4d9dd1bb3..9c313d81315 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -181,6 +181,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->permInfos = estate->es_rteperminfos; pstmt->resultRelations = NIL; diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 7e71d422a62..16aec59d0ec 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1786,6 +1786,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 * + * '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 @@ -1798,11 +1801,23 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap) PartitionPruneState * ExecInitPartitionPruning(PlanState *planstate, int n_total_subplans, - PartitionPruneInfo *pruneinfo, + int part_prune_index, + Bitmapset *relids, Bitmapset **initially_valid_subplans) { PartitionPruneState *prunestate; EState *estate = planstate->state; + PartitionPruneInfo *pruneinfo; + + /* Obtain the pruneinfo we need. */ + pruneinfo = list_nth_node(PartitionPruneInfo, estate->es_part_prune_infos, + part_prune_index); + + /* Its relids better match the plan node's or the planner messed up. */ + if (!bms_equal(relids, pruneinfo->relids)) + elog(ERROR, "wrong pruneinfo with relids=%s found at part_prune_index=%d contained in plan node with relids=%s", + bmsToString(pruneinfo->relids), part_prune_index, + bmsToString(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 7c539de5cf2..6aac6f3a872 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -118,6 +118,7 @@ CreateExecutorState(void) estate->es_rowmarks = NULL; estate->es_rteperminfos = NIL; 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 0bd0e4e54d3..986ef34030a 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -135,7 +135,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; @@ -146,7 +146,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 e152c9ee3a0..1468f942388 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -83,7 +83,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; @@ -94,7 +94,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 1106cd85f0c..816a2b2a576 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1227,7 +1227,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; @@ -1378,6 +1377,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 @@ -1401,16 +1403,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); @@ -1449,7 +1449,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 @@ -1542,6 +1541,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 @@ -1557,13 +1559,12 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, Assert(best_path->path.param_info == NULL); 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 6803edd0854..8a474a50be7 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -555,6 +555,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->permInfos = glob->finalrteperminfos; result->resultRelations = glob->resultRelations; diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 1e7b7bc6ffc..0868249be94 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -1731,6 +1731,53 @@ set_customscan_references(PlannerInfo *root, cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset); } +/* + * register_partpruneinfo + * Subroutine for set_append_references and set_mergeappend_references + * + * Add the PartitionPruneInfo from root->partPruneInfos at the given index + * into PlannerGlobal->partPruneInfos and return its index there. + * + * Also update the RT indexes present in PartitionedRelPruneInfos to add the + * offset. + */ +static int +register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset) +{ + PlannerGlobal *glob = root->glob; + PartitionPruneInfo *pinfo; + ListCell *l; + + Assert(part_prune_index >= 0 && + part_prune_index < list_length(root->partPruneInfos)); + pinfo = list_nth_node(PartitionPruneInfo, root->partPruneInfos, + part_prune_index); + + pinfo->relids = offset_relid_set(pinfo->relids, rtoffset); + foreach(l, pinfo->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *prelinfo = lfirst(l2); + + prelinfo->rtindex += rtoffset; + prelinfo->initial_pruning_steps = + fix_scan_list(root, prelinfo->initial_pruning_steps, + rtoffset, 1); + prelinfo->exec_pruning_steps = + fix_scan_list(root, prelinfo->exec_pruning_steps, + rtoffset, 1); + } + } + + glob->partPruneInfos = lappend(glob->partPruneInfos, pinfo); + + return list_length(glob->partPruneInfos) - 1; +} + /* * set_append_references * Do set_plan_references processing on an Append @@ -1783,27 +1830,13 @@ 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; - pinfo->initial_pruning_steps = - fix_scan_list(root, pinfo->initial_pruning_steps, - rtoffset, 1); - pinfo->exec_pruning_steps = - fix_scan_list(root, pinfo->exec_pruning_steps, - rtoffset, 1); - } - } - } + /* + * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index. + * Also update the RT indexes present in it to add the offset. + */ + if (aplan->part_prune_index >= 0) + aplan->part_prune_index = + register_partpruneinfo(root, aplan->part_prune_index, rtoffset); /* We don't need to recurse to lefttree or righttree ... */ Assert(aplan->plan.lefttree == NULL); @@ -1865,27 +1898,13 @@ 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; - pinfo->initial_pruning_steps = - fix_scan_list(root, pinfo->initial_pruning_steps, - rtoffset, 1); - pinfo->exec_pruning_steps = - fix_scan_list(root, pinfo->exec_pruning_steps, - rtoffset, 1); - } - } - } + /* + * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index. + * Also update the RT indexes present in it to add the offset. + */ + if (mplan->part_prune_index >= 0) + mplan->part_prune_index = + register_partpruneinfo(root, mplan->part_prune_index, rtoffset); /* 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 fa3c5b3c3bb..d3f60cc87c9 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -207,16 +207,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) @@ -330,10 +334,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->relids = bms_copy(parentrel->relids); pruneinfo->prune_infos = prunerelinfos; /* @@ -356,7 +361,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/executor/execPartition.h b/src/include/executor/execPartition.h index 265f836bcda..13177831d9f 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -123,7 +123,8 @@ typedef struct PartitionPruneState extern PartitionPruneState *ExecInitPartitionPruning(PlanState *planstate, int n_total_subplans, - PartitionPruneInfo *pruneinfo, + int part_prune_index, + Bitmapset *relids, Bitmapset **initially_valid_subplans); extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate, bool initial_prune); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index d0f2dca5928..8ce4430af04 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -655,6 +655,7 @@ typedef struct EState * ExecRowMarks, or NULL if none */ List *es_rteperminfos; /* List of RTEPermissionInfo */ PlannedStmt *es_plannedstmt; /* link to top of plan tree */ + List *es_part_prune_infos; /* List of PartitionPruneInfo */ 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 54ee17697e5..52d44f43021 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -128,6 +128,9 @@ typedef struct PlannerGlobal /* "flat" list of AppendRelInfos */ List *appendRelations; + /* "flat" list of PartitionPruneInfos */ + List *partPruneInfos; + /* OIDs of relations the plan depends on */ List *relationOids; @@ -559,6 +562,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 6ef5d0b3759..8143744e89c 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -69,6 +69,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 */ List *permInfos; /* list of RTEPermissionInfo nodes for rtable @@ -278,8 +281,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; /* ---------------- @@ -313,8 +316,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; /* ---------------- @@ -1413,6 +1416,10 @@ 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. * + * relids RelOptInfo.relids of the parent plan node (e.g. Append + * or MergeAppend) to which this PartitionPruneInfo node + * belongs. The pruning logic ensures that this matches + * the parent plan node's apprelids. * prune_infos List of Lists containing PartitionedRelPruneInfo nodes, * one sublist per run-time-prunable partition hierarchy * appearing in the parent plan node's subplans. @@ -1425,6 +1432,7 @@ typedef struct PartitionPruneInfo pg_node_attr(no_equal, no_query_jumble) NodeTag type; + Bitmapset *relids; List *prune_infos; Bitmapset *other_subplans; } PartitionPruneInfo; diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h index 3aff23be21d..c413734789a 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);