diff options
Diffstat (limited to 'src/backend/optimizer/plan')
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 34 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 49 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planmain.c | 18 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 18 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 82 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/subselect.c | 9 |
6 files changed, 166 insertions, 44 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index f812c93979..7bddf33e5c 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.250 2008/10/07 19:27:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.251 2008/10/21 20:42:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,7 +37,7 @@ static Plan *create_scan_plan(PlannerInfo *root, Path *best_path); static List *build_relation_tlist(RelOptInfo *rel); -static bool use_physical_tlist(RelOptInfo *rel); +static bool use_physical_tlist(PlannerInfo *root, RelOptInfo *rel); static void disuse_physical_tlist(Plan *plan, Path *path); static Plan *create_gating_plan(PlannerInfo *root, Plan *plan, List *quals); static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path); @@ -212,7 +212,7 @@ create_scan_plan(PlannerInfo *root, Path *best_path) * planner.c may replace the tlist we generate here, forcing projection to * occur.) */ - if (use_physical_tlist(rel)) + if (use_physical_tlist(root, rel)) { tlist = build_physical_tlist(root, rel); /* if fail because of dropped cols, use regular method */ @@ -325,9 +325,9 @@ build_relation_tlist(RelOptInfo *rel) foreach(v, rel->reltargetlist) { /* Do we really need to copy here? Not sure */ - Var *var = (Var *) copyObject(lfirst(v)); + Node *node = (Node *) copyObject(lfirst(v)); - tlist = lappend(tlist, makeTargetEntry((Expr *) var, + tlist = lappend(tlist, makeTargetEntry((Expr *) node, resno, NULL, false)); @@ -342,9 +342,10 @@ build_relation_tlist(RelOptInfo *rel) * rather than only those Vars actually referenced. */ static bool -use_physical_tlist(RelOptInfo *rel) +use_physical_tlist(PlannerInfo *root, RelOptInfo *rel) { int i; + ListCell *lc; /* * We can do this for real relation scans, subquery scans, function scans, @@ -365,9 +366,9 @@ use_physical_tlist(RelOptInfo *rel) return false; /* - * Can't do it if any system columns or whole-row Vars are requested, - * either. (This could possibly be fixed but would take some fragile - * assumptions in setrefs.c, I think.) + * Can't do it if any system columns or whole-row Vars are requested. + * (This could possibly be fixed but would take some fragile assumptions + * in setrefs.c, I think.) */ for (i = rel->min_attr; i <= 0; i++) { @@ -375,6 +376,19 @@ use_physical_tlist(RelOptInfo *rel) return false; } + /* + * Can't do it if the rel is required to emit any placeholder expressions, + * either. + */ + foreach(lc, root->placeholder_list) + { + PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); + + if (bms_nonempty_difference(phinfo->ph_needed, rel->relids) && + bms_is_subset(phinfo->ph_eval_at, rel->relids)) + return false; + } + return true; } @@ -2925,7 +2939,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, if (em->em_is_const || em->em_is_child) continue; sortexpr = em->em_expr; - exprvars = pull_var_clause((Node *) sortexpr, false); + exprvars = pull_var_clause((Node *) sortexpr, true); foreach(k, exprvars) { if (!tlist_member_ignore_relabel(lfirst(k), tlist)) diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 49c2cdf2f5..1208262b8e 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.142 2008/08/17 01:19:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.143 2008/10/21 20:42:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "optimizer/joininfo.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" +#include "optimizer/placeholder.h" #include "optimizer/planmain.h" #include "optimizer/prep.h" #include "optimizer/restrictinfo.h" @@ -131,7 +132,7 @@ add_base_rels_to_query(PlannerInfo *root, Node *jtnode) void build_base_rel_tlists(PlannerInfo *root, List *final_tlist) { - List *tlist_vars = pull_var_clause((Node *) final_tlist, false); + List *tlist_vars = pull_var_clause((Node *) final_tlist, true); if (tlist_vars != NIL) { @@ -146,6 +147,10 @@ build_base_rel_tlists(PlannerInfo *root, List *final_tlist) * relation's targetlist if not already present, and mark the variable * as being needed for the indicated join (or for final output if * where_needed includes "relation 0"). + * + * The list may also contain PlaceHolderVars. These don't necessarily + * have a single owning relation; we keep their attr_needed info in + * root->placeholder_list instead. */ void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed) @@ -156,20 +161,36 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed) foreach(temp, vars) { - Var *var = (Var *) lfirst(temp); - RelOptInfo *rel = find_base_rel(root, var->varno); - int attrno = var->varattno; + Node *node = (Node *) lfirst(temp); + + if (IsA(node, Var)) + { + Var *var = (Var *) node; + RelOptInfo *rel = find_base_rel(root, var->varno); + int attno = var->varattno; - Assert(attrno >= rel->min_attr && attrno <= rel->max_attr); - attrno -= rel->min_attr; - if (bms_is_empty(rel->attr_needed[attrno])) + Assert(attno >= rel->min_attr && attno <= rel->max_attr); + attno -= rel->min_attr; + if (rel->attr_needed[attno] == NULL) + { + /* Variable not yet requested, so add to reltargetlist */ + /* XXX is copyObject necessary here? */ + rel->reltargetlist = lappend(rel->reltargetlist, + copyObject(var)); + } + rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno], + where_needed); + } + else if (IsA(node, PlaceHolderVar)) { - /* Variable not yet requested, so add to reltargetlist */ - /* XXX is copyObject necessary here? */ - rel->reltargetlist = lappend(rel->reltargetlist, copyObject(var)); + PlaceHolderVar *phv = (PlaceHolderVar *) node; + PlaceHolderInfo *phinfo = find_placeholder_info(root, phv); + + phinfo->ph_needed = bms_add_members(phinfo->ph_needed, + where_needed); } - rel->attr_needed[attrno] = bms_add_members(rel->attr_needed[attrno], - where_needed); + else + elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); } } @@ -934,7 +955,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, */ if (bms_membership(relids) == BMS_MULTIPLE) { - List *vars = pull_var_clause(clause, false); + List *vars = pull_var_clause(clause, true); add_vars_to_targetlist(root, vars, relids); list_free(vars); diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 7dcdaf250f..171724983d 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.110 2008/08/14 18:47:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.111 2008/10/21 20:42:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,6 +23,7 @@ #include "optimizer/cost.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" +#include "optimizer/placeholder.h" #include "optimizer/planmain.h" #include "optimizer/tlist.h" #include "utils/selfuncs.h" @@ -132,7 +133,7 @@ query_planner(PlannerInfo *root, List *tlist, * for "simple" rels. * * NOTE: append_rel_list was set up by subquery_planner, so do not touch - * here; eq_classes may contain data already, too. + * here; ditto placeholder_list; eq_classes may contain data already, too. */ root->simple_rel_array_size = list_length(parse->rtable) + 1; root->simple_rel_array = (RelOptInfo **) @@ -204,12 +205,6 @@ query_planner(PlannerInfo *root, List *tlist, * added to appropriate lists belonging to the mentioned relations. We * also build EquivalenceClasses for provably equivalent expressions, and * form a target joinlist for make_one_rel() to work from. - * - * Note: all subplan nodes will have "flat" (var-only) tlists. This - * implies that all expression evaluations are done at the root of the - * plan tree. Once upon a time there was code to try to push expensive - * function calls down to lower plan nodes, but that's dead code and has - * been for a long time... */ build_base_rel_tlists(root, tlist); @@ -241,6 +236,13 @@ query_planner(PlannerInfo *root, List *tlist, root->sort_pathkeys = canonicalize_pathkeys(root, root->sort_pathkeys); /* + * Examine any "placeholder" expressions generated during subquery pullup. + * Make sure that we know what level to evaluate them at, and that the + * Vars they need are marked as needed. + */ + fix_placeholder_eval_levels(root); + + /* * Ready to do the primary planning. */ final_rel = make_one_rel(root, joinlist); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 0a704dc654..05de001a87 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.244 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.245 2008/10/21 20:42:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -55,7 +55,7 @@ planner_hook_type planner_hook = NULL; #define EXPRKIND_RTFUNC 2 #define EXPRKIND_VALUES 3 #define EXPRKIND_LIMIT 4 -#define EXPRKIND_APPINFO 5 +#define EXPRKIND_AUXINFO 5 static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind); @@ -141,6 +141,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->finalrtable = NIL; glob->relationOids = NIL; glob->invalItems = NIL; + glob->lastPHId = 0; glob->transientPlan = false; /* Determine what fraction of the plan is likely to be scanned */ @@ -273,6 +274,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, root->cte_plan_ids = NIL; root->eq_classes = NIL; root->append_rel_list = NIL; + root->placeholder_list = NIL; root->hasRecursion = hasRecursion; if (hasRecursion) @@ -378,7 +380,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse, root->append_rel_list = (List *) preprocess_expression(root, (Node *) root->append_rel_list, - EXPRKIND_APPINFO); + EXPRKIND_AUXINFO); + root->placeholder_list = (List *) + preprocess_expression(root, (Node *) root->placeholder_list, + EXPRKIND_AUXINFO); /* Also need to preprocess expressions for function and values RTEs */ foreach(l, parse->rtable) @@ -656,7 +661,12 @@ inheritance_planner(PlannerInfo *root) subroot.parse = (Query *) adjust_appendrel_attrs((Node *) parse, appinfo); + subroot.returningLists = NIL; subroot.init_plans = NIL; + /* We needn't modify the child's append_rel_list */ + subroot.placeholder_list = (List *) + adjust_appendrel_attrs((Node *) root->placeholder_list, + appinfo); /* There shouldn't be any OJ info to translate, as yet */ Assert(subroot.join_info_list == NIL); @@ -2046,7 +2056,7 @@ make_subplanTargetList(PlannerInfo *root, * Vars; they will be replaced by Params later on). */ sub_tlist = flatten_tlist(tlist); - extravars = pull_var_clause(parse->havingQual, false); + extravars = pull_var_clause(parse->havingQual, true); sub_tlist = add_to_flat_tlist(sub_tlist, extravars); list_free(extravars); *need_tlist_eval = false; /* only eval if not flat tlist */ diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 6d7ec283b3..9bec109f6f 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.145 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.146 2008/10/21 20:42:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -38,7 +38,8 @@ typedef struct { List *tlist; /* underlying target list */ int num_vars; /* number of plain Var tlist entries */ - bool has_non_vars; /* are there non-plain-Var entries? */ + bool has_ph_vars; /* are there PlaceHolderVar entries? */ + bool has_non_vars; /* are there other entries? */ /* array of num_vars entries: */ tlist_vinfo vars[1]; /* VARIABLE LENGTH ARRAY */ } indexed_tlist; /* VARIABLE LENGTH STRUCT */ @@ -741,15 +742,16 @@ fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset) context.glob = glob; context.rtoffset = rtoffset; - if (rtoffset != 0) + if (rtoffset != 0 || glob->lastPHId != 0) { return fix_scan_expr_mutator(node, &context); } else { /* - * If rtoffset == 0, we don't need to change any Vars, which makes - * it OK to just scribble on the input node tree instead of copying + * If rtoffset == 0, we don't need to change any Vars, and if there + * are no placeholders anywhere we won't need to remove them. Then + * it's OK to just scribble on the input node tree instead of copying * (since the only change, filling in any unset opfuncid fields, * is harmless). This saves just enough cycles to be noticeable on * trivial queries. @@ -790,6 +792,13 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context) cexpr->cvarno += context->rtoffset; return (Node *) cexpr; } + if (IsA(node, PlaceHolderVar)) + { + /* At scan level, we should always just evaluate the contained expr */ + PlaceHolderVar *phv = (PlaceHolderVar *) node; + + return fix_scan_expr_mutator((Node *) phv->phexpr, context); + } fix_expr_common(context->glob, node); return expression_tree_mutator(node, fix_scan_expr_mutator, (void *) context); @@ -800,6 +809,7 @@ fix_scan_expr_walker(Node *node, fix_scan_expr_context *context) { if (node == NULL) return false; + Assert(!IsA(node, PlaceHolderVar)); fix_expr_common(context->glob, node); return expression_tree_walker(node, fix_scan_expr_walker, (void *) context); @@ -1199,6 +1209,7 @@ build_tlist_index(List *tlist) list_length(tlist) * sizeof(tlist_vinfo)); itlist->tlist = tlist; + itlist->has_ph_vars = false; itlist->has_non_vars = false; /* Find the Vars and fill in the index array */ @@ -1216,6 +1227,8 @@ build_tlist_index(List *tlist) vinfo->resno = tle->resno; vinfo++; } + else if (tle->expr && IsA(tle->expr, PlaceHolderVar)) + itlist->has_ph_vars = true; else itlist->has_non_vars = true; } @@ -1229,7 +1242,9 @@ build_tlist_index(List *tlist) * build_tlist_index_other_vars --- build a restricted tlist index * * This is like build_tlist_index, but we only index tlist entries that - * are Vars and belong to some rel other than the one specified. + * are Vars belonging to some rel other than the one specified. We will set + * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars + * (so nothing other than Vars and PlaceHolderVars can be matched). */ static indexed_tlist * build_tlist_index_other_vars(List *tlist, Index ignore_rel) @@ -1244,6 +1259,7 @@ build_tlist_index_other_vars(List *tlist, Index ignore_rel) list_length(tlist) * sizeof(tlist_vinfo)); itlist->tlist = tlist; + itlist->has_ph_vars = false; itlist->has_non_vars = false; /* Find the desired Vars and fill in the index array */ @@ -1264,6 +1280,8 @@ build_tlist_index_other_vars(List *tlist, Index ignore_rel) vinfo++; } } + else if (tle->expr && IsA(tle->expr, PlaceHolderVar)) + itlist->has_ph_vars = true; } itlist->num_vars = (vinfo - itlist->vars); @@ -1314,7 +1332,8 @@ search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, * If a match is found, return a Var constructed to reference the tlist item. * If no match, return NULL. * - * NOTE: it is a waste of time to call this if !itlist->has_non_vars + * NOTE: it is a waste of time to call this unless itlist->has_ph_vars or + * itlist->has_non_vars */ static Var * search_indexed_tlist_for_non_var(Node *node, @@ -1429,6 +1448,31 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) /* No referent found for Var */ elog(ERROR, "variable not found in subplan target lists"); } + if (IsA(node, PlaceHolderVar)) + { + PlaceHolderVar *phv = (PlaceHolderVar *) node; + + /* See if the PlaceHolderVar has bubbled up from a lower plan node */ + if (context->outer_itlist->has_ph_vars) + { + newvar = search_indexed_tlist_for_non_var((Node *) phv, + context->outer_itlist, + OUTER); + if (newvar) + return (Node *) newvar; + } + if (context->inner_itlist && context->inner_itlist->has_ph_vars) + { + newvar = search_indexed_tlist_for_non_var((Node *) phv, + context->inner_itlist, + INNER); + if (newvar) + return (Node *) newvar; + } + + /* If not supplied by input plans, evaluate the contained expr */ + return fix_join_expr_mutator((Node *) phv->phexpr, context); + } /* Try matching more complex expressions too, if tlists have any */ if (context->outer_itlist->has_non_vars) { @@ -1512,6 +1556,22 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) elog(ERROR, "variable not found in subplan target list"); return (Node *) newvar; } + if (IsA(node, PlaceHolderVar)) + { + PlaceHolderVar *phv = (PlaceHolderVar *) node; + + /* See if the PlaceHolderVar has bubbled up from a lower plan node */ + if (context->subplan_itlist->has_ph_vars) + { + newvar = search_indexed_tlist_for_non_var((Node *) phv, + context->subplan_itlist, + OUTER); + if (newvar) + return (Node *) newvar; + } + /* If not supplied by input plan, evaluate the contained expr */ + return fix_upper_expr_mutator((Node *) phv->phexpr, context); + } /* Try matching more complex expressions too, if tlist has any */ if (context->subplan_itlist->has_non_vars) { @@ -1564,6 +1624,13 @@ set_returning_clause_references(PlannerGlobal *glob, * top plan's targetlist for Vars of non-result relations, and use * fix_join_expr to convert RETURNING Vars into references to those tlist * entries, while leaving result-rel Vars as-is. + * + * PlaceHolderVars will also be sought in the targetlist, but no + * more-complex expressions will be. Note that it is not possible for + * a PlaceHolderVar to refer to the result relation, since the result + * is never below an outer join. If that case could happen, we'd have + * to be prepared to pick apart the PlaceHolderVar and evaluate its + * contained expression instead. */ itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation); @@ -1721,6 +1788,7 @@ extract_query_dependencies_walker(Node *node, PlannerGlobal *context) { if (node == NULL) return false; + Assert(!IsA(node, PlaceHolderVar)); /* Extract function dependencies and check for regclass Consts */ fix_expr_common(context, node); if (IsA(node, Query)) diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 00d84d5682..b80427f041 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.141 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.142 2008/10/21 20:42:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1040,6 +1040,10 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink, /* * And finally, build the FlattenedSubLink node. + * + * Note: at this point left_varnos may well contain join relids, since + * the testexpr hasn't been run through flatten_join_alias_vars. This + * will get fixed when flatten_join_alias_vars is run. */ fslink = makeNode(FlattenedSubLink); fslink->jointype = JOIN_SEMI; @@ -1189,6 +1193,9 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink, /* * And finally, build the FlattenedSubLink node. + * + * Note: at this point left_varnos and subselect_varnos may well contain + * join relids. This will get fixed when flatten_join_alias_vars is run. */ fslink = makeNode(FlattenedSubLink); fslink->jointype = under_not ? JOIN_ANTI : JOIN_SEMI; |
