Relids required_outer);
static void accumulate_append_subpath(Path *path,
List **subpaths,
- List **special_subpaths);
-static Path *get_singleton_append_subpath(Path *path);
+ List **special_subpaths,
+ List **child_append_relid_sets);
+static Path *get_singleton_append_subpath(Path *path,
+ List **child_append_relid_sets);
static void set_dummy_rel_pathlist(RelOptInfo *rel);
static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels)
{
- List *subpaths = NIL;
- bool subpaths_valid = true;
- List *startup_subpaths = NIL;
- bool startup_subpaths_valid = true;
- List *partial_subpaths = NIL;
- List *pa_partial_subpaths = NIL;
- List *pa_nonpartial_subpaths = NIL;
- bool partial_subpaths_valid = true;
- bool pa_subpaths_valid;
+ AppendPathInput unparameterized = {0};
+ AppendPathInput startup = {0};
+ AppendPathInput partial_only = {0};
+ AppendPathInput parallel_append = {0};
+ bool unparameterized_valid = true;
+ bool startup_valid = true;
+ bool partial_only_valid = true;
+ bool parallel_append_valid = true;
List *all_child_pathkeys = NIL;
List *all_child_outers = NIL;
ListCell *l;
double partial_rows = -1;
/* If appropriate, consider parallel append */
- pa_subpaths_valid = enable_parallel_append && rel->consider_parallel;
+ parallel_append_valid = enable_parallel_append && rel->consider_parallel;
/*
* For every non-dummy child, remember the cheapest path. Also, identify
if (childrel->pathlist != NIL &&
childrel->cheapest_total_path->param_info == NULL)
accumulate_append_subpath(childrel->cheapest_total_path,
- &subpaths, NULL);
+ &unparameterized.subpaths, NULL, &unparameterized.child_append_relid_sets);
else
- subpaths_valid = false;
+ unparameterized_valid = false;
/*
* When the planner is considering cheap startup plans, we'll also
/* cheapest_startup_path must not be a parameterized path. */
Assert(cheapest_path->param_info == NULL);
accumulate_append_subpath(cheapest_path,
- &startup_subpaths,
- NULL);
+ &startup.subpaths,
+ NULL,
+ &startup.child_append_relid_sets);
}
else
- startup_subpaths_valid = false;
+ startup_valid = false;
/* Same idea, but for a partial plan. */
{
cheapest_partial_path = linitial(childrel->partial_pathlist);
accumulate_append_subpath(cheapest_partial_path,
- &partial_subpaths, NULL);
+ &partial_only.partial_subpaths, NULL,
+ &partial_only.child_append_relid_sets);
}
else
- partial_subpaths_valid = false;
+ partial_only_valid = false;
/*
* Same idea, but for a parallel append mixing partial and non-partial
* paths.
*/
- if (pa_subpaths_valid)
+ if (parallel_append_valid)
{
Path *nppath = NULL;
if (cheapest_partial_path == NULL && nppath == NULL)
{
/* Neither a partial nor a parallel-safe path? Forget it. */
- pa_subpaths_valid = false;
+ parallel_append_valid = false;
}
else if (nppath == NULL ||
(cheapest_partial_path != NULL &&
/* Partial path is cheaper or the only option. */
Assert(cheapest_partial_path != NULL);
accumulate_append_subpath(cheapest_partial_path,
- &pa_partial_subpaths,
- &pa_nonpartial_subpaths);
+ ¶llel_append.partial_subpaths,
+ ¶llel_append.subpaths,
+ ¶llel_append.child_append_relid_sets);
}
else
{
* figure that out.
*/
accumulate_append_subpath(nppath,
- &pa_nonpartial_subpaths,
- NULL);
+ ¶llel_append.subpaths,
+ NULL,
+ ¶llel_append.child_append_relid_sets);
}
}
* unparameterized Append path for the rel. (Note: this is correct even
* if we have zero or one live subpath due to constraint exclusion.)
*/
- if (subpaths_valid)
- add_path(rel, (Path *) create_append_path(root, rel, subpaths, NIL,
+ if (unparameterized_valid)
+ add_path(rel, (Path *) create_append_path(root, rel, unparameterized,
NIL, NULL, 0, false,
-1));
/* build an AppendPath for the cheap startup paths, if valid */
- if (startup_subpaths_valid)
- add_path(rel, (Path *) create_append_path(root, rel, startup_subpaths,
- NIL, NIL, NULL, 0, false, -1));
+ if (startup_valid)
+ add_path(rel, (Path *) create_append_path(root, rel, startup,
+ NIL, NULL, 0, false, -1));
/*
* Consider an append of unordered, unparameterized partial paths. Make
* it parallel-aware if possible.
*/
- if (partial_subpaths_valid && partial_subpaths != NIL)
+ if (partial_only_valid && partial_only.partial_subpaths != NIL)
{
AppendPath *appendpath;
ListCell *lc;
int parallel_workers = 0;
/* Find the highest number of workers requested for any subpath. */
- foreach(lc, partial_subpaths)
+ foreach(lc, partial_only.partial_subpaths)
{
Path *path = lfirst(lc);
Assert(parallel_workers > 0);
/* Generate a partial append path. */
- appendpath = create_append_path(root, rel, NIL, partial_subpaths,
+ appendpath = create_append_path(root, rel, partial_only,
NIL, NULL, parallel_workers,
enable_parallel_append,
-1);
* a non-partial path that is substantially cheaper than any partial path;
* otherwise, we should use the append path added in the previous step.)
*/
- if (pa_subpaths_valid && pa_nonpartial_subpaths != NIL)
+ if (parallel_append_valid && parallel_append.subpaths != NIL)
{
AppendPath *appendpath;
ListCell *lc;
* Find the highest number of workers requested for any partial
* subpath.
*/
- foreach(lc, pa_partial_subpaths)
+ foreach(lc, parallel_append.partial_subpaths)
{
Path *path = lfirst(lc);
max_parallel_workers_per_gather);
Assert(parallel_workers > 0);
- appendpath = create_append_path(root, rel, pa_nonpartial_subpaths,
- pa_partial_subpaths,
+ appendpath = create_append_path(root, rel, parallel_append,
NIL, NULL, parallel_workers, true,
partial_rows);
add_partial_path(rel, (Path *) appendpath);
* Also build unparameterized ordered append paths based on the collected
* list of child pathkeys.
*/
- if (subpaths_valid)
+ if (unparameterized_valid)
generate_orderedappend_paths(root, rel, live_childrels,
all_child_pathkeys);
{
Relids required_outer = (Relids) lfirst(l);
ListCell *lcr;
+ AppendPathInput parameterized = {0};
+ bool parameterized_valid = true;
/* Select the child paths for an Append with this parameterization */
- subpaths = NIL;
- subpaths_valid = true;
foreach(lcr, live_childrels)
{
RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
if (childrel->pathlist == NIL)
{
/* failed to make a suitable path for this child */
- subpaths_valid = false;
+ parameterized_valid = false;
break;
}
if (subpath == NULL)
{
/* failed to make a suitable path for this child */
- subpaths_valid = false;
+ parameterized_valid = false;
break;
}
- accumulate_append_subpath(subpath, &subpaths, NULL);
+ accumulate_append_subpath(subpath, ¶meterized.subpaths, NULL,
+ ¶meterized.child_append_relid_sets);
}
- if (subpaths_valid)
+ if (parameterized_valid)
add_path(rel, (Path *)
- create_append_path(root, rel, subpaths, NIL,
+ create_append_path(root, rel, parameterized,
NIL, required_outer, 0, false,
-1));
}
{
Path *path = (Path *) lfirst(l);
AppendPath *appendpath;
+ AppendPathInput append = {0};
/* skip paths with no pathkeys. */
if (path->pathkeys == NIL)
continue;
- appendpath = create_append_path(root, rel, NIL, list_make1(path),
- NIL, NULL,
+ append.partial_subpaths = list_make1(path);
+ appendpath = create_append_path(root, rel, append, NIL, NULL,
path->parallel_workers, true,
partial_rows);
add_partial_path(rel, (Path *) appendpath);
foreach(lcp, all_child_pathkeys)
{
List *pathkeys = (List *) lfirst(lcp);
- List *startup_subpaths = NIL;
- List *total_subpaths = NIL;
- List *fractional_subpaths = NIL;
+ AppendPathInput startup = {0};
+ AppendPathInput total = {0};
+ AppendPathInput fractional = {0};
bool startup_neq_total = false;
bool fraction_neq_total = false;
bool match_partition_order;
* just a single subpath (and hence aren't doing anything
* useful).
*/
- cheapest_startup = get_singleton_append_subpath(cheapest_startup);
- cheapest_total = get_singleton_append_subpath(cheapest_total);
+ cheapest_startup =
+ get_singleton_append_subpath(cheapest_startup,
+ &startup.child_append_relid_sets);
+ cheapest_total =
+ get_singleton_append_subpath(cheapest_total,
+ &total.child_append_relid_sets);
- startup_subpaths = lappend(startup_subpaths, cheapest_startup);
- total_subpaths = lappend(total_subpaths, cheapest_total);
+ startup.subpaths = lappend(startup.subpaths, cheapest_startup);
+ total.subpaths = lappend(total.subpaths, cheapest_total);
if (cheapest_fractional)
{
- cheapest_fractional = get_singleton_append_subpath(cheapest_fractional);
- fractional_subpaths = lappend(fractional_subpaths, cheapest_fractional);
+ cheapest_fractional =
+ get_singleton_append_subpath(cheapest_fractional,
+ &fractional.child_append_relid_sets);
+ fractional.subpaths =
+ lappend(fractional.subpaths, cheapest_fractional);
}
}
else
* child paths for the MergeAppend.
*/
accumulate_append_subpath(cheapest_startup,
- &startup_subpaths, NULL);
+ &startup.subpaths, NULL,
+ &startup.child_append_relid_sets);
accumulate_append_subpath(cheapest_total,
- &total_subpaths, NULL);
+ &total.subpaths, NULL,
+ &total.child_append_relid_sets);
if (cheapest_fractional)
accumulate_append_subpath(cheapest_fractional,
- &fractional_subpaths, NULL);
+ &fractional.subpaths, NULL,
+ &fractional.child_append_relid_sets);
}
}
/* We only need Append */
add_path(rel, (Path *) create_append_path(root,
rel,
- startup_subpaths,
- NIL,
+ startup,
pathkeys,
NULL,
0,
if (startup_neq_total)
add_path(rel, (Path *) create_append_path(root,
rel,
- total_subpaths,
- NIL,
+ total,
pathkeys,
NULL,
0,
false,
-1));
- if (fractional_subpaths && fraction_neq_total)
+ if (fractional.subpaths && fraction_neq_total)
add_path(rel, (Path *) create_append_path(root,
rel,
- fractional_subpaths,
- NIL,
+ fractional,
pathkeys,
NULL,
0,
/* We need MergeAppend */
add_path(rel, (Path *) create_merge_append_path(root,
rel,
- startup_subpaths,
+ startup.subpaths,
+ startup.child_append_relid_sets,
pathkeys,
NULL));
if (startup_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
- total_subpaths,
+ total.subpaths,
+ total.child_append_relid_sets,
pathkeys,
NULL));
- if (fractional_subpaths && fraction_neq_total)
+ if (fractional.subpaths && fraction_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
- fractional_subpaths,
+ fractional.subpaths,
+ fractional.child_append_relid_sets,
pathkeys,
NULL));
}
* paths).
*/
static void
-accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths)
+accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths,
+ List **child_append_relid_sets)
{
if (IsA(path, AppendPath))
{
if (!apath->path.parallel_aware || apath->first_partial_path == 0)
{
*subpaths = list_concat(*subpaths, apath->subpaths);
+ *child_append_relid_sets =
+ lappend(*child_append_relid_sets, path->parent->relids);
+ *child_append_relid_sets =
+ list_concat(*child_append_relid_sets,
+ apath->child_append_relid_sets);
return;
}
else if (special_subpaths != NULL)
apath->first_partial_path);
*special_subpaths = list_concat(*special_subpaths,
new_special_subpaths);
+ *child_append_relid_sets =
+ lappend(*child_append_relid_sets, path->parent->relids);
+ *child_append_relid_sets =
+ list_concat(*child_append_relid_sets,
+ apath->child_append_relid_sets);
return;
}
}
MergeAppendPath *mpath = (MergeAppendPath *) path;
*subpaths = list_concat(*subpaths, mpath->subpaths);
+ *child_append_relid_sets =
+ lappend(*child_append_relid_sets, path->parent->relids);
+ *child_append_relid_sets =
+ list_concat(*child_append_relid_sets,
+ mpath->child_append_relid_sets);
return;
}
* Returns the single subpath of an Append/MergeAppend, or just
* return 'path' if it's not a single sub-path Append/MergeAppend.
*
+ * As a side effect, whenever we return a single subpath rather than the
+ * original path, add the relid sets for the original path to
+ * child_append_relid_sets, so that those relids don't entirely disappear
+ * from the final plan.
+ *
* Note: 'path' must not be a parallel-aware path.
*/
static Path *
-get_singleton_append_subpath(Path *path)
+get_singleton_append_subpath(Path *path, List **child_append_relid_sets)
{
Assert(!path->parallel_aware);
AppendPath *apath = (AppendPath *) path;
if (list_length(apath->subpaths) == 1)
+ {
+ *child_append_relid_sets =
+ lappend(*child_append_relid_sets, path->parent->relids);
+ *child_append_relid_sets =
+ list_concat(*child_append_relid_sets,
+ apath->child_append_relid_sets);
return (Path *) linitial(apath->subpaths);
+ }
}
else if (IsA(path, MergeAppendPath))
{
MergeAppendPath *mpath = (MergeAppendPath *) path;
if (list_length(mpath->subpaths) == 1)
+ {
+ *child_append_relid_sets =
+ lappend(*child_append_relid_sets, path->parent->relids);
+ *child_append_relid_sets =
+ list_concat(*child_append_relid_sets,
+ mpath->child_append_relid_sets);
return (Path *) linitial(mpath->subpaths);
+ }
}
return path;
static void
set_dummy_rel_pathlist(RelOptInfo *rel)
{
+ AppendPathInput in = {0};
+
/* Set dummy size estimates --- we leave attr_widths[] as zeroes */
rel->rows = 0;
rel->reltarget->width = 0;
rel->partial_pathlist = NIL;
/* Set up the dummy path */
- add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NIL,
+ add_path(rel, (Path *) create_append_path(NULL, rel, in,
NIL, rel->lateral_relids,
0, false, -1));
ListCell *lc;
ListCell *lc2;
ListCell *lc3;
- List *cheapest_pathlist = NIL;
- List *ordered_pathlist = NIL;
- List *partial_pathlist = NIL;
+ AppendPathInput cheapest = {0};
+ AppendPathInput ordered = {0};
+ AppendPathInput partial = {0};
bool partial_paths_valid = true;
bool consider_parallel = true;
List *rellist;
if (is_dummy_rel(rel))
continue;
- cheapest_pathlist = lappend(cheapest_pathlist,
+ cheapest.subpaths = lappend(cheapest.subpaths,
rel->cheapest_total_path);
if (try_sorted)
false);
if (ordered_path != NULL)
- ordered_pathlist = lappend(ordered_pathlist, ordered_path);
+ ordered.subpaths = lappend(ordered.subpaths, ordered_path);
else
{
/*
else if (rel->partial_pathlist == NIL)
partial_paths_valid = false;
else
- partial_pathlist = lappend(partial_pathlist,
- linitial(rel->partial_pathlist));
+ partial.partial_subpaths = lappend(partial.partial_subpaths,
+ linitial(rel->partial_pathlist));
}
}
/* Build result relation. */
result_rel = fetch_upper_rel(root, UPPERREL_SETOP, relids);
result_rel->reltarget = create_setop_pathtarget(root, tlist,
- cheapest_pathlist);
+ cheapest.subpaths);
result_rel->consider_parallel = consider_parallel;
result_rel->consider_startup = (root->tuple_fraction > 0);
/* If all UNION children were dummy rels, make the resulting rel dummy */
- if (cheapest_pathlist == NIL)
+ if (cheapest.subpaths == NIL)
{
mark_dummy_rel(result_rel);
* Append the child results together using the cheapest paths from each
* union child.
*/
- apath = (Path *) create_append_path(root, result_rel, cheapest_pathlist,
- NIL, NIL, NULL, 0, false, -1);
+ apath = (Path *) create_append_path(root, result_rel, cheapest,
+ NIL, NULL, 0, false, -1);
/*
* Estimate number of groups. For now we just assume the output is unique
int parallel_workers = 0;
/* Find the highest number of workers requested for any subpath. */
- foreach(lc, partial_pathlist)
+ foreach(lc, partial.partial_subpaths)
{
Path *subpath = lfirst(lc);
if (enable_parallel_append)
{
parallel_workers = Max(parallel_workers,
- pg_leftmost_one_pos32(list_length(partial_pathlist)) + 1);
+ pg_leftmost_one_pos32(list_length(partial.partial_subpaths)) + 1);
parallel_workers = Min(parallel_workers,
max_parallel_workers_per_gather);
}
Assert(parallel_workers > 0);
papath = (Path *)
- create_append_path(root, result_rel, NIL, partial_pathlist,
+ create_append_path(root, result_rel, partial,
NIL, NULL, parallel_workers,
enable_parallel_append, -1);
gpath = (Path *)
double dNumGroups;
bool can_sort = grouping_is_sortable(groupList);
bool can_hash = grouping_is_hashable(groupList);
- Path *first_path = linitial(cheapest_pathlist);
+ Path *first_path = linitial(cheapest.subpaths);
/*
* Estimate the number of UNION output rows. In the case when only a
* contain Vars with varno==0, which estimate_num_groups() wouldn't
* like.
*/
- if (list_length(cheapest_pathlist) == 1 &&
+ if (list_length(cheapest.subpaths) == 1 &&
first_path->parent->reloptkind != RELOPT_UPPER_REL)
{
dNumGroups = estimate_num_groups(root,
path = (Path *) create_merge_append_path(root,
result_rel,
- ordered_pathlist,
+ ordered.subpaths,
+ NIL,
union_pathkeys,
NULL);
if (op->all)
{
Path *apath;
+ AppendPathInput append = {0};
+
+ append.subpaths = list_make1(lpath);
/*
* EXCEPT ALL: If the right-hand input is dummy then we can
* between the set op targetlist and the targetlist of the
* left input. The Append will be removed in setrefs.c.
*/
- apath = (Path *) create_append_path(root, result_rel, list_make1(lpath),
- NIL, NIL, NULL, 0, false, -1);
+ apath = (Path *) create_append_path(root, result_rel,
+ append, NIL, NULL, 0,
+ false, -1);
add_path(result_rel, apath);