diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 171724983dc..0a1d1d1559f 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.111 2008/10/21 20:42:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.112 2008/10/22 20:17:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -133,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; ditto placeholder_list; eq_classes may contain data already, too. + * here; eq_classes may contain data already, too. */ root->simple_rel_array_size = list_length(parse->rtable) + 1; root->simple_rel_array = (RelOptInfo **) @@ -145,6 +145,7 @@ query_planner(PlannerInfo *root, List *tlist, root->right_join_clauses = NIL; root->full_join_clauses = NIL; root->join_info_list = NIL; + root->placeholder_list = NIL; root->initial_rels = NIL; /* diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 05de001a877..467ff39a31b 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.245 2008/10/21 20:42:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.246 2008/10/22 20:17:51 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_AUXINFO 5 +#define EXPRKIND_APPINFO 5 static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind); @@ -274,7 +274,6 @@ 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) @@ -380,10 +379,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, root->append_rel_list = (List *) preprocess_expression(root, (Node *) root->append_rel_list, - EXPRKIND_AUXINFO); - root->placeholder_list = (List *) - preprocess_expression(root, (Node *) root->placeholder_list, - EXPRKIND_AUXINFO); + EXPRKIND_APPINFO); /* Also need to preprocess expressions for function and values RTEs */ foreach(l, parse->rtable) @@ -664,11 +660,10 @@ inheritance_planner(PlannerInfo *root) 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); + /* and we haven't created PlaceHolderInfos, either */ + Assert(subroot.placeholder_list == NIL); /* Generate plan */ subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ ); diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 45de5096198..b15a0e5dd40 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -16,7 +16,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.57 2008/10/21 20:42:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.58 2008/10/22 20:17:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -565,7 +565,6 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, subroot->cte_plan_ids = NIL; subroot->eq_classes = NIL; subroot->append_rel_list = NIL; - subroot->placeholder_list = NIL; subroot->hasRecursion = false; subroot->wt_param_id = -1; subroot->non_recursive_plan = NULL; @@ -627,12 +626,11 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, /* * Adjust level-0 varnos in subquery so that we can append its rangetable * to upper query's. We have to fix the subquery's append_rel_list - * and placeholder_list as well. + * as well. */ rtoffset = list_length(parse->rtable); OffsetVarNodes((Node *) subquery, rtoffset, 0); OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0); - OffsetVarNodes((Node *) subroot->placeholder_list, rtoffset, 0); /* * Upper-level vars in subquery are now one level closer to their parent @@ -640,7 +638,6 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, */ IncrementVarSublevelsUp((Node *) subquery, -1, 1); IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1); - IncrementVarSublevelsUp((Node *) subroot->placeholder_list, -1, 1); /* * The subquery's targetlist items are now in the appropriate form to @@ -706,48 +703,42 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks); /* - * We also have to fix the relid sets of any FlattenedSubLink, - * PlaceHolderVar, and PlaceHolderInfo nodes in the parent query. - * (This could perhaps be done by ResolveNew, but it would clutter that - * routine's API unreasonably.) Note in particular that any placeholder - * nodes just created by insert_targetlist_placeholders() wiil be adjusted. + * We also have to fix the relid sets of any FlattenedSubLink and + * PlaceHolderVar nodes in the parent query. (This could perhaps be done + * by ResolveNew, but it would clutter that routine's API unreasonably.) + * Note in particular that any PlaceHolderVar nodes just created by + * insert_targetlist_placeholders() will be adjusted, so having created + * them with the subquery's varno is correct. * * Likewise, relids appearing in AppendRelInfo nodes have to be fixed (but * we took care of their translated_vars lists above). We already checked * that this won't require introducing multiple subrelids into the * single-slot AppendRelInfo structs. */ - if (parse->hasSubLinks || root->placeholder_list || root->append_rel_list) + if (parse->hasSubLinks || root->glob->lastPHId != 0 || + root->append_rel_list) { Relids subrelids; subrelids = get_relids_in_jointree((Node *) subquery->jointree, false); - substitute_multiple_relids((Node *) parse, - varno, subrelids); - substitute_multiple_relids((Node *) root->placeholder_list, - varno, subrelids); - fix_append_rel_relids(root->append_rel_list, - varno, subrelids); + substitute_multiple_relids((Node *) parse, varno, subrelids); + fix_append_rel_relids(root->append_rel_list, varno, subrelids); } /* - * And now add subquery's AppendRelInfos and PlaceHolderInfos to our lists. - * Note that any placeholders pulled up from the subquery will appear - * after any we just created; this preserves the property that placeholders - * can only refer to other placeholders that appear later in the list - * (needed by fix_placeholder_eval_levels). + * And now add subquery's AppendRelInfos to our list. */ root->append_rel_list = list_concat(root->append_rel_list, subroot->append_rel_list); - root->placeholder_list = list_concat(root->placeholder_list, - subroot->placeholder_list); /* * We don't have to do the equivalent bookkeeping for outer-join info, - * because that hasn't been set up yet. + * because that hasn't been set up yet. placeholder_list likewise. */ Assert(root->join_info_list == NIL); Assert(subroot->join_info_list == NIL); + Assert(root->placeholder_list == NIL); + Assert(subroot->placeholder_list == NIL); /* * Miscellaneous housekeeping. @@ -1606,10 +1597,10 @@ reduce_outer_joins_pass2(Node *jtnode, * substitute_multiple_relids - adjust node relid sets after pulling up * a subquery * - * Find any FlattenedSubLink, PlaceHolderVar, or PlaceHolderInfo nodes in the - * given tree that reference the pulled-up relid, and change them to reference - * the replacement relid(s). We do not need to recurse into subqueries, since - * no subquery of the current top query could (yet) contain such a reference. + * Find any FlattenedSubLink or PlaceHolderVar nodes in the given tree that + * reference the pulled-up relid, and change them to reference the replacement + * relid(s). We do not need to recurse into subqueries, since no subquery of + * the current top query could (yet) contain such a reference. * * NOTE: although this has the form of a walker, we cheat and modify the * nodes in-place. This should be OK since the tree was copied by ResolveNew @@ -1662,26 +1653,11 @@ substitute_multiple_relids_walker(Node *node, } /* fall through to examine children */ } - if (IsA(node, PlaceHolderInfo)) - { - PlaceHolderInfo *phinfo = (PlaceHolderInfo *) node; + /* Shouldn't need to handle planner auxiliary nodes here */ + Assert(!IsA(node, SpecialJoinInfo)); + Assert(!IsA(node, AppendRelInfo)); + Assert(!IsA(node, PlaceHolderInfo)); - if (bms_is_member(context->varno, phinfo->ph_eval_at)) - { - phinfo->ph_eval_at = bms_union(phinfo->ph_eval_at, - context->subrelids); - phinfo->ph_eval_at = bms_del_member(phinfo->ph_eval_at, - context->varno); - } - if (bms_is_member(context->varno, phinfo->ph_needed)) - { - phinfo->ph_needed = bms_union(phinfo->ph_needed, - context->subrelids); - phinfo->ph_needed = bms_del_member(phinfo->ph_needed, - context->varno); - } - /* fall through to examine children */ - } return expression_tree_walker(node, substitute_multiple_relids_walker, (void *) context); } diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 0efd150f6bf..dd7f2f28e0a 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.159 2008/10/21 20:42:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.160 2008/10/22 20:17:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1599,26 +1599,10 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context) context->child_relid); return (Node *) phv; } - if (IsA(node, PlaceHolderInfo)) - { - /* Copy the PlaceHolderInfo node with correct mutation of subnodes */ - PlaceHolderInfo *phinfo; - - phinfo = (PlaceHolderInfo *) expression_tree_mutator(node, - adjust_appendrel_attrs_mutator, - (void *) context); - /* now fix PlaceHolderInfo's relid sets */ - phinfo->ph_eval_at = adjust_relid_set(phinfo->ph_eval_at, - context->parent_relid, - context->child_relid); - phinfo->ph_needed = adjust_relid_set(phinfo->ph_needed, - context->parent_relid, - context->child_relid); - return (Node *) phinfo; - } - /* Shouldn't need to handle other planner auxiliary nodes here */ + /* Shouldn't need to handle planner auxiliary nodes here */ Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, AppendRelInfo)); + Assert(!IsA(node, PlaceHolderInfo)); /* * We have to process RestrictInfo nodes specially. diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index aef212b3604..3e2feea1cbf 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/placeholder.c,v 1.1 2008/10/21 20:42:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/placeholder.c,v 1.2 2008/10/22 20:17:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -25,8 +25,7 @@ /* * make_placeholder_expr - * Make a PlaceHolderVar (and corresponding PlaceHolderInfo) - * for the given expression. + * Make a PlaceHolderVar for the given expression. * * phrels is the syntactic location (as a set of baserels) to attribute * to the expression. @@ -35,34 +34,25 @@ PlaceHolderVar * make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels) { PlaceHolderVar *phv = makeNode(PlaceHolderVar); - PlaceHolderInfo *phinfo = makeNode(PlaceHolderInfo); phv->phexpr = expr; phv->phrels = phrels; phv->phid = ++(root->glob->lastPHId); phv->phlevelsup = 0; - phinfo->phid = phv->phid; - phinfo->ph_var = copyObject(phv); - phinfo->ph_eval_at = pull_varnos((Node *) phv); - /* ph_eval_at may change later, see fix_placeholder_eval_levels */ - phinfo->ph_needed = NULL; /* initially it's unused */ - /* for the moment, estimate width using just the datatype info */ - phinfo->ph_width = get_typavgwidth(exprType((Node *) expr), - exprTypmod((Node *) expr)); - - root->placeholder_list = lappend(root->placeholder_list, phinfo); - return phv; } /* * find_placeholder_info - * Fetch the PlaceHolderInfo for the given PHV; error if not found + * Fetch the PlaceHolderInfo for the given PHV; create it if not found + * + * Note: this should only be called after query_planner() has started. */ PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv) { + PlaceHolderInfo *phinfo; ListCell *lc; /* if this ever isn't true, we'd need to be able to look in parent lists */ @@ -70,20 +60,33 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv) foreach(lc, root->placeholder_list) { - PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); - + phinfo = (PlaceHolderInfo *) lfirst(lc); if (phinfo->phid == phv->phid) return phinfo; } - elog(ERROR, "could not find PlaceHolderInfo with id %u", phv->phid); - return NULL; /* keep compiler quiet */ + + /* Not found, so create it */ + phinfo = makeNode(PlaceHolderInfo); + + phinfo->phid = phv->phid; + phinfo->ph_var = copyObject(phv); + phinfo->ph_eval_at = pull_varnos((Node *) phv); + /* ph_eval_at may change later, see fix_placeholder_eval_levels */ + phinfo->ph_needed = NULL; /* initially it's unused */ + /* for the moment, estimate width using just the datatype info */ + phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr), + exprTypmod((Node *) phv->phexpr)); + + root->placeholder_list = lappend(root->placeholder_list, phinfo); + + return phinfo; } /* * fix_placeholder_eval_levels * Adjust the target evaluation levels for placeholders * - * The initial eval_at level set by make_placeholder_expr was the set of + * The initial eval_at level set by find_placeholder_info was the set of * rels used in the placeholder's expression (or the whole subselect if * the expr is variable-free). If the subselect contains any outer joins * that can null any of those rels, we must delay evaluation to above those @@ -103,19 +106,9 @@ fix_placeholder_eval_levels(PlannerInfo *root) PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc1); Relids syn_level = phinfo->ph_var->phrels; Relids eval_at = phinfo->ph_eval_at; - BMS_Membership eval_membership; bool found_some; ListCell *lc2; - /* - * Ignore unreferenced placeholders. Note: if a placeholder is - * referenced only by some other placeholder's expr, we will do - * the right things because the referencing placeholder must appear - * earlier in the list. - */ - if (bms_is_empty(phinfo->ph_needed)) - continue; - /* * Check for delays due to lower outer joins. This is the same logic * as in check_outerjoin_delay in initsplan.c, except that we don't @@ -160,11 +153,13 @@ fix_placeholder_eval_levels(PlannerInfo *root) /* * Now that we know where to evaluate the placeholder, make sure that * any vars or placeholders it uses will be available at that join - * level. (Note that this has to be done within this loop to make - * sure we don't skip over such placeholders when we get to them.) + * level. NOTE: this could cause more PlaceHolderInfos to be added + * to placeholder_list. That is okay because we'll process them + * before falling out of the foreach loop. Also, it could cause + * the ph_needed sets of existing list entries to expand, which + * is also okay because this loop doesn't examine those. */ - eval_membership = bms_membership(eval_at); - if (eval_membership == BMS_MULTIPLE) + if (bms_membership(eval_at) == BMS_MULTIPLE) { List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr, true); @@ -172,14 +167,22 @@ fix_placeholder_eval_levels(PlannerInfo *root) add_vars_to_targetlist(root, vars, eval_at); list_free(vars); } + } - /* - * Also, if the placeholder can be computed at a base rel and is - * needed above it, add it to that rel's targetlist. (This is - * essentially the same logic as in add_placeholders_to_joinrel, but - * we can't do that part until joinrels are formed.) - */ - if (eval_membership == BMS_SINGLETON) + /* + * Now, if any placeholder can be computed at a base rel and is needed + * above it, add it to that rel's targetlist. (This is essentially the + * same logic as in add_placeholders_to_joinrel, but we can't do that part + * until joinrels are formed.) We have to do this as a separate step + * because the ph_needed values aren't stable until the previous loop + * finishes. + */ + foreach(lc1, root->placeholder_list) + { + PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc1); + Relids eval_at = phinfo->ph_eval_at; + + if (bms_membership(eval_at) == BMS_SINGLETON) { int varno = bms_singleton_member(eval_at); RelOptInfo *rel = find_base_rel(root, varno); diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 31749e46c05..235e465d18f 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.81 2008/10/21 20:42:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.82 2008/10/22 20:17:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -800,24 +800,6 @@ flatten_join_alias_vars_mutator(Node *node, } return (Node *) phv; } - if (IsA(node, PlaceHolderInfo)) - { - /* Copy the PlaceHolderInfo node with correct mutation of subnodes */ - PlaceHolderInfo *phinfo; - - phinfo = (PlaceHolderInfo *) expression_tree_mutator(node, - flatten_join_alias_vars_mutator, - (void *) context); - /* now fix PlaceHolderInfo's relid sets */ - if (context->sublevels_up == 0) - { - phinfo->ph_eval_at = alias_relid_set(context->root, - phinfo->ph_eval_at); - phinfo->ph_needed = alias_relid_set(context->root, - phinfo->ph_needed); - } - return (Node *) phinfo; - } if (IsA(node, Query)) { @@ -834,6 +816,9 @@ flatten_join_alias_vars_mutator(Node *node, } /* Already-planned tree not supported */ Assert(!IsA(node, SubPlan)); + /* Shouldn't need to handle these planner auxiliary nodes here */ + Assert(!IsA(node, SpecialJoinInfo)); + Assert(!IsA(node, PlaceHolderInfo)); return expression_tree_mutator(node, flatten_join_alias_vars_mutator, (void *) context); diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 8ab486bfc2d..0322c58f3f0 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.116 2008/10/21 20:42:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.117 2008/10/22 20:17:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -298,19 +298,10 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context) } /* fall through to examine children */ } - if (IsA(node, PlaceHolderInfo)) - { - PlaceHolderInfo *phinfo = (PlaceHolderInfo *) node; + /* Shouldn't need to handle other planner auxiliary nodes here */ + Assert(!IsA(node, SpecialJoinInfo)); + Assert(!IsA(node, PlaceHolderInfo)); - if (context->sublevels_up == 0) - { - phinfo->ph_eval_at = offset_relid_set(phinfo->ph_eval_at, - context->offset); - phinfo->ph_needed = offset_relid_set(phinfo->ph_needed, - context->offset); - } - /* fall through to examine children */ - } if (IsA(node, Query)) { /* Recurse into subselects */ @@ -489,21 +480,10 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context) } /* fall through to examine children */ } - if (IsA(node, PlaceHolderInfo)) - { - PlaceHolderInfo *phinfo = (PlaceHolderInfo *) node; + /* Shouldn't need to handle other planner auxiliary nodes here */ + Assert(!IsA(node, SpecialJoinInfo)); + Assert(!IsA(node, PlaceHolderInfo)); - if (context->sublevels_up == 0) - { - phinfo->ph_eval_at = adjust_relid_set(phinfo->ph_eval_at, - context->rt_index, - context->new_index); - phinfo->ph_needed = adjust_relid_set(phinfo->ph_needed, - context->rt_index, - context->new_index); - } - /* fall through to examine children */ - } if (IsA(node, Query)) { /* Recurse into subselects */ diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index b5eb00a7a67..4ce13f808a2 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.162 2008/10/21 20:42:53 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.163 2008/10/22 20:17:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1290,6 +1290,9 @@ typedef struct AppendRelInfo * The idea is to evaluate the expression at (only) the ph_eval_at join level, * then allow it to bubble up like a Var until the ph_needed join level. * ph_needed has the same definition as attr_needed for a regular Var. + * + * We create a PlaceHolderInfo only after determining that the PlaceHolderVar + * is actually referenced in the plan tree. */ typedef struct PlaceHolderInfo