1 /*-------------------------------------------------------------------------
4 * Post-processing of a completed plan tree: fix references to subplan
5 * vars, compute regproc values for operators, etc
7 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/optimizer/plan/setrefs.c
14 *-------------------------------------------------------------------------
18 #include "access/transam.h"
19 #include "catalog/pg_type.h"
20 #include "nodes/makefuncs.h"
21 #include "nodes/nodeFuncs.h"
22 #include "optimizer/pathnode.h"
23 #include "optimizer/planmain.h"
24 #include "optimizer/tlist.h"
25 #include "tcop/utility.h"
26 #include "utils/lsyscache.h"
27 #include "utils/syscache.h"
32 Index varno; /* RT index of Var */
33 AttrNumber varattno; /* attr number of Var */
34 AttrNumber resno; /* TLE position of Var */
39 List *tlist; /* underlying target list */
40 int num_vars; /* number of plain Var tlist entries */
41 bool has_ph_vars; /* are there PlaceHolderVar entries? */
42 bool has_non_vars; /* are there other entries? */
43 /* array of num_vars entries: */
44 tlist_vinfo vars[1]; /* VARIABLE LENGTH ARRAY */
45 } indexed_tlist; /* VARIABLE LENGTH STRUCT */
51 } fix_scan_expr_context;
56 indexed_tlist *outer_itlist;
57 indexed_tlist *inner_itlist;
60 } fix_join_expr_context;
65 indexed_tlist *subplan_itlist;
68 } fix_upper_expr_context;
71 * Check if a Const node is a regclass value. We accept plain OID too,
72 * since a regclass Const will get folded to that type if it's an argument
73 * to oideq or similar operators. (This might result in some extraneous
74 * values in a plan's list of relation dependencies, but the worst result
75 * would be occasional useless replans.)
77 #define ISREGCLASSCONST(con) \
78 (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
81 #define fix_scan_list(root, lst, rtoffset) \
82 ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))
84 static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
85 static Plan *set_indexonlyscan_references(PlannerInfo *root,
88 static Plan *set_subqueryscan_references(PlannerInfo *root,
91 static bool trivial_subqueryscan(SubqueryScan *plan);
92 static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
93 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
94 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
95 static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
96 static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset);
97 static void set_dummy_tlist_references(Plan *plan, int rtoffset);
98 static indexed_tlist *build_tlist_index(List *tlist);
99 static Var *search_indexed_tlist_for_var(Var *var,
100 indexed_tlist *itlist,
103 static Var *search_indexed_tlist_for_non_var(Node *node,
104 indexed_tlist *itlist,
106 static Var *search_indexed_tlist_for_sortgroupref(Node *node,
108 indexed_tlist *itlist,
110 static List *fix_join_expr(PlannerInfo *root,
112 indexed_tlist *outer_itlist,
113 indexed_tlist *inner_itlist,
114 Index acceptable_rel, int rtoffset);
115 static Node *fix_join_expr_mutator(Node *node,
116 fix_join_expr_context *context);
117 static Node *fix_upper_expr(PlannerInfo *root,
119 indexed_tlist *subplan_itlist,
122 static Node *fix_upper_expr_mutator(Node *node,
123 fix_upper_expr_context *context);
124 static List *set_returning_clause_references(PlannerInfo *root,
127 Index resultRelation,
129 static bool fix_opfuncids_walker(Node *node, void *context);
130 static bool extract_query_dependencies_walker(Node *node,
131 PlannerInfo *context);
134 /*****************************************************************************
138 *****************************************************************************/
141 * set_plan_references
143 * This is the final processing pass of the planner/optimizer. The plan
144 * tree is complete; we just have to adjust some representational details
145 * for the convenience of the executor:
147 * 1. We flatten the various subquery rangetables into a single list, and
148 * zero out RangeTblEntry fields that are not useful to the executor.
150 * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
152 * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
155 * 4. We compute regproc OIDs for operators (ie, we look up the function
156 * that implements each op).
158 * 5. We create lists of specific objects that the plan depends on.
159 * This will be used by plancache.c to drive invalidation of cached plans.
160 * Relation dependencies are represented by OIDs, and everything else by
161 * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
162 * Currently, relations and user-defined functions are the only types of
163 * objects that are explicitly tracked this way.
165 * We also perform one final optimization step, which is to delete
166 * SubqueryScan plan nodes that aren't doing anything useful (ie, have
167 * no qual and a no-op targetlist). The reason for doing this last is that
168 * it can't readily be done before set_plan_references, because it would
169 * break set_upper_references: the Vars in the subquery's top tlist
170 * wouldn't match up with the Vars in the outer plan tree. The SubqueryScan
171 * serves a necessary function as a buffer between outer query and subquery
172 * variable numbering ... but after we've flattened the rangetable this is
173 * no longer a problem, since then there's only one rtindex namespace.
175 * set_plan_references recursively traverses the whole plan tree.
177 * The return value is normally the same Plan node passed in, but can be
178 * different when the passed-in Plan is a SubqueryScan we decide isn't needed.
180 * The flattened rangetable entries are appended to root->glob->finalrtable.
181 * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the
182 * RT indexes of ModifyTable result relations to root->glob->resultRelations.
183 * Plan dependencies are appended to root->glob->relationOids (for relations)
184 * and root->glob->invalItems (for everything else).
186 * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
187 * to process targetlist and qual expressions. We can assume that the Plan
188 * nodes were just built by the planner and are not multiply referenced, but
189 * it's not so safe to assume that for expression tree nodes.
192 set_plan_references(PlannerInfo *root, Plan *plan)
194 PlannerGlobal *glob = root->glob;
195 int rtoffset = list_length(glob->finalrtable);
199 * In the flat rangetable, we zero out substructure pointers that are not
200 * needed by the executor; this reduces the storage space and copying cost
201 * for cached plans. We keep only the alias and eref Alias fields, which
202 * are needed by EXPLAIN, and the selectedCols and modifiedCols bitmaps,
203 * which are needed for executor-startup permissions checking and for
204 * trigger event checking.
206 foreach(lc, root->parse->rtable)
208 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
209 RangeTblEntry *newrte;
211 /* flat copy to duplicate all the scalar fields */
212 newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
213 memcpy(newrte, rte, sizeof(RangeTblEntry));
215 /* zap unneeded sub-structure */
216 newrte->subquery = NULL;
217 newrte->joinaliasvars = NIL;
218 newrte->funcexpr = NULL;
219 newrte->funccoltypes = NIL;
220 newrte->funccoltypmods = NIL;
221 newrte->funccolcollations = NIL;
222 newrte->values_lists = NIL;
223 newrte->values_collations = NIL;
224 newrte->ctecoltypes = NIL;
225 newrte->ctecoltypmods = NIL;
226 newrte->ctecolcollations = NIL;
228 glob->finalrtable = lappend(glob->finalrtable, newrte);
231 * If it's a plain relation RTE, add the table to relationOids.
233 * We do this even though the RTE might be unreferenced in the plan
234 * tree; this would correspond to cases such as views that were
235 * expanded, child tables that were eliminated by constraint
236 * exclusion, etc. Schema invalidation on such a rel must still force
237 * rebuilding of the plan.
239 * Note we don't bother to avoid duplicate list entries. We could,
240 * but it would probably cost more cycles than it would save.
242 if (newrte->rtekind == RTE_RELATION)
243 glob->relationOids = lappend_oid(glob->relationOids,
248 * Check for RT index overflow; it's very unlikely, but if it did happen,
249 * the executor would get confused by varnos that match the special varno
252 if (IS_SPECIAL_VARNO(list_length(glob->finalrtable)))
254 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
255 errmsg("too many range table entries")));
258 * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
260 foreach(lc, root->rowMarks)
262 PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
265 Assert(IsA(rc, PlanRowMark));
267 /* flat copy is enough since all fields are scalars */
268 newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
269 memcpy(newrc, rc, sizeof(PlanRowMark));
271 /* adjust indexes ... but *not* the rowmarkId */
272 newrc->rti += rtoffset;
273 newrc->prti += rtoffset;
275 glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
278 /* Now fix the Plan tree */
279 return set_plan_refs(root, plan, rtoffset);
283 * set_plan_refs: recurse through the Plan nodes of a single subquery level
286 set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
294 * Plan-type-specific fixes
296 switch (nodeTag(plan))
300 SeqScan *splan = (SeqScan *) plan;
302 splan->scanrelid += rtoffset;
303 splan->plan.targetlist =
304 fix_scan_list(root, splan->plan.targetlist, rtoffset);
306 fix_scan_list(root, splan->plan.qual, rtoffset);
311 IndexScan *splan = (IndexScan *) plan;
313 splan->scan.scanrelid += rtoffset;
314 splan->scan.plan.targetlist =
315 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
316 splan->scan.plan.qual =
317 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
319 fix_scan_list(root, splan->indexqual, rtoffset);
320 splan->indexqualorig =
321 fix_scan_list(root, splan->indexqualorig, rtoffset);
322 splan->indexorderby =
323 fix_scan_list(root, splan->indexorderby, rtoffset);
324 splan->indexorderbyorig =
325 fix_scan_list(root, splan->indexorderbyorig, rtoffset);
328 case T_IndexOnlyScan:
330 IndexOnlyScan *splan = (IndexOnlyScan *) plan;
332 return set_indexonlyscan_references(root, splan, rtoffset);
335 case T_BitmapIndexScan:
337 BitmapIndexScan *splan = (BitmapIndexScan *) plan;
339 splan->scan.scanrelid += rtoffset;
340 /* no need to fix targetlist and qual */
341 Assert(splan->scan.plan.targetlist == NIL);
342 Assert(splan->scan.plan.qual == NIL);
344 fix_scan_list(root, splan->indexqual, rtoffset);
345 splan->indexqualorig =
346 fix_scan_list(root, splan->indexqualorig, rtoffset);
349 case T_BitmapHeapScan:
351 BitmapHeapScan *splan = (BitmapHeapScan *) plan;
353 splan->scan.scanrelid += rtoffset;
354 splan->scan.plan.targetlist =
355 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
356 splan->scan.plan.qual =
357 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
358 splan->bitmapqualorig =
359 fix_scan_list(root, splan->bitmapqualorig, rtoffset);
364 TidScan *splan = (TidScan *) plan;
366 splan->scan.scanrelid += rtoffset;
367 splan->scan.plan.targetlist =
368 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
369 splan->scan.plan.qual =
370 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
372 fix_scan_list(root, splan->tidquals, rtoffset);
376 /* Needs special treatment, see comments below */
377 return set_subqueryscan_references(root,
378 (SubqueryScan *) plan,
382 FunctionScan *splan = (FunctionScan *) plan;
384 splan->scan.scanrelid += rtoffset;
385 splan->scan.plan.targetlist =
386 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
387 splan->scan.plan.qual =
388 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
390 fix_scan_expr(root, splan->funcexpr, rtoffset);
395 ValuesScan *splan = (ValuesScan *) plan;
397 splan->scan.scanrelid += rtoffset;
398 splan->scan.plan.targetlist =
399 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
400 splan->scan.plan.qual =
401 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
402 splan->values_lists =
403 fix_scan_list(root, splan->values_lists, rtoffset);
408 CteScan *splan = (CteScan *) plan;
410 splan->scan.scanrelid += rtoffset;
411 splan->scan.plan.targetlist =
412 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
413 splan->scan.plan.qual =
414 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
417 case T_WorkTableScan:
419 WorkTableScan *splan = (WorkTableScan *) plan;
421 splan->scan.scanrelid += rtoffset;
422 splan->scan.plan.targetlist =
423 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
424 splan->scan.plan.qual =
425 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
430 ForeignScan *splan = (ForeignScan *) plan;
432 splan->scan.scanrelid += rtoffset;
433 splan->scan.plan.targetlist =
434 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
435 splan->scan.plan.qual =
436 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
438 fix_scan_list(root, splan->fdw_exprs, rtoffset);
445 set_join_references(root, (Join *) plan, rtoffset);
455 * These plan types don't actually bother to evaluate their
456 * targetlists, because they just return their unmodified input
457 * tuples. Even though the targetlist won't be used by the
458 * executor, we fix it up for possible use by EXPLAIN (not to
459 * mention ease of debugging --- wrong varnos are very confusing).
461 set_dummy_tlist_references(plan, rtoffset);
464 * Since these plan types don't check quals either, we should not
465 * find any qual expression attached to them.
467 Assert(plan->qual == NIL);
471 LockRows *splan = (LockRows *) plan;
474 * Like the plan types above, LockRows doesn't evaluate its
475 * tlist or quals. But we have to fix up the RT indexes in
478 set_dummy_tlist_references(plan, rtoffset);
479 Assert(splan->plan.qual == NIL);
481 foreach(l, splan->rowMarks)
483 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
486 rc->prti += rtoffset;
492 Limit *splan = (Limit *) plan;
495 * Like the plan types above, Limit doesn't evaluate its tlist
496 * or quals. It does have live expressions for limit/offset,
497 * however; and those cannot contain subplan variable refs, so
498 * fix_scan_expr works for them.
500 set_dummy_tlist_references(plan, rtoffset);
501 Assert(splan->plan.qual == NIL);
504 fix_scan_expr(root, splan->limitOffset, rtoffset);
506 fix_scan_expr(root, splan->limitCount, rtoffset);
511 set_upper_references(root, plan, rtoffset);
515 WindowAgg *wplan = (WindowAgg *) plan;
517 set_upper_references(root, plan, rtoffset);
520 * Like Limit node limit/offset expressions, WindowAgg has
521 * frame offset expressions, which cannot contain subplan
522 * variable refs, so fix_scan_expr works for them.
525 fix_scan_expr(root, wplan->startOffset, rtoffset);
527 fix_scan_expr(root, wplan->endOffset, rtoffset);
532 Result *splan = (Result *) plan;
535 * Result may or may not have a subplan; if not, it's more
536 * like a scan node than an upper node.
538 if (splan->plan.lefttree != NULL)
539 set_upper_references(root, plan, rtoffset);
542 splan->plan.targetlist =
543 fix_scan_list(root, splan->plan.targetlist, rtoffset);
545 fix_scan_list(root, splan->plan.qual, rtoffset);
547 /* resconstantqual can't contain any subplan variable refs */
548 splan->resconstantqual =
549 fix_scan_expr(root, splan->resconstantqual, rtoffset);
554 ModifyTable *splan = (ModifyTable *) plan;
556 Assert(splan->plan.targetlist == NIL);
557 Assert(splan->plan.qual == NIL);
559 if (splan->returningLists)
567 * Pass each per-subplan returningList through
568 * set_returning_clause_references().
570 Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
571 Assert(list_length(splan->returningLists) == list_length(splan->plans));
572 forthree(lcrl, splan->returningLists,
573 lcrr, splan->resultRelations,
576 List *rlist = (List *) lfirst(lcrl);
577 Index resultrel = lfirst_int(lcrr);
578 Plan *subplan = (Plan *) lfirst(lcp);
580 rlist = set_returning_clause_references(root,
585 newRL = lappend(newRL, rlist);
587 splan->returningLists = newRL;
590 * Set up the visible plan targetlist as being the same as
591 * the first RETURNING list. This is for the use of
592 * EXPLAIN; the executor won't pay any attention to the
593 * targetlist. We postpone this step until here so that
594 * we don't have to do set_returning_clause_references()
595 * twice on identical targetlists.
597 splan->plan.targetlist = copyObject(linitial(newRL));
600 foreach(l, splan->resultRelations)
602 lfirst_int(l) += rtoffset;
604 foreach(l, splan->rowMarks)
606 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
609 rc->prti += rtoffset;
611 foreach(l, splan->plans)
613 lfirst(l) = set_plan_refs(root,
619 * Append this ModifyTable node's final result relation RT
620 * index(es) to the global list for the plan, and set its
621 * resultRelIndex to reflect their starting position in the
624 splan->resultRelIndex = list_length(root->glob->resultRelations);
625 root->glob->resultRelations =
626 list_concat(root->glob->resultRelations,
627 list_copy(splan->resultRelations));
632 Append *splan = (Append *) plan;
635 * Append, like Sort et al, doesn't actually evaluate its
636 * targetlist or check quals.
638 set_dummy_tlist_references(plan, rtoffset);
639 Assert(splan->plan.qual == NIL);
640 foreach(l, splan->appendplans)
642 lfirst(l) = set_plan_refs(root,
650 MergeAppend *splan = (MergeAppend *) plan;
653 * MergeAppend, like Sort et al, doesn't actually evaluate its
654 * targetlist or check quals.
656 set_dummy_tlist_references(plan, rtoffset);
657 Assert(splan->plan.qual == NIL);
658 foreach(l, splan->mergeplans)
660 lfirst(l) = set_plan_refs(root,
666 case T_RecursiveUnion:
667 /* This doesn't evaluate targetlist or check quals either */
668 set_dummy_tlist_references(plan, rtoffset);
669 Assert(plan->qual == NIL);
673 BitmapAnd *splan = (BitmapAnd *) plan;
675 /* BitmapAnd works like Append, but has no tlist */
676 Assert(splan->plan.targetlist == NIL);
677 Assert(splan->plan.qual == NIL);
678 foreach(l, splan->bitmapplans)
680 lfirst(l) = set_plan_refs(root,
688 BitmapOr *splan = (BitmapOr *) plan;
690 /* BitmapOr works like Append, but has no tlist */
691 Assert(splan->plan.targetlist == NIL);
692 Assert(splan->plan.qual == NIL);
693 foreach(l, splan->bitmapplans)
695 lfirst(l) = set_plan_refs(root,
702 elog(ERROR, "unrecognized node type: %d",
703 (int) nodeTag(plan));
708 * Now recurse into child plans, if any
710 * NOTE: it is essential that we recurse into child plans AFTER we set
711 * subplan references in this plan's tlist and quals. If we did the
712 * reference-adjustments bottom-up, then we would fail to match this
713 * plan's var nodes against the already-modified nodes of the children.
715 plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
716 plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
722 * set_indexonlyscan_references
723 * Do set_plan_references processing on an IndexOnlyScan
725 * This is unlike the handling of a plain IndexScan because we have to
726 * convert Vars referencing the heap into Vars referencing the index.
727 * We can use the fix_upper_expr machinery for that, by working from a
728 * targetlist describing the index columns.
731 set_indexonlyscan_references(PlannerInfo *root,
735 indexed_tlist *index_itlist;
737 index_itlist = build_tlist_index(plan->indextlist);
739 plan->scan.scanrelid += rtoffset;
740 plan->scan.plan.targetlist = (List *)
742 (Node *) plan->scan.plan.targetlist,
746 plan->scan.plan.qual = (List *)
748 (Node *) plan->scan.plan.qual,
752 /* indexqual is already transformed to reference index columns */
753 plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset);
754 /* indexorderby is already transformed to reference index columns */
755 plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset);
756 /* indextlist must NOT be transformed to reference index columns */
757 plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset);
761 return (Plan *) plan;
765 * set_subqueryscan_references
766 * Do set_plan_references processing on a SubqueryScan
768 * We try to strip out the SubqueryScan entirely; if we can't, we have
769 * to do the normal processing on it.
772 set_subqueryscan_references(PlannerInfo *root,
779 /* Need to look up the subquery's RelOptInfo, since we need its subroot */
780 rel = find_base_rel(root, plan->scan.scanrelid);
781 Assert(rel->subplan == plan->subplan);
783 /* Recursively process the subplan */
784 plan->subplan = set_plan_references(rel->subroot, plan->subplan);
786 if (trivial_subqueryscan(plan))
789 * We can omit the SubqueryScan node and just pull up the subplan.
794 result = plan->subplan;
796 /* We have to be sure we don't lose any initplans */
797 result->initPlan = list_concat(plan->scan.plan.initPlan,
801 * We also have to transfer the SubqueryScan's result-column names
802 * into the subplan, else columns sent to client will be improperly
803 * labeled if this is the topmost plan level. Copy the "source
804 * column" information too.
806 forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist)
808 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
809 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
811 ctle->resname = ptle->resname;
812 ctle->resorigtbl = ptle->resorigtbl;
813 ctle->resorigcol = ptle->resorigcol;
819 * Keep the SubqueryScan node. We have to do the processing that
820 * set_plan_references would otherwise have done on it. Notice we do
821 * not do set_upper_references() here, because a SubqueryScan will
822 * always have been created with correct references to its subplan's
823 * outputs to begin with.
825 plan->scan.scanrelid += rtoffset;
826 plan->scan.plan.targetlist =
827 fix_scan_list(root, plan->scan.plan.targetlist, rtoffset);
828 plan->scan.plan.qual =
829 fix_scan_list(root, plan->scan.plan.qual, rtoffset);
831 result = (Plan *) plan;
838 * trivial_subqueryscan
839 * Detect whether a SubqueryScan can be deleted from the plan tree.
841 * We can delete it if it has no qual to check and the targetlist just
842 * regurgitates the output of the child plan.
845 trivial_subqueryscan(SubqueryScan *plan)
851 if (plan->scan.plan.qual != NIL)
854 if (list_length(plan->scan.plan.targetlist) !=
855 list_length(plan->subplan->targetlist))
856 return false; /* tlists not same length */
859 forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
861 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
862 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
864 if (ptle->resjunk != ctle->resjunk)
865 return false; /* tlist doesn't match junk status */
868 * We accept either a Var referencing the corresponding element of the
869 * subplan tlist, or a Const equaling the subplan element. See
870 * generate_setop_tlist() for motivation.
872 if (ptle->expr && IsA(ptle->expr, Var))
874 Var *var = (Var *) ptle->expr;
876 Assert(var->varno == plan->scan.scanrelid);
877 Assert(var->varlevelsup == 0);
878 if (var->varattno != attrno)
879 return false; /* out of order */
881 else if (ptle->expr && IsA(ptle->expr, Const))
883 if (!equal(ptle->expr, ctle->expr))
899 * fix_scan_expr and friends do this enough times that it's worth having
900 * a bespoke routine instead of using the generic copyObject() function.
905 Var *newvar = (Var *) palloc(sizeof(Var));
913 * Do generic set_plan_references processing on an expression node
915 * This is code that is common to all variants of expression-fixing.
916 * We must look up operator opcode info for OpExpr and related nodes,
917 * add OIDs from regclass Const nodes into root->glob->relationOids, and
918 * add catalog TIDs for user-defined functions into root->glob->invalItems.
920 * We assume it's okay to update opcode info in-place. So this could possibly
921 * scribble on the planner's input data structures, but it's OK.
924 fix_expr_common(PlannerInfo *root, Node *node)
926 /* We assume callers won't call us on a NULL pointer */
927 if (IsA(node, Aggref))
929 record_plan_function_dependency(root,
930 ((Aggref *) node)->aggfnoid);
932 else if (IsA(node, WindowFunc))
934 record_plan_function_dependency(root,
935 ((WindowFunc *) node)->winfnoid);
937 else if (IsA(node, FuncExpr))
939 record_plan_function_dependency(root,
940 ((FuncExpr *) node)->funcid);
942 else if (IsA(node, OpExpr))
944 set_opfuncid((OpExpr *) node);
945 record_plan_function_dependency(root,
946 ((OpExpr *) node)->opfuncid);
948 else if (IsA(node, DistinctExpr))
950 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
951 record_plan_function_dependency(root,
952 ((DistinctExpr *) node)->opfuncid);
954 else if (IsA(node, NullIfExpr))
956 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
957 record_plan_function_dependency(root,
958 ((NullIfExpr *) node)->opfuncid);
960 else if (IsA(node, ScalarArrayOpExpr))
962 set_sa_opfuncid((ScalarArrayOpExpr *) node);
963 record_plan_function_dependency(root,
964 ((ScalarArrayOpExpr *) node)->opfuncid);
966 else if (IsA(node, ArrayCoerceExpr))
968 if (OidIsValid(((ArrayCoerceExpr *) node)->elemfuncid))
969 record_plan_function_dependency(root,
970 ((ArrayCoerceExpr *) node)->elemfuncid);
972 else if (IsA(node, Const))
974 Const *con = (Const *) node;
976 /* Check for regclass reference */
977 if (ISREGCLASSCONST(con))
978 root->glob->relationOids =
979 lappend_oid(root->glob->relationOids,
980 DatumGetObjectId(con->constvalue));
986 * Do set_plan_references processing on a scan-level expression
988 * This consists of incrementing all Vars' varnos by rtoffset,
989 * looking up operator opcode info for OpExpr and related nodes,
990 * and adding OIDs from regclass Const nodes into root->glob->relationOids.
993 fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
995 fix_scan_expr_context context;
998 context.rtoffset = rtoffset;
1000 if (rtoffset != 0 || root->glob->lastPHId != 0)
1002 return fix_scan_expr_mutator(node, &context);
1007 * If rtoffset == 0, we don't need to change any Vars, and if there
1008 * are no placeholders anywhere we won't need to remove them. Then
1009 * it's OK to just scribble on the input node tree instead of copying
1010 * (since the only change, filling in any unset opfuncid fields, is
1011 * harmless). This saves just enough cycles to be noticeable on
1014 (void) fix_scan_expr_walker(node, &context);
1020 fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
1026 Var *var = copyVar((Var *) node);
1028 Assert(var->varlevelsup == 0);
1031 * We should not see any Vars marked INNER_VAR or OUTER_VAR. But an
1032 * indexqual expression could contain INDEX_VAR Vars.
1034 Assert(var->varno != INNER_VAR);
1035 Assert(var->varno != OUTER_VAR);
1036 if (!IS_SPECIAL_VARNO(var->varno))
1037 var->varno += context->rtoffset;
1038 if (var->varnoold > 0)
1039 var->varnoold += context->rtoffset;
1040 return (Node *) var;
1042 if (IsA(node, CurrentOfExpr))
1044 CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
1046 Assert(cexpr->cvarno != INNER_VAR);
1047 Assert(cexpr->cvarno != OUTER_VAR);
1048 if (!IS_SPECIAL_VARNO(cexpr->cvarno))
1049 cexpr->cvarno += context->rtoffset;
1050 return (Node *) cexpr;
1052 if (IsA(node, PlaceHolderVar))
1054 /* At scan level, we should always just evaluate the contained expr */
1055 PlaceHolderVar *phv = (PlaceHolderVar *) node;
1057 return fix_scan_expr_mutator((Node *) phv->phexpr, context);
1059 fix_expr_common(context->root, node);
1060 return expression_tree_mutator(node, fix_scan_expr_mutator,
1065 fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
1069 Assert(!IsA(node, PlaceHolderVar));
1070 fix_expr_common(context->root, node);
1071 return expression_tree_walker(node, fix_scan_expr_walker,
1076 * set_join_references
1077 * Modify the target list and quals of a join node to reference its
1078 * subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting
1079 * attno values to the result domain number of either the corresponding
1080 * outer or inner join tuple item. Also perform opcode lookup for these
1081 * expressions. and add regclass OIDs to root->glob->relationOids.
1084 set_join_references(PlannerInfo *root, Join *join, int rtoffset)
1086 Plan *outer_plan = join->plan.lefttree;
1087 Plan *inner_plan = join->plan.righttree;
1088 indexed_tlist *outer_itlist;
1089 indexed_tlist *inner_itlist;
1091 outer_itlist = build_tlist_index(outer_plan->targetlist);
1092 inner_itlist = build_tlist_index(inner_plan->targetlist);
1094 /* All join plans have tlist, qual, and joinqual */
1095 join->plan.targetlist = fix_join_expr(root,
1096 join->plan.targetlist,
1101 join->plan.qual = fix_join_expr(root,
1107 join->joinqual = fix_join_expr(root,
1114 /* Now do join-type-specific stuff */
1115 if (IsA(join, NestLoop))
1117 NestLoop *nl = (NestLoop *) join;
1120 foreach(lc, nl->nestParams)
1122 NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
1124 nlp->paramval = (Var *) fix_upper_expr(root,
1125 (Node *) nlp->paramval,
1129 /* Check we replaced any PlaceHolderVar with simple Var */
1130 if (!(IsA(nlp->paramval, Var) &&
1131 nlp->paramval->varno == OUTER_VAR))
1132 elog(ERROR, "NestLoopParam was not reduced to a simple Var");
1135 else if (IsA(join, MergeJoin))
1137 MergeJoin *mj = (MergeJoin *) join;
1139 mj->mergeclauses = fix_join_expr(root,
1146 else if (IsA(join, HashJoin))
1148 HashJoin *hj = (HashJoin *) join;
1150 hj->hashclauses = fix_join_expr(root,
1158 pfree(outer_itlist);
1159 pfree(inner_itlist);
1163 * set_upper_references
1164 * Update the targetlist and quals of an upper-level plan node
1165 * to refer to the tuples returned by its lefttree subplan.
1166 * Also perform opcode lookup for these expressions, and
1167 * add regclass OIDs to root->glob->relationOids.
1169 * This is used for single-input plan types like Agg, Group, Result.
1171 * In most cases, we have to match up individual Vars in the tlist and
1172 * qual expressions with elements of the subplan's tlist (which was
1173 * generated by flatten_tlist() from these selfsame expressions, so it
1174 * should have all the required variables). There is an important exception,
1175 * however: GROUP BY and ORDER BY expressions will have been pushed into the
1176 * subplan tlist unflattened. If these values are also needed in the output
1177 * then we want to reference the subplan tlist element rather than recomputing
1181 set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
1183 Plan *subplan = plan->lefttree;
1184 indexed_tlist *subplan_itlist;
1185 List *output_targetlist;
1188 subplan_itlist = build_tlist_index(subplan->targetlist);
1190 output_targetlist = NIL;
1191 foreach(l, plan->targetlist)
1193 TargetEntry *tle = (TargetEntry *) lfirst(l);
1196 /* If it's a non-Var sort/group item, first try to match by sortref */
1197 if (tle->ressortgroupref != 0 && !IsA(tle->expr, Var))
1200 search_indexed_tlist_for_sortgroupref((Node *) tle->expr,
1201 tle->ressortgroupref,
1205 newexpr = fix_upper_expr(root,
1212 newexpr = fix_upper_expr(root,
1217 tle = flatCopyTargetEntry(tle);
1218 tle->expr = (Expr *) newexpr;
1219 output_targetlist = lappend(output_targetlist, tle);
1221 plan->targetlist = output_targetlist;
1223 plan->qual = (List *)
1224 fix_upper_expr(root,
1225 (Node *) plan->qual,
1230 pfree(subplan_itlist);
1234 * set_dummy_tlist_references
1235 * Replace the targetlist of an upper-level plan node with a simple
1236 * list of OUTER_VAR references to its child.
1238 * This is used for plan types like Sort and Append that don't evaluate
1239 * their targetlists. Although the executor doesn't care at all what's in
1240 * the tlist, EXPLAIN needs it to be realistic.
1242 * Note: we could almost use set_upper_references() here, but it fails for
1243 * Append for lack of a lefttree subplan. Single-purpose code is faster
1247 set_dummy_tlist_references(Plan *plan, int rtoffset)
1249 List *output_targetlist;
1252 output_targetlist = NIL;
1253 foreach(l, plan->targetlist)
1255 TargetEntry *tle = (TargetEntry *) lfirst(l);
1256 Var *oldvar = (Var *) tle->expr;
1259 newvar = makeVar(OUTER_VAR,
1261 exprType((Node *) oldvar),
1262 exprTypmod((Node *) oldvar),
1263 exprCollation((Node *) oldvar),
1265 if (IsA(oldvar, Var))
1267 newvar->varnoold = oldvar->varno + rtoffset;
1268 newvar->varoattno = oldvar->varattno;
1272 newvar->varnoold = 0; /* wasn't ever a plain Var */
1273 newvar->varoattno = 0;
1276 tle = flatCopyTargetEntry(tle);
1277 tle->expr = (Expr *) newvar;
1278 output_targetlist = lappend(output_targetlist, tle);
1280 plan->targetlist = output_targetlist;
1282 /* We don't touch plan->qual here */
1287 * build_tlist_index --- build an index data structure for a child tlist
1289 * In most cases, subplan tlists will be "flat" tlists with only Vars,
1290 * so we try to optimize that case by extracting information about Vars
1291 * in advance. Matching a parent tlist to a child is still an O(N^2)
1292 * operation, but at least with a much smaller constant factor than plain
1293 * tlist_member() searches.
1295 * The result of this function is an indexed_tlist struct to pass to
1296 * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
1297 * When done, the indexed_tlist may be freed with a single pfree().
1299 static indexed_tlist *
1300 build_tlist_index(List *tlist)
1302 indexed_tlist *itlist;
1306 /* Create data structure with enough slots for all tlist entries */
1307 itlist = (indexed_tlist *)
1308 palloc(offsetof(indexed_tlist, vars) +
1309 list_length(tlist) * sizeof(tlist_vinfo));
1311 itlist->tlist = tlist;
1312 itlist->has_ph_vars = false;
1313 itlist->has_non_vars = false;
1315 /* Find the Vars and fill in the index array */
1316 vinfo = itlist->vars;
1319 TargetEntry *tle = (TargetEntry *) lfirst(l);
1321 if (tle->expr && IsA(tle->expr, Var))
1323 Var *var = (Var *) tle->expr;
1325 vinfo->varno = var->varno;
1326 vinfo->varattno = var->varattno;
1327 vinfo->resno = tle->resno;
1330 else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
1331 itlist->has_ph_vars = true;
1333 itlist->has_non_vars = true;
1336 itlist->num_vars = (vinfo - itlist->vars);
1342 * build_tlist_index_other_vars --- build a restricted tlist index
1344 * This is like build_tlist_index, but we only index tlist entries that
1345 * are Vars belonging to some rel other than the one specified. We will set
1346 * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
1347 * (so nothing other than Vars and PlaceHolderVars can be matched).
1349 static indexed_tlist *
1350 build_tlist_index_other_vars(List *tlist, Index ignore_rel)
1352 indexed_tlist *itlist;
1356 /* Create data structure with enough slots for all tlist entries */
1357 itlist = (indexed_tlist *)
1358 palloc(offsetof(indexed_tlist, vars) +
1359 list_length(tlist) * sizeof(tlist_vinfo));
1361 itlist->tlist = tlist;
1362 itlist->has_ph_vars = false;
1363 itlist->has_non_vars = false;
1365 /* Find the desired Vars and fill in the index array */
1366 vinfo = itlist->vars;
1369 TargetEntry *tle = (TargetEntry *) lfirst(l);
1371 if (tle->expr && IsA(tle->expr, Var))
1373 Var *var = (Var *) tle->expr;
1375 if (var->varno != ignore_rel)
1377 vinfo->varno = var->varno;
1378 vinfo->varattno = var->varattno;
1379 vinfo->resno = tle->resno;
1383 else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
1384 itlist->has_ph_vars = true;
1387 itlist->num_vars = (vinfo - itlist->vars);
1393 * search_indexed_tlist_for_var --- find a Var in an indexed tlist
1395 * If a match is found, return a copy of the given Var with suitably
1396 * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
1397 * Also ensure that varnoold is incremented by rtoffset.
1398 * If no match, return NULL.
1401 search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
1402 Index newvarno, int rtoffset)
1404 Index varno = var->varno;
1405 AttrNumber varattno = var->varattno;
1409 vinfo = itlist->vars;
1410 i = itlist->num_vars;
1413 if (vinfo->varno == varno && vinfo->varattno == varattno)
1416 Var *newvar = copyVar(var);
1418 newvar->varno = newvarno;
1419 newvar->varattno = vinfo->resno;
1420 if (newvar->varnoold > 0)
1421 newvar->varnoold += rtoffset;
1426 return NULL; /* no match */
1430 * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
1432 * If a match is found, return a Var constructed to reference the tlist item.
1433 * If no match, return NULL.
1435 * NOTE: it is a waste of time to call this unless itlist->has_ph_vars or
1436 * itlist->has_non_vars
1439 search_indexed_tlist_for_non_var(Node *node,
1440 indexed_tlist *itlist, Index newvarno)
1444 tle = tlist_member(node, itlist->tlist);
1447 /* Found a matching subplan output expression */
1450 newvar = makeVarFromTargetEntry(newvarno, tle);
1451 newvar->varnoold = 0; /* wasn't ever a plain Var */
1452 newvar->varoattno = 0;
1455 return NULL; /* no match */
1459 * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
1460 * (which is assumed not to be just a Var)
1462 * If a match is found, return a Var constructed to reference the tlist item.
1463 * If no match, return NULL.
1465 * This is needed to ensure that we select the right subplan TLE in cases
1466 * where there are multiple textually-equal()-but-volatile sort expressions.
1467 * And it's also faster than search_indexed_tlist_for_non_var.
1470 search_indexed_tlist_for_sortgroupref(Node *node,
1472 indexed_tlist *itlist,
1477 foreach(lc, itlist->tlist)
1479 TargetEntry *tle = (TargetEntry *) lfirst(lc);
1481 /* The equal() check should be redundant, but let's be paranoid */
1482 if (tle->ressortgroupref == sortgroupref &&
1483 equal(node, tle->expr))
1485 /* Found a matching subplan output expression */
1488 newvar = makeVarFromTargetEntry(newvarno, tle);
1489 newvar->varnoold = 0; /* wasn't ever a plain Var */
1490 newvar->varoattno = 0;
1494 return NULL; /* no match */
1499 * Create a new set of targetlist entries or join qual clauses by
1500 * changing the varno/varattno values of variables in the clauses
1501 * to reference target list values from the outer and inner join
1502 * relation target lists. Also perform opcode lookup and add
1503 * regclass OIDs to root->glob->relationOids.
1505 * This is used in two different scenarios: a normal join clause, where all
1506 * the Vars in the clause *must* be replaced by OUTER_VAR or INNER_VAR
1507 * references; and a RETURNING clause, which may contain both Vars of the
1508 * target relation and Vars of other relations. In the latter case we want
1509 * to replace the other-relation Vars by OUTER_VAR references, while leaving
1510 * target Vars alone.
1512 * For a normal join, acceptable_rel should be zero so that any failure to
1513 * match a Var will be reported as an error. For the RETURNING case, pass
1514 * inner_itlist = NULL and acceptable_rel = the ID of the target relation.
1516 * 'clauses' is the targetlist or list of join clauses
1517 * 'outer_itlist' is the indexed target list of the outer join relation
1518 * 'inner_itlist' is the indexed target list of the inner join relation,
1520 * 'acceptable_rel' is either zero or the rangetable index of a relation
1521 * whose Vars may appear in the clause without provoking an error
1522 * 'rtoffset': how much to increment varnoold by
1524 * Returns the new expression tree. The original clause structure is
1528 fix_join_expr(PlannerInfo *root,
1530 indexed_tlist *outer_itlist,
1531 indexed_tlist *inner_itlist,
1532 Index acceptable_rel,
1535 fix_join_expr_context context;
1537 context.root = root;
1538 context.outer_itlist = outer_itlist;
1539 context.inner_itlist = inner_itlist;
1540 context.acceptable_rel = acceptable_rel;
1541 context.rtoffset = rtoffset;
1542 return (List *) fix_join_expr_mutator((Node *) clauses, &context);
1546 fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
1554 Var *var = (Var *) node;
1556 /* First look for the var in the input tlists */
1557 newvar = search_indexed_tlist_for_var(var,
1558 context->outer_itlist,
1562 return (Node *) newvar;
1563 if (context->inner_itlist)
1565 newvar = search_indexed_tlist_for_var(var,
1566 context->inner_itlist,
1570 return (Node *) newvar;
1573 /* If it's for acceptable_rel, adjust and return it */
1574 if (var->varno == context->acceptable_rel)
1577 var->varno += context->rtoffset;
1578 if (var->varnoold > 0)
1579 var->varnoold += context->rtoffset;
1580 return (Node *) var;
1583 /* No referent found for Var */
1584 elog(ERROR, "variable not found in subplan target lists");
1586 if (IsA(node, PlaceHolderVar))
1588 PlaceHolderVar *phv = (PlaceHolderVar *) node;
1590 /* See if the PlaceHolderVar has bubbled up from a lower plan node */
1591 if (context->outer_itlist->has_ph_vars)
1593 newvar = search_indexed_tlist_for_non_var((Node *) phv,
1594 context->outer_itlist,
1597 return (Node *) newvar;
1599 if (context->inner_itlist && context->inner_itlist->has_ph_vars)
1601 newvar = search_indexed_tlist_for_non_var((Node *) phv,
1602 context->inner_itlist,
1605 return (Node *) newvar;
1608 /* If not supplied by input plans, evaluate the contained expr */
1609 return fix_join_expr_mutator((Node *) phv->phexpr, context);
1611 /* Try matching more complex expressions too, if tlists have any */
1612 if (context->outer_itlist->has_non_vars)
1614 newvar = search_indexed_tlist_for_non_var(node,
1615 context->outer_itlist,
1618 return (Node *) newvar;
1620 if (context->inner_itlist && context->inner_itlist->has_non_vars)
1622 newvar = search_indexed_tlist_for_non_var(node,
1623 context->inner_itlist,
1626 return (Node *) newvar;
1628 fix_expr_common(context->root, node);
1629 return expression_tree_mutator(node,
1630 fix_join_expr_mutator,
1636 * Modifies an expression tree so that all Var nodes reference outputs
1637 * of a subplan. Also performs opcode lookup, and adds regclass OIDs to
1638 * root->glob->relationOids.
1640 * This is used to fix up target and qual expressions of non-join upper-level
1641 * plan nodes, as well as index-only scan nodes.
1643 * An error is raised if no matching var can be found in the subplan tlist
1644 * --- so this routine should only be applied to nodes whose subplans'
1645 * targetlists were generated via flatten_tlist() or some such method.
1647 * If itlist->has_non_vars is true, then we try to match whole subexpressions
1648 * against elements of the subplan tlist, so that we can avoid recomputing
1649 * expressions that were already computed by the subplan. (This is relatively
1650 * expensive, so we don't want to try it in the common case where the
1651 * subplan tlist is just a flattened list of Vars.)
1653 * 'node': the tree to be fixed (a target item or qual)
1654 * 'subplan_itlist': indexed target list for subplan (or index)
1655 * 'newvarno': varno to use for Vars referencing tlist elements
1656 * 'rtoffset': how much to increment varnoold by
1658 * The resulting tree is a copy of the original in which all Var nodes have
1659 * varno = newvarno, varattno = resno of corresponding targetlist element.
1660 * The original tree is not modified.
1663 fix_upper_expr(PlannerInfo *root,
1665 indexed_tlist *subplan_itlist,
1669 fix_upper_expr_context context;
1671 context.root = root;
1672 context.subplan_itlist = subplan_itlist;
1673 context.newvarno = newvarno;
1674 context.rtoffset = rtoffset;
1675 return fix_upper_expr_mutator(node, &context);
1679 fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
1687 Var *var = (Var *) node;
1689 newvar = search_indexed_tlist_for_var(var,
1690 context->subplan_itlist,
1694 elog(ERROR, "variable not found in subplan target list");
1695 return (Node *) newvar;
1697 if (IsA(node, PlaceHolderVar))
1699 PlaceHolderVar *phv = (PlaceHolderVar *) node;
1701 /* See if the PlaceHolderVar has bubbled up from a lower plan node */
1702 if (context->subplan_itlist->has_ph_vars)
1704 newvar = search_indexed_tlist_for_non_var((Node *) phv,
1705 context->subplan_itlist,
1708 return (Node *) newvar;
1710 /* If not supplied by input plan, evaluate the contained expr */
1711 return fix_upper_expr_mutator((Node *) phv->phexpr, context);
1713 /* Try matching more complex expressions too, if tlist has any */
1714 if (context->subplan_itlist->has_non_vars)
1716 newvar = search_indexed_tlist_for_non_var(node,
1717 context->subplan_itlist,
1720 return (Node *) newvar;
1722 fix_expr_common(context->root, node);
1723 return expression_tree_mutator(node,
1724 fix_upper_expr_mutator,
1729 * set_returning_clause_references
1730 * Perform setrefs.c's work on a RETURNING targetlist
1732 * If the query involves more than just the result table, we have to
1733 * adjust any Vars that refer to other tables to reference junk tlist
1734 * entries in the top subplan's targetlist. Vars referencing the result
1735 * table should be left alone, however (the executor will evaluate them
1736 * using the actual heap tuple, after firing triggers if any). In the
1737 * adjusted RETURNING list, result-table Vars will have their original
1738 * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
1740 * We also must perform opcode lookup and add regclass OIDs to
1741 * root->glob->relationOids.
1743 * 'rlist': the RETURNING targetlist to be fixed
1744 * 'topplan': the top subplan node that will be just below the ModifyTable
1745 * node (note it's not yet passed through set_plan_refs)
1746 * 'resultRelation': RT index of the associated result relation
1747 * 'rtoffset': how much to increment varnos by
1749 * Note: the given 'root' is for the parent query level, not the 'topplan'.
1750 * This does not matter currently since we only access the dependency-item
1751 * lists in root->glob, but it would need some hacking if we wanted a root
1752 * that actually matches the subplan.
1754 * Note: resultRelation is not yet adjusted by rtoffset.
1757 set_returning_clause_references(PlannerInfo *root,
1760 Index resultRelation,
1763 indexed_tlist *itlist;
1766 * We can perform the desired Var fixup by abusing the fix_join_expr
1767 * machinery that formerly handled inner indexscan fixup. We search the
1768 * top plan's targetlist for Vars of non-result relations, and use
1769 * fix_join_expr to convert RETURNING Vars into references to those tlist
1770 * entries, while leaving result-rel Vars as-is.
1772 * PlaceHolderVars will also be sought in the targetlist, but no
1773 * more-complex expressions will be. Note that it is not possible for a
1774 * PlaceHolderVar to refer to the result relation, since the result is
1775 * never below an outer join. If that case could happen, we'd have to be
1776 * prepared to pick apart the PlaceHolderVar and evaluate its contained
1777 * expression instead.
1779 itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
1781 rlist = fix_join_expr(root,
1793 /*****************************************************************************
1794 * OPERATOR REGPROC LOOKUP
1795 *****************************************************************************/
1799 * Calculate opfuncid field from opno for each OpExpr node in given tree.
1800 * The given tree can be anything expression_tree_walker handles.
1802 * The argument is modified in-place. (This is OK since we'd want the
1803 * same change for any node, even if it gets visited more than once due to
1804 * shared structure.)
1807 fix_opfuncids(Node *node)
1809 /* This tree walk requires no special setup, so away we go... */
1810 fix_opfuncids_walker(node, NULL);
1814 fix_opfuncids_walker(Node *node, void *context)
1818 if (IsA(node, OpExpr))
1819 set_opfuncid((OpExpr *) node);
1820 else if (IsA(node, DistinctExpr))
1821 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1822 else if (IsA(node, NullIfExpr))
1823 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1824 else if (IsA(node, ScalarArrayOpExpr))
1825 set_sa_opfuncid((ScalarArrayOpExpr *) node);
1826 return expression_tree_walker(node, fix_opfuncids_walker, context);
1831 * Set the opfuncid (procedure OID) in an OpExpr node,
1832 * if it hasn't been set already.
1834 * Because of struct equivalence, this can also be used for
1835 * DistinctExpr and NullIfExpr nodes.
1838 set_opfuncid(OpExpr *opexpr)
1840 if (opexpr->opfuncid == InvalidOid)
1841 opexpr->opfuncid = get_opcode(opexpr->opno);
1846 * As above, for ScalarArrayOpExpr nodes.
1849 set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
1851 if (opexpr->opfuncid == InvalidOid)
1852 opexpr->opfuncid = get_opcode(opexpr->opno);
1855 /*****************************************************************************
1856 * QUERY DEPENDENCY MANAGEMENT
1857 *****************************************************************************/
1860 * record_plan_function_dependency
1861 * Mark the current plan as depending on a particular function.
1863 * This is exported so that the function-inlining code can record a
1864 * dependency on a function that it's removed from the plan tree.
1867 record_plan_function_dependency(PlannerInfo *root, Oid funcid)
1870 * For performance reasons, we don't bother to track built-in functions;
1871 * we just assume they'll never change (or at least not in ways that'd
1872 * invalidate plans using them). For this purpose we can consider a
1873 * built-in function to be one with OID less than FirstBootstrapObjectId.
1874 * Note that the OID generator guarantees never to generate such an OID
1875 * after startup, even at OID wraparound.
1877 if (funcid >= (Oid) FirstBootstrapObjectId)
1879 PlanInvalItem *inval_item = makeNode(PlanInvalItem);
1882 * It would work to use any syscache on pg_proc, but the easiest is
1883 * PROCOID since we already have the function's OID at hand. Note
1884 * that plancache.c knows we use PROCOID.
1886 inval_item->cacheId = PROCOID;
1887 inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
1888 ObjectIdGetDatum(funcid));
1890 root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
1895 * extract_query_dependencies
1896 * Given a not-yet-planned query or queries (i.e. a Query node or list
1897 * of Query nodes), extract dependencies just as set_plan_references
1900 * This is needed by plancache.c to handle invalidation of cached unplanned
1904 extract_query_dependencies(Node *query,
1905 List **relationOids,
1911 /* Make up dummy planner state so we can use this module's machinery */
1912 MemSet(&glob, 0, sizeof(glob));
1913 glob.type = T_PlannerGlobal;
1914 glob.relationOids = NIL;
1915 glob.invalItems = NIL;
1917 MemSet(&root, 0, sizeof(root));
1918 root.type = T_PlannerInfo;
1921 (void) extract_query_dependencies_walker(query, &root);
1923 *relationOids = glob.relationOids;
1924 *invalItems = glob.invalItems;
1928 extract_query_dependencies_walker(Node *node, PlannerInfo *context)
1932 Assert(!IsA(node, PlaceHolderVar));
1933 /* Extract function dependencies and check for regclass Consts */
1934 fix_expr_common(context, node);
1935 if (IsA(node, Query))
1937 Query *query = (Query *) node;
1940 if (query->commandType == CMD_UTILITY)
1943 * Ignore utility statements, except those (such as EXPLAIN) that
1944 * contain a parsed-but-not-planned query.
1946 query = UtilityContainsQuery(query->utilityStmt);
1951 /* Collect relation OIDs in this Query's rtable */
1952 foreach(lc, query->rtable)
1954 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1956 if (rte->rtekind == RTE_RELATION)
1957 context->glob->relationOids =
1958 lappend_oid(context->glob->relationOids, rte->relid);
1961 /* And recurse into the query's subexpressions */
1962 return query_tree_walker(query, extract_query_dependencies_walker,
1963 (void *) context, 0);
1965 return expression_tree_walker(node, extract_query_dependencies_walker,