1 /*-------------------------------------------------------------------------
4 * Post-processing of a completed plan tree: fix references to subplan
5 * vars, and compute regproc values for operators
7 * Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.58 1999/10/30 23:07:55 tgl Exp $
13 *-------------------------------------------------------------------------
15 #include <sys/types.h>
19 #include "nodes/makefuncs.h"
20 #include "nodes/nodeFuncs.h"
21 #include "optimizer/clauses.h"
22 #include "optimizer/planmain.h"
23 #include "optimizer/tlist.h"
24 #include "optimizer/var.h"
30 } join_references_context;
34 List *subplanTargetList;
35 } replace_vars_with_subplan_refs_context;
37 static void set_join_references(Join *join);
38 static void set_uppernode_references(Plan *plan, Index subvarno);
39 static Node *join_references_mutator(Node *node,
40 join_references_context *context);
41 static Node *replace_vars_with_subplan_refs(Node *node,
43 List *subplanTargetList);
44 static Node *replace_vars_with_subplan_refs_mutator(Node *node,
45 replace_vars_with_subplan_refs_context *context);
46 static bool fix_opids_walker(Node *node, void *context);
48 /*****************************************************************************
52 *****************************************************************************/
56 * This is the final processing pass of the planner/optimizer. The plan
57 * tree is complete; we just have to adjust some representational details
58 * for the convenience of the executor. We update Vars in upper plan nodes
59 * to refer to the outputs of their subplans, and we compute regproc OIDs
60 * for operators (ie, we look up the function that implements each op).
62 * set_plan_references recursively traverses the whole plan tree.
64 * Returns nothing of interest, but modifies internal fields of nodes.
67 set_plan_references(Plan *plan)
75 * Plan-type-specific fixes
77 switch (nodeTag(plan))
83 fix_opids((Node *) ((IndexScan *) plan)->indxqual);
84 fix_opids((Node *) ((IndexScan *) plan)->indxqualorig);
87 set_join_references((Join *) plan);
90 set_join_references((Join *) plan);
91 fix_opids((Node *) ((MergeJoin *) plan)->mergeclauses);
94 set_join_references((Join *) plan);
95 fix_opids((Node *) ((HashJoin *) plan)->hashclauses);
101 /* These plan types don't actually bother to evaluate their
102 * targetlists or quals (because they just return their
103 * unmodified input tuples). The optimizer is lazy about
104 * creating really valid targetlists for them. Best to
105 * just leave the targetlist alone.
110 set_uppernode_references(plan, (Index) 0);
113 /* Result may or may not have a subplan; no need to fix up
114 * subplan references if it hasn't got one...
116 * XXX why does Result use a different subvarno from Agg/Group?
118 if (plan->lefttree != NULL)
119 set_uppernode_references(plan, (Index) OUTER);
120 fix_opids(((Result *) plan)->resconstantqual);
123 foreach(pl, ((Append *) plan)->appendplans)
125 set_plan_references((Plan *) lfirst(pl));
129 elog(ERROR, "set_plan_references: unknown plan type %d",
135 * For all plan types, fix operators in targetlist and qual expressions
137 fix_opids((Node *) plan->targetlist);
138 fix_opids((Node *) plan->qual);
141 * Now recurse into subplans, if any
143 * NOTE: it is essential that we recurse into subplans AFTER we set
144 * subplan references in this plan's tlist and quals. If we did the
145 * reference-adjustments bottom-up, then we would fail to match this
146 * plan's var nodes against the already-modified nodes of the subplans.
148 set_plan_references(plan->lefttree);
149 set_plan_references(plan->righttree);
150 foreach(pl, plan->initPlan)
152 SubPlan *sp = (SubPlan *) lfirst(pl);
154 Assert(IsA(sp, SubPlan));
155 set_plan_references(sp->plan);
157 foreach(pl, plan->subPlan)
159 SubPlan *sp = (SubPlan *) lfirst(pl);
161 Assert(IsA(sp, SubPlan));
162 set_plan_references(sp->plan);
167 * set_join_references
168 * Modifies the target list of a join node to reference its subplans,
169 * by setting the varnos to OUTER or INNER and setting attno values to the
170 * result domain number of either the corresponding outer or inner join
173 * Note: this same transformation has already been applied to the quals
174 * of the join by createplan.c. It's a little odd to do it here for the
175 * targetlist and there for the quals, but it's easier that way. (Look
176 * at switch_outer() and the handling of nestloop inner indexscans to
179 * Because the quals are reference-adjusted sooner, we cannot do equal()
180 * comparisons between qual and tlist var nodes during the time between
181 * creation of a plan node by createplan.c and its fixing by this module.
182 * Fortunately, there doesn't seem to be any need to do that.
184 * 'join' is a join plan node
187 set_join_references(Join *join)
189 Plan *outer = join->lefttree;
190 Plan *inner = join->righttree;
191 List *outer_tlist = ((outer == NULL) ? NIL : outer->targetlist);
192 List *inner_tlist = ((inner == NULL) ? NIL : inner->targetlist);
194 join->targetlist = join_references(join->targetlist,
201 * set_uppernode_references
202 * Update the targetlist and quals of an upper-level plan node
203 * to refer to the tuples returned by its lefttree subplan.
205 * This is used for single-input plan types like Agg, Group, Result.
208 set_uppernode_references(Plan *plan, Index subvarno)
210 Plan *subplan = plan->lefttree;
211 List *subplanTargetList;
214 subplanTargetList = subplan->targetlist;
216 subplanTargetList = NIL;
218 plan->targetlist = (List *)
219 replace_vars_with_subplan_refs((Node *) plan->targetlist,
223 plan->qual = (List *)
224 replace_vars_with_subplan_refs((Node *) plan->qual,
231 * Creates a new set of targetlist entries or join qual clauses by
232 * changing the varno/varattno values of variables in the clauses
233 * to reference target list values from the outer and inner join
234 * relation target lists.
236 * This is used in two different scenarios: a normal join clause, where
237 * all the Vars in the clause *must* be replaced by OUTER or INNER references;
238 * and an indexscan being used on the inner side of a nestloop join.
239 * In the latter case we want to replace the outer-relation Vars by OUTER
240 * references, but not touch the Vars of the inner relation.
242 * For a normal join, acceptable_rel should be zero so that any failure to
243 * match a Var will be reported as an error. For the indexscan case,
244 * pass inner_tlist = NIL and acceptable_rel = the ID of the inner relation.
246 * 'clauses' is the targetlist or list of join clauses
247 * 'outer_tlist' is the target list of the outer join relation
248 * 'inner_tlist' is the target list of the inner join relation, or NIL
249 * 'acceptable_rel' is either zero or the rangetable index of a relation
250 * whose Vars may appear in the clause without provoking an error.
252 * Returns the new expression tree. The original clause structure is
256 join_references(List *clauses,
259 Index acceptable_rel)
261 join_references_context context;
263 context.outer_tlist = outer_tlist;
264 context.inner_tlist = inner_tlist;
265 context.acceptable_rel = acceptable_rel;
266 return (List *) join_references_mutator((Node *) clauses, &context);
270 join_references_mutator(Node *node,
271 join_references_context *context)
277 Var *var = (Var *) node;
278 Var *newvar = (Var *) copyObject(var);
281 resdom = tlist_member((Node *) var, context->outer_tlist);
284 newvar->varno = OUTER;
285 newvar->varattno = resdom->resno;
286 return (Node *) newvar;
288 resdom = tlist_member((Node *) var, context->inner_tlist);
291 newvar->varno = INNER;
292 newvar->varattno = resdom->resno;
293 return (Node *) newvar;
296 * Var not in either tlist --- either raise an error,
297 * or return the Var unmodified.
299 if (var->varno != context->acceptable_rel)
300 elog(ERROR, "join_references: variable not in subplan target lists");
301 return (Node *) newvar; /* copy is probably not necessary here... */
304 * expression_tree_mutator will copy SubPlan nodes if given a chance.
305 * We do not want to do that here, because subselect.c has already
306 * constructed the initPlan and subPlan lists of the current plan node
307 * and we mustn't leave those dangling (ie, pointing to different
308 * copies of the nodes than what's in the targetlist & quals...)
309 * Instead, alter the SubPlan in-place. Grotty --- is there a better way?
311 if (is_subplan(node))
313 Expr *expr = (Expr *) node;
314 SubLink *sublink = ((SubPlan *) expr->oper)->sublink;
316 /* transform args list (params to be passed to subplan) */
317 expr->args = (List *)
318 join_references_mutator((Node *) expr->args,
320 /* transform sublink's oper list as well */
321 sublink->oper = (List *)
322 join_references_mutator((Node *) sublink->oper,
325 return (Node *) expr;
327 return expression_tree_mutator(node,
328 join_references_mutator,
333 * replace_vars_with_subplan_refs
334 * This routine modifies an expression tree so that all Var nodes
335 * reference target nodes of a subplan. It is used to fix up
336 * target and qual expressions of non-join upper-level plan nodes.
338 * An error is raised if no matching var can be found in the subplan tlist
339 * --- so this routine should only be applied to nodes whose subplans'
340 * targetlists were generated via flatten_tlist() or some such method.
342 * 'node': the tree to be fixed (a targetlist or qual list)
343 * 'subvarno': varno to be assigned to all Vars
344 * 'subplanTargetList': target list for subplan
346 * The resulting tree is a copy of the original in which all Var nodes have
347 * varno = subvarno, varattno = resno of corresponding subplan target.
348 * The original tree is not modified.
351 replace_vars_with_subplan_refs(Node *node,
353 List *subplanTargetList)
355 replace_vars_with_subplan_refs_context context;
357 context.subvarno = subvarno;
358 context.subplanTargetList = subplanTargetList;
359 return replace_vars_with_subplan_refs_mutator(node, &context);
363 replace_vars_with_subplan_refs_mutator(Node *node,
364 replace_vars_with_subplan_refs_context *context)
370 Var *var = (Var *) node;
371 Var *newvar = (Var *) copyObject(var);
374 resdom = tlist_member((Node *) var, context->subplanTargetList);
376 elog(ERROR, "replace_vars_with_subplan_refs: variable not in subplan target list");
378 newvar->varno = context->subvarno;
379 newvar->varattno = resdom->resno;
380 return (Node *) newvar;
383 * expression_tree_mutator will copy SubPlan nodes if given a chance.
384 * We do not want to do that here, because subselect.c has already
385 * constructed the initPlan and subPlan lists of the current plan node
386 * and we mustn't leave those dangling (ie, pointing to different
387 * copies of the nodes than what's in the targetlist & quals...)
388 * Instead, alter the SubPlan in-place. Grotty --- is there a better way?
390 if (is_subplan(node))
392 Expr *expr = (Expr *) node;
393 SubLink *sublink = ((SubPlan *) expr->oper)->sublink;
395 /* transform args list (params to be passed to subplan) */
396 expr->args = (List *)
397 replace_vars_with_subplan_refs_mutator((Node *) expr->args,
399 /* transform sublink's oper list as well */
400 sublink->oper = (List *)
401 replace_vars_with_subplan_refs_mutator((Node *) sublink->oper,
404 return (Node *) expr;
406 return expression_tree_mutator(node,
407 replace_vars_with_subplan_refs_mutator,
411 /*****************************************************************************
412 * OPERATOR REGPROC LOOKUP
413 *****************************************************************************/
417 * Calculate opid field from opno for each Oper node in given tree.
418 * The given tree can be anything expression_tree_walker handles.
420 * The argument is modified in-place. (This is OK since we'd want the
421 * same change for any node, even if it gets visited more than once due to
425 fix_opids(Node *node)
427 /* This tree walk requires no special setup, so away we go... */
428 fix_opids_walker(node, NULL);
432 fix_opids_walker (Node *node, void *context)
436 if (is_opclause(node))
437 replace_opid((Oper *) ((Expr *) node)->oper);
438 return expression_tree_walker(node, fix_opids_walker, context);