diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planagg.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 78 | ||||
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 87 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 5 |
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, ¶mIds); 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); |