summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/allpaths.c6
-rw-r--r--src/backend/optimizer/plan/planagg.c3
-rw-r--r--src/backend/optimizer/plan/planner.c78
-rw-r--r--src/backend/optimizer/plan/subselect.c87
-rw-r--r--src/backend/optimizer/prep/prepjointree.c1
-rw-r--r--src/backend/optimizer/prep/prepunion.c5
6 files changed, 145 insertions, 35 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d7ff36d89be..1f82239b4e0 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -2529,6 +2529,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *sub_final_rel;
Bitmapset *run_cond_attrs = NULL;
ListCell *lc;
+ char *plan_name;
/*
* Must copy the Query so that planning doesn't mess up the RTE contents
@@ -2671,8 +2672,9 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
Assert(root->plan_params == NIL);
/* Generate a subroot and Paths for the subquery */
- rel->subroot = subquery_planner(root->glob, subquery, root, false,
- tuple_fraction, NULL);
+ plan_name = choose_plan_name(root->glob, rte->eref->aliasname, false);
+ rel->subroot = subquery_planner(root->glob, subquery, plan_name,
+ root, false, tuple_fraction, NULL);
/* Isolate the params needed by this specific subplan */
rel->subplan_params = root->plan_params;
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index 2ef0bb7f663..a2ac58d246e 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -38,6 +38,7 @@
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
+#include "optimizer/planner.h"
#include "optimizer/subselect.h"
#include "optimizer/tlist.h"
#include "parser/parse_clause.h"
@@ -339,6 +340,8 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo,
memcpy(subroot, root, sizeof(PlannerInfo));
subroot->query_level++;
subroot->parent_root = root;
+ subroot->plan_name = choose_plan_name(root->glob, "minmax", true);
+
/* reset subplan-related stuff */
subroot->plan_params = NIL;
subroot->outer_params = NULL;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 41bd8353430..3b130e724f7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -439,7 +439,8 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
}
/* primary planning entry point (may recurse for subqueries) */
- root = subquery_planner(glob, parse, NULL, false, tuple_fraction, NULL);
+ root = subquery_planner(glob, parse, NULL, NULL, false, tuple_fraction,
+ NULL);
/* Select best Path and turn it into a Plan */
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
@@ -630,6 +631,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
*
* glob is the global state for the current planner run.
* parse is the querytree produced by the parser & rewriter.
+ * plan_name is the name to assign to this subplan (NULL at the top level).
* parent_root is the immediate parent Query's info (NULL at the top level).
* hasRecursion is true if this is a recursive WITH query.
* tuple_fraction is the fraction of tuples we expect will be retrieved.
@@ -656,9 +658,9 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
*--------------------
*/
PlannerInfo *
-subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
- bool hasRecursion, double tuple_fraction,
- SetOperationStmt *setops)
+subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name,
+ PlannerInfo *parent_root, bool hasRecursion,
+ double tuple_fraction, SetOperationStmt *setops)
{
PlannerInfo *root;
List *newWithCheckOptions;
@@ -673,6 +675,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
root->parse = parse;
root->glob = glob;
root->query_level = parent_root ? parent_root->query_level + 1 : 1;
+ root->plan_name = plan_name;
root->parent_root = parent_root;
root->plan_params = NIL;
root->outer_params = NULL;
@@ -8833,3 +8836,70 @@ create_partial_unique_paths(PlannerInfo *root, RelOptInfo *input_rel,
sjinfo, unique_rel);
}
}
+
+/*
+ * Choose a unique name for some subroot.
+ *
+ * Modifies glob->subplanNames to track names already used.
+ */
+char *
+choose_plan_name(PlannerGlobal *glob, const char *name, bool always_number)
+{
+ unsigned n;
+
+ /*
+ * If a numeric suffix is not required, then search the list of
+ * previously-assigned names for a match. If none is found, then we can
+ * use the provided name without modification.
+ */
+ if (!always_number)
+ {
+ bool found = false;
+
+ foreach_ptr(char, subplan_name, glob->subplanNames)
+ {
+ if (strcmp(subplan_name, name) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ /* pstrdup here is just to avoid cast-away-const */
+ char *chosen_name = pstrdup(name);
+
+ glob->subplanNames = lappend(glob->subplanNames, chosen_name);
+ return chosen_name;
+ }
+ }
+
+ /*
+ * If a numeric suffix is required or if the un-suffixed name is already
+ * in use, then loop until we find a positive integer that produces a
+ * novel name.
+ */
+ for (n = 1; true; ++n)
+ {
+ char *proposed_name = psprintf("%s_%u", name, n);
+ bool found = false;
+
+ foreach_ptr(char, subplan_name, glob->subplanNames)
+ {
+ if (strcmp(subplan_name, proposed_name) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ glob->subplanNames = lappend(glob->subplanNames, proposed_name);
+ return proposed_name;
+ }
+
+ pfree(proposed_name);
+ }
+}
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index fae18548e07..14192a13236 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -103,6 +103,7 @@ static Bitmapset *finalize_plan(PlannerInfo *root,
Bitmapset *scan_params);
static bool finalize_primnode(Node *node, finalize_primnode_context *context);
static bool finalize_agg_primnode(Node *node, finalize_primnode_context *context);
+static const char *sublinktype_to_string(SubLinkType subLinkType);
/*
@@ -172,6 +173,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
Plan *plan;
List *plan_params;
Node *result;
+ const char *sublinkstr = sublinktype_to_string(subLinkType);
/*
* Copy the source Query node. This is a quick and dirty kluge to resolve
@@ -218,8 +220,9 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
Assert(root->plan_params == NIL);
/* Generate Paths for the subquery */
- subroot = subquery_planner(root->glob, subquery, root, false,
- tuple_fraction, NULL);
+ subroot = subquery_planner(root->glob, subquery,
+ choose_plan_name(root->glob, sublinkstr, true),
+ root, false, tuple_fraction, NULL);
/* Isolate the params needed by this specific subplan */
plan_params = root->plan_params;
@@ -264,9 +267,12 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
&newtestexpr, &paramIds);
if (subquery)
{
+ char *plan_name;
+
/* Generate Paths for the ANY subquery; we'll need all rows */
- subroot = subquery_planner(root->glob, subquery, root, false, 0.0,
- NULL);
+ plan_name = choose_plan_name(root->glob, sublinkstr, true);
+ subroot = subquery_planner(root->glob, subquery, plan_name,
+ root, false, 0.0, NULL);
/* Isolate the params needed by this specific subplan */
plan_params = root->plan_params;
@@ -324,15 +330,16 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
{
Node *result;
SubPlan *splan;
- bool isInitPlan;
ListCell *lc;
/*
- * Initialize the SubPlan node. Note plan_id, plan_name, and cost fields
- * are set further down.
+ * Initialize the SubPlan node.
+ *
+ * Note: plan_id and cost fields are set further down.
*/
splan = makeNode(SubPlan);
splan->subLinkType = subLinkType;
+ splan->plan_name = subroot->plan_name;
splan->testexpr = NULL;
splan->paramIds = NIL;
get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod,
@@ -391,7 +398,7 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
Assert(testexpr == NULL);
prm = generate_new_exec_param(root, BOOLOID, -1, InvalidOid);
splan->setParam = list_make1_int(prm->paramid);
- isInitPlan = true;
+ splan->isInitPlan = true;
result = (Node *) prm;
}
else if (splan->parParam == NIL && subLinkType == EXPR_SUBLINK)
@@ -406,7 +413,7 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
exprTypmod((Node *) te->expr),
exprCollation((Node *) te->expr));
splan->setParam = list_make1_int(prm->paramid);
- isInitPlan = true;
+ splan->isInitPlan = true;
result = (Node *) prm;
}
else if (splan->parParam == NIL && subLinkType == ARRAY_SUBLINK)
@@ -426,7 +433,7 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
exprTypmod((Node *) te->expr),
exprCollation((Node *) te->expr));
splan->setParam = list_make1_int(prm->paramid);
- isInitPlan = true;
+ splan->isInitPlan = true;
result = (Node *) prm;
}
else if (splan->parParam == NIL && subLinkType == ROWCOMPARE_SUBLINK)
@@ -442,7 +449,7 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
testexpr,
params);
splan->setParam = list_copy(splan->paramIds);
- isInitPlan = true;
+ splan->isInitPlan = true;
/*
* The executable expression is returned to become part of the outer
@@ -476,12 +483,12 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
/* It can be an initplan if there are no parParams. */
if (splan->parParam == NIL)
{
- isInitPlan = true;
+ splan->isInitPlan = true;
result = (Node *) makeNullConst(RECORDOID, -1, InvalidOid);
}
else
{
- isInitPlan = false;
+ splan->isInitPlan = false;
result = (Node *) splan;
}
}
@@ -536,7 +543,7 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
plan = materialize_finished_plan(plan);
result = (Node *) splan;
- isInitPlan = false;
+ splan->isInitPlan = false;
}
/*
@@ -547,7 +554,7 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
root->glob->subroots = lappend(root->glob->subroots, subroot);
splan->plan_id = list_length(root->glob->subplans);
- if (isInitPlan)
+ if (splan->isInitPlan)
root->init_plans = lappend(root->init_plans, splan);
/*
@@ -557,15 +564,10 @@ build_subplan(PlannerInfo *root, Plan *plan, Path *path,
* there's no point since it won't get re-run without parameter changes
* anyway. The input of a hashed subplan doesn't need REWIND either.
*/
- if (splan->parParam == NIL && !isInitPlan && !splan->useHashTable)
+ if (splan->parParam == NIL && !splan->isInitPlan && !splan->useHashTable)
root->glob->rewindPlanIDs = bms_add_member(root->glob->rewindPlanIDs,
splan->plan_id);
- /* Label the subplan for EXPLAIN purposes */
- splan->plan_name = psprintf("%s %d",
- isInitPlan ? "InitPlan" : "SubPlan",
- splan->plan_id);
-
/* Lastly, fill in the cost estimates for use later */
cost_subplan(root, splan, plan);
@@ -965,8 +967,9 @@ SS_process_ctes(PlannerInfo *root)
* Generate Paths for the CTE query. Always plan for full retrieval
* --- we don't have enough info to predict otherwise.
*/
- subroot = subquery_planner(root->glob, subquery, root,
- cte->cterecursive, 0.0, NULL);
+ subroot = subquery_planner(root->glob, subquery,
+ choose_plan_name(root->glob, cte->ctename, false),
+ root, cte->cterecursive, 0.0, NULL);
/*
* Since the current query level doesn't yet contain any RTEs, it
@@ -989,10 +992,11 @@ SS_process_ctes(PlannerInfo *root)
* Make a SubPlan node for it. This is just enough unlike
* build_subplan that we can't share code.
*
- * Note plan_id, plan_name, and cost fields are set further down.
+ * Note: plan_id and cost fields are set further down.
*/
splan = makeNode(SubPlan);
splan->subLinkType = CTE_SUBLINK;
+ splan->plan_name = subroot->plan_name;
splan->testexpr = NULL;
splan->paramIds = NIL;
get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod,
@@ -1039,9 +1043,6 @@ SS_process_ctes(PlannerInfo *root)
root->cte_plan_ids = lappend_int(root->cte_plan_ids, splan->plan_id);
- /* Label the subplan for EXPLAIN purposes */
- splan->plan_name = psprintf("CTE %s", cte->ctename);
-
/* Lastly, fill in the cost estimates for use later */
cost_subplan(root, splan, plan);
}
@@ -3185,7 +3186,8 @@ SS_make_initplan_from_plan(PlannerInfo *root,
node = makeNode(SubPlan);
node->subLinkType = EXPR_SUBLINK;
node->plan_id = list_length(root->glob->subplans);
- node->plan_name = psprintf("InitPlan %d", node->plan_id);
+ node->plan_name = subroot->plan_name;
+ node->isInitPlan = true;
get_first_col_type(plan, &node->firstColType, &node->firstColTypmod,
&node->firstColCollation);
node->parallel_safe = plan->parallel_safe;
@@ -3201,3 +3203,32 @@ SS_make_initplan_from_plan(PlannerInfo *root,
/* Set costs of SubPlan using info from the plan tree */
cost_subplan(subroot, node, plan);
}
+
+/*
+ * Get a string equivalent of a given subLinkType.
+ */
+static const char *
+sublinktype_to_string(SubLinkType subLinkType)
+{
+ switch (subLinkType)
+ {
+ case EXISTS_SUBLINK:
+ return "exists";
+ case ALL_SUBLINK:
+ return "all";
+ case ANY_SUBLINK:
+ return "any";
+ case ROWCOMPARE_SUBLINK:
+ return "rowcompare";
+ case EXPR_SUBLINK:
+ return "expr";
+ case MULTIEXPR_SUBLINK:
+ return "multiexpr";
+ case ARRAY_SUBLINK:
+ return "array";
+ case CTE_SUBLINK:
+ return "cte";
+ }
+ Assert(false);
+ return "???";
+}
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 35e8d3c183b..563be151a4d 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -1356,6 +1356,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
subroot->parse = subquery;
subroot->glob = root->glob;
subroot->query_level = root->query_level;
+ subroot->plan_name = root->plan_name;
subroot->parent_root = root->parent_root;
subroot->plan_params = NIL;
subroot->outer_params = NULL;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index f5197779684..55665824179 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -232,6 +232,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
PlannerInfo *subroot;
List *tlist;
bool trivial_tlist;
+ char *plan_name;
Assert(subquery != NULL);
@@ -246,7 +247,9 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
* parentOp, pass that down to encourage subquery_planner to consider
* suitably-sorted Paths.
*/
- subroot = rel->subroot = subquery_planner(root->glob, subquery, root,
+ plan_name = choose_plan_name(root->glob, "setop", true);
+ subroot = rel->subroot = subquery_planner(root->glob, subquery,
+ plan_name, root,
false, root->tuple_fraction,
parentOp);