1 /*-------------------------------------------------------------------------
4 * Post-processing of a completed plan tree: fix references to subplan
5 * vars, and compute regproc values for operators
7 * Portions Copyright (c) 1996-2007, 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.128 2007/01/22 01:35:20 tgl Exp $
14 *-------------------------------------------------------------------------
18 #include "nodes/makefuncs.h"
19 #include "optimizer/clauses.h"
20 #include "optimizer/planmain.h"
21 #include "optimizer/tlist.h"
22 #include "parser/parse_expr.h"
23 #include "parser/parsetree.h"
24 #include "utils/lsyscache.h"
29 Index varno; /* RT index of Var */
30 AttrNumber varattno; /* attr number of Var */
31 AttrNumber resno; /* TLE position of Var */
36 List *tlist; /* underlying target list */
37 int num_vars; /* number of plain Var tlist entries */
38 bool has_non_vars; /* are there non-plain-Var entries? */
39 /* array of num_vars entries: */
40 tlist_vinfo vars[1]; /* VARIABLE LENGTH ARRAY */
41 } indexed_tlist; /* VARIABLE LENGTH STRUCT */
45 indexed_tlist *outer_itlist;
46 indexed_tlist *inner_itlist;
48 } join_references_context;
52 indexed_tlist *subplan_itlist;
54 } replace_vars_with_subplan_refs_context;
56 static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable);
57 static bool trivial_subqueryscan(SubqueryScan *plan);
58 static void adjust_plan_varnos(Plan *plan, int rtoffset);
59 static void adjust_expr_varnos(Node *node, int rtoffset);
60 static bool adjust_expr_varnos_walker(Node *node, int *context);
61 static void fix_expr_references(Plan *plan, Node *node);
62 static bool fix_expr_references_walker(Node *node, void *context);
63 static void set_join_references(Join *join);
64 static void set_inner_join_references(Plan *inner_plan,
65 indexed_tlist *outer_itlist);
66 static void set_uppernode_references(Plan *plan, Index subvarno);
67 static indexed_tlist *build_tlist_index(List *tlist);
68 static Var *search_indexed_tlist_for_var(Var *var,
69 indexed_tlist *itlist,
71 static Var *search_indexed_tlist_for_non_var(Node *node,
72 indexed_tlist *itlist,
74 static List *join_references(List *clauses,
75 indexed_tlist *outer_itlist,
76 indexed_tlist *inner_itlist,
77 Index acceptable_rel);
78 static Node *join_references_mutator(Node *node,
79 join_references_context *context);
80 static Node *replace_vars_with_subplan_refs(Node *node,
81 indexed_tlist *subplan_itlist,
83 static Node *replace_vars_with_subplan_refs_mutator(Node *node,
84 replace_vars_with_subplan_refs_context *context);
85 static bool fix_opfuncids_walker(Node *node, void *context);
88 /*****************************************************************************
92 *****************************************************************************/
97 * This is the final processing pass of the planner/optimizer. The plan
98 * tree is complete; we just have to adjust some representational details
99 * for the convenience of the executor. We update Vars in upper plan nodes
100 * to refer to the outputs of their subplans, and we compute regproc OIDs
101 * for operators (ie, we look up the function that implements each op).
103 * We also perform one final optimization step, which is to delete
104 * SubqueryScan plan nodes that aren't doing anything useful (ie, have
105 * no qual and a no-op targetlist). The reason for doing this last is that
106 * it can't readily be done before set_plan_references, because it would
107 * break set_uppernode_references: the Vars in the subquery's top tlist
108 * won't match up with the Vars in the outer plan tree. The SubqueryScan
109 * serves a necessary function as a buffer between outer query and subquery
110 * variable numbering ... but the executor doesn't care about that, only the
113 * set_plan_references recursively traverses the whole plan tree.
115 * The return value is normally the same Plan node passed in, but can be
116 * different when the passed-in Plan is a SubqueryScan we decide isn't needed.
118 * Note: to delete a SubqueryScan, we have to renumber Vars in its child nodes
119 * and append the modified subquery rangetable to the outer rangetable.
120 * Therefore "rtable" is an in/out argument and really should be declared
121 * "List **". But in the interest of notational simplicity we don't do that.
122 * (Since rtable can't be NIL if there's a SubqueryScan, the list header
123 * address won't change when we append a subquery rangetable.)
126 set_plan_references(Plan *plan, List *rtable)
134 * Plan-type-specific fixes
136 switch (nodeTag(plan))
139 fix_expr_references(plan, (Node *) plan->targetlist);
140 fix_expr_references(plan, (Node *) plan->qual);
143 fix_expr_references(plan, (Node *) plan->targetlist);
144 fix_expr_references(plan, (Node *) plan->qual);
145 fix_expr_references(plan,
146 (Node *) ((IndexScan *) plan)->indexqual);
147 fix_expr_references(plan,
148 (Node *) ((IndexScan *) plan)->indexqualorig);
150 case T_BitmapIndexScan:
151 /* no need to fix targetlist and qual */
152 Assert(plan->targetlist == NIL);
153 Assert(plan->qual == NIL);
154 fix_expr_references(plan,
155 (Node *) ((BitmapIndexScan *) plan)->indexqual);
156 fix_expr_references(plan,
157 (Node *) ((BitmapIndexScan *) plan)->indexqualorig);
159 case T_BitmapHeapScan:
160 fix_expr_references(plan, (Node *) plan->targetlist);
161 fix_expr_references(plan, (Node *) plan->qual);
162 fix_expr_references(plan,
163 (Node *) ((BitmapHeapScan *) plan)->bitmapqualorig);
166 fix_expr_references(plan, (Node *) plan->targetlist);
167 fix_expr_references(plan, (Node *) plan->qual);
168 fix_expr_references(plan, (Node *) ((TidScan *) plan)->tidquals);
171 /* Needs special treatment, see comments below */
172 return set_subqueryscan_references((SubqueryScan *) plan, rtable);
177 fix_expr_references(plan, (Node *) plan->targetlist);
178 fix_expr_references(plan, (Node *) plan->qual);
179 rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
181 Assert(rte->rtekind == RTE_FUNCTION);
182 fix_expr_references(plan, rte->funcexpr);
189 fix_expr_references(plan, (Node *) plan->targetlist);
190 fix_expr_references(plan, (Node *) plan->qual);
191 rte = rt_fetch(((ValuesScan *) plan)->scan.scanrelid,
193 Assert(rte->rtekind == RTE_VALUES);
194 fix_expr_references(plan, (Node *) rte->values_lists);
198 set_join_references((Join *) plan);
199 fix_expr_references(plan, (Node *) plan->targetlist);
200 fix_expr_references(plan, (Node *) plan->qual);
201 fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
204 set_join_references((Join *) plan);
205 fix_expr_references(plan, (Node *) plan->targetlist);
206 fix_expr_references(plan, (Node *) plan->qual);
207 fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
208 fix_expr_references(plan,
209 (Node *) ((MergeJoin *) plan)->mergeclauses);
212 set_join_references((Join *) plan);
213 fix_expr_references(plan, (Node *) plan->targetlist);
214 fix_expr_references(plan, (Node *) plan->qual);
215 fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
216 fix_expr_references(plan,
217 (Node *) ((HashJoin *) plan)->hashclauses);
226 * These plan types don't actually bother to evaluate their
227 * targetlists (because they just return their unmodified input
228 * tuples). The optimizer is lazy about creating really valid
229 * targetlists for them --- it tends to just put in a pointer to
230 * the child plan node's tlist. Hence, we leave the tlist alone.
231 * In particular, we do not want to process subplans in the tlist,
232 * since we will likely end up reprocessing subplans that also
233 * appear in lower levels of the plan tree!
235 * Since these plan types don't check quals either, we should not
236 * find any qual expression attached to them.
238 Assert(plan->qual == NIL);
243 * Like the plan types above, Limit doesn't evaluate its tlist or
244 * quals. It does have live expressions for limit/offset,
247 Assert(plan->qual == NIL);
248 fix_expr_references(plan, ((Limit *) plan)->limitOffset);
249 fix_expr_references(plan, ((Limit *) plan)->limitCount);
253 set_uppernode_references(plan, (Index) 0);
254 fix_expr_references(plan, (Node *) plan->targetlist);
255 fix_expr_references(plan, (Node *) plan->qual);
260 * Result may or may not have a subplan; no need to fix up subplan
261 * references if it hasn't got one...
263 * XXX why does Result use a different subvarno from Agg/Group?
265 if (plan->lefttree != NULL)
266 set_uppernode_references(plan, (Index) OUTER);
267 fix_expr_references(plan, (Node *) plan->targetlist);
268 fix_expr_references(plan, (Node *) plan->qual);
269 fix_expr_references(plan, ((Result *) plan)->resconstantqual);
274 * Append, like Sort et al, doesn't actually evaluate its
275 * targetlist or check quals, and we haven't bothered to give it
276 * its own tlist copy. So, don't fix targetlist/qual. But do
277 * recurse into child plans.
279 Assert(plan->qual == NIL);
280 foreach(l, ((Append *) plan)->appendplans)
281 lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
284 /* BitmapAnd works like Append, but has no tlist */
285 Assert(plan->targetlist == NIL);
286 Assert(plan->qual == NIL);
287 foreach(l, ((BitmapAnd *) plan)->bitmapplans)
288 lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
291 /* BitmapOr works like Append, but has no tlist */
292 Assert(plan->targetlist == NIL);
293 Assert(plan->qual == NIL);
294 foreach(l, ((BitmapOr *) plan)->bitmapplans)
295 lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
298 elog(ERROR, "unrecognized node type: %d",
299 (int) nodeTag(plan));
304 * Now recurse into child plans and initplans, if any
306 * NOTE: it is essential that we recurse into child plans AFTER we set
307 * subplan references in this plan's tlist and quals. If we did the
308 * reference-adjustments bottom-up, then we would fail to match this
309 * plan's var nodes against the already-modified nodes of the children.
310 * Fortunately, that consideration doesn't apply to SubPlan nodes; else
311 * we'd need two passes over the expression trees.
313 plan->lefttree = set_plan_references(plan->lefttree, rtable);
314 plan->righttree = set_plan_references(plan->righttree, rtable);
316 foreach(l, plan->initPlan)
318 SubPlan *sp = (SubPlan *) lfirst(l);
320 Assert(IsA(sp, SubPlan));
321 sp->plan = set_plan_references(sp->plan, sp->rtable);
328 * set_subqueryscan_references
329 * Do set_plan_references processing on a SubqueryScan
331 * We try to strip out the SubqueryScan entirely; if we can't, we have
332 * to do the normal processing on it.
335 set_subqueryscan_references(SubqueryScan *plan, List *rtable)
341 /* First, recursively process the subplan */
342 rte = rt_fetch(plan->scan.scanrelid, rtable);
343 Assert(rte->rtekind == RTE_SUBQUERY);
344 plan->subplan = set_plan_references(plan->subplan,
345 rte->subquery->rtable);
348 * We have to process any initplans too; set_plan_references can't do it
349 * for us because of the possibility of double-processing.
351 foreach(l, plan->scan.plan.initPlan)
353 SubPlan *sp = (SubPlan *) lfirst(l);
355 Assert(IsA(sp, SubPlan));
356 sp->plan = set_plan_references(sp->plan, sp->rtable);
359 if (trivial_subqueryscan(plan))
362 * We can omit the SubqueryScan node and just pull up the subplan. We
363 * have to merge its rtable into the outer rtable, which means
364 * adjusting varnos throughout the subtree.
366 int rtoffset = list_length(rtable);
371 sub_rtable = copyObject(rte->subquery->rtable);
372 range_table_walker(sub_rtable,
373 adjust_expr_varnos_walker,
375 QTW_IGNORE_RT_SUBQUERIES);
376 rtable = list_concat(rtable, sub_rtable);
379 * we have to copy the subplan to make sure there are no duplicately
380 * linked nodes in it, else adjust_plan_varnos might increment some
383 result = copyObject(plan->subplan);
385 adjust_plan_varnos(result, rtoffset);
387 result->initPlan = list_concat(plan->scan.plan.initPlan,
391 * We also have to transfer the SubqueryScan's result-column names
392 * into the subplan, else columns sent to client will be improperly
393 * labeled if this is the topmost plan level. Copy the "source
394 * column" information too.
396 forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist)
398 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
399 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
401 ctle->resname = ptle->resname;
402 ctle->resorigtbl = ptle->resorigtbl;
403 ctle->resorigcol = ptle->resorigcol;
409 * Keep the SubqueryScan node. We have to do the processing that
410 * set_plan_references would otherwise have done on it. Notice we do
411 * not do set_uppernode_references() here, because a SubqueryScan will
412 * always have been created with correct references to its subplan's
413 * outputs to begin with.
415 result = (Plan *) plan;
417 fix_expr_references(result, (Node *) result->targetlist);
418 fix_expr_references(result, (Node *) result->qual);
425 * trivial_subqueryscan
426 * Detect whether a SubqueryScan can be deleted from the plan tree.
428 * We can delete it if it has no qual to check and the targetlist just
429 * regurgitates the output of the child plan.
432 trivial_subqueryscan(SubqueryScan *plan)
438 if (plan->scan.plan.qual != NIL)
441 if (list_length(plan->scan.plan.targetlist) !=
442 list_length(plan->subplan->targetlist))
443 return false; /* tlists not same length */
446 forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
448 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
449 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
451 if (ptle->resjunk != ctle->resjunk)
452 return false; /* tlist doesn't match junk status */
455 * We accept either a Var referencing the corresponding element of the
456 * subplan tlist, or a Const equaling the subplan element. See
457 * generate_setop_tlist() for motivation.
459 if (ptle->expr && IsA(ptle->expr, Var))
461 Var *var = (Var *) ptle->expr;
463 Assert(var->varno == plan->scan.scanrelid);
464 Assert(var->varlevelsup == 0);
465 if (var->varattno != attrno)
466 return false; /* out of order */
468 else if (ptle->expr && IsA(ptle->expr, Const))
470 if (!equal(ptle->expr, ctle->expr))
484 * Offset varnos and other rangetable indexes in a plan tree by rtoffset.
487 adjust_plan_varnos(Plan *plan, int rtoffset)
495 * Plan-type-specific fixes
497 switch (nodeTag(plan))
500 ((SeqScan *) plan)->scanrelid += rtoffset;
501 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
502 adjust_expr_varnos((Node *) plan->qual, rtoffset);
505 ((IndexScan *) plan)->scan.scanrelid += rtoffset;
506 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
507 adjust_expr_varnos((Node *) plan->qual, rtoffset);
508 adjust_expr_varnos((Node *) ((IndexScan *) plan)->indexqual,
510 adjust_expr_varnos((Node *) ((IndexScan *) plan)->indexqualorig,
513 case T_BitmapIndexScan:
514 ((BitmapIndexScan *) plan)->scan.scanrelid += rtoffset;
515 /* no need to fix targetlist and qual */
516 Assert(plan->targetlist == NIL);
517 Assert(plan->qual == NIL);
518 adjust_expr_varnos((Node *) ((BitmapIndexScan *) plan)->indexqual,
520 adjust_expr_varnos((Node *) ((BitmapIndexScan *) plan)->indexqualorig,
523 case T_BitmapHeapScan:
524 ((BitmapHeapScan *) plan)->scan.scanrelid += rtoffset;
525 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
526 adjust_expr_varnos((Node *) plan->qual, rtoffset);
527 adjust_expr_varnos((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig,
531 ((TidScan *) plan)->scan.scanrelid += rtoffset;
532 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
533 adjust_expr_varnos((Node *) plan->qual, rtoffset);
534 adjust_expr_varnos((Node *) ((TidScan *) plan)->tidquals,
538 ((SubqueryScan *) plan)->scan.scanrelid += rtoffset;
539 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
540 adjust_expr_varnos((Node *) plan->qual, rtoffset);
541 /* we should not recurse into the subquery! */
544 ((FunctionScan *) plan)->scan.scanrelid += rtoffset;
545 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
546 adjust_expr_varnos((Node *) plan->qual, rtoffset);
547 /* rte was already fixed by set_subqueryscan_references */
550 ((ValuesScan *) plan)->scan.scanrelid += rtoffset;
551 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
552 adjust_expr_varnos((Node *) plan->qual, rtoffset);
553 /* rte was already fixed by set_subqueryscan_references */
556 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
557 adjust_expr_varnos((Node *) plan->qual, rtoffset);
558 adjust_expr_varnos((Node *) ((Join *) plan)->joinqual, rtoffset);
561 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
562 adjust_expr_varnos((Node *) plan->qual, rtoffset);
563 adjust_expr_varnos((Node *) ((Join *) plan)->joinqual, rtoffset);
564 adjust_expr_varnos((Node *) ((MergeJoin *) plan)->mergeclauses,
568 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
569 adjust_expr_varnos((Node *) plan->qual, rtoffset);
570 adjust_expr_varnos((Node *) ((Join *) plan)->joinqual, rtoffset);
571 adjust_expr_varnos((Node *) ((HashJoin *) plan)->hashclauses,
581 * Even though the targetlist won't be used by the executor, we
582 * fix it up for possible use by EXPLAIN (not to mention ease of
583 * debugging --- wrong varnos are very confusing).
585 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
586 Assert(plan->qual == NIL);
591 * Like the plan types above, Limit doesn't evaluate its tlist or
592 * quals. It does have live expressions for limit/offset,
595 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
596 Assert(plan->qual == NIL);
597 adjust_expr_varnos(((Limit *) plan)->limitOffset, rtoffset);
598 adjust_expr_varnos(((Limit *) plan)->limitCount, rtoffset);
602 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
603 adjust_expr_varnos((Node *) plan->qual, rtoffset);
606 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
607 adjust_expr_varnos((Node *) plan->qual, rtoffset);
608 adjust_expr_varnos(((Result *) plan)->resconstantqual, rtoffset);
611 adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
612 Assert(plan->qual == NIL);
613 foreach(l, ((Append *) plan)->appendplans)
614 adjust_plan_varnos((Plan *) lfirst(l), rtoffset);
617 /* BitmapAnd works like Append, but has no tlist */
618 Assert(plan->targetlist == NIL);
619 Assert(plan->qual == NIL);
620 foreach(l, ((BitmapAnd *) plan)->bitmapplans)
621 adjust_plan_varnos((Plan *) lfirst(l), rtoffset);
624 /* BitmapOr works like Append, but has no tlist */
625 Assert(plan->targetlist == NIL);
626 Assert(plan->qual == NIL);
627 foreach(l, ((BitmapOr *) plan)->bitmapplans)
628 adjust_plan_varnos((Plan *) lfirst(l), rtoffset);
631 elog(ERROR, "unrecognized node type: %d",
632 (int) nodeTag(plan));
637 * Now recurse into child plans.
639 * We don't need to (and in fact mustn't) recurse into subqueries, so no
640 * need to examine initPlan list.
642 adjust_plan_varnos(plan->lefttree, rtoffset);
643 adjust_plan_varnos(plan->righttree, rtoffset);
648 * Offset varnos of Vars in an expression by rtoffset.
650 * This is different from the rewriter's OffsetVarNodes in that it has to
651 * work on an already-planned expression tree; in particular, we should not
652 * disturb INNER and OUTER references. On the other hand, we don't have to
653 * recurse into subqueries nor deal with outer-level Vars, so it's pretty
657 adjust_expr_varnos(Node *node, int rtoffset)
659 /* This tree walk requires no special setup, so away we go... */
660 adjust_expr_varnos_walker(node, &rtoffset);
664 adjust_expr_varnos_walker(Node *node, int *context)
670 Var *var = (Var *) node;
672 Assert(var->varlevelsup == 0);
673 if (var->varno > 0 && var->varno != INNER && var->varno != OUTER)
674 var->varno += *context;
675 if (var->varnoold > 0)
676 var->varnoold += *context;
679 return expression_tree_walker(node, adjust_expr_varnos_walker,
684 * fix_expr_references
685 * Do final cleanup on expressions (targetlists or quals).
687 * This consists of looking up operator opcode info for OpExpr nodes
688 * and recursively performing set_plan_references on subplans.
690 * The Plan argument is currently unused, but might be needed again someday.
693 fix_expr_references(Plan *plan, Node *node)
695 /* This tree walk requires no special setup, so away we go... */
696 fix_expr_references_walker(node, NULL);
700 fix_expr_references_walker(Node *node, void *context)
704 if (IsA(node, OpExpr))
705 set_opfuncid((OpExpr *) node);
706 else if (IsA(node, DistinctExpr))
707 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
708 else if (IsA(node, ScalarArrayOpExpr))
709 set_sa_opfuncid((ScalarArrayOpExpr *) node);
710 else if (IsA(node, NullIfExpr))
711 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
712 else if (IsA(node, SubPlan))
714 SubPlan *sp = (SubPlan *) node;
716 sp->plan = set_plan_references(sp->plan, sp->rtable);
718 return expression_tree_walker(node, fix_expr_references_walker, context);
722 * set_join_references
723 * Modifies the target list and quals of a join node to reference its
724 * subplans, by setting the varnos to OUTER or INNER and setting attno
725 * values to the result domain number of either the corresponding outer
726 * or inner join tuple item.
728 * In the case of a nestloop with inner indexscan, we will also need to
729 * apply the same transformation to any outer vars appearing in the
730 * quals of the child indexscan. set_inner_join_references does that.
732 * 'join' is a join plan node
735 set_join_references(Join *join)
737 Plan *outer_plan = join->plan.lefttree;
738 Plan *inner_plan = join->plan.righttree;
739 indexed_tlist *outer_itlist;
740 indexed_tlist *inner_itlist;
742 outer_itlist = build_tlist_index(outer_plan->targetlist);
743 inner_itlist = build_tlist_index(inner_plan->targetlist);
745 /* All join plans have tlist, qual, and joinqual */
746 join->plan.targetlist = join_references(join->plan.targetlist,
750 join->plan.qual = join_references(join->plan.qual,
754 join->joinqual = join_references(join->joinqual,
759 /* Now do join-type-specific stuff */
760 if (IsA(join, NestLoop))
762 /* This processing is split out to handle possible recursion */
763 set_inner_join_references(inner_plan,
766 else if (IsA(join, MergeJoin))
768 MergeJoin *mj = (MergeJoin *) join;
770 mj->mergeclauses = join_references(mj->mergeclauses,
775 else if (IsA(join, HashJoin))
777 HashJoin *hj = (HashJoin *) join;
779 hj->hashclauses = join_references(hj->hashclauses,
790 * set_inner_join_references
791 * Handle join references appearing in an inner indexscan's quals
793 * To handle bitmap-scan plan trees, we have to be able to recurse down
794 * to the bottom BitmapIndexScan nodes; likewise, appendrel indexscans
795 * require recursing through Append nodes. This is split out as a separate
796 * function so that it can recurse.
799 set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
801 if (IsA(inner_plan, IndexScan))
804 * An index is being used to reduce the number of tuples scanned in
805 * the inner relation. If there are join clauses being used with the
806 * index, we must update their outer-rel var nodes to refer to the
807 * outer side of the join.
809 IndexScan *innerscan = (IndexScan *) inner_plan;
810 List *indexqualorig = innerscan->indexqualorig;
812 /* No work needed if indexqual refers only to its own rel... */
813 if (NumRelids((Node *) indexqualorig) > 1)
815 Index innerrel = innerscan->scan.scanrelid;
817 /* only refs to outer vars get changed in the inner qual */
818 innerscan->indexqualorig = join_references(indexqualorig,
822 innerscan->indexqual = join_references(innerscan->indexqual,
828 * We must fix the inner qpqual too, if it has join clauses (this
829 * could happen if special operators are involved: some indexquals
830 * may get rechecked as qpquals).
832 if (NumRelids((Node *) inner_plan->qual) > 1)
833 inner_plan->qual = join_references(inner_plan->qual,
839 else if (IsA(inner_plan, BitmapIndexScan))
842 * Same, but index is being used within a bitmap plan.
844 BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan;
845 List *indexqualorig = innerscan->indexqualorig;
847 /* No work needed if indexqual refers only to its own rel... */
848 if (NumRelids((Node *) indexqualorig) > 1)
850 Index innerrel = innerscan->scan.scanrelid;
852 /* only refs to outer vars get changed in the inner qual */
853 innerscan->indexqualorig = join_references(indexqualorig,
857 innerscan->indexqual = join_references(innerscan->indexqual,
861 /* no need to fix inner qpqual */
862 Assert(inner_plan->qual == NIL);
865 else if (IsA(inner_plan, BitmapHeapScan))
868 * The inner side is a bitmap scan plan. Fix the top node, and
869 * recurse to get the lower nodes.
871 * Note: create_bitmap_scan_plan removes clauses from bitmapqualorig
872 * if they are duplicated in qpqual, so must test these independently.
874 BitmapHeapScan *innerscan = (BitmapHeapScan *) inner_plan;
875 Index innerrel = innerscan->scan.scanrelid;
876 List *bitmapqualorig = innerscan->bitmapqualorig;
878 /* only refs to outer vars get changed in the inner qual */
879 if (NumRelids((Node *) bitmapqualorig) > 1)
880 innerscan->bitmapqualorig = join_references(bitmapqualorig,
886 * We must fix the inner qpqual too, if it has join clauses (this
887 * could happen if special operators are involved: some indexquals may
888 * get rechecked as qpquals).
890 if (NumRelids((Node *) inner_plan->qual) > 1)
891 inner_plan->qual = join_references(inner_plan->qual,
897 set_inner_join_references(inner_plan->lefttree,
900 else if (IsA(inner_plan, BitmapAnd))
902 /* All we need do here is recurse */
903 BitmapAnd *innerscan = (BitmapAnd *) inner_plan;
906 foreach(l, innerscan->bitmapplans)
908 set_inner_join_references((Plan *) lfirst(l),
912 else if (IsA(inner_plan, BitmapOr))
914 /* All we need do here is recurse */
915 BitmapOr *innerscan = (BitmapOr *) inner_plan;
918 foreach(l, innerscan->bitmapplans)
920 set_inner_join_references((Plan *) lfirst(l),
924 else if (IsA(inner_plan, Append))
927 * The inner side is an append plan. Recurse to see if it contains
928 * indexscans that need to be fixed.
930 Append *appendplan = (Append *) inner_plan;
933 foreach(l, appendplan->appendplans)
935 set_inner_join_references((Plan *) lfirst(l),
939 else if (IsA(inner_plan, TidScan))
941 TidScan *innerscan = (TidScan *) inner_plan;
942 Index innerrel = innerscan->scan.scanrelid;
944 innerscan->tidquals = join_references(innerscan->tidquals,
952 * set_uppernode_references
953 * Update the targetlist and quals of an upper-level plan node
954 * to refer to the tuples returned by its lefttree subplan.
956 * This is used for single-input plan types like Agg, Group, Result.
958 * In most cases, we have to match up individual Vars in the tlist and
959 * qual expressions with elements of the subplan's tlist (which was
960 * generated by flatten_tlist() from these selfsame expressions, so it
961 * should have all the required variables). There is an important exception,
962 * however: GROUP BY and ORDER BY expressions will have been pushed into the
963 * subplan tlist unflattened. If these values are also needed in the output
964 * then we want to reference the subplan tlist element rather than recomputing
968 set_uppernode_references(Plan *plan, Index subvarno)
970 Plan *subplan = plan->lefttree;
971 indexed_tlist *subplan_itlist;
972 List *output_targetlist;
976 subplan_itlist = build_tlist_index(subplan->targetlist);
978 subplan_itlist = build_tlist_index(NIL);
980 output_targetlist = NIL;
981 foreach(l, plan->targetlist)
983 TargetEntry *tle = (TargetEntry *) lfirst(l);
986 newexpr = replace_vars_with_subplan_refs((Node *) tle->expr,
989 tle = flatCopyTargetEntry(tle);
990 tle->expr = (Expr *) newexpr;
991 output_targetlist = lappend(output_targetlist, tle);
993 plan->targetlist = output_targetlist;
995 plan->qual = (List *)
996 replace_vars_with_subplan_refs((Node *) plan->qual,
1000 pfree(subplan_itlist);
1004 * build_tlist_index --- build an index data structure for a child tlist
1006 * In most cases, subplan tlists will be "flat" tlists with only Vars,
1007 * so we try to optimize that case by extracting information about Vars
1008 * in advance. Matching a parent tlist to a child is still an O(N^2)
1009 * operation, but at least with a much smaller constant factor than plain
1010 * tlist_member() searches.
1012 * The result of this function is an indexed_tlist struct to pass to
1013 * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
1014 * When done, the indexed_tlist may be freed with a single pfree().
1016 static indexed_tlist *
1017 build_tlist_index(List *tlist)
1019 indexed_tlist *itlist;
1023 /* Create data structure with enough slots for all tlist entries */
1024 itlist = (indexed_tlist *)
1025 palloc(offsetof(indexed_tlist, vars) +
1026 list_length(tlist) * sizeof(tlist_vinfo));
1028 itlist->tlist = tlist;
1029 itlist->has_non_vars = false;
1031 /* Find the Vars and fill in the index array */
1032 vinfo = itlist->vars;
1035 TargetEntry *tle = (TargetEntry *) lfirst(l);
1037 if (tle->expr && IsA(tle->expr, Var))
1039 Var *var = (Var *) tle->expr;
1041 vinfo->varno = var->varno;
1042 vinfo->varattno = var->varattno;
1043 vinfo->resno = tle->resno;
1047 itlist->has_non_vars = true;
1050 itlist->num_vars = (vinfo - itlist->vars);
1056 * build_tlist_index_other_vars --- build a restricted tlist index
1058 * This is like build_tlist_index, but we only index tlist entries that
1059 * are Vars and belong to some rel other than the one specified.
1061 static indexed_tlist *
1062 build_tlist_index_other_vars(List *tlist, Index ignore_rel)
1064 indexed_tlist *itlist;
1068 /* Create data structure with enough slots for all tlist entries */
1069 itlist = (indexed_tlist *)
1070 palloc(offsetof(indexed_tlist, vars) +
1071 list_length(tlist) * sizeof(tlist_vinfo));
1073 itlist->tlist = tlist;
1074 itlist->has_non_vars = false;
1076 /* Find the desired Vars and fill in the index array */
1077 vinfo = itlist->vars;
1080 TargetEntry *tle = (TargetEntry *) lfirst(l);
1082 if (tle->expr && IsA(tle->expr, Var))
1084 Var *var = (Var *) tle->expr;
1086 if (var->varno != ignore_rel)
1088 vinfo->varno = var->varno;
1089 vinfo->varattno = var->varattno;
1090 vinfo->resno = tle->resno;
1096 itlist->num_vars = (vinfo - itlist->vars);
1102 * search_indexed_tlist_for_var --- find a Var in an indexed tlist
1104 * If a match is found, return a copy of the given Var with suitably
1105 * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
1106 * If no match, return NULL.
1109 search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, Index newvarno)
1111 Index varno = var->varno;
1112 AttrNumber varattno = var->varattno;
1116 vinfo = itlist->vars;
1117 i = itlist->num_vars;
1120 if (vinfo->varno == varno && vinfo->varattno == varattno)
1123 Var *newvar = (Var *) copyObject(var);
1125 newvar->varno = newvarno;
1126 newvar->varattno = vinfo->resno;
1131 return NULL; /* no match */
1135 * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
1137 * If a match is found, return a Var constructed to reference the tlist item.
1138 * If no match, return NULL.
1140 * NOTE: it is a waste of time to call this if !itlist->has_non_vars
1143 search_indexed_tlist_for_non_var(Node *node,
1144 indexed_tlist *itlist, Index newvarno)
1148 tle = tlist_member(node, itlist->tlist);
1151 /* Found a matching subplan output expression */
1154 newvar = makeVar(newvarno,
1156 exprType((Node *) tle->expr),
1157 exprTypmod((Node *) tle->expr),
1159 newvar->varnoold = 0; /* wasn't ever a plain Var */
1160 newvar->varoattno = 0;
1163 return NULL; /* no match */
1168 * Creates a new set of targetlist entries or join qual clauses by
1169 * changing the varno/varattno values of variables in the clauses
1170 * to reference target list values from the outer and inner join
1171 * relation target lists.
1173 * This is used in two different scenarios: a normal join clause, where
1174 * all the Vars in the clause *must* be replaced by OUTER or INNER references;
1175 * and an indexscan being used on the inner side of a nestloop join.
1176 * In the latter case we want to replace the outer-relation Vars by OUTER
1177 * references, but not touch the Vars of the inner relation. (We also
1178 * implement RETURNING clause fixup using this second scenario.)
1180 * For a normal join, acceptable_rel should be zero so that any failure to
1181 * match a Var will be reported as an error. For the indexscan case,
1182 * pass inner_itlist = NULL and acceptable_rel = the ID of the inner relation.
1184 * 'clauses' is the targetlist or list of join clauses
1185 * 'outer_itlist' is the indexed target list of the outer join relation
1186 * 'inner_itlist' is the indexed target list of the inner join relation,
1188 * 'acceptable_rel' is either zero or the rangetable index of a relation
1189 * whose Vars may appear in the clause without provoking an error.
1191 * Returns the new expression tree. The original clause structure is
1195 join_references(List *clauses,
1196 indexed_tlist *outer_itlist,
1197 indexed_tlist *inner_itlist,
1198 Index acceptable_rel)
1200 join_references_context context;
1202 context.outer_itlist = outer_itlist;
1203 context.inner_itlist = inner_itlist;
1204 context.acceptable_rel = acceptable_rel;
1205 return (List *) join_references_mutator((Node *) clauses, &context);
1209 join_references_mutator(Node *node,
1210 join_references_context *context)
1218 Var *var = (Var *) node;
1220 /* First look for the var in the input tlists */
1221 newvar = search_indexed_tlist_for_var(var,
1222 context->outer_itlist,
1225 return (Node *) newvar;
1226 if (context->inner_itlist)
1228 newvar = search_indexed_tlist_for_var(var,
1229 context->inner_itlist,
1232 return (Node *) newvar;
1235 /* Return the Var unmodified, if it's for acceptable_rel */
1236 if (var->varno == context->acceptable_rel)
1237 return (Node *) copyObject(var);
1239 /* No referent found for Var */
1240 elog(ERROR, "variable not found in subplan target lists");
1242 /* Try matching more complex expressions too, if tlists have any */
1243 if (context->outer_itlist->has_non_vars)
1245 newvar = search_indexed_tlist_for_non_var(node,
1246 context->outer_itlist,
1249 return (Node *) newvar;
1251 if (context->inner_itlist && context->inner_itlist->has_non_vars)
1253 newvar = search_indexed_tlist_for_non_var(node,
1254 context->inner_itlist,
1257 return (Node *) newvar;
1259 return expression_tree_mutator(node,
1260 join_references_mutator,
1265 * replace_vars_with_subplan_refs
1266 * This routine modifies an expression tree so that all Var nodes
1267 * reference target nodes of a subplan. It is used to fix up
1268 * target and qual expressions of non-join upper-level plan nodes.
1270 * An error is raised if no matching var can be found in the subplan tlist
1271 * --- so this routine should only be applied to nodes whose subplans'
1272 * targetlists were generated via flatten_tlist() or some such method.
1274 * If itlist->has_non_vars is true, then we try to match whole subexpressions
1275 * against elements of the subplan tlist, so that we can avoid recomputing
1276 * expressions that were already computed by the subplan. (This is relatively
1277 * expensive, so we don't want to try it in the common case where the
1278 * subplan tlist is just a flattened list of Vars.)
1280 * 'node': the tree to be fixed (a target item or qual)
1281 * 'subplan_itlist': indexed target list for subplan
1282 * 'subvarno': varno to be assigned to all Vars
1284 * The resulting tree is a copy of the original in which all Var nodes have
1285 * varno = subvarno, varattno = resno of corresponding subplan target.
1286 * The original tree is not modified.
1289 replace_vars_with_subplan_refs(Node *node,
1290 indexed_tlist *subplan_itlist,
1293 replace_vars_with_subplan_refs_context context;
1295 context.subplan_itlist = subplan_itlist;
1296 context.subvarno = subvarno;
1297 return replace_vars_with_subplan_refs_mutator(node, &context);
1301 replace_vars_with_subplan_refs_mutator(Node *node,
1302 replace_vars_with_subplan_refs_context *context)
1310 Var *var = (Var *) node;
1312 newvar = search_indexed_tlist_for_var(var,
1313 context->subplan_itlist,
1316 elog(ERROR, "variable not found in subplan target list");
1317 return (Node *) newvar;
1319 /* Try matching more complex expressions too, if tlist has any */
1320 if (context->subplan_itlist->has_non_vars)
1322 newvar = search_indexed_tlist_for_non_var(node,
1323 context->subplan_itlist,
1326 return (Node *) newvar;
1328 return expression_tree_mutator(node,
1329 replace_vars_with_subplan_refs_mutator,
1334 * set_returning_clause_references
1335 * Perform setrefs.c's work on a RETURNING targetlist
1337 * If the query involves more than just the result table, we have to
1338 * adjust any Vars that refer to other tables to reference junk tlist
1339 * entries in the top plan's targetlist. Vars referencing the result
1340 * table should be left alone, however (the executor will evaluate them
1341 * using the actual heap tuple, after firing triggers if any). In the
1342 * adjusted RETURNING list, result-table Vars will still have their
1343 * original varno, but Vars for other rels will have varno OUTER.
1345 * We also must apply fix_expr_references to the list.
1347 * 'rlist': the RETURNING targetlist to be fixed
1348 * 'topplan': the top Plan node for the query (not yet passed through
1349 * set_plan_references)
1350 * 'resultRelation': RT index of the query's result relation
1353 set_returning_clause_references(List *rlist,
1355 Index resultRelation)
1357 indexed_tlist *itlist;
1360 * We can perform the desired Var fixup by abusing the join_references
1361 * machinery that normally handles inner indexscan fixup. We search the
1362 * top plan's targetlist for Vars of non-result relations, and use
1363 * join_references to convert RETURNING Vars into references to those
1364 * tlist entries, while leaving result-rel Vars as-is.
1366 itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
1368 rlist = join_references(rlist,
1373 fix_expr_references(topplan, (Node *) rlist);
1380 /*****************************************************************************
1381 * OPERATOR REGPROC LOOKUP
1382 *****************************************************************************/
1386 * Calculate opfuncid field from opno for each OpExpr node in given tree.
1387 * The given tree can be anything expression_tree_walker handles.
1389 * The argument is modified in-place. (This is OK since we'd want the
1390 * same change for any node, even if it gets visited more than once due to
1391 * shared structure.)
1394 fix_opfuncids(Node *node)
1396 /* This tree walk requires no special setup, so away we go... */
1397 fix_opfuncids_walker(node, NULL);
1401 fix_opfuncids_walker(Node *node, void *context)
1405 if (IsA(node, OpExpr))
1406 set_opfuncid((OpExpr *) node);
1407 else if (IsA(node, DistinctExpr))
1408 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1409 else if (IsA(node, ScalarArrayOpExpr))
1410 set_sa_opfuncid((ScalarArrayOpExpr *) node);
1411 else if (IsA(node, NullIfExpr))
1412 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1413 return expression_tree_walker(node, fix_opfuncids_walker, context);
1418 * Set the opfuncid (procedure OID) in an OpExpr node,
1419 * if it hasn't been set already.
1421 * Because of struct equivalence, this can also be used for
1422 * DistinctExpr and NullIfExpr nodes.
1425 set_opfuncid(OpExpr *opexpr)
1427 if (opexpr->opfuncid == InvalidOid)
1428 opexpr->opfuncid = get_opcode(opexpr->opno);
1433 * As above, for ScalarArrayOpExpr nodes.
1436 set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
1438 if (opexpr->opfuncid == InvalidOid)
1439 opexpr->opfuncid = get_opcode(opexpr->opno);