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-2008, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.144 2008/09/09 18:58:08 tgl Exp $
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/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"
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_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 */
50 } fix_scan_expr_context;
55 indexed_tlist *outer_itlist;
56 indexed_tlist *inner_itlist;
59 } fix_join_expr_context;
64 indexed_tlist *subplan_itlist;
66 } fix_upper_expr_context;
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.)
75 #define ISREGCLASSCONST(con) \
76 (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
79 #define fix_scan_list(glob, lst, rtoffset) \
80 ((List *) fix_scan_expr(glob, (Node *) (lst), rtoffset))
82 static Plan *set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset);
83 static Plan *set_subqueryscan_references(PlannerGlobal *glob,
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,
100 static Var *search_indexed_tlist_for_non_var(Node *node,
101 indexed_tlist *itlist,
103 static List *fix_join_expr(PlannerGlobal *glob,
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,
112 indexed_tlist *subplan_itlist,
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);
121 /*****************************************************************************
125 *****************************************************************************/
128 * set_plan_references
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:
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.
137 * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
139 * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
142 * 4. We compute regproc OIDs for operators (ie, we look up the function
143 * that implements each op).
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.
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.
162 * set_plan_references recursively traverses the whole plan tree.
165 * glob: global data for planner run
166 * plan: the topmost node of the plan
167 * rtable: the rangetable for the current subquery
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.
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).
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.
182 set_plan_references(PlannerGlobal *glob, Plan *plan, List *rtable)
184 int rtoffset = list_length(glob->finalrtable);
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.
195 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
196 RangeTblEntry *newrte;
198 /* flat copy to duplicate all the scalar fields */
199 newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
200 memcpy(newrte, rte, sizeof(RangeTblEntry));
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;
210 glob->finalrtable = lappend(glob->finalrtable, newrte);
213 * If it's a plain relation RTE, add the table to relationOids.
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.
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.
224 if (newrte->rtekind == RTE_RELATION)
225 glob->relationOids = lappend_oid(glob->relationOids,
229 /* Now fix the Plan tree */
230 return set_plan_refs(glob, plan, rtoffset);
234 * set_plan_refs: recurse through the Plan nodes of a single subquery level
237 set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
245 * Plan-type-specific fixes
247 switch (nodeTag(plan))
251 SeqScan *splan = (SeqScan *) plan;
253 splan->scanrelid += rtoffset;
254 splan->plan.targetlist =
255 fix_scan_list(glob, splan->plan.targetlist, rtoffset);
257 fix_scan_list(glob, splan->plan.qual, rtoffset);
262 IndexScan *splan = (IndexScan *) plan;
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);
270 fix_scan_list(glob, splan->indexqual, rtoffset);
271 splan->indexqualorig =
272 fix_scan_list(glob, splan->indexqualorig, rtoffset);
275 case T_BitmapIndexScan:
277 BitmapIndexScan *splan = (BitmapIndexScan *) plan;
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);
284 fix_scan_list(glob, splan->indexqual, rtoffset);
285 splan->indexqualorig =
286 fix_scan_list(glob, splan->indexqualorig, rtoffset);
289 case T_BitmapHeapScan:
291 BitmapHeapScan *splan = (BitmapHeapScan *) plan;
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);
304 TidScan *splan = (TidScan *) plan;
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);
312 fix_scan_list(glob, splan->tidquals, rtoffset);
316 /* Needs special treatment, see comments below */
317 return set_subqueryscan_references(glob,
318 (SubqueryScan *) plan,
322 FunctionScan *splan = (FunctionScan *) plan;
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);
330 fix_scan_expr(glob, splan->funcexpr, rtoffset);
335 ValuesScan *splan = (ValuesScan *) plan;
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);
350 set_join_references(glob, (Join *) plan, rtoffset);
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).
366 set_dummy_tlist_references(plan, rtoffset);
369 * Since these plan types don't check quals either, we should not
370 * find any qual expression attached to them.
372 Assert(plan->qual == NIL);
376 Limit *splan = (Limit *) plan;
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.
384 set_dummy_tlist_references(plan, rtoffset);
385 Assert(splan->plan.qual == NIL);
388 fix_scan_expr(glob, splan->limitOffset, rtoffset);
390 fix_scan_expr(glob, splan->limitCount, rtoffset);
395 set_upper_references(glob, plan, rtoffset);
399 Result *splan = (Result *) plan;
402 * Result may or may not have a subplan; if not, it's more
403 * like a scan node than an upper node.
405 if (splan->plan.lefttree != NULL)
406 set_upper_references(glob, plan, rtoffset);
409 splan->plan.targetlist =
410 fix_scan_list(glob, splan->plan.targetlist, rtoffset);
412 fix_scan_list(glob, splan->plan.qual, rtoffset);
414 /* resconstantqual can't contain any subplan variable refs */
415 splan->resconstantqual =
416 fix_scan_expr(glob, splan->resconstantqual, rtoffset);
421 Append *splan = (Append *) plan;
424 * Append, like Sort et al, doesn't actually evaluate its
425 * targetlist or check quals.
427 set_dummy_tlist_references(plan, rtoffset);
428 Assert(splan->plan.qual == NIL);
429 foreach(l, splan->appendplans)
431 lfirst(l) = set_plan_refs(glob,
439 BitmapAnd *splan = (BitmapAnd *) plan;
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)
446 lfirst(l) = set_plan_refs(glob,
454 BitmapOr *splan = (BitmapOr *) plan;
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)
461 lfirst(l) = set_plan_refs(glob,
468 elog(ERROR, "unrecognized node type: %d",
469 (int) nodeTag(plan));
474 * Now recurse into child plans, if any
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.
481 plan->lefttree = set_plan_refs(glob, plan->lefttree, rtoffset);
482 plan->righttree = set_plan_refs(glob, plan->righttree, rtoffset);
488 * set_subqueryscan_references
489 * Do set_plan_references processing on a SubqueryScan
491 * We try to strip out the SubqueryScan entirely; if we can't, we have
492 * to do the normal processing on it.
495 set_subqueryscan_references(PlannerGlobal *glob,
501 /* First, recursively process the subplan */
502 plan->subplan = set_plan_references(glob, plan->subplan, plan->subrtable);
504 /* subrtable is no longer needed in the plan tree */
505 plan->subrtable = NIL;
507 if (trivial_subqueryscan(plan))
510 * We can omit the SubqueryScan node and just pull up the subplan.
515 result = plan->subplan;
517 /* We have to be sure we don't lose any initplans */
518 result->initPlan = list_concat(plan->scan.plan.initPlan,
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.
527 forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist)
529 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
530 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
532 ctle->resname = ptle->resname;
533 ctle->resorigtbl = ptle->resorigtbl;
534 ctle->resorigcol = ptle->resorigcol;
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.
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);
552 result = (Plan *) plan;
559 * trivial_subqueryscan
560 * Detect whether a SubqueryScan can be deleted from the plan tree.
562 * We can delete it if it has no qual to check and the targetlist just
563 * regurgitates the output of the child plan.
566 trivial_subqueryscan(SubqueryScan *plan)
572 if (plan->scan.plan.qual != NIL)
575 if (list_length(plan->scan.plan.targetlist) !=
576 list_length(plan->subplan->targetlist))
577 return false; /* tlists not same length */
580 forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
582 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
583 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
585 if (ptle->resjunk != ctle->resjunk)
586 return false; /* tlist doesn't match junk status */
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.
593 if (ptle->expr && IsA(ptle->expr, Var))
595 Var *var = (Var *) ptle->expr;
597 Assert(var->varno == plan->scan.scanrelid);
598 Assert(var->varlevelsup == 0);
599 if (var->varattno != attrno)
600 return false; /* out of order */
602 else if (ptle->expr && IsA(ptle->expr, Const))
604 if (!equal(ptle->expr, ctle->expr))
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.
626 Var *newvar = (Var *) palloc(sizeof(Var));
634 * Do generic set_plan_references processing on an expression node
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.
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.
645 fix_expr_common(PlannerGlobal *glob, Node *node)
647 /* We assume callers won't call us on a NULL pointer */
648 if (IsA(node, Aggref))
650 record_plan_function_dependency(glob,
651 ((Aggref *) node)->aggfnoid);
653 else if (IsA(node, FuncExpr))
655 record_plan_function_dependency(glob,
656 ((FuncExpr *) node)->funcid);
658 else if (IsA(node, OpExpr))
660 set_opfuncid((OpExpr *) node);
661 record_plan_function_dependency(glob,
662 ((OpExpr *) node)->opfuncid);
664 else if (IsA(node, DistinctExpr))
666 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
667 record_plan_function_dependency(glob,
668 ((DistinctExpr *) node)->opfuncid);
670 else if (IsA(node, NullIfExpr))
672 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
673 record_plan_function_dependency(glob,
674 ((NullIfExpr *) node)->opfuncid);
676 else if (IsA(node, ScalarArrayOpExpr))
678 set_sa_opfuncid((ScalarArrayOpExpr *) node);
679 record_plan_function_dependency(glob,
680 ((ScalarArrayOpExpr *) node)->opfuncid);
682 else if (IsA(node, ArrayCoerceExpr))
684 if (OidIsValid(((ArrayCoerceExpr *) node)->elemfuncid))
685 record_plan_function_dependency(glob,
686 ((ArrayCoerceExpr *) node)->elemfuncid);
688 else if (IsA(node, Const))
690 Const *con = (Const *) node;
692 /* Check for regclass reference */
693 if (ISREGCLASSCONST(con))
695 lappend_oid(glob->relationOids,
696 DatumGetObjectId(con->constvalue));
702 * Do set_plan_references processing on a scan-level expression
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.
709 fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset)
711 fix_scan_expr_context context;
714 context.rtoffset = rtoffset;
718 return fix_scan_expr_mutator(node, &context);
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
729 (void) fix_scan_expr_walker(node, &context);
735 fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
741 Var *var = copyVar((Var *) node);
743 Assert(var->varlevelsup == 0);
746 * We should not see any Vars marked INNER, but in a nestloop inner
747 * scan there could be OUTER Vars. Leave them alone.
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;
756 if (IsA(node, CurrentOfExpr))
758 CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
760 Assert(cexpr->cvarno != INNER);
761 Assert(cexpr->cvarno != OUTER);
762 cexpr->cvarno += context->rtoffset;
763 return (Node *) cexpr;
765 fix_expr_common(context->glob, node);
766 return expression_tree_mutator(node, fix_scan_expr_mutator,
771 fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
775 fix_expr_common(context->glob, node);
776 return expression_tree_walker(node, fix_scan_expr_walker,
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.
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.
793 set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
795 Plan *outer_plan = join->plan.lefttree;
796 Plan *inner_plan = join->plan.righttree;
797 indexed_tlist *outer_itlist;
798 indexed_tlist *inner_itlist;
800 outer_itlist = build_tlist_index(outer_plan->targetlist);
801 inner_itlist = build_tlist_index(inner_plan->targetlist);
803 /* All join plans have tlist, qual, and joinqual */
804 join->plan.targetlist = fix_join_expr(glob,
805 join->plan.targetlist,
810 join->plan.qual = fix_join_expr(glob,
816 join->joinqual = fix_join_expr(glob,
823 /* Now do join-type-specific stuff */
824 if (IsA(join, NestLoop))
826 /* This processing is split out to handle possible recursion */
827 set_inner_join_references(glob, inner_plan, outer_itlist);
829 else if (IsA(join, MergeJoin))
831 MergeJoin *mj = (MergeJoin *) join;
833 mj->mergeclauses = fix_join_expr(glob,
840 else if (IsA(join, HashJoin))
842 HashJoin *hj = (HashJoin *) join;
844 hj->hashclauses = fix_join_expr(glob,
857 * set_inner_join_references
858 * Handle join references appearing in an inner indexscan's quals
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.
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.
870 set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
871 indexed_tlist *outer_itlist)
873 if (IsA(inner_plan, IndexScan))
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.
881 IndexScan *innerscan = (IndexScan *) inner_plan;
882 List *indexqualorig = innerscan->indexqualorig;
884 /* No work needed if indexqual refers only to its own rel... */
885 if (NumRelids((Node *) indexqualorig) > 1)
887 Index innerrel = innerscan->scan.scanrelid;
889 /* only refs to outer vars get changed in the inner qual */
890 innerscan->indexqualorig = fix_join_expr(glob,
896 innerscan->indexqual = fix_join_expr(glob,
897 innerscan->indexqual,
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).
908 if (NumRelids((Node *) inner_plan->qual) > 1)
909 inner_plan->qual = fix_join_expr(glob,
917 else if (IsA(inner_plan, BitmapIndexScan))
920 * Same, but index is being used within a bitmap plan.
922 BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan;
923 List *indexqualorig = innerscan->indexqualorig;
925 /* No work needed if indexqual refers only to its own rel... */
926 if (NumRelids((Node *) indexqualorig) > 1)
928 Index innerrel = innerscan->scan.scanrelid;
930 /* only refs to outer vars get changed in the inner qual */
931 innerscan->indexqualorig = fix_join_expr(glob,
937 innerscan->indexqual = fix_join_expr(glob,
938 innerscan->indexqual,
943 /* no need to fix inner qpqual */
944 Assert(inner_plan->qual == NIL);
947 else if (IsA(inner_plan, BitmapHeapScan))
950 * The inner side is a bitmap scan plan. Fix the top node, and
951 * recurse to get the lower nodes.
953 * Note: create_bitmap_scan_plan removes clauses from bitmapqualorig
954 * if they are duplicated in qpqual, so must test these independently.
956 BitmapHeapScan *innerscan = (BitmapHeapScan *) inner_plan;
957 Index innerrel = innerscan->scan.scanrelid;
958 List *bitmapqualorig = innerscan->bitmapqualorig;
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,
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).
974 if (NumRelids((Node *) inner_plan->qual) > 1)
975 inner_plan->qual = fix_join_expr(glob,
983 set_inner_join_references(glob, inner_plan->lefttree, outer_itlist);
985 else if (IsA(inner_plan, BitmapAnd))
987 /* All we need do here is recurse */
988 BitmapAnd *innerscan = (BitmapAnd *) inner_plan;
991 foreach(l, innerscan->bitmapplans)
993 set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
996 else if (IsA(inner_plan, BitmapOr))
998 /* All we need do here is recurse */
999 BitmapOr *innerscan = (BitmapOr *) inner_plan;
1002 foreach(l, innerscan->bitmapplans)
1004 set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
1007 else if (IsA(inner_plan, TidScan))
1009 TidScan *innerscan = (TidScan *) inner_plan;
1010 Index innerrel = innerscan->scan.scanrelid;
1012 innerscan->tidquals = fix_join_expr(glob,
1013 innerscan->tidquals,
1019 else if (IsA(inner_plan, Append))
1022 * The inner side is an append plan. Recurse to see if it contains
1023 * indexscans that need to be fixed.
1025 Append *appendplan = (Append *) inner_plan;
1028 foreach(l, appendplan->appendplans)
1030 set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
1033 else if (IsA(inner_plan, Result))
1035 /* Recurse through a gating Result node (similar to Append case) */
1036 Result *result = (Result *) inner_plan;
1038 if (result->plan.lefttree)
1039 set_inner_join_references(glob, result->plan.lefttree, outer_itlist);
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.
1050 * This is used for single-input plan types like Agg, Group, Result.
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
1062 set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset)
1064 Plan *subplan = plan->lefttree;
1065 indexed_tlist *subplan_itlist;
1066 List *output_targetlist;
1069 subplan_itlist = build_tlist_index(subplan->targetlist);
1071 output_targetlist = NIL;
1072 foreach(l, plan->targetlist)
1074 TargetEntry *tle = (TargetEntry *) lfirst(l);
1077 newexpr = fix_upper_expr(glob,
1081 tle = flatCopyTargetEntry(tle);
1082 tle->expr = (Expr *) newexpr;
1083 output_targetlist = lappend(output_targetlist, tle);
1085 plan->targetlist = output_targetlist;
1087 plan->qual = (List *)
1088 fix_upper_expr(glob,
1089 (Node *) plan->qual,
1093 pfree(subplan_itlist);
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.
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.
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
1110 set_dummy_tlist_references(Plan *plan, int rtoffset)
1112 List *output_targetlist;
1115 output_targetlist = NIL;
1116 foreach(l, plan->targetlist)
1118 TargetEntry *tle = (TargetEntry *) lfirst(l);
1119 Var *oldvar = (Var *) tle->expr;
1122 newvar = makeVar(OUTER,
1124 exprType((Node *) oldvar),
1125 exprTypmod((Node *) oldvar),
1127 if (IsA(oldvar, Var))
1129 newvar->varnoold = oldvar->varno + rtoffset;
1130 newvar->varoattno = oldvar->varattno;
1134 newvar->varnoold = 0; /* wasn't ever a plain Var */
1135 newvar->varoattno = 0;
1138 tle = flatCopyTargetEntry(tle);
1139 tle->expr = (Expr *) newvar;
1140 output_targetlist = lappend(output_targetlist, tle);
1142 plan->targetlist = output_targetlist;
1144 /* We don't touch plan->qual here */
1149 * build_tlist_index --- build an index data structure for a child tlist
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.
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().
1161 static indexed_tlist *
1162 build_tlist_index(List *tlist)
1164 indexed_tlist *itlist;
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));
1173 itlist->tlist = tlist;
1174 itlist->has_non_vars = false;
1176 /* Find the Vars and fill in the index array */
1177 vinfo = itlist->vars;
1180 TargetEntry *tle = (TargetEntry *) lfirst(l);
1182 if (tle->expr && IsA(tle->expr, Var))
1184 Var *var = (Var *) tle->expr;
1186 vinfo->varno = var->varno;
1187 vinfo->varattno = var->varattno;
1188 vinfo->resno = tle->resno;
1192 itlist->has_non_vars = true;
1195 itlist->num_vars = (vinfo - itlist->vars);
1201 * build_tlist_index_other_vars --- build a restricted tlist index
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.
1206 static indexed_tlist *
1207 build_tlist_index_other_vars(List *tlist, Index ignore_rel)
1209 indexed_tlist *itlist;
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));
1218 itlist->tlist = tlist;
1219 itlist->has_non_vars = false;
1221 /* Find the desired Vars and fill in the index array */
1222 vinfo = itlist->vars;
1225 TargetEntry *tle = (TargetEntry *) lfirst(l);
1227 if (tle->expr && IsA(tle->expr, Var))
1229 Var *var = (Var *) tle->expr;
1231 if (var->varno != ignore_rel)
1233 vinfo->varno = var->varno;
1234 vinfo->varattno = var->varattno;
1235 vinfo->resno = tle->resno;
1241 itlist->num_vars = (vinfo - itlist->vars);
1247 * search_indexed_tlist_for_var --- find a Var in an indexed tlist
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.
1255 search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
1256 Index newvarno, int rtoffset)
1258 Index varno = var->varno;
1259 AttrNumber varattno = var->varattno;
1263 vinfo = itlist->vars;
1264 i = itlist->num_vars;
1267 if (vinfo->varno == varno && vinfo->varattno == varattno)
1270 Var *newvar = copyVar(var);
1272 newvar->varno = newvarno;
1273 newvar->varattno = vinfo->resno;
1274 if (newvar->varnoold > 0)
1275 newvar->varnoold += rtoffset;
1280 return NULL; /* no match */
1284 * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
1286 * If a match is found, return a Var constructed to reference the tlist item.
1287 * If no match, return NULL.
1289 * NOTE: it is a waste of time to call this if !itlist->has_non_vars
1292 search_indexed_tlist_for_non_var(Node *node,
1293 indexed_tlist *itlist, Index newvarno)
1297 tle = tlist_member(node, itlist->tlist);
1300 /* Found a matching subplan output expression */
1303 newvar = makeVar(newvarno,
1305 exprType((Node *) tle->expr),
1306 exprTypmod((Node *) tle->expr),
1308 newvar->varnoold = 0; /* wasn't ever a plain Var */
1309 newvar->varoattno = 0;
1312 return NULL; /* no match */
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.
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.)
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.
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,
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.
1343 * Returns the new expression tree. The original clause structure is
1347 fix_join_expr(PlannerGlobal *glob,
1349 indexed_tlist *outer_itlist,
1350 indexed_tlist *inner_itlist,
1351 Index acceptable_rel,
1354 fix_join_expr_context context;
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);
1365 fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
1373 Var *var = (Var *) node;
1375 /* First look for the var in the input tlists */
1376 newvar = search_indexed_tlist_for_var(var,
1377 context->outer_itlist,
1381 return (Node *) newvar;
1382 if (context->inner_itlist)
1384 newvar = search_indexed_tlist_for_var(var,
1385 context->inner_itlist,
1389 return (Node *) newvar;
1392 /* If it's for acceptable_rel, adjust and return it */
1393 if (var->varno == context->acceptable_rel)
1396 var->varno += context->rtoffset;
1397 var->varnoold += context->rtoffset;
1398 return (Node *) var;
1401 /* No referent found for Var */
1402 elog(ERROR, "variable not found in subplan target lists");
1404 /* Try matching more complex expressions too, if tlists have any */
1405 if (context->outer_itlist->has_non_vars)
1407 newvar = search_indexed_tlist_for_non_var(node,
1408 context->outer_itlist,
1411 return (Node *) newvar;
1413 if (context->inner_itlist && context->inner_itlist->has_non_vars)
1415 newvar = search_indexed_tlist_for_non_var(node,
1416 context->inner_itlist,
1419 return (Node *) newvar;
1421 fix_expr_common(context->glob, node);
1422 return expression_tree_mutator(node,
1423 fix_join_expr_mutator,
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.
1433 * This is used to fix up target and qual expressions of non-join upper-level
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.
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.)
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
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.
1455 fix_upper_expr(PlannerGlobal *glob,
1457 indexed_tlist *subplan_itlist,
1460 fix_upper_expr_context context;
1462 context.glob = glob;
1463 context.subplan_itlist = subplan_itlist;
1464 context.rtoffset = rtoffset;
1465 return fix_upper_expr_mutator(node, &context);
1469 fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
1477 Var *var = (Var *) node;
1479 newvar = search_indexed_tlist_for_var(var,
1480 context->subplan_itlist,
1484 elog(ERROR, "variable not found in subplan target list");
1485 return (Node *) newvar;
1487 /* Try matching more complex expressions too, if tlist has any */
1488 if (context->subplan_itlist->has_non_vars)
1490 newvar = search_indexed_tlist_for_non_var(node,
1491 context->subplan_itlist,
1494 return (Node *) newvar;
1496 fix_expr_common(context->glob, node);
1497 return expression_tree_mutator(node,
1498 fix_upper_expr_mutator,
1503 * set_returning_clause_references
1504 * Perform setrefs.c's work on a RETURNING targetlist
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.
1514 * We also must perform opcode lookup and add regclass OIDs to
1515 * glob->relationOids.
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
1522 * Note: we assume that result relations will have rtoffset zero, that is,
1523 * they are not coming from a subplan.
1526 set_returning_clause_references(PlannerGlobal *glob,
1529 Index resultRelation)
1531 indexed_tlist *itlist;
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.
1540 itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
1542 rlist = fix_join_expr(glob,
1554 /*****************************************************************************
1555 * OPERATOR REGPROC LOOKUP
1556 *****************************************************************************/
1560 * Calculate opfuncid field from opno for each OpExpr node in given tree.
1561 * The given tree can be anything expression_tree_walker handles.
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.)
1568 fix_opfuncids(Node *node)
1570 /* This tree walk requires no special setup, so away we go... */
1571 fix_opfuncids_walker(node, NULL);
1575 fix_opfuncids_walker(Node *node, void *context)
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);
1592 * Set the opfuncid (procedure OID) in an OpExpr node,
1593 * if it hasn't been set already.
1595 * Because of struct equivalence, this can also be used for
1596 * DistinctExpr and NullIfExpr nodes.
1599 set_opfuncid(OpExpr *opexpr)
1601 if (opexpr->opfuncid == InvalidOid)
1602 opexpr->opfuncid = get_opcode(opexpr->opno);
1607 * As above, for ScalarArrayOpExpr nodes.
1610 set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
1612 if (opexpr->opfuncid == InvalidOid)
1613 opexpr->opfuncid = get_opcode(opexpr->opno);
1616 /*****************************************************************************
1617 * QUERY DEPENDENCY MANAGEMENT
1618 *****************************************************************************/
1621 * record_plan_function_dependency
1622 * Mark the current plan as depending on a particular function.
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.
1628 record_plan_function_dependency(PlannerGlobal *glob, Oid funcid)
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.
1638 if (funcid >= (Oid) FirstBootstrapObjectId)
1640 HeapTuple func_tuple;
1641 PlanInvalItem *inval_item;
1643 func_tuple = SearchSysCache(PROCOID,
1644 ObjectIdGetDatum(funcid),
1646 if (!HeapTupleIsValid(func_tuple))
1647 elog(ERROR, "cache lookup failed for function %u", funcid);
1649 inval_item = makeNode(PlanInvalItem);
1652 * It would work to use any syscache on pg_proc, but plancache.c
1653 * expects us to use PROCOID.
1655 inval_item->cacheId = PROCOID;
1656 inval_item->tupleId = func_tuple->t_self;
1658 glob->invalItems = lappend(glob->invalItems, inval_item);
1660 ReleaseSysCache(func_tuple);
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.
1669 * This is needed by plancache.c to handle invalidation of cached unplanned
1673 extract_query_dependencies(List *queries,
1674 List **relationOids,
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;
1685 (void) extract_query_dependencies_walker((Node *) queries, &glob);
1687 *relationOids = glob.relationOids;
1688 *invalItems = glob.invalItems;
1692 extract_query_dependencies_walker(Node *node, PlannerGlobal *context)
1696 /* Extract function dependencies and check for regclass Consts */
1697 fix_expr_common(context, node);
1698 if (IsA(node, Query))
1700 Query *query = (Query *) node;
1703 /* Collect relation OIDs in this Query's rtable */
1704 foreach(lc, query->rtable)
1706 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1708 if (rte->rtekind == RTE_RELATION)
1709 context->relationOids = lappend_oid(context->relationOids,
1713 /* And recurse into the query's subexpressions */
1714 return query_tree_walker(query, extract_query_dependencies_walker,
1715 (void *) context, 0);
1717 return expression_tree_walker(node, extract_query_dependencies_walker,