]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/plan/setrefs.c
Skip invoking set_uppernode_references() for a RESULT node
[postgresql] / src / backend / optimizer / plan / setrefs.c
1 /*-------------------------------------------------------------------------
2  *
3  * setrefs.c
4  *        Post-processing of a completed plan tree: fix references to subplan
5  *        vars, and compute regproc values for operators
6  *
7  * Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.58 1999/10/30 23:07:55 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include <sys/types.h>
16
17 #include "postgres.h"
18
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"
25
26 typedef struct {
27         List       *outer_tlist;
28         List       *inner_tlist;
29         Index           acceptable_rel;
30 } join_references_context;
31
32 typedef struct {
33         Index           subvarno;
34         List       *subplanTargetList;
35 } replace_vars_with_subplan_refs_context;
36
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,
42                                                                                         Index subvarno,
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);
47
48 /*****************************************************************************
49  *
50  *              SUBPLAN REFERENCES
51  *
52  *****************************************************************************/
53
54 /*
55  * set_plan_references
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).
61  *
62  *        set_plan_references recursively traverses the whole plan tree.
63  *
64  * Returns nothing of interest, but modifies internal fields of nodes.
65  */
66 void
67 set_plan_references(Plan *plan)
68 {
69         List       *pl;
70
71         if (plan == NULL)
72                 return;
73
74         /*
75          * Plan-type-specific fixes
76          */
77         switch (nodeTag(plan))
78         {
79                 case T_SeqScan:
80                         /* nothing special */
81                         break;
82                 case T_IndexScan:
83                         fix_opids((Node *) ((IndexScan *) plan)->indxqual);
84                         fix_opids((Node *) ((IndexScan *) plan)->indxqualorig);
85                         break;
86                 case T_NestLoop:
87                         set_join_references((Join *) plan);
88                         break;
89                 case T_MergeJoin:
90                         set_join_references((Join *) plan);
91                         fix_opids((Node *) ((MergeJoin *) plan)->mergeclauses);
92                         break;
93                 case T_HashJoin:
94                         set_join_references((Join *) plan);
95                         fix_opids((Node *) ((HashJoin *) plan)->hashclauses);
96                         break;
97                 case T_Material:
98                 case T_Sort:
99                 case T_Unique:
100                 case T_Hash:
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.
106                          */
107                         break;
108                 case T_Agg:
109                 case T_Group:
110                         set_uppernode_references(plan, (Index) 0);
111                         break;
112                 case T_Result:
113                         /* Result may or may not have a subplan; no need to fix up
114                          * subplan references if it hasn't got one...
115                          *
116                          * XXX why does Result use a different subvarno from Agg/Group?
117                          */
118                         if (plan->lefttree != NULL)
119                                 set_uppernode_references(plan, (Index) OUTER);
120                         fix_opids(((Result *) plan)->resconstantqual);
121                         break;
122                 case T_Append:
123                         foreach(pl, ((Append *) plan)->appendplans)
124                         {
125                                 set_plan_references((Plan *) lfirst(pl));
126                         }
127                         break;
128                 default:
129                         elog(ERROR, "set_plan_references: unknown plan type %d",
130                                  nodeTag(plan));
131                         break;
132         }
133
134         /*
135          * For all plan types, fix operators in targetlist and qual expressions
136          */
137         fix_opids((Node *) plan->targetlist);
138         fix_opids((Node *) plan->qual);
139
140         /*
141          * Now recurse into subplans, if any
142          *
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.
147          */
148         set_plan_references(plan->lefttree);
149         set_plan_references(plan->righttree);
150         foreach(pl, plan->initPlan)
151         {
152                 SubPlan    *sp = (SubPlan *) lfirst(pl);
153
154                 Assert(IsA(sp, SubPlan));
155                 set_plan_references(sp->plan);
156         }
157         foreach(pl, plan->subPlan)
158         {
159                 SubPlan    *sp = (SubPlan *) lfirst(pl);
160
161                 Assert(IsA(sp, SubPlan));
162                 set_plan_references(sp->plan);
163         }
164 }
165
166 /*
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
171  *        tuple item.
172  *
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
177  * see why.)
178  *
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.
183  *
184  * 'join' is a join plan node
185  */
186 static void
187 set_join_references(Join *join)
188 {
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);
193
194         join->targetlist = join_references(join->targetlist,
195                                                                            outer_tlist,
196                                                                            inner_tlist,
197                                                                            (Index) 0);
198 }
199
200 /*
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.
204  *
205  * This is used for single-input plan types like Agg, Group, Result.
206  */
207 static void
208 set_uppernode_references(Plan *plan, Index subvarno)
209 {
210         Plan       *subplan = plan->lefttree;
211         List       *subplanTargetList;
212
213         if (subplan != NULL)
214                 subplanTargetList = subplan->targetlist;
215         else
216                 subplanTargetList = NIL;
217
218         plan->targetlist = (List *)
219                 replace_vars_with_subplan_refs((Node *) plan->targetlist,
220                                                                            subvarno,
221                                                                            subplanTargetList);
222
223         plan->qual = (List *)
224                 replace_vars_with_subplan_refs((Node *) plan->qual,
225                                                                            subvarno,
226                                                                            subplanTargetList);
227 }
228
229 /*
230  * join_references
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.
235  *
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.
241  *
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.
245  *
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.
251  *
252  * Returns the new expression tree.  The original clause structure is
253  * not modified.
254  */
255 List *
256 join_references(List *clauses,
257                                 List *outer_tlist,
258                                 List *inner_tlist,
259                                 Index acceptable_rel)
260 {
261         join_references_context context;
262
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);
267 }
268
269 static Node *
270 join_references_mutator(Node *node,
271                                                 join_references_context *context)
272 {
273         if (node == NULL)
274                 return NULL;
275         if (IsA(node, Var))
276         {
277                 Var                *var = (Var *) node;
278                 Var                *newvar = (Var *) copyObject(var);
279                 Resdom     *resdom;
280
281                 resdom = tlist_member((Node *) var, context->outer_tlist);
282                 if (resdom)
283                 {
284                         newvar->varno = OUTER;
285                         newvar->varattno = resdom->resno;
286                         return (Node *) newvar;
287                 }
288                 resdom = tlist_member((Node *) var, context->inner_tlist);
289                 if (resdom)
290                 {
291                         newvar->varno = INNER;
292                         newvar->varattno = resdom->resno;
293                         return (Node *) newvar;
294                 }
295                 /*
296                  * Var not in either tlist --- either raise an error,
297                  * or return the Var unmodified.
298                  */
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... */
302         }
303         /*
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?
310          */
311         if (is_subplan(node))
312         {
313                 Expr       *expr = (Expr *) node;
314                 SubLink    *sublink = ((SubPlan *) expr->oper)->sublink;
315
316                 /* transform args list (params to be passed to subplan) */
317                 expr->args = (List *)
318                         join_references_mutator((Node *) expr->args,
319                                                                         context);
320                 /* transform sublink's oper list as well */
321                 sublink->oper = (List *)
322                         join_references_mutator((Node *) sublink->oper,
323                                                                         context);
324
325                 return (Node *) expr;
326         }
327         return expression_tree_mutator(node,
328                                                                    join_references_mutator,
329                                                                    (void *) context);
330 }
331
332 /*
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.
337  *
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.
341  *
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
345  *
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.
349  */
350 static Node *
351 replace_vars_with_subplan_refs(Node *node,
352                                                            Index subvarno,
353                                                            List *subplanTargetList)
354 {
355         replace_vars_with_subplan_refs_context context;
356
357         context.subvarno = subvarno;
358         context.subplanTargetList = subplanTargetList;
359         return replace_vars_with_subplan_refs_mutator(node, &context);
360 }
361
362 static Node *
363 replace_vars_with_subplan_refs_mutator(Node *node,
364                                                          replace_vars_with_subplan_refs_context *context)
365 {
366         if (node == NULL)
367                 return NULL;
368         if (IsA(node, Var))
369         {
370                 Var                *var = (Var *) node;
371                 Var                *newvar = (Var *) copyObject(var);
372                 Resdom     *resdom;
373
374                 resdom = tlist_member((Node *) var, context->subplanTargetList);
375                 if (!resdom)
376                         elog(ERROR, "replace_vars_with_subplan_refs: variable not in subplan target list");
377
378                 newvar->varno = context->subvarno;
379                 newvar->varattno = resdom->resno;
380                 return (Node *) newvar;
381         }
382         /*
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?
389          */
390         if (is_subplan(node))
391         {
392                 Expr       *expr = (Expr *) node;
393                 SubLink    *sublink = ((SubPlan *) expr->oper)->sublink;
394
395                 /* transform args list (params to be passed to subplan) */
396                 expr->args = (List *)
397                         replace_vars_with_subplan_refs_mutator((Node *) expr->args,
398                                                                                                    context);
399                 /* transform sublink's oper list as well */
400                 sublink->oper = (List *)
401                         replace_vars_with_subplan_refs_mutator((Node *) sublink->oper,
402                                                                                                    context);
403
404                 return (Node *) expr;
405         }
406         return expression_tree_mutator(node,
407                                                                    replace_vars_with_subplan_refs_mutator,
408                                                                    (void *) context);
409 }
410
411 /*****************************************************************************
412  *                                      OPERATOR REGPROC LOOKUP
413  *****************************************************************************/
414
415 /*
416  * fix_opids
417  *        Calculate opid field from opno for each Oper node in given tree.
418  *        The given tree can be anything expression_tree_walker handles.
419  *
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
422  * shared structure.)
423  */
424 void
425 fix_opids(Node *node)
426 {
427         /* This tree walk requires no special setup, so away we go... */
428         fix_opids_walker(node, NULL);
429 }
430
431 static bool
432 fix_opids_walker (Node *node, void *context)
433 {
434         if (node == NULL)
435                 return false;
436         if (is_opclause(node))
437                 replace_opid((Oper *) ((Expr *) node)->oper);
438         return expression_tree_walker(node, fix_opids_walker, context);
439 }