ExplainState *es);
static void overexplain_bitmapset(const char *qlabel, Bitmapset *bms,
ExplainState *es);
+static void overexplain_bitmapset_list(const char *qlabel, List *bms_list,
+ ExplainState *es);
static void overexplain_intlist(const char *qlabel, List *list,
ExplainState *es);
overexplain_bitmapset("Append RTIs",
((Append *) plan)->apprelids,
es);
+ overexplain_bitmapset_list("Child Append RTIs",
+ ((Append *) plan)->child_append_relid_sets,
+ es);
break;
case T_MergeAppend:
overexplain_bitmapset("Append RTIs",
((MergeAppend *) plan)->apprelids,
es);
+ overexplain_bitmapset_list("Child Append RTIs",
+ ((MergeAppend *) plan)->child_append_relid_sets,
+ es);
break;
case T_Result:
pfree(buf.data);
}
+/*
+ * Emit a text property describing the contents of a list of bitmapsets.
+ * If a bitmapset contains exactly 1 member, we just print an integer;
+ * otherwise, we surround the list of members by parentheses.
+ *
+ * If there are no bitmapsets in the list, we print the word "none".
+ */
+static void
+overexplain_bitmapset_list(const char *qlabel, List *bms_list,
+ ExplainState *es)
+{
+ StringInfoData buf;
+
+ initStringInfo(&buf);
+
+ foreach_node(Bitmapset, bms, bms_list)
+ {
+ if (bms_membership(bms) == BMS_SINGLETON)
+ appendStringInfo(&buf, " %d", bms_singleton_member(bms));
+ else
+ {
+ int x = -1;
+ bool first = true;
+
+ appendStringInfoString(&buf, " (");
+ while ((x = bms_next_member(bms, x)) >= 0)
+ {
+ if (first)
+ first = false;
+ else
+ appendStringInfoChar(&buf, ' ');
+ appendStringInfo(&buf, "%d", x);
+ }
+ appendStringInfoChar(&buf, ')');
+ }
+ }
+
+ if (buf.len == 0)
+ {
+ ExplainPropertyText(qlabel, "none", es);
+ return;
+ }
+
+ Assert(buf.data[0] == ' ');
+ ExplainPropertyText(qlabel, buf.data + 1, es);
+ pfree(buf.data);
+}
+
/*
* Emit a text property describing the contents of a list of integers, OIDs,
* or XIDs -- either a space-separated list of integer members, or the word
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);
{
List *subpaths = NIL;
bool subpaths_valid = true;
+ List *subpath_cars = NIL;
List *startup_subpaths = NIL;
bool startup_subpaths_valid = true;
+ List *startup_subpath_cars = NIL;
List *partial_subpaths = NIL;
+ List *partial_subpath_cars = NIL;
List *pa_partial_subpaths = NIL;
List *pa_nonpartial_subpaths = NIL;
+ List *pa_subpath_cars = NIL;
bool partial_subpaths_valid = true;
bool pa_subpaths_valid;
List *all_child_pathkeys = NIL;
if (childrel->pathlist != NIL &&
childrel->cheapest_total_path->param_info == NULL)
accumulate_append_subpath(childrel->cheapest_total_path,
- &subpaths, NULL);
+ &subpaths, NULL, &subpath_cars);
else
subpaths_valid = false;
Assert(cheapest_path->param_info == NULL);
accumulate_append_subpath(cheapest_path,
&startup_subpaths,
- NULL);
+ NULL,
+ &startup_subpath_cars);
}
else
startup_subpaths_valid = false;
{
cheapest_partial_path = linitial(childrel->partial_pathlist);
accumulate_append_subpath(cheapest_partial_path,
- &partial_subpaths, NULL);
+ &partial_subpaths, NULL,
+ &partial_subpath_cars);
}
else
partial_subpaths_valid = false;
Assert(cheapest_partial_path != NULL);
accumulate_append_subpath(cheapest_partial_path,
&pa_partial_subpaths,
- &pa_nonpartial_subpaths);
+ &pa_nonpartial_subpaths,
+ &pa_subpath_cars);
}
else
{
*/
accumulate_append_subpath(nppath,
&pa_nonpartial_subpaths,
- NULL);
+ NULL,
+ &pa_subpath_cars);
}
}
* 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,
+ add_path(rel, (Path *) create_append_path(root, rel, subpaths,
+ NIL, subpath_cars,
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));
+ NIL, startup_subpath_cars,
+ NIL, NULL, 0, false, -1));
/*
* Consider an append of unordered, unparameterized partial paths. Make
/* Generate a partial append path. */
appendpath = create_append_path(root, rel, NIL, partial_subpaths,
+ partial_subpath_cars,
NIL, NULL, parallel_workers,
enable_parallel_append,
-1);
appendpath = create_append_path(root, rel, pa_nonpartial_subpaths,
pa_partial_subpaths,
+ pa_subpath_cars,
NIL, NULL, parallel_workers, true,
partial_rows);
add_partial_path(rel, (Path *) appendpath);
/* Select the child paths for an Append with this parameterization */
subpaths = NIL;
+ subpath_cars = NIL;
subpaths_valid = true;
foreach(lcr, live_childrels)
{
subpaths_valid = false;
break;
}
- accumulate_append_subpath(subpath, &subpaths, NULL);
+ accumulate_append_subpath(subpath, &subpaths, NULL,
+ &subpath_cars);
}
if (subpaths_valid)
add_path(rel, (Path *)
- create_append_path(root, rel, subpaths, NIL,
+ create_append_path(root, rel, subpaths, NIL, subpath_cars,
NIL, required_outer, 0, false,
-1));
}
continue;
appendpath = create_append_path(root, rel, NIL, list_make1(path),
+ list_make1(rel->relids),
NIL, NULL,
path->parallel_workers, true,
partial_rows);
{
List *pathkeys = (List *) lfirst(lcp);
List *startup_subpaths = NIL;
+ List *startup_subpath_cars = NIL;
List *total_subpaths = NIL;
+ List *total_subpath_cars = NIL;
List *fractional_subpaths = NIL;
+ List *fractional_subpath_cars = NIL;
bool startup_neq_total = false;
bool match_partition_order;
bool match_partition_order_desc;
* 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_subpath_cars);
+ cheapest_total =
+ get_singleton_append_subpath(cheapest_total,
+ &total_subpath_cars);
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_subpath_cars);
+ 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_subpath_cars);
accumulate_append_subpath(cheapest_total,
- &total_subpaths, NULL);
+ &total_subpaths, NULL,
+ &total_subpath_cars);
if (cheapest_fractional)
accumulate_append_subpath(cheapest_fractional,
- &fractional_subpaths, NULL);
+ &fractional_subpaths, NULL,
+ &fractional_subpath_cars);
}
}
rel,
startup_subpaths,
NIL,
+ startup_subpath_cars,
pathkeys,
NULL,
0,
rel,
total_subpaths,
NIL,
+ total_subpath_cars,
pathkeys,
NULL,
0,
rel,
fractional_subpaths,
NIL,
+ fractional_subpath_cars,
pathkeys,
NULL,
0,
add_path(rel, (Path *) create_merge_append_path(root,
rel,
startup_subpaths,
+ startup_subpath_cars,
pathkeys,
NULL));
if (startup_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
total_subpaths,
+ total_subpath_cars,
pathkeys,
NULL));
add_path(rel, (Path *) create_merge_append_path(root,
rel,
fractional_subpaths,
+ fractional_subpath_cars,
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);
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);
return;
}
}
MergeAppendPath *mpath = (MergeAppendPath *) path;
*subpaths = list_concat(*subpaths, mpath->subpaths);
+ *child_append_relid_sets =
+ lappend(*child_append_relid_sets, path->parent->relids);
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 set 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);
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);
return (Path *) linitial(mpath->subpaths);
+ }
}
return path;
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, NIL, NIL, NIL,
NIL, rel->lateral_relids,
0, false, -1));