*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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 **)
root->right_join_clauses = NIL;
root->full_join_clauses = NIL;
root->join_info_list = NIL;
+ root->placeholder_list = NIL;
root->initial_rels = NIL;
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);
root->cte_plan_ids = NIL;
root->eq_classes = NIL;
root->append_rel_list = NIL;
- root->placeholder_list = NIL;
root->hasRecursion = hasRecursion;
if (hasRecursion)
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)
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 */ );
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
/*
* 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
*/
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
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.
* 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
}
/* 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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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.
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 */
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
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
/*
* 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);
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
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))
{
}
/* 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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
/* 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 */
}
/* 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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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