]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/plan/setrefs.c
Improve the plan cache invalidation mechanism to make it invalidate plans
[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, compute regproc values for operators, etc
6  *
7  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.144 2008/09/09 18:58:08 tgl Exp $
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include "access/transam.h"
19 #include "catalog/pg_type.h"
20 #include "nodes/makefuncs.h"
21 #include "nodes/nodeFuncs.h"
22 #include "optimizer/clauses.h"
23 #include "optimizer/planmain.h"
24 #include "optimizer/tlist.h"
25 #include "parser/parsetree.h"
26 #include "utils/lsyscache.h"
27 #include "utils/syscache.h"
28
29
30 typedef struct
31 {
32         Index           varno;                  /* RT index of Var */
33         AttrNumber      varattno;               /* attr number of Var */
34         AttrNumber      resno;                  /* TLE position of Var */
35 } tlist_vinfo;
36
37 typedef struct
38 {
39         List       *tlist;                      /* underlying target list */
40         int                     num_vars;               /* number of plain Var tlist entries */
41         bool            has_non_vars;   /* are there non-plain-Var entries? */
42         /* array of num_vars entries: */
43         tlist_vinfo vars[1];            /* VARIABLE LENGTH ARRAY */
44 } indexed_tlist;                                /* VARIABLE LENGTH STRUCT */
45
46 typedef struct
47 {
48         PlannerGlobal *glob;
49         int                     rtoffset;
50 } fix_scan_expr_context;
51
52 typedef struct
53 {
54         PlannerGlobal *glob;
55         indexed_tlist *outer_itlist;
56         indexed_tlist *inner_itlist;
57         Index           acceptable_rel;
58         int                     rtoffset;
59 } fix_join_expr_context;
60
61 typedef struct
62 {
63         PlannerGlobal *glob;
64         indexed_tlist *subplan_itlist;
65         int                     rtoffset;
66 } fix_upper_expr_context;
67
68 /*
69  * Check if a Const node is a regclass value.  We accept plain OID too,
70  * since a regclass Const will get folded to that type if it's an argument
71  * to oideq or similar operators.  (This might result in some extraneous
72  * values in a plan's list of relation dependencies, but the worst result
73  * would be occasional useless replans.)
74  */
75 #define ISREGCLASSCONST(con) \
76         (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
77          !(con)->constisnull)
78
79 #define fix_scan_list(glob, lst, rtoffset) \
80         ((List *) fix_scan_expr(glob, (Node *) (lst), rtoffset))
81
82 static Plan *set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset);
83 static Plan *set_subqueryscan_references(PlannerGlobal *glob,
84                                                         SubqueryScan *plan,
85                                                         int rtoffset);
86 static bool trivial_subqueryscan(SubqueryScan *plan);
87 static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset);
88 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
89 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
90 static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset);
91 static void set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
92                                                   indexed_tlist *outer_itlist);
93 static void set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset);
94 static void set_dummy_tlist_references(Plan *plan, int rtoffset);
95 static indexed_tlist *build_tlist_index(List *tlist);
96 static Var *search_indexed_tlist_for_var(Var *var,
97                                                          indexed_tlist *itlist,
98                                                          Index newvarno,
99                                                          int rtoffset);
100 static Var *search_indexed_tlist_for_non_var(Node *node,
101                                                                  indexed_tlist *itlist,
102                                                                  Index newvarno);
103 static List *fix_join_expr(PlannerGlobal *glob,
104                           List *clauses,
105                           indexed_tlist *outer_itlist,
106                           indexed_tlist *inner_itlist,
107                           Index acceptable_rel, int rtoffset);
108 static Node *fix_join_expr_mutator(Node *node,
109                                           fix_join_expr_context *context);
110 static Node *fix_upper_expr(PlannerGlobal *glob,
111                            Node *node,
112                            indexed_tlist *subplan_itlist,
113                            int rtoffset);
114 static Node *fix_upper_expr_mutator(Node *node,
115                                            fix_upper_expr_context *context);
116 static bool fix_opfuncids_walker(Node *node, void *context);
117 static bool extract_query_dependencies_walker(Node *node,
118                                                                                           PlannerGlobal *context);
119
120
121 /*****************************************************************************
122  *
123  *              SUBPLAN REFERENCES
124  *
125  *****************************************************************************/
126
127 /*
128  * set_plan_references
129  *
130  * This is the final processing pass of the planner/optimizer.  The plan
131  * tree is complete; we just have to adjust some representational details
132  * for the convenience of the executor:
133  *
134  * 1. We flatten the various subquery rangetables into a single list, and
135  * zero out RangeTblEntry fields that are not useful to the executor.
136  *
137  * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
138  *
139  * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
140  * subplans.
141  *
142  * 4. We compute regproc OIDs for operators (ie, we look up the function
143  * that implements each op).
144  *
145  * 5. We create lists of specific objects that the plan depends on.
146  * This will be used by plancache.c to drive invalidation of cached plans.
147  * Relation dependencies are represented by OIDs, and everything else by
148  * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
149  * Currently, relations and user-defined functions are the only types of
150  * objects that are explicitly tracked this way.
151  *
152  * We also perform one final optimization step, which is to delete
153  * SubqueryScan plan nodes that aren't doing anything useful (ie, have
154  * no qual and a no-op targetlist).  The reason for doing this last is that
155  * it can't readily be done before set_plan_references, because it would
156  * break set_upper_references: the Vars in the subquery's top tlist
157  * wouldn't match up with the Vars in the outer plan tree.  The SubqueryScan
158  * serves a necessary function as a buffer between outer query and subquery
159  * variable numbering ... but after we've flattened the rangetable this is
160  * no longer a problem, since then there's only one rtindex namespace.
161  *
162  * set_plan_references recursively traverses the whole plan tree.
163  *
164  * Inputs:
165  *      glob: global data for planner run
166  *      plan: the topmost node of the plan
167  *      rtable: the rangetable for the current subquery
168  *
169  * The return value is normally the same Plan node passed in, but can be
170  * different when the passed-in Plan is a SubqueryScan we decide isn't needed.
171  *
172  * The flattened rangetable entries are appended to glob->finalrtable, and
173  * plan dependencies are appended to glob->relationOids (for relations)
174  * and glob->invalItems (for everything else).
175  *
176  * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
177  * to process targetlist and qual expressions.  We can assume that the Plan
178  * nodes were just built by the planner and are not multiply referenced, but
179  * it's not so safe to assume that for expression tree nodes.
180  */
181 Plan *
182 set_plan_references(PlannerGlobal *glob, Plan *plan, List *rtable)
183 {
184         int                     rtoffset = list_length(glob->finalrtable);
185         ListCell   *lc;
186
187         /*
188          * In the flat rangetable, we zero out substructure pointers that are not
189          * needed by the executor; this reduces the storage space and copying cost
190          * for cached plans.  We keep only the alias and eref Alias fields, which
191          * are needed by EXPLAIN.
192          */
193         foreach(lc, rtable)
194         {
195                 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
196                 RangeTblEntry *newrte;
197
198                 /* flat copy to duplicate all the scalar fields */
199                 newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
200                 memcpy(newrte, rte, sizeof(RangeTblEntry));
201
202                 /* zap unneeded sub-structure */
203                 newrte->subquery = NULL;
204                 newrte->funcexpr = NULL;
205                 newrte->funccoltypes = NIL;
206                 newrte->funccoltypmods = NIL;
207                 newrte->values_lists = NIL;
208                 newrte->joinaliasvars = NIL;
209
210                 glob->finalrtable = lappend(glob->finalrtable, newrte);
211
212                 /*
213                  * If it's a plain relation RTE, add the table to relationOids.
214                  *
215                  * We do this even though the RTE might be unreferenced in the plan
216                  * tree; this would correspond to cases such as views that were
217                  * expanded, child tables that were eliminated by constraint
218                  * exclusion, etc.      Schema invalidation on such a rel must still force
219                  * rebuilding of the plan.
220                  *
221                  * Note we don't bother to avoid duplicate list entries.  We could,
222                  * but it would probably cost more cycles than it would save.
223                  */
224                 if (newrte->rtekind == RTE_RELATION)
225                         glob->relationOids = lappend_oid(glob->relationOids,
226                                                                                          newrte->relid);
227         }
228
229         /* Now fix the Plan tree */
230         return set_plan_refs(glob, plan, rtoffset);
231 }
232
233 /*
234  * set_plan_refs: recurse through the Plan nodes of a single subquery level
235  */
236 static Plan *
237 set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
238 {
239         ListCell   *l;
240
241         if (plan == NULL)
242                 return NULL;
243
244         /*
245          * Plan-type-specific fixes
246          */
247         switch (nodeTag(plan))
248         {
249                 case T_SeqScan:
250                         {
251                                 SeqScan    *splan = (SeqScan *) plan;
252
253                                 splan->scanrelid += rtoffset;
254                                 splan->plan.targetlist =
255                                         fix_scan_list(glob, splan->plan.targetlist, rtoffset);
256                                 splan->plan.qual =
257                                         fix_scan_list(glob, splan->plan.qual, rtoffset);
258                         }
259                         break;
260                 case T_IndexScan:
261                         {
262                                 IndexScan  *splan = (IndexScan *) plan;
263
264                                 splan->scan.scanrelid += rtoffset;
265                                 splan->scan.plan.targetlist =
266                                         fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
267                                 splan->scan.plan.qual =
268                                         fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
269                                 splan->indexqual =
270                                         fix_scan_list(glob, splan->indexqual, rtoffset);
271                                 splan->indexqualorig =
272                                         fix_scan_list(glob, splan->indexqualorig, rtoffset);
273                         }
274                         break;
275                 case T_BitmapIndexScan:
276                         {
277                                 BitmapIndexScan *splan = (BitmapIndexScan *) plan;
278
279                                 splan->scan.scanrelid += rtoffset;
280                                 /* no need to fix targetlist and qual */
281                                 Assert(splan->scan.plan.targetlist == NIL);
282                                 Assert(splan->scan.plan.qual == NIL);
283                                 splan->indexqual =
284                                         fix_scan_list(glob, splan->indexqual, rtoffset);
285                                 splan->indexqualorig =
286                                         fix_scan_list(glob, splan->indexqualorig, rtoffset);
287                         }
288                         break;
289                 case T_BitmapHeapScan:
290                         {
291                                 BitmapHeapScan *splan = (BitmapHeapScan *) plan;
292
293                                 splan->scan.scanrelid += rtoffset;
294                                 splan->scan.plan.targetlist =
295                                         fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
296                                 splan->scan.plan.qual =
297                                         fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
298                                 splan->bitmapqualorig =
299                                         fix_scan_list(glob, splan->bitmapqualorig, rtoffset);
300                         }
301                         break;
302                 case T_TidScan:
303                         {
304                                 TidScan    *splan = (TidScan *) plan;
305
306                                 splan->scan.scanrelid += rtoffset;
307                                 splan->scan.plan.targetlist =
308                                         fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
309                                 splan->scan.plan.qual =
310                                         fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
311                                 splan->tidquals =
312                                         fix_scan_list(glob, splan->tidquals, rtoffset);
313                         }
314                         break;
315                 case T_SubqueryScan:
316                         /* Needs special treatment, see comments below */
317                         return set_subqueryscan_references(glob,
318                                                                                            (SubqueryScan *) plan,
319                                                                                            rtoffset);
320                 case T_FunctionScan:
321                         {
322                                 FunctionScan *splan = (FunctionScan *) plan;
323
324                                 splan->scan.scanrelid += rtoffset;
325                                 splan->scan.plan.targetlist =
326                                         fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
327                                 splan->scan.plan.qual =
328                                         fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
329                                 splan->funcexpr =
330                                         fix_scan_expr(glob, splan->funcexpr, rtoffset);
331                         }
332                         break;
333                 case T_ValuesScan:
334                         {
335                                 ValuesScan *splan = (ValuesScan *) plan;
336
337                                 splan->scan.scanrelid += rtoffset;
338                                 splan->scan.plan.targetlist =
339                                         fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
340                                 splan->scan.plan.qual =
341                                         fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
342                                 splan->values_lists =
343                                         fix_scan_list(glob, splan->values_lists, rtoffset);
344                         }
345                         break;
346
347                 case T_NestLoop:
348                 case T_MergeJoin:
349                 case T_HashJoin:
350                         set_join_references(glob, (Join *) plan, rtoffset);
351                         break;
352
353                 case T_Hash:
354                 case T_Material:
355                 case T_Sort:
356                 case T_Unique:
357                 case T_SetOp:
358
359                         /*
360                          * These plan types don't actually bother to evaluate their
361                          * targetlists, because they just return their unmodified input
362                          * tuples.      Even though the targetlist won't be used by the
363                          * executor, we fix it up for possible use by EXPLAIN (not to
364                          * mention ease of debugging --- wrong varnos are very confusing).
365                          */
366                         set_dummy_tlist_references(plan, rtoffset);
367
368                         /*
369                          * Since these plan types don't check quals either, we should not
370                          * find any qual expression attached to them.
371                          */
372                         Assert(plan->qual == NIL);
373                         break;
374                 case T_Limit:
375                         {
376                                 Limit      *splan = (Limit *) plan;
377
378                                 /*
379                                  * Like the plan types above, Limit doesn't evaluate its tlist
380                                  * or quals.  It does have live expressions for limit/offset,
381                                  * however; and those cannot contain subplan variable refs, so
382                                  * fix_scan_expr works for them.
383                                  */
384                                 set_dummy_tlist_references(plan, rtoffset);
385                                 Assert(splan->plan.qual == NIL);
386
387                                 splan->limitOffset =
388                                         fix_scan_expr(glob, splan->limitOffset, rtoffset);
389                                 splan->limitCount =
390                                         fix_scan_expr(glob, splan->limitCount, rtoffset);
391                         }
392                         break;
393                 case T_Agg:
394                 case T_Group:
395                         set_upper_references(glob, plan, rtoffset);
396                         break;
397                 case T_Result:
398                         {
399                                 Result     *splan = (Result *) plan;
400
401                                 /*
402                                  * Result may or may not have a subplan; if not, it's more
403                                  * like a scan node than an upper node.
404                                  */
405                                 if (splan->plan.lefttree != NULL)
406                                         set_upper_references(glob, plan, rtoffset);
407                                 else
408                                 {
409                                         splan->plan.targetlist =
410                                                 fix_scan_list(glob, splan->plan.targetlist, rtoffset);
411                                         splan->plan.qual =
412                                                 fix_scan_list(glob, splan->plan.qual, rtoffset);
413                                 }
414                                 /* resconstantqual can't contain any subplan variable refs */
415                                 splan->resconstantqual =
416                                         fix_scan_expr(glob, splan->resconstantqual, rtoffset);
417                         }
418                         break;
419                 case T_Append:
420                         {
421                                 Append     *splan = (Append *) plan;
422
423                                 /*
424                                  * Append, like Sort et al, doesn't actually evaluate its
425                                  * targetlist or check quals.
426                                  */
427                                 set_dummy_tlist_references(plan, rtoffset);
428                                 Assert(splan->plan.qual == NIL);
429                                 foreach(l, splan->appendplans)
430                                 {
431                                         lfirst(l) = set_plan_refs(glob,
432                                                                                           (Plan *) lfirst(l),
433                                                                                           rtoffset);
434                                 }
435                         }
436                         break;
437                 case T_BitmapAnd:
438                         {
439                                 BitmapAnd  *splan = (BitmapAnd *) plan;
440
441                                 /* BitmapAnd works like Append, but has no tlist */
442                                 Assert(splan->plan.targetlist == NIL);
443                                 Assert(splan->plan.qual == NIL);
444                                 foreach(l, splan->bitmapplans)
445                                 {
446                                         lfirst(l) = set_plan_refs(glob,
447                                                                                           (Plan *) lfirst(l),
448                                                                                           rtoffset);
449                                 }
450                         }
451                         break;
452                 case T_BitmapOr:
453                         {
454                                 BitmapOr   *splan = (BitmapOr *) plan;
455
456                                 /* BitmapOr works like Append, but has no tlist */
457                                 Assert(splan->plan.targetlist == NIL);
458                                 Assert(splan->plan.qual == NIL);
459                                 foreach(l, splan->bitmapplans)
460                                 {
461                                         lfirst(l) = set_plan_refs(glob,
462                                                                                           (Plan *) lfirst(l),
463                                                                                           rtoffset);
464                                 }
465                         }
466                         break;
467                 default:
468                         elog(ERROR, "unrecognized node type: %d",
469                                  (int) nodeTag(plan));
470                         break;
471         }
472
473         /*
474          * Now recurse into child plans, if any
475          *
476          * NOTE: it is essential that we recurse into child plans AFTER we set
477          * subplan references in this plan's tlist and quals.  If we did the
478          * reference-adjustments bottom-up, then we would fail to match this
479          * plan's var nodes against the already-modified nodes of the children.
480          */
481         plan->lefttree = set_plan_refs(glob, plan->lefttree, rtoffset);
482         plan->righttree = set_plan_refs(glob, plan->righttree, rtoffset);
483
484         return plan;
485 }
486
487 /*
488  * set_subqueryscan_references
489  *              Do set_plan_references processing on a SubqueryScan
490  *
491  * We try to strip out the SubqueryScan entirely; if we can't, we have
492  * to do the normal processing on it.
493  */
494 static Plan *
495 set_subqueryscan_references(PlannerGlobal *glob,
496                                                         SubqueryScan *plan,
497                                                         int rtoffset)
498 {
499         Plan       *result;
500
501         /* First, recursively process the subplan */
502         plan->subplan = set_plan_references(glob, plan->subplan, plan->subrtable);
503
504         /* subrtable is no longer needed in the plan tree */
505         plan->subrtable = NIL;
506
507         if (trivial_subqueryscan(plan))
508         {
509                 /*
510                  * We can omit the SubqueryScan node and just pull up the subplan.
511                  */
512                 ListCell   *lp,
513                                    *lc;
514
515                 result = plan->subplan;
516
517                 /* We have to be sure we don't lose any initplans */
518                 result->initPlan = list_concat(plan->scan.plan.initPlan,
519                                                                            result->initPlan);
520
521                 /*
522                  * We also have to transfer the SubqueryScan's result-column names
523                  * into the subplan, else columns sent to client will be improperly
524                  * labeled if this is the topmost plan level.  Copy the "source
525                  * column" information too.
526                  */
527                 forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist)
528                 {
529                         TargetEntry *ptle = (TargetEntry *) lfirst(lp);
530                         TargetEntry *ctle = (TargetEntry *) lfirst(lc);
531
532                         ctle->resname = ptle->resname;
533                         ctle->resorigtbl = ptle->resorigtbl;
534                         ctle->resorigcol = ptle->resorigcol;
535                 }
536         }
537         else
538         {
539                 /*
540                  * Keep the SubqueryScan node.  We have to do the processing that
541                  * set_plan_references would otherwise have done on it.  Notice we do
542                  * not do set_upper_references() here, because a SubqueryScan will
543                  * always have been created with correct references to its subplan's
544                  * outputs to begin with.
545                  */
546                 plan->scan.scanrelid += rtoffset;
547                 plan->scan.plan.targetlist =
548                         fix_scan_list(glob, plan->scan.plan.targetlist, rtoffset);
549                 plan->scan.plan.qual =
550                         fix_scan_list(glob, plan->scan.plan.qual, rtoffset);
551
552                 result = (Plan *) plan;
553         }
554
555         return result;
556 }
557
558 /*
559  * trivial_subqueryscan
560  *              Detect whether a SubqueryScan can be deleted from the plan tree.
561  *
562  * We can delete it if it has no qual to check and the targetlist just
563  * regurgitates the output of the child plan.
564  */
565 static bool
566 trivial_subqueryscan(SubqueryScan *plan)
567 {
568         int                     attrno;
569         ListCell   *lp,
570                            *lc;
571
572         if (plan->scan.plan.qual != NIL)
573                 return false;
574
575         if (list_length(plan->scan.plan.targetlist) !=
576                 list_length(plan->subplan->targetlist))
577                 return false;                   /* tlists not same length */
578
579         attrno = 1;
580         forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
581         {
582                 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
583                 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
584
585                 if (ptle->resjunk != ctle->resjunk)
586                         return false;           /* tlist doesn't match junk status */
587
588                 /*
589                  * We accept either a Var referencing the corresponding element of the
590                  * subplan tlist, or a Const equaling the subplan element. See
591                  * generate_setop_tlist() for motivation.
592                  */
593                 if (ptle->expr && IsA(ptle->expr, Var))
594                 {
595                         Var                *var = (Var *) ptle->expr;
596
597                         Assert(var->varno == plan->scan.scanrelid);
598                         Assert(var->varlevelsup == 0);
599                         if (var->varattno != attrno)
600                                 return false;   /* out of order */
601                 }
602                 else if (ptle->expr && IsA(ptle->expr, Const))
603                 {
604                         if (!equal(ptle->expr, ctle->expr))
605                                 return false;
606                 }
607                 else
608                         return false;
609
610                 attrno++;
611         }
612
613         return true;
614 }
615
616 /*
617  * copyVar
618  *              Copy a Var node.
619  *
620  * fix_scan_expr and friends do this enough times that it's worth having
621  * a bespoke routine instead of using the generic copyObject() function.
622  */
623 static inline Var *
624 copyVar(Var *var)
625 {
626         Var                *newvar = (Var *) palloc(sizeof(Var));
627
628         *newvar = *var;
629         return newvar;
630 }
631
632 /*
633  * fix_expr_common
634  *              Do generic set_plan_references processing on an expression node
635  *
636  * This is code that is common to all variants of expression-fixing.
637  * We must look up operator opcode info for OpExpr and related nodes,
638  * add OIDs from regclass Const nodes into glob->relationOids,
639  * and add catalog TIDs for user-defined functions into glob->invalItems.
640  *
641  * We assume it's okay to update opcode info in-place.  So this could possibly
642  * scribble on the planner's input data structures, but it's OK.
643  */
644 static void
645 fix_expr_common(PlannerGlobal *glob, Node *node)
646 {
647         /* We assume callers won't call us on a NULL pointer */
648         if (IsA(node, Aggref))
649         {
650                 record_plan_function_dependency(glob,
651                                                                                 ((Aggref *) node)->aggfnoid);
652         }
653         else if (IsA(node, FuncExpr))
654         {
655                 record_plan_function_dependency(glob,
656                                                                                 ((FuncExpr *) node)->funcid);
657         }
658         else if (IsA(node, OpExpr))
659         {
660                 set_opfuncid((OpExpr *) node);
661                 record_plan_function_dependency(glob,
662                                                                                 ((OpExpr *) node)->opfuncid);
663         }
664         else if (IsA(node, DistinctExpr))
665         {
666                 set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
667                 record_plan_function_dependency(glob,
668                                                                                 ((DistinctExpr *) node)->opfuncid);
669         }
670         else if (IsA(node, NullIfExpr))
671         {
672                 set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
673                 record_plan_function_dependency(glob,
674                                                                                 ((NullIfExpr *) node)->opfuncid);
675         }
676         else if (IsA(node, ScalarArrayOpExpr))
677         {
678                 set_sa_opfuncid((ScalarArrayOpExpr *) node);
679                 record_plan_function_dependency(glob,
680                                                                                 ((ScalarArrayOpExpr *) node)->opfuncid);
681         }
682         else if (IsA(node, ArrayCoerceExpr))
683         {
684                 if (OidIsValid(((ArrayCoerceExpr *) node)->elemfuncid))
685                         record_plan_function_dependency(glob,
686                                                                                         ((ArrayCoerceExpr *) node)->elemfuncid);
687         }
688         else if (IsA(node, Const))
689         {
690                 Const      *con = (Const *) node;
691
692                 /* Check for regclass reference */
693                 if (ISREGCLASSCONST(con))
694                         glob->relationOids =
695                                 lappend_oid(glob->relationOids,
696                                                         DatumGetObjectId(con->constvalue));
697         }
698 }
699
700 /*
701  * fix_scan_expr
702  *              Do set_plan_references processing on a scan-level expression
703  *
704  * This consists of incrementing all Vars' varnos by rtoffset,
705  * looking up operator opcode info for OpExpr and related nodes,
706  * and adding OIDs from regclass Const nodes into glob->relationOids.
707  */
708 static Node *
709 fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset)
710 {
711         fix_scan_expr_context context;
712
713         context.glob = glob;
714         context.rtoffset = rtoffset;
715
716         if (rtoffset != 0)
717         {
718                 return fix_scan_expr_mutator(node, &context);
719         }
720         else
721         {
722                 /*
723                  * If rtoffset == 0, we don't need to change any Vars, which makes
724                  * it OK to just scribble on the input node tree instead of copying
725                  * (since the only change, filling in any unset opfuncid fields,
726                  * is harmless).  This saves just enough cycles to be noticeable on
727                  * trivial queries.
728                  */
729                 (void) fix_scan_expr_walker(node, &context);
730                 return node;
731         }
732 }
733
734 static Node *
735 fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
736 {
737         if (node == NULL)
738                 return NULL;
739         if (IsA(node, Var))
740         {
741                 Var                *var = copyVar((Var *) node);
742
743                 Assert(var->varlevelsup == 0);
744
745                 /*
746                  * We should not see any Vars marked INNER, but in a nestloop inner
747                  * scan there could be OUTER Vars.      Leave them alone.
748                  */
749                 Assert(var->varno != INNER);
750                 if (var->varno > 0 && var->varno != OUTER)
751                         var->varno += context->rtoffset;
752                 if (var->varnoold > 0)
753                         var->varnoold += context->rtoffset;
754                 return (Node *) var;
755         }
756         if (IsA(node, CurrentOfExpr))
757         {
758                 CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
759
760                 Assert(cexpr->cvarno != INNER);
761                 Assert(cexpr->cvarno != OUTER);
762                 cexpr->cvarno += context->rtoffset;
763                 return (Node *) cexpr;
764         }
765         fix_expr_common(context->glob, node);
766         return expression_tree_mutator(node, fix_scan_expr_mutator,
767                                                                    (void *) context);
768 }
769
770 static bool
771 fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
772 {
773         if (node == NULL)
774                 return false;
775         fix_expr_common(context->glob, node);
776         return expression_tree_walker(node, fix_scan_expr_walker,
777                                                                   (void *) context);
778 }
779
780 /*
781  * set_join_references
782  *        Modify the target list and quals of a join node to reference its
783  *        subplans, by setting the varnos to OUTER or INNER and setting attno
784  *        values to the result domain number of either the corresponding outer
785  *        or inner join tuple item.  Also perform opcode lookup for these
786  *        expressions. and add regclass OIDs to glob->relationOids.
787  *
788  * In the case of a nestloop with inner indexscan, we will also need to
789  * apply the same transformation to any outer vars appearing in the
790  * quals of the child indexscan.  set_inner_join_references does that.
791  */
792 static void
793 set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
794 {
795         Plan       *outer_plan = join->plan.lefttree;
796         Plan       *inner_plan = join->plan.righttree;
797         indexed_tlist *outer_itlist;
798         indexed_tlist *inner_itlist;
799
800         outer_itlist = build_tlist_index(outer_plan->targetlist);
801         inner_itlist = build_tlist_index(inner_plan->targetlist);
802
803         /* All join plans have tlist, qual, and joinqual */
804         join->plan.targetlist = fix_join_expr(glob,
805                                                                                   join->plan.targetlist,
806                                                                                   outer_itlist,
807                                                                                   inner_itlist,
808                                                                                   (Index) 0,
809                                                                                   rtoffset);
810         join->plan.qual = fix_join_expr(glob,
811                                                                         join->plan.qual,
812                                                                         outer_itlist,
813                                                                         inner_itlist,
814                                                                         (Index) 0,
815                                                                         rtoffset);
816         join->joinqual = fix_join_expr(glob,
817                                                                    join->joinqual,
818                                                                    outer_itlist,
819                                                                    inner_itlist,
820                                                                    (Index) 0,
821                                                                    rtoffset);
822
823         /* Now do join-type-specific stuff */
824         if (IsA(join, NestLoop))
825         {
826                 /* This processing is split out to handle possible recursion */
827                 set_inner_join_references(glob, inner_plan, outer_itlist);
828         }
829         else if (IsA(join, MergeJoin))
830         {
831                 MergeJoin  *mj = (MergeJoin *) join;
832
833                 mj->mergeclauses = fix_join_expr(glob,
834                                                                                  mj->mergeclauses,
835                                                                                  outer_itlist,
836                                                                                  inner_itlist,
837                                                                                  (Index) 0,
838                                                                                  rtoffset);
839         }
840         else if (IsA(join, HashJoin))
841         {
842                 HashJoin   *hj = (HashJoin *) join;
843
844                 hj->hashclauses = fix_join_expr(glob,
845                                                                                 hj->hashclauses,
846                                                                                 outer_itlist,
847                                                                                 inner_itlist,
848                                                                                 (Index) 0,
849                                                                                 rtoffset);
850         }
851
852         pfree(outer_itlist);
853         pfree(inner_itlist);
854 }
855
856 /*
857  * set_inner_join_references
858  *              Handle join references appearing in an inner indexscan's quals
859  *
860  * To handle bitmap-scan plan trees, we have to be able to recurse down
861  * to the bottom BitmapIndexScan nodes; likewise, appendrel indexscans
862  * require recursing through Append nodes.      This is split out as a separate
863  * function so that it can recurse.
864  *
865  * Note we do *not* apply any rtoffset for non-join Vars; this is because
866  * the quals will be processed again by fix_scan_expr when the set_plan_refs
867  * recursion reaches the inner indexscan, and so we'd have done it twice.
868  */
869 static void
870 set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
871                                                   indexed_tlist *outer_itlist)
872 {
873         if (IsA(inner_plan, IndexScan))
874         {
875                 /*
876                  * An index is being used to reduce the number of tuples scanned in
877                  * the inner relation.  If there are join clauses being used with the
878                  * index, we must update their outer-rel var nodes to refer to the
879                  * outer side of the join.
880                  */
881                 IndexScan  *innerscan = (IndexScan *) inner_plan;
882                 List       *indexqualorig = innerscan->indexqualorig;
883
884                 /* No work needed if indexqual refers only to its own rel... */
885                 if (NumRelids((Node *) indexqualorig) > 1)
886                 {
887                         Index           innerrel = innerscan->scan.scanrelid;
888
889                         /* only refs to outer vars get changed in the inner qual */
890                         innerscan->indexqualorig = fix_join_expr(glob,
891                                                                                                          indexqualorig,
892                                                                                                          outer_itlist,
893                                                                                                          NULL,
894                                                                                                          innerrel,
895                                                                                                          0);
896                         innerscan->indexqual = fix_join_expr(glob,
897                                                                                                  innerscan->indexqual,
898                                                                                                  outer_itlist,
899                                                                                                  NULL,
900                                                                                                  innerrel,
901                                                                                                  0);
902
903                         /*
904                          * We must fix the inner qpqual too, if it has join clauses (this
905                          * could happen if special operators are involved: some indexquals
906                          * may get rechecked as qpquals).
907                          */
908                         if (NumRelids((Node *) inner_plan->qual) > 1)
909                                 inner_plan->qual = fix_join_expr(glob,
910                                                                                                  inner_plan->qual,
911                                                                                                  outer_itlist,
912                                                                                                  NULL,
913                                                                                                  innerrel,
914                                                                                                  0);
915                 }
916         }
917         else if (IsA(inner_plan, BitmapIndexScan))
918         {
919                 /*
920                  * Same, but index is being used within a bitmap plan.
921                  */
922                 BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan;
923                 List       *indexqualorig = innerscan->indexqualorig;
924
925                 /* No work needed if indexqual refers only to its own rel... */
926                 if (NumRelids((Node *) indexqualorig) > 1)
927                 {
928                         Index           innerrel = innerscan->scan.scanrelid;
929
930                         /* only refs to outer vars get changed in the inner qual */
931                         innerscan->indexqualorig = fix_join_expr(glob,
932                                                                                                          indexqualorig,
933                                                                                                          outer_itlist,
934                                                                                                          NULL,
935                                                                                                          innerrel,
936                                                                                                          0);
937                         innerscan->indexqual = fix_join_expr(glob,
938                                                                                                  innerscan->indexqual,
939                                                                                                  outer_itlist,
940                                                                                                  NULL,
941                                                                                                  innerrel,
942                                                                                                  0);
943                         /* no need to fix inner qpqual */
944                         Assert(inner_plan->qual == NIL);
945                 }
946         }
947         else if (IsA(inner_plan, BitmapHeapScan))
948         {
949                 /*
950                  * The inner side is a bitmap scan plan.  Fix the top node, and
951                  * recurse to get the lower nodes.
952                  *
953                  * Note: create_bitmap_scan_plan removes clauses from bitmapqualorig
954                  * if they are duplicated in qpqual, so must test these independently.
955                  */
956                 BitmapHeapScan *innerscan = (BitmapHeapScan *) inner_plan;
957                 Index           innerrel = innerscan->scan.scanrelid;
958                 List       *bitmapqualorig = innerscan->bitmapqualorig;
959
960                 /* only refs to outer vars get changed in the inner qual */
961                 if (NumRelids((Node *) bitmapqualorig) > 1)
962                         innerscan->bitmapqualorig = fix_join_expr(glob,
963                                                                                                           bitmapqualorig,
964                                                                                                           outer_itlist,
965                                                                                                           NULL,
966                                                                                                           innerrel,
967                                                                                                           0);
968
969                 /*
970                  * We must fix the inner qpqual too, if it has join clauses (this
971                  * could happen if special operators are involved: some indexquals may
972                  * get rechecked as qpquals).
973                  */
974                 if (NumRelids((Node *) inner_plan->qual) > 1)
975                         inner_plan->qual = fix_join_expr(glob,
976                                                                                          inner_plan->qual,
977                                                                                          outer_itlist,
978                                                                                          NULL,
979                                                                                          innerrel,
980                                                                                          0);
981
982                 /* Now recurse */
983                 set_inner_join_references(glob, inner_plan->lefttree, outer_itlist);
984         }
985         else if (IsA(inner_plan, BitmapAnd))
986         {
987                 /* All we need do here is recurse */
988                 BitmapAnd  *innerscan = (BitmapAnd *) inner_plan;
989                 ListCell   *l;
990
991                 foreach(l, innerscan->bitmapplans)
992                 {
993                         set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
994                 }
995         }
996         else if (IsA(inner_plan, BitmapOr))
997         {
998                 /* All we need do here is recurse */
999                 BitmapOr   *innerscan = (BitmapOr *) inner_plan;
1000                 ListCell   *l;
1001
1002                 foreach(l, innerscan->bitmapplans)
1003                 {
1004                         set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
1005                 }
1006         }
1007         else if (IsA(inner_plan, TidScan))
1008         {
1009                 TidScan    *innerscan = (TidScan *) inner_plan;
1010                 Index           innerrel = innerscan->scan.scanrelid;
1011
1012                 innerscan->tidquals = fix_join_expr(glob,
1013                                                                                         innerscan->tidquals,
1014                                                                                         outer_itlist,
1015                                                                                         NULL,
1016                                                                                         innerrel,
1017                                                                                         0);
1018         }
1019         else if (IsA(inner_plan, Append))
1020         {
1021                 /*
1022                  * The inner side is an append plan.  Recurse to see if it contains
1023                  * indexscans that need to be fixed.
1024                  */
1025                 Append     *appendplan = (Append *) inner_plan;
1026                 ListCell   *l;
1027
1028                 foreach(l, appendplan->appendplans)
1029                 {
1030                         set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
1031                 }
1032         }
1033         else if (IsA(inner_plan, Result))
1034         {
1035                 /* Recurse through a gating Result node (similar to Append case) */
1036                 Result     *result = (Result *) inner_plan;
1037
1038                 if (result->plan.lefttree)
1039                         set_inner_join_references(glob, result->plan.lefttree, outer_itlist);
1040         }
1041 }
1042
1043 /*
1044  * set_upper_references
1045  *        Update the targetlist and quals of an upper-level plan node
1046  *        to refer to the tuples returned by its lefttree subplan.
1047  *        Also perform opcode lookup for these expressions, and
1048  *        add regclass OIDs to glob->relationOids.
1049  *
1050  * This is used for single-input plan types like Agg, Group, Result.
1051  *
1052  * In most cases, we have to match up individual Vars in the tlist and
1053  * qual expressions with elements of the subplan's tlist (which was
1054  * generated by flatten_tlist() from these selfsame expressions, so it
1055  * should have all the required variables).  There is an important exception,
1056  * however: GROUP BY and ORDER BY expressions will have been pushed into the
1057  * subplan tlist unflattened.  If these values are also needed in the output
1058  * then we want to reference the subplan tlist element rather than recomputing
1059  * the expression.
1060  */
1061 static void
1062 set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset)
1063 {
1064         Plan       *subplan = plan->lefttree;
1065         indexed_tlist *subplan_itlist;
1066         List       *output_targetlist;
1067         ListCell   *l;
1068
1069         subplan_itlist = build_tlist_index(subplan->targetlist);
1070
1071         output_targetlist = NIL;
1072         foreach(l, plan->targetlist)
1073         {
1074                 TargetEntry *tle = (TargetEntry *) lfirst(l);
1075                 Node       *newexpr;
1076
1077                 newexpr = fix_upper_expr(glob,
1078                                                                  (Node *) tle->expr,
1079                                                                  subplan_itlist,
1080                                                                  rtoffset);
1081                 tle = flatCopyTargetEntry(tle);
1082                 tle->expr = (Expr *) newexpr;
1083                 output_targetlist = lappend(output_targetlist, tle);
1084         }
1085         plan->targetlist = output_targetlist;
1086
1087         plan->qual = (List *)
1088                 fix_upper_expr(glob,
1089                                            (Node *) plan->qual,
1090                                            subplan_itlist,
1091                                            rtoffset);
1092
1093         pfree(subplan_itlist);
1094 }
1095
1096 /*
1097  * set_dummy_tlist_references
1098  *        Replace the targetlist of an upper-level plan node with a simple
1099  *        list of OUTER references to its child.
1100  *
1101  * This is used for plan types like Sort and Append that don't evaluate
1102  * their targetlists.  Although the executor doesn't care at all what's in
1103  * the tlist, EXPLAIN needs it to be realistic.
1104  *
1105  * Note: we could almost use set_upper_references() here, but it fails for
1106  * Append for lack of a lefttree subplan.  Single-purpose code is faster
1107  * anyway.
1108  */
1109 static void
1110 set_dummy_tlist_references(Plan *plan, int rtoffset)
1111 {
1112         List       *output_targetlist;
1113         ListCell   *l;
1114
1115         output_targetlist = NIL;
1116         foreach(l, plan->targetlist)
1117         {
1118                 TargetEntry *tle = (TargetEntry *) lfirst(l);
1119                 Var                *oldvar = (Var *) tle->expr;
1120                 Var                *newvar;
1121
1122                 newvar = makeVar(OUTER,
1123                                                  tle->resno,
1124                                                  exprType((Node *) oldvar),
1125                                                  exprTypmod((Node *) oldvar),
1126                                                  0);
1127                 if (IsA(oldvar, Var))
1128                 {
1129                         newvar->varnoold = oldvar->varno + rtoffset;
1130                         newvar->varoattno = oldvar->varattno;
1131                 }
1132                 else
1133                 {
1134                         newvar->varnoold = 0;           /* wasn't ever a plain Var */
1135                         newvar->varoattno = 0;
1136                 }
1137
1138                 tle = flatCopyTargetEntry(tle);
1139                 tle->expr = (Expr *) newvar;
1140                 output_targetlist = lappend(output_targetlist, tle);
1141         }
1142         plan->targetlist = output_targetlist;
1143
1144         /* We don't touch plan->qual here */
1145 }
1146
1147
1148 /*
1149  * build_tlist_index --- build an index data structure for a child tlist
1150  *
1151  * In most cases, subplan tlists will be "flat" tlists with only Vars,
1152  * so we try to optimize that case by extracting information about Vars
1153  * in advance.  Matching a parent tlist to a child is still an O(N^2)
1154  * operation, but at least with a much smaller constant factor than plain
1155  * tlist_member() searches.
1156  *
1157  * The result of this function is an indexed_tlist struct to pass to
1158  * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
1159  * When done, the indexed_tlist may be freed with a single pfree().
1160  */
1161 static indexed_tlist *
1162 build_tlist_index(List *tlist)
1163 {
1164         indexed_tlist *itlist;
1165         tlist_vinfo *vinfo;
1166         ListCell   *l;
1167
1168         /* Create data structure with enough slots for all tlist entries */
1169         itlist = (indexed_tlist *)
1170                 palloc(offsetof(indexed_tlist, vars) +
1171                            list_length(tlist) * sizeof(tlist_vinfo));
1172
1173         itlist->tlist = tlist;
1174         itlist->has_non_vars = false;
1175
1176         /* Find the Vars and fill in the index array */
1177         vinfo = itlist->vars;
1178         foreach(l, tlist)
1179         {
1180                 TargetEntry *tle = (TargetEntry *) lfirst(l);
1181
1182                 if (tle->expr && IsA(tle->expr, Var))
1183                 {
1184                         Var                *var = (Var *) tle->expr;
1185
1186                         vinfo->varno = var->varno;
1187                         vinfo->varattno = var->varattno;
1188                         vinfo->resno = tle->resno;
1189                         vinfo++;
1190                 }
1191                 else
1192                         itlist->has_non_vars = true;
1193         }
1194
1195         itlist->num_vars = (vinfo - itlist->vars);
1196
1197         return itlist;
1198 }
1199
1200 /*
1201  * build_tlist_index_other_vars --- build a restricted tlist index
1202  *
1203  * This is like build_tlist_index, but we only index tlist entries that
1204  * are Vars and belong to some rel other than the one specified.
1205  */
1206 static indexed_tlist *
1207 build_tlist_index_other_vars(List *tlist, Index ignore_rel)
1208 {
1209         indexed_tlist *itlist;
1210         tlist_vinfo *vinfo;
1211         ListCell   *l;
1212
1213         /* Create data structure with enough slots for all tlist entries */
1214         itlist = (indexed_tlist *)
1215                 palloc(offsetof(indexed_tlist, vars) +
1216                            list_length(tlist) * sizeof(tlist_vinfo));
1217
1218         itlist->tlist = tlist;
1219         itlist->has_non_vars = false;
1220
1221         /* Find the desired Vars and fill in the index array */
1222         vinfo = itlist->vars;
1223         foreach(l, tlist)
1224         {
1225                 TargetEntry *tle = (TargetEntry *) lfirst(l);
1226
1227                 if (tle->expr && IsA(tle->expr, Var))
1228                 {
1229                         Var                *var = (Var *) tle->expr;
1230
1231                         if (var->varno != ignore_rel)
1232                         {
1233                                 vinfo->varno = var->varno;
1234                                 vinfo->varattno = var->varattno;
1235                                 vinfo->resno = tle->resno;
1236                                 vinfo++;
1237                         }
1238                 }
1239         }
1240
1241         itlist->num_vars = (vinfo - itlist->vars);
1242
1243         return itlist;
1244 }
1245
1246 /*
1247  * search_indexed_tlist_for_var --- find a Var in an indexed tlist
1248  *
1249  * If a match is found, return a copy of the given Var with suitably
1250  * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
1251  * Also ensure that varnoold is incremented by rtoffset.
1252  * If no match, return NULL.
1253  */
1254 static Var *
1255 search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
1256                                                          Index newvarno, int rtoffset)
1257 {
1258         Index           varno = var->varno;
1259         AttrNumber      varattno = var->varattno;
1260         tlist_vinfo *vinfo;
1261         int                     i;
1262
1263         vinfo = itlist->vars;
1264         i = itlist->num_vars;
1265         while (i-- > 0)
1266         {
1267                 if (vinfo->varno == varno && vinfo->varattno == varattno)
1268                 {
1269                         /* Found a match */
1270                         Var                *newvar = copyVar(var);
1271
1272                         newvar->varno = newvarno;
1273                         newvar->varattno = vinfo->resno;
1274                         if (newvar->varnoold > 0)
1275                                 newvar->varnoold += rtoffset;
1276                         return newvar;
1277                 }
1278                 vinfo++;
1279         }
1280         return NULL;                            /* no match */
1281 }
1282
1283 /*
1284  * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
1285  *
1286  * If a match is found, return a Var constructed to reference the tlist item.
1287  * If no match, return NULL.
1288  *
1289  * NOTE: it is a waste of time to call this if !itlist->has_non_vars
1290  */
1291 static Var *
1292 search_indexed_tlist_for_non_var(Node *node,
1293                                                                  indexed_tlist *itlist, Index newvarno)
1294 {
1295         TargetEntry *tle;
1296
1297         tle = tlist_member(node, itlist->tlist);
1298         if (tle)
1299         {
1300                 /* Found a matching subplan output expression */
1301                 Var                *newvar;
1302
1303                 newvar = makeVar(newvarno,
1304                                                  tle->resno,
1305                                                  exprType((Node *) tle->expr),
1306                                                  exprTypmod((Node *) tle->expr),
1307                                                  0);
1308                 newvar->varnoold = 0;   /* wasn't ever a plain Var */
1309                 newvar->varoattno = 0;
1310                 return newvar;
1311         }
1312         return NULL;                            /* no match */
1313 }
1314
1315 /*
1316  * fix_join_expr
1317  *         Create a new set of targetlist entries or join qual clauses by
1318  *         changing the varno/varattno values of variables in the clauses
1319  *         to reference target list values from the outer and inner join
1320  *         relation target lists.  Also perform opcode lookup and add
1321  *         regclass OIDs to glob->relationOids.
1322  *
1323  * This is used in two different scenarios: a normal join clause, where
1324  * all the Vars in the clause *must* be replaced by OUTER or INNER references;
1325  * and an indexscan being used on the inner side of a nestloop join.
1326  * In the latter case we want to replace the outer-relation Vars by OUTER
1327  * references, while Vars of the inner relation should be adjusted by rtoffset.
1328  * (We also implement RETURNING clause fixup using this second scenario.)
1329  *
1330  * For a normal join, acceptable_rel should be zero so that any failure to
1331  * match a Var will be reported as an error.  For the indexscan case,
1332  * pass inner_itlist = NULL and acceptable_rel = the (not-offseted-yet) ID
1333  * of the inner relation.
1334  *
1335  * 'clauses' is the targetlist or list of join clauses
1336  * 'outer_itlist' is the indexed target list of the outer join relation
1337  * 'inner_itlist' is the indexed target list of the inner join relation,
1338  *              or NULL
1339  * 'acceptable_rel' is either zero or the rangetable index of a relation
1340  *              whose Vars may appear in the clause without provoking an error.
1341  * 'rtoffset' is what to add to varno for Vars of acceptable_rel.
1342  *
1343  * Returns the new expression tree.  The original clause structure is
1344  * not modified.
1345  */
1346 static List *
1347 fix_join_expr(PlannerGlobal *glob,
1348                           List *clauses,
1349                           indexed_tlist *outer_itlist,
1350                           indexed_tlist *inner_itlist,
1351                           Index acceptable_rel,
1352                           int rtoffset)
1353 {
1354         fix_join_expr_context context;
1355
1356         context.glob = glob;
1357         context.outer_itlist = outer_itlist;
1358         context.inner_itlist = inner_itlist;
1359         context.acceptable_rel = acceptable_rel;
1360         context.rtoffset = rtoffset;
1361         return (List *) fix_join_expr_mutator((Node *) clauses, &context);
1362 }
1363
1364 static Node *
1365 fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
1366 {
1367         Var                *newvar;
1368
1369         if (node == NULL)
1370                 return NULL;
1371         if (IsA(node, Var))
1372         {
1373                 Var                *var = (Var *) node;
1374
1375                 /* First look for the var in the input tlists */
1376                 newvar = search_indexed_tlist_for_var(var,
1377                                                                                           context->outer_itlist,
1378                                                                                           OUTER,
1379                                                                                           context->rtoffset);
1380                 if (newvar)
1381                         return (Node *) newvar;
1382                 if (context->inner_itlist)
1383                 {
1384                         newvar = search_indexed_tlist_for_var(var,
1385                                                                                                   context->inner_itlist,
1386                                                                                                   INNER,
1387                                                                                                   context->rtoffset);
1388                         if (newvar)
1389                                 return (Node *) newvar;
1390                 }
1391
1392                 /* If it's for acceptable_rel, adjust and return it */
1393                 if (var->varno == context->acceptable_rel)
1394                 {
1395                         var = copyVar(var);
1396                         var->varno += context->rtoffset;
1397                         var->varnoold += context->rtoffset;
1398                         return (Node *) var;
1399                 }
1400
1401                 /* No referent found for Var */
1402                 elog(ERROR, "variable not found in subplan target lists");
1403         }
1404         /* Try matching more complex expressions too, if tlists have any */
1405         if (context->outer_itlist->has_non_vars)
1406         {
1407                 newvar = search_indexed_tlist_for_non_var(node,
1408                                                                                                   context->outer_itlist,
1409                                                                                                   OUTER);
1410                 if (newvar)
1411                         return (Node *) newvar;
1412         }
1413         if (context->inner_itlist && context->inner_itlist->has_non_vars)
1414         {
1415                 newvar = search_indexed_tlist_for_non_var(node,
1416                                                                                                   context->inner_itlist,
1417                                                                                                   INNER);
1418                 if (newvar)
1419                         return (Node *) newvar;
1420         }
1421         fix_expr_common(context->glob, node);
1422         return expression_tree_mutator(node,
1423                                                                    fix_join_expr_mutator,
1424                                                                    (void *) context);
1425 }
1426
1427 /*
1428  * fix_upper_expr
1429  *              Modifies an expression tree so that all Var nodes reference outputs
1430  *              of a subplan.  Also performs opcode lookup, and adds regclass OIDs to
1431  *              glob->relationOids.
1432  *
1433  * This is used to fix up target and qual expressions of non-join upper-level
1434  * plan nodes.
1435  *
1436  * An error is raised if no matching var can be found in the subplan tlist
1437  * --- so this routine should only be applied to nodes whose subplans'
1438  * targetlists were generated via flatten_tlist() or some such method.
1439  *
1440  * If itlist->has_non_vars is true, then we try to match whole subexpressions
1441  * against elements of the subplan tlist, so that we can avoid recomputing
1442  * expressions that were already computed by the subplan.  (This is relatively
1443  * expensive, so we don't want to try it in the common case where the
1444  * subplan tlist is just a flattened list of Vars.)
1445  *
1446  * 'node': the tree to be fixed (a target item or qual)
1447  * 'subplan_itlist': indexed target list for subplan
1448  * 'rtoffset': how much to increment varnoold by
1449  *
1450  * The resulting tree is a copy of the original in which all Var nodes have
1451  * varno = OUTER, varattno = resno of corresponding subplan target.
1452  * The original tree is not modified.
1453  */
1454 static Node *
1455 fix_upper_expr(PlannerGlobal *glob,
1456                            Node *node,
1457                            indexed_tlist *subplan_itlist,
1458                            int rtoffset)
1459 {
1460         fix_upper_expr_context context;
1461
1462         context.glob = glob;
1463         context.subplan_itlist = subplan_itlist;
1464         context.rtoffset = rtoffset;
1465         return fix_upper_expr_mutator(node, &context);
1466 }
1467
1468 static Node *
1469 fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
1470 {
1471         Var                *newvar;
1472
1473         if (node == NULL)
1474                 return NULL;
1475         if (IsA(node, Var))
1476         {
1477                 Var                *var = (Var *) node;
1478
1479                 newvar = search_indexed_tlist_for_var(var,
1480                                                                                           context->subplan_itlist,
1481                                                                                           OUTER,
1482                                                                                           context->rtoffset);
1483                 if (!newvar)
1484                         elog(ERROR, "variable not found in subplan target list");
1485                 return (Node *) newvar;
1486         }
1487         /* Try matching more complex expressions too, if tlist has any */
1488         if (context->subplan_itlist->has_non_vars)
1489         {
1490                 newvar = search_indexed_tlist_for_non_var(node,
1491                                                                                                   context->subplan_itlist,
1492                                                                                                   OUTER);
1493                 if (newvar)
1494                         return (Node *) newvar;
1495         }
1496         fix_expr_common(context->glob, node);
1497         return expression_tree_mutator(node,
1498                                                                    fix_upper_expr_mutator,
1499                                                                    (void *) context);
1500 }
1501
1502 /*
1503  * set_returning_clause_references
1504  *              Perform setrefs.c's work on a RETURNING targetlist
1505  *
1506  * If the query involves more than just the result table, we have to
1507  * adjust any Vars that refer to other tables to reference junk tlist
1508  * entries in the top plan's targetlist.  Vars referencing the result
1509  * table should be left alone, however (the executor will evaluate them
1510  * using the actual heap tuple, after firing triggers if any).  In the
1511  * adjusted RETURNING list, result-table Vars will still have their
1512  * original varno, but Vars for other rels will have varno OUTER.
1513  *
1514  * We also must perform opcode lookup and add regclass OIDs to
1515  * glob->relationOids.
1516  *
1517  * 'rlist': the RETURNING targetlist to be fixed
1518  * 'topplan': the top Plan node for the query (not yet passed through
1519  *              set_plan_references)
1520  * 'resultRelation': RT index of the associated result relation
1521  *
1522  * Note: we assume that result relations will have rtoffset zero, that is,
1523  * they are not coming from a subplan.
1524  */
1525 List *
1526 set_returning_clause_references(PlannerGlobal *glob,
1527                                                                 List *rlist,
1528                                                                 Plan *topplan,
1529                                                                 Index resultRelation)
1530 {
1531         indexed_tlist *itlist;
1532
1533         /*
1534          * We can perform the desired Var fixup by abusing the fix_join_expr
1535          * machinery that normally handles inner indexscan fixup.  We search the
1536          * top plan's targetlist for Vars of non-result relations, and use
1537          * fix_join_expr to convert RETURNING Vars into references to those tlist
1538          * entries, while leaving result-rel Vars as-is.
1539          */
1540         itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
1541
1542         rlist = fix_join_expr(glob,
1543                                                   rlist,
1544                                                   itlist,
1545                                                   NULL,
1546                                                   resultRelation,
1547                                                   0);
1548
1549         pfree(itlist);
1550
1551         return rlist;
1552 }
1553
1554 /*****************************************************************************
1555  *                                      OPERATOR REGPROC LOOKUP
1556  *****************************************************************************/
1557
1558 /*
1559  * fix_opfuncids
1560  *        Calculate opfuncid field from opno for each OpExpr node in given tree.
1561  *        The given tree can be anything expression_tree_walker handles.
1562  *
1563  * The argument is modified in-place.  (This is OK since we'd want the
1564  * same change for any node, even if it gets visited more than once due to
1565  * shared structure.)
1566  */
1567 void
1568 fix_opfuncids(Node *node)
1569 {
1570         /* This tree walk requires no special setup, so away we go... */
1571         fix_opfuncids_walker(node, NULL);
1572 }
1573
1574 static bool
1575 fix_opfuncids_walker(Node *node, void *context)
1576 {
1577         if (node == NULL)
1578                 return false;
1579         if (IsA(node, OpExpr))
1580                 set_opfuncid((OpExpr *) node);
1581         else if (IsA(node, DistinctExpr))
1582                 set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
1583         else if (IsA(node, NullIfExpr))
1584                 set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
1585         else if (IsA(node, ScalarArrayOpExpr))
1586                 set_sa_opfuncid((ScalarArrayOpExpr *) node);
1587         return expression_tree_walker(node, fix_opfuncids_walker, context);
1588 }
1589
1590 /*
1591  * set_opfuncid
1592  *              Set the opfuncid (procedure OID) in an OpExpr node,
1593  *              if it hasn't been set already.
1594  *
1595  * Because of struct equivalence, this can also be used for
1596  * DistinctExpr and NullIfExpr nodes.
1597  */
1598 void
1599 set_opfuncid(OpExpr *opexpr)
1600 {
1601         if (opexpr->opfuncid == InvalidOid)
1602                 opexpr->opfuncid = get_opcode(opexpr->opno);
1603 }
1604
1605 /*
1606  * set_sa_opfuncid
1607  *              As above, for ScalarArrayOpExpr nodes.
1608  */
1609 void
1610 set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
1611 {
1612         if (opexpr->opfuncid == InvalidOid)
1613                 opexpr->opfuncid = get_opcode(opexpr->opno);
1614 }
1615
1616 /*****************************************************************************
1617  *                                      QUERY DEPENDENCY MANAGEMENT
1618  *****************************************************************************/
1619
1620 /*
1621  * record_plan_function_dependency
1622  *              Mark the current plan as depending on a particular function.
1623  *
1624  * This is exported so that the function-inlining code can record a
1625  * dependency on a function that it's removed from the plan tree.
1626  */
1627 void
1628 record_plan_function_dependency(PlannerGlobal *glob, Oid funcid)
1629 {
1630         /*
1631          * For performance reasons, we don't bother to track built-in functions;
1632          * we just assume they'll never change (or at least not in ways that'd
1633          * invalidate plans using them).  For this purpose we can consider a
1634          * built-in function to be one with OID less than FirstBootstrapObjectId.
1635          * Note that the OID generator guarantees never to generate such an
1636          * OID after startup, even at OID wraparound.
1637          */
1638         if (funcid >= (Oid) FirstBootstrapObjectId)
1639         {
1640                 HeapTuple       func_tuple;
1641                 PlanInvalItem *inval_item;
1642
1643                 func_tuple = SearchSysCache(PROCOID,
1644                                                                         ObjectIdGetDatum(funcid),
1645                                                                         0, 0, 0);
1646                 if (!HeapTupleIsValid(func_tuple))
1647                         elog(ERROR, "cache lookup failed for function %u", funcid);
1648
1649                 inval_item = makeNode(PlanInvalItem);
1650
1651                 /*
1652                  * It would work to use any syscache on pg_proc, but plancache.c
1653                  * expects us to use PROCOID.
1654                  */
1655                 inval_item->cacheId = PROCOID;
1656                 inval_item->tupleId = func_tuple->t_self;
1657
1658                 glob->invalItems = lappend(glob->invalItems, inval_item);
1659
1660                 ReleaseSysCache(func_tuple);
1661         }
1662 }
1663
1664 /*
1665  * extract_query_dependencies
1666  *              Given a list of not-yet-planned queries (i.e. Query nodes),
1667  *              extract their dependencies just as set_plan_references would do.
1668  *
1669  * This is needed by plancache.c to handle invalidation of cached unplanned
1670  * queries.
1671  */
1672 void
1673 extract_query_dependencies(List *queries,
1674                                                    List **relationOids,
1675                                                    List **invalItems)
1676 {
1677         PlannerGlobal glob;
1678
1679         /* Make up a dummy PlannerGlobal so we can use this module's machinery */
1680         MemSet(&glob, 0, sizeof(glob));
1681         glob.type = T_PlannerGlobal;
1682         glob.relationOids = NIL;
1683         glob.invalItems = NIL;
1684
1685         (void) extract_query_dependencies_walker((Node *) queries, &glob);
1686
1687         *relationOids = glob.relationOids;
1688         *invalItems = glob.invalItems;
1689 }
1690
1691 static bool
1692 extract_query_dependencies_walker(Node *node, PlannerGlobal *context)
1693 {
1694         if (node == NULL)
1695                 return false;
1696         /* Extract function dependencies and check for regclass Consts */
1697         fix_expr_common(context, node);
1698         if (IsA(node, Query))
1699         {
1700                 Query      *query = (Query *) node;
1701                 ListCell   *lc;
1702
1703                 /* Collect relation OIDs in this Query's rtable */
1704                 foreach(lc, query->rtable)
1705                 {
1706                         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1707
1708                         if (rte->rtekind == RTE_RELATION)
1709                                 context->relationOids = lappend_oid(context->relationOids,
1710                                                                                                         rte->relid);
1711                 }
1712
1713                 /* And recurse into the query's subexpressions */
1714                 return query_tree_walker(query, extract_query_dependencies_walker,
1715                                                                  (void *) context, 0);
1716         }
1717         return expression_tree_walker(node, extract_query_dependencies_walker,
1718                                                                   (void *) context);
1719 }