diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2018-08-01 19:42:46 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2018-08-01 19:42:53 -0400 |
commit | 1b54e91faabf3764b6786915881e514e42dccf89 (patch) | |
tree | de03f8f7eff455000b7c2b14b8c2dac88e9ab60a /src/backend/optimizer/plan/createplan.c | |
parent | 7326a7d63801673d3569def65cb7955d6486f254 (diff) |
Fix run-time partition pruning for appends with multiple source rels.
The previous coding here supposed that if run-time partitioning applied to
a particular Append/MergeAppend plan, then all child plans of that node
must be members of a single partitioning hierarchy. This is totally wrong,
since an Append could be formed from a UNION ALL: we could have multiple
hierarchies sharing the same Append, or child plans that aren't part of any
hierarchy.
To fix, restructure the related plan-time and execution-time data
structures so that we can have a separate list or array for each
partitioning hierarchy. Also track subplans that are not part of any
hierarchy, and make sure they don't get pruned.
Per reports from Phil Florent and others. Back-patch to v11, since
the bug originated there.
David Rowley, with a lot of cosmetic adjustments by me; thanks also
to Amit Langote for review.
Discussion: https://postgr.es/m/HE1PR03MB17068BB27404C90B5B788BCABA7B0@HE1PR03MB1706.eurprd03.prod.outlook.com
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 52 |
1 files changed, 41 insertions, 11 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 165a9e9b8e7..4debdad76fc 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -124,6 +124,7 @@ static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo *root, static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, List **qual, List **indexqual, List **indexECs); static void bitmap_subplan_mark_shared(Plan *plan); +static List *flatten_partitioned_rels(List *partitioned_rels); static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path, List *tlist, List *scan_clauses); static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root, @@ -202,7 +203,8 @@ static NamedTuplestoreScan *make_namedtuplestorescan(List *qptlist, List *qpqual static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual, Index scanrelid, int wtParam); static Append *make_append(List *appendplans, int first_partial_plan, - List *tlist, List *partitioned_rels, List *partpruneinfos); + List *tlist, List *partitioned_rels, + PartitionPruneInfo *partpruneinfo); static RecursiveUnion *make_recursive_union(List *tlist, Plan *lefttree, Plan *righttree, @@ -1030,7 +1032,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path) List *subplans = NIL; ListCell *subpaths; RelOptInfo *rel = best_path->path.parent; - List *partpruneinfos = NIL; + PartitionPruneInfo *partpruneinfo = NULL; /* * The subpaths list could be empty, if every child was proven empty by @@ -1068,6 +1070,11 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path) subplans = lappend(subplans, subplan); } + /* + * If any quals exist, they may be useful to perform further partition + * pruning during execution. Gather information needed by the executor to + * do partition pruning. + */ if (enable_partition_pruning && rel->reloptkind == RELOPT_BASEREL && best_path->partitioned_rels != NIL) @@ -1095,10 +1102,11 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path) * partition indexes into subpath indexes. */ if (prunequal != NIL) - partpruneinfos = - make_partition_pruneinfo(root, + partpruneinfo = + make_partition_pruneinfo(root, rel, + best_path->subpaths, best_path->partitioned_rels, - best_path->subpaths, prunequal); + prunequal); } /* @@ -1110,7 +1118,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path) plan = make_append(subplans, best_path->first_partial_path, tlist, best_path->partitioned_rels, - partpruneinfos); + partpruneinfo); copy_generic_path_info(&plan->plan, (Path *) best_path); @@ -1218,7 +1226,8 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path) subplans = lappend(subplans, subplan); } - node->partitioned_rels = best_path->partitioned_rels; + node->partitioned_rels = + flatten_partitioned_rels(best_path->partitioned_rels); node->mergeplans = subplans; return (Plan *) node; @@ -4968,6 +4977,27 @@ bitmap_subplan_mark_shared(Plan *plan) elog(ERROR, "unrecognized node type: %d", nodeTag(plan)); } +/* + * flatten_partitioned_rels + * Convert List of Lists into a single List with all elements from the + * sub-lists. + */ +static List * +flatten_partitioned_rels(List *partitioned_rels) +{ + List *newlist = NIL; + ListCell *lc; + + foreach(lc, partitioned_rels) + { + List *sublist = lfirst(lc); + + newlist = list_concat(newlist, list_copy(sublist)); + } + + return newlist; +} + /***************************************************************************** * * PLAN NODE BUILDING ROUTINES @@ -5311,7 +5341,7 @@ make_foreignscan(List *qptlist, static Append * make_append(List *appendplans, int first_partial_plan, List *tlist, List *partitioned_rels, - List *partpruneinfos) + PartitionPruneInfo *partpruneinfo) { Append *node = makeNode(Append); Plan *plan = &node->plan; @@ -5322,8 +5352,8 @@ make_append(List *appendplans, int first_partial_plan, plan->righttree = NULL; node->appendplans = appendplans; node->first_partial_plan = first_partial_plan; - node->partitioned_rels = partitioned_rels; - node->part_prune_infos = partpruneinfos; + node->partitioned_rels = flatten_partitioned_rels(partitioned_rels); + node->part_prune_info = partpruneinfo; return node; } @@ -6480,7 +6510,7 @@ make_modifytable(PlannerInfo *root, node->operation = operation; node->canSetTag = canSetTag; node->nominalRelation = nominalRelation; - node->partitioned_rels = partitioned_rels; + node->partitioned_rels = flatten_partitioned_rels(partitioned_rels); node->partColsUpdated = partColsUpdated; node->resultRelations = resultRelations; node->resultRelIndex = -1; /* will be set correctly in setrefs.c */ |