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-2020, 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/optimizer.h"
23 #include "optimizer/pathnode.h"
24 #include "optimizer/planmain.h"
25 #include "optimizer/planner.h"
26 #include "optimizer/tlist.h"
27 #include "tcop/utility.h"
28 #include "utils/lsyscache.h"
29 #include "utils/syscache.h"
34 Index varno
; /* RT index of Var */
35 AttrNumber varattno
; /* attr number of Var */
36 AttrNumber resno
; /* TLE position of Var */
41 List
*tlist
; /* underlying target list */
42 int num_vars
; /* number of plain Var tlist entries */
43 bool has_ph_vars
; /* are there PlaceHolderVar entries? */
44 bool has_non_vars
; /* are there other entries? */
45 tlist_vinfo vars
[FLEXIBLE_ARRAY_MEMBER
]; /* has num_vars entries */
52 } fix_scan_expr_context
;
57 indexed_tlist
*outer_itlist
;
58 indexed_tlist
*inner_itlist
;
61 } fix_join_expr_context
;
66 indexed_tlist
*subplan_itlist
;
69 } fix_upper_expr_context
;
72 * Check if a Const node is a regclass value. We accept plain OID too,
73 * since a regclass Const will get folded to that type if it's an argument
74 * to oideq or similar operators. (This might result in some extraneous
75 * values in a plan's list of relation dependencies, but the worst result
76 * would be occasional useless replans.)
78 #define ISREGCLASSCONST(con) \
79 (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
82 #define fix_scan_list(root, lst, rtoffset) \
83 ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))
85 static void add_rtes_to_flat_rtable(PlannerInfo
*root
, bool recursing
);
86 static void flatten_unplanned_rtes(PlannerGlobal
*glob
, RangeTblEntry
*rte
);
87 static bool flatten_rtes_walker(Node
*node
, PlannerGlobal
*glob
);
88 static void add_rte_to_flat_rtable(PlannerGlobal
*glob
, RangeTblEntry
*rte
);
89 static Plan
*set_plan_refs(PlannerInfo
*root
, Plan
*plan
, int rtoffset
);
90 static Plan
*set_indexonlyscan_references(PlannerInfo
*root
,
93 static Plan
*set_subqueryscan_references(PlannerInfo
*root
,
96 static bool trivial_subqueryscan(SubqueryScan
*plan
);
97 static Plan
*clean_up_removed_plan_level(Plan
*parent
, Plan
*child
);
98 static void set_foreignscan_references(PlannerInfo
*root
,
101 static void set_customscan_references(PlannerInfo
*root
,
104 static Plan
*set_append_references(PlannerInfo
*root
,
107 static Plan
*set_mergeappend_references(PlannerInfo
*root
,
110 static void set_hash_references(PlannerInfo
*root
, Plan
*plan
, int rtoffset
);
111 static Relids
offset_relid_set(Relids relids
, int rtoffset
);
112 static Node
*fix_scan_expr(PlannerInfo
*root
, Node
*node
, int rtoffset
);
113 static Node
*fix_scan_expr_mutator(Node
*node
, fix_scan_expr_context
*context
);
114 static bool fix_scan_expr_walker(Node
*node
, fix_scan_expr_context
*context
);
115 static void set_join_references(PlannerInfo
*root
, Join
*join
, int rtoffset
);
116 static void set_upper_references(PlannerInfo
*root
, Plan
*plan
, int rtoffset
);
117 static void set_param_references(PlannerInfo
*root
, Plan
*plan
);
118 static Node
*convert_combining_aggrefs(Node
*node
, void *context
);
119 static void set_dummy_tlist_references(Plan
*plan
, int rtoffset
);
120 static indexed_tlist
*build_tlist_index(List
*tlist
);
121 static Var
*search_indexed_tlist_for_var(Var
*var
,
122 indexed_tlist
*itlist
,
125 static Var
*search_indexed_tlist_for_non_var(Expr
*node
,
126 indexed_tlist
*itlist
,
128 static Var
*search_indexed_tlist_for_sortgroupref(Expr
*node
,
130 indexed_tlist
*itlist
,
132 static List
*fix_join_expr(PlannerInfo
*root
,
134 indexed_tlist
*outer_itlist
,
135 indexed_tlist
*inner_itlist
,
136 Index acceptable_rel
, int rtoffset
);
137 static Node
*fix_join_expr_mutator(Node
*node
,
138 fix_join_expr_context
*context
);
139 static Node
*fix_upper_expr(PlannerInfo
*root
,
141 indexed_tlist
*subplan_itlist
,
144 static Node
*fix_upper_expr_mutator(Node
*node
,
145 fix_upper_expr_context
*context
);
146 static List
*set_returning_clause_references(PlannerInfo
*root
,
149 Index resultRelation
,
153 /*****************************************************************************
157 *****************************************************************************/
160 * set_plan_references
162 * This is the final processing pass of the planner/optimizer. The plan
163 * tree is complete; we just have to adjust some representational details
164 * for the convenience of the executor:
166 * 1. We flatten the various subquery rangetables into a single list, and
167 * zero out RangeTblEntry fields that are not useful to the executor.
169 * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
171 * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
174 * 4. Aggrefs in Agg plan nodes need to be adjusted in some cases involving
175 * partial aggregation or minmax aggregate optimization.
177 * 5. PARAM_MULTIEXPR Params are replaced by regular PARAM_EXEC Params,
178 * now that we have finished planning all MULTIEXPR subplans.
180 * 6. We compute regproc OIDs for operators (ie, we look up the function
181 * that implements each op).
183 * 7. We create lists of specific objects that the plan depends on.
184 * This will be used by plancache.c to drive invalidation of cached plans.
185 * Relation dependencies are represented by OIDs, and everything else by
186 * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
187 * Currently, relations, user-defined functions, and domains are the only
188 * types of objects that are explicitly tracked this way.
190 * 8. We assign every plan node in the tree a unique ID.
192 * We also perform one final optimization step, which is to delete
193 * SubqueryScan, Append, and MergeAppend plan nodes that aren't doing
194 * anything useful. The reason for doing this last is that
195 * it can't readily be done before set_plan_references, because it would
196 * break set_upper_references: the Vars in the child plan's top tlist
197 * wouldn't match up with the Vars in the outer plan tree. A SubqueryScan
198 * serves a necessary function as a buffer between outer query and subquery
199 * variable numbering ... but after we've flattened the rangetable this is
200 * no longer a problem, since then there's only one rtindex namespace.
201 * Likewise, Append and MergeAppend buffer between the parent and child vars
202 * of an appendrel, but we don't need to worry about that once we've done
203 * set_plan_references.
205 * set_plan_references recursively traverses the whole plan tree.
207 * The return value is normally the same Plan node passed in, but can be
208 * different when the passed-in Plan is a node we decide isn't needed.
210 * The flattened rangetable entries are appended to root->glob->finalrtable.
211 * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the
212 * RT indexes of ModifyTable result relations to root->glob->resultRelations,
213 * and flattened AppendRelInfos are appended to root->glob->appendRelations.
214 * Plan dependencies are appended to root->glob->relationOids (for relations)
215 * and root->glob->invalItems (for everything else).
217 * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
218 * to process targetlist and qual expressions. We can assume that the Plan
219 * nodes were just built by the planner and are not multiply referenced, but
220 * it's not so safe to assume that for expression tree nodes.
223 set_plan_references(PlannerInfo
*root
, Plan
*plan
)
225 PlannerGlobal
*glob
= root
->glob
;
226 int rtoffset
= list_length(glob
->finalrtable
);
230 * Add all the query's RTEs to the flattened rangetable. The live ones
231 * will have their rangetable indexes increased by rtoffset. (Additional
232 * RTEs, not referenced by the Plan tree, might get added after those.)
234 add_rtes_to_flat_rtable(root
, false);
237 * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
239 foreach(lc
, root
->rowMarks
)
241 PlanRowMark
*rc
= lfirst_node(PlanRowMark
, lc
);
244 /* flat copy is enough since all fields are scalars */
245 newrc
= (PlanRowMark
*) palloc(sizeof(PlanRowMark
));
246 memcpy(newrc
, rc
, sizeof(PlanRowMark
));
248 /* adjust indexes ... but *not* the rowmarkId */
249 newrc
->rti
+= rtoffset
;
250 newrc
->prti
+= rtoffset
;
252 glob
->finalrowmarks
= lappend(glob
->finalrowmarks
, newrc
);
256 * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
257 * We assume the AppendRelInfos were built during planning and don't need
260 foreach(lc
, root
->append_rel_list
)
262 AppendRelInfo
*appinfo
= lfirst_node(AppendRelInfo
, lc
);
264 /* adjust RT indexes */
265 appinfo
->parent_relid
+= rtoffset
;
266 appinfo
->child_relid
+= rtoffset
;
269 * Rather than adjust the translated_vars entries, just drop 'em.
270 * Neither the executor nor EXPLAIN currently need that data.
272 appinfo
->translated_vars
= NIL
;
274 glob
->appendRelations
= lappend(glob
->appendRelations
, appinfo
);
277 /* Now fix the Plan tree */
278 return set_plan_refs(root
, plan
, rtoffset
);
282 * Extract RangeTblEntries from the plan's rangetable, and add to flat rtable
284 * This can recurse into subquery plans; "recursing" is true if so.
287 add_rtes_to_flat_rtable(PlannerInfo
*root
, bool recursing
)
289 PlannerGlobal
*glob
= root
->glob
;
294 * Add the query's own RTEs to the flattened rangetable.
296 * At top level, we must add all RTEs so that their indexes in the
297 * flattened rangetable match up with their original indexes. When
298 * recursing, we only care about extracting relation RTEs.
300 foreach(lc
, root
->parse
->rtable
)
302 RangeTblEntry
*rte
= (RangeTblEntry
*) lfirst(lc
);
304 if (!recursing
|| rte
->rtekind
== RTE_RELATION
)
305 add_rte_to_flat_rtable(glob
, rte
);
309 * If there are any dead subqueries, they are not referenced in the Plan
310 * tree, so we must add RTEs contained in them to the flattened rtable
311 * separately. (If we failed to do this, the executor would not perform
312 * expected permission checks for tables mentioned in such subqueries.)
314 * Note: this pass over the rangetable can't be combined with the previous
315 * one, because that would mess up the numbering of the live RTEs in the
316 * flattened rangetable.
319 foreach(lc
, root
->parse
->rtable
)
321 RangeTblEntry
*rte
= (RangeTblEntry
*) lfirst(lc
);
324 * We should ignore inheritance-parent RTEs: their contents have been
325 * pulled up into our rangetable already. Also ignore any subquery
326 * RTEs without matching RelOptInfos, as they likewise have been
329 if (rte
->rtekind
== RTE_SUBQUERY
&& !rte
->inh
&&
330 rti
< root
->simple_rel_array_size
)
332 RelOptInfo
*rel
= root
->simple_rel_array
[rti
];
336 Assert(rel
->relid
== rti
); /* sanity check on array */
339 * The subquery might never have been planned at all, if it
340 * was excluded on the basis of self-contradictory constraints
341 * in our query level. In this case apply
342 * flatten_unplanned_rtes.
344 * If it was planned but the result rel is dummy, we assume
345 * that it has been omitted from our plan tree (see
346 * set_subquery_pathlist), and recurse to pull up its RTEs.
348 * Otherwise, it should be represented by a SubqueryScan node
349 * somewhere in our plan tree, and we'll pull up its RTEs when
350 * we process that plan node.
352 * However, if we're recursing, then we should pull up RTEs
353 * whether the subquery is dummy or not, because we've found
354 * that some upper query level is treating this one as dummy,
355 * and so we won't scan this level's plan tree at all.
357 if (rel
->subroot
== NULL
)
358 flatten_unplanned_rtes(glob
, rte
);
359 else if (recursing
||
360 IS_DUMMY_REL(fetch_upper_rel(rel
->subroot
,
361 UPPERREL_FINAL
, NULL
)))
362 add_rtes_to_flat_rtable(rel
->subroot
, true);
370 * Extract RangeTblEntries from a subquery that was never planned at all
373 flatten_unplanned_rtes(PlannerGlobal
*glob
, RangeTblEntry
*rte
)
375 /* Use query_tree_walker to find all RTEs in the parse tree */
376 (void) query_tree_walker(rte
->subquery
,
379 QTW_EXAMINE_RTES_BEFORE
);
383 flatten_rtes_walker(Node
*node
, PlannerGlobal
*glob
)
387 if (IsA(node
, RangeTblEntry
))
389 RangeTblEntry
*rte
= (RangeTblEntry
*) node
;
391 /* As above, we need only save relation RTEs */
392 if (rte
->rtekind
== RTE_RELATION
)
393 add_rte_to_flat_rtable(glob
, rte
);
396 if (IsA(node
, Query
))
398 /* Recurse into subselects */
399 return query_tree_walker((Query
*) node
,
402 QTW_EXAMINE_RTES_BEFORE
);
404 return expression_tree_walker(node
, flatten_rtes_walker
,
409 * Add (a copy of) the given RTE to the final rangetable
411 * In the flat rangetable, we zero out substructure pointers that are not
412 * needed by the executor; this reduces the storage space and copying cost
413 * for cached plans. We keep only the ctename, alias and eref Alias fields,
414 * which are needed by EXPLAIN, and the selectedCols, insertedCols,
415 * updatedCols, and extraUpdatedCols bitmaps, which are needed for
416 * executor-startup permissions checking and for trigger event checking.
419 add_rte_to_flat_rtable(PlannerGlobal
*glob
, RangeTblEntry
*rte
)
421 RangeTblEntry
*newrte
;
423 /* flat copy to duplicate all the scalar fields */
424 newrte
= (RangeTblEntry
*) palloc(sizeof(RangeTblEntry
));
425 memcpy(newrte
, rte
, sizeof(RangeTblEntry
));
427 /* zap unneeded sub-structure */
428 newrte
->tablesample
= NULL
;
429 newrte
->subquery
= NULL
;
430 newrte
->joinaliasvars
= NIL
;
431 newrte
->joinleftcols
= NIL
;
432 newrte
->joinrightcols
= NIL
;
433 newrte
->functions
= NIL
;
434 newrte
->tablefunc
= NULL
;
435 newrte
->values_lists
= NIL
;
436 newrte
->coltypes
= NIL
;
437 newrte
->coltypmods
= NIL
;
438 newrte
->colcollations
= NIL
;
439 newrte
->securityQuals
= NIL
;
441 glob
->finalrtable
= lappend(glob
->finalrtable
, newrte
);
444 * Check for RT index overflow; it's very unlikely, but if it did happen,
445 * the executor would get confused by varnos that match the special varno
448 if (IS_SPECIAL_VARNO(list_length(glob
->finalrtable
)))
450 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED
),
451 errmsg("too many range table entries")));
454 * If it's a plain relation RTE, add the table to relationOids.
456 * We do this even though the RTE might be unreferenced in the plan tree;
457 * this would correspond to cases such as views that were expanded, child
458 * tables that were eliminated by constraint exclusion, etc. Schema
459 * invalidation on such a rel must still force rebuilding of the plan.
461 * Note we don't bother to avoid making duplicate list entries. We could,
462 * but it would probably cost more cycles than it would save.
464 if (newrte
->rtekind
== RTE_RELATION
)
465 glob
->relationOids
= lappend_oid(glob
->relationOids
, newrte
->relid
);
469 * set_plan_refs: recurse through the Plan nodes of a single subquery level
472 set_plan_refs(PlannerInfo
*root
, Plan
*plan
, int rtoffset
)
479 /* Assign this node a unique ID. */
480 plan
->plan_node_id
= root
->glob
->lastPlanNodeId
++;
483 * Plan-type-specific fixes
485 switch (nodeTag(plan
))
489 SeqScan
*splan
= (SeqScan
*) plan
;
491 splan
->scanrelid
+= rtoffset
;
492 splan
->plan
.targetlist
=
493 fix_scan_list(root
, splan
->plan
.targetlist
, rtoffset
);
495 fix_scan_list(root
, splan
->plan
.qual
, rtoffset
);
500 SampleScan
*splan
= (SampleScan
*) plan
;
502 splan
->scan
.scanrelid
+= rtoffset
;
503 splan
->scan
.plan
.targetlist
=
504 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
505 splan
->scan
.plan
.qual
=
506 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
507 splan
->tablesample
= (TableSampleClause
*)
508 fix_scan_expr(root
, (Node
*) splan
->tablesample
, rtoffset
);
513 IndexScan
*splan
= (IndexScan
*) plan
;
515 splan
->scan
.scanrelid
+= rtoffset
;
516 splan
->scan
.plan
.targetlist
=
517 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
518 splan
->scan
.plan
.qual
=
519 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
521 fix_scan_list(root
, splan
->indexqual
, rtoffset
);
522 splan
->indexqualorig
=
523 fix_scan_list(root
, splan
->indexqualorig
, rtoffset
);
524 splan
->indexorderby
=
525 fix_scan_list(root
, splan
->indexorderby
, rtoffset
);
526 splan
->indexorderbyorig
=
527 fix_scan_list(root
, splan
->indexorderbyorig
, rtoffset
);
530 case T_IndexOnlyScan
:
532 IndexOnlyScan
*splan
= (IndexOnlyScan
*) plan
;
534 return set_indexonlyscan_references(root
, splan
, rtoffset
);
537 case T_BitmapIndexScan
:
539 BitmapIndexScan
*splan
= (BitmapIndexScan
*) plan
;
541 splan
->scan
.scanrelid
+= rtoffset
;
542 /* no need to fix targetlist and qual */
543 Assert(splan
->scan
.plan
.targetlist
== NIL
);
544 Assert(splan
->scan
.plan
.qual
== NIL
);
546 fix_scan_list(root
, splan
->indexqual
, rtoffset
);
547 splan
->indexqualorig
=
548 fix_scan_list(root
, splan
->indexqualorig
, rtoffset
);
551 case T_BitmapHeapScan
:
553 BitmapHeapScan
*splan
= (BitmapHeapScan
*) plan
;
555 splan
->scan
.scanrelid
+= rtoffset
;
556 splan
->scan
.plan
.targetlist
=
557 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
558 splan
->scan
.plan
.qual
=
559 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
560 splan
->bitmapqualorig
=
561 fix_scan_list(root
, splan
->bitmapqualorig
, rtoffset
);
566 TidScan
*splan
= (TidScan
*) plan
;
568 splan
->scan
.scanrelid
+= rtoffset
;
569 splan
->scan
.plan
.targetlist
=
570 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
571 splan
->scan
.plan
.qual
=
572 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
574 fix_scan_list(root
, splan
->tidquals
, rtoffset
);
578 /* Needs special treatment, see comments below */
579 return set_subqueryscan_references(root
,
580 (SubqueryScan
*) plan
,
584 FunctionScan
*splan
= (FunctionScan
*) plan
;
586 splan
->scan
.scanrelid
+= rtoffset
;
587 splan
->scan
.plan
.targetlist
=
588 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
589 splan
->scan
.plan
.qual
=
590 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
592 fix_scan_list(root
, splan
->functions
, rtoffset
);
595 case T_TableFuncScan
:
597 TableFuncScan
*splan
= (TableFuncScan
*) plan
;
599 splan
->scan
.scanrelid
+= rtoffset
;
600 splan
->scan
.plan
.targetlist
=
601 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
602 splan
->scan
.plan
.qual
=
603 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
604 splan
->tablefunc
= (TableFunc
*)
605 fix_scan_expr(root
, (Node
*) splan
->tablefunc
, rtoffset
);
610 ValuesScan
*splan
= (ValuesScan
*) plan
;
612 splan
->scan
.scanrelid
+= rtoffset
;
613 splan
->scan
.plan
.targetlist
=
614 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
615 splan
->scan
.plan
.qual
=
616 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
617 splan
->values_lists
=
618 fix_scan_list(root
, splan
->values_lists
, rtoffset
);
623 CteScan
*splan
= (CteScan
*) plan
;
625 splan
->scan
.scanrelid
+= rtoffset
;
626 splan
->scan
.plan
.targetlist
=
627 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
628 splan
->scan
.plan
.qual
=
629 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
632 case T_NamedTuplestoreScan
:
634 NamedTuplestoreScan
*splan
= (NamedTuplestoreScan
*) plan
;
636 splan
->scan
.scanrelid
+= rtoffset
;
637 splan
->scan
.plan
.targetlist
=
638 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
639 splan
->scan
.plan
.qual
=
640 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
643 case T_WorkTableScan
:
645 WorkTableScan
*splan
= (WorkTableScan
*) plan
;
647 splan
->scan
.scanrelid
+= rtoffset
;
648 splan
->scan
.plan
.targetlist
=
649 fix_scan_list(root
, splan
->scan
.plan
.targetlist
, rtoffset
);
650 splan
->scan
.plan
.qual
=
651 fix_scan_list(root
, splan
->scan
.plan
.qual
, rtoffset
);
655 set_foreignscan_references(root
, (ForeignScan
*) plan
, rtoffset
);
658 set_customscan_references(root
, (CustomScan
*) plan
, rtoffset
);
664 set_join_references(root
, (Join
*) plan
, rtoffset
);
670 set_upper_references(root
, plan
, rtoffset
);
671 set_param_references(root
, plan
);
676 set_hash_references(root
, plan
, rtoffset
);
681 case T_IncrementalSort
:
686 * These plan types don't actually bother to evaluate their
687 * targetlists, because they just return their unmodified input
688 * tuples. Even though the targetlist won't be used by the
689 * executor, we fix it up for possible use by EXPLAIN (not to
690 * mention ease of debugging --- wrong varnos are very confusing).
692 set_dummy_tlist_references(plan
, rtoffset
);
695 * Since these plan types don't check quals either, we should not
696 * find any qual expression attached to them.
698 Assert(plan
->qual
== NIL
);
702 LockRows
*splan
= (LockRows
*) plan
;
705 * Like the plan types above, LockRows doesn't evaluate its
706 * tlist or quals. But we have to fix up the RT indexes in
709 set_dummy_tlist_references(plan
, rtoffset
);
710 Assert(splan
->plan
.qual
== NIL
);
712 foreach(l
, splan
->rowMarks
)
714 PlanRowMark
*rc
= (PlanRowMark
*) lfirst(l
);
717 rc
->prti
+= rtoffset
;
723 Limit
*splan
= (Limit
*) plan
;
726 * Like the plan types above, Limit doesn't evaluate its tlist
727 * or quals. It does have live expressions for limit/offset,
728 * however; and those cannot contain subplan variable refs, so
729 * fix_scan_expr works for them.
731 set_dummy_tlist_references(plan
, rtoffset
);
732 Assert(splan
->plan
.qual
== NIL
);
735 fix_scan_expr(root
, splan
->limitOffset
, rtoffset
);
737 fix_scan_expr(root
, splan
->limitCount
, rtoffset
);
742 Agg
*agg
= (Agg
*) plan
;
745 * If this node is combining partial-aggregation results, we
746 * must convert its Aggrefs to contain references to the
747 * partial-aggregate subexpressions that will be available
748 * from the child plan node.
750 if (DO_AGGSPLIT_COMBINE(agg
->aggsplit
))
752 plan
->targetlist
= (List
*)
753 convert_combining_aggrefs((Node
*) plan
->targetlist
,
755 plan
->qual
= (List
*)
756 convert_combining_aggrefs((Node
*) plan
->qual
,
760 set_upper_references(root
, plan
, rtoffset
);
764 set_upper_references(root
, plan
, rtoffset
);
768 WindowAgg
*wplan
= (WindowAgg
*) plan
;
770 set_upper_references(root
, plan
, rtoffset
);
773 * Like Limit node limit/offset expressions, WindowAgg has
774 * frame offset expressions, which cannot contain subplan
775 * variable refs, so fix_scan_expr works for them.
778 fix_scan_expr(root
, wplan
->startOffset
, rtoffset
);
780 fix_scan_expr(root
, wplan
->endOffset
, rtoffset
);
785 Result
*splan
= (Result
*) plan
;
788 * Result may or may not have a subplan; if not, it's more
789 * like a scan node than an upper node.
791 if (splan
->plan
.lefttree
!= NULL
)
792 set_upper_references(root
, plan
, rtoffset
);
795 splan
->plan
.targetlist
=
796 fix_scan_list(root
, splan
->plan
.targetlist
, rtoffset
);
798 fix_scan_list(root
, splan
->plan
.qual
, rtoffset
);
800 /* resconstantqual can't contain any subplan variable refs */
801 splan
->resconstantqual
=
802 fix_scan_expr(root
, splan
->resconstantqual
, rtoffset
);
806 set_upper_references(root
, plan
, rtoffset
);
810 ModifyTable
*splan
= (ModifyTable
*) plan
;
812 Assert(splan
->plan
.targetlist
== NIL
);
813 Assert(splan
->plan
.qual
== NIL
);
815 splan
->withCheckOptionLists
=
816 fix_scan_list(root
, splan
->withCheckOptionLists
, rtoffset
);
818 if (splan
->returningLists
)
826 * Pass each per-subplan returningList through
827 * set_returning_clause_references().
829 Assert(list_length(splan
->returningLists
) == list_length(splan
->resultRelations
));
830 Assert(list_length(splan
->returningLists
) == list_length(splan
->plans
));
831 forthree(lcrl
, splan
->returningLists
,
832 lcrr
, splan
->resultRelations
,
835 List
*rlist
= (List
*) lfirst(lcrl
);
836 Index resultrel
= lfirst_int(lcrr
);
837 Plan
*subplan
= (Plan
*) lfirst(lcp
);
839 rlist
= set_returning_clause_references(root
,
844 newRL
= lappend(newRL
, rlist
);
846 splan
->returningLists
= newRL
;
849 * Set up the visible plan targetlist as being the same as
850 * the first RETURNING list. This is for the use of
851 * EXPLAIN; the executor won't pay any attention to the
852 * targetlist. We postpone this step until here so that
853 * we don't have to do set_returning_clause_references()
854 * twice on identical targetlists.
856 splan
->plan
.targetlist
= copyObject(linitial(newRL
));
860 * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
861 * join', where the inner side is the EXCLUDED tuple.
862 * Therefore use fix_join_expr to setup the relevant variables
863 * to INNER_VAR. We explicitly don't create any OUTER_VARs as
864 * those are already used by RETURNING and it seems better to
865 * be non-conflicting.
867 if (splan
->onConflictSet
)
869 indexed_tlist
*itlist
;
871 itlist
= build_tlist_index(splan
->exclRelTlist
);
873 splan
->onConflictSet
=
874 fix_join_expr(root
, splan
->onConflictSet
,
876 linitial_int(splan
->resultRelations
),
879 splan
->onConflictWhere
= (Node
*)
880 fix_join_expr(root
, (List
*) splan
->onConflictWhere
,
882 linitial_int(splan
->resultRelations
),
887 splan
->exclRelTlist
=
888 fix_scan_list(root
, splan
->exclRelTlist
, rtoffset
);
891 splan
->nominalRelation
+= rtoffset
;
892 if (splan
->rootRelation
)
893 splan
->rootRelation
+= rtoffset
;
894 splan
->exclRelRTI
+= rtoffset
;
896 foreach(l
, splan
->resultRelations
)
898 lfirst_int(l
) += rtoffset
;
900 foreach(l
, splan
->rowMarks
)
902 PlanRowMark
*rc
= (PlanRowMark
*) lfirst(l
);
905 rc
->prti
+= rtoffset
;
907 foreach(l
, splan
->plans
)
909 lfirst(l
) = set_plan_refs(root
,
915 * Append this ModifyTable node's final result relation RT
916 * index(es) to the global list for the plan, and set its
917 * resultRelIndex to reflect their starting position in the
920 splan
->resultRelIndex
= list_length(root
->glob
->resultRelations
);
921 root
->glob
->resultRelations
=
922 list_concat(root
->glob
->resultRelations
,
923 splan
->resultRelations
);
926 * If the main target relation is a partitioned table, also
927 * add the partition root's RT index to rootResultRelations,
928 * and remember its index in that list in rootResultRelIndex.
930 if (splan
->rootRelation
)
932 splan
->rootResultRelIndex
=
933 list_length(root
->glob
->rootResultRelations
);
934 root
->glob
->rootResultRelations
=
935 lappend_int(root
->glob
->rootResultRelations
,
936 splan
->rootRelation
);
941 /* Needs special treatment, see comments below */
942 return set_append_references(root
,
946 /* Needs special treatment, see comments below */
947 return set_mergeappend_references(root
,
948 (MergeAppend
*) plan
,
950 case T_RecursiveUnion
:
951 /* This doesn't evaluate targetlist or check quals either */
952 set_dummy_tlist_references(plan
, rtoffset
);
953 Assert(plan
->qual
== NIL
);
957 BitmapAnd
*splan
= (BitmapAnd
*) plan
;
959 /* BitmapAnd works like Append, but has no tlist */
960 Assert(splan
->plan
.targetlist
== NIL
);
961 Assert(splan
->plan
.qual
== NIL
);
962 foreach(l
, splan
->bitmapplans
)
964 lfirst(l
) = set_plan_refs(root
,
972 BitmapOr
*splan
= (BitmapOr
*) plan
;
974 /* BitmapOr works like Append, but has no tlist */
975 Assert(splan
->plan
.targetlist
== NIL
);
976 Assert(splan
->plan
.qual
== NIL
);
977 foreach(l
, splan
->bitmapplans
)
979 lfirst(l
) = set_plan_refs(root
,
986 elog(ERROR
, "unrecognized node type: %d",
987 (int) nodeTag(plan
));
992 * Now recurse into child plans, if any
994 * NOTE: it is essential that we recurse into child plans AFTER we set
995 * subplan references in this plan's tlist and quals. If we did the
996 * reference-adjustments bottom-up, then we would fail to match this
997 * plan's var nodes against the already-modified nodes of the children.
999 plan
->lefttree
= set_plan_refs(root
, plan
->lefttree
, rtoffset
);
1000 plan
->righttree
= set_plan_refs(root
, plan
->righttree
, rtoffset
);
1006 * set_indexonlyscan_references
1007 * Do set_plan_references processing on an IndexOnlyScan
1009 * This is unlike the handling of a plain IndexScan because we have to
1010 * convert Vars referencing the heap into Vars referencing the index.
1011 * We can use the fix_upper_expr machinery for that, by working from a
1012 * targetlist describing the index columns.
1015 set_indexonlyscan_references(PlannerInfo
*root
,
1016 IndexOnlyScan
*plan
,
1019 indexed_tlist
*index_itlist
;
1020 List
*stripped_indextlist
;
1024 * Vars in the plan node's targetlist, qual, and recheckqual must only
1025 * reference columns that the index AM can actually return. To ensure
1026 * this, remove non-returnable columns (which are marked as resjunk) from
1027 * the indexed tlist. We can just drop them because the indexed_tlist
1028 * machinery pays attention to TLE resnos, not physical list position.
1030 stripped_indextlist
= NIL
;
1031 foreach(lc
, plan
->indextlist
)
1033 TargetEntry
*indextle
= (TargetEntry
*) lfirst(lc
);
1035 if (!indextle
->resjunk
)
1036 stripped_indextlist
= lappend(stripped_indextlist
, indextle
);
1039 index_itlist
= build_tlist_index(stripped_indextlist
);
1041 plan
->scan
.scanrelid
+= rtoffset
;
1042 plan
->scan
.plan
.targetlist
= (List
*)
1043 fix_upper_expr(root
,
1044 (Node
*) plan
->scan
.plan
.targetlist
,
1048 plan
->scan
.plan
.qual
= (List
*)
1049 fix_upper_expr(root
,
1050 (Node
*) plan
->scan
.plan
.qual
,
1054 plan
->recheckqual
= (List
*)
1055 fix_upper_expr(root
,
1056 (Node
*) plan
->recheckqual
,
1060 /* indexqual is already transformed to reference index columns */
1061 plan
->indexqual
= fix_scan_list(root
, plan
->indexqual
, rtoffset
);
1062 /* indexorderby is already transformed to reference index columns */
1063 plan
->indexorderby
= fix_scan_list(root
, plan
->indexorderby
, rtoffset
);
1064 /* indextlist must NOT be transformed to reference index columns */
1065 plan
->indextlist
= fix_scan_list(root
, plan
->indextlist
, rtoffset
);
1067 pfree(index_itlist
);
1069 return (Plan
*) plan
;
1073 * set_subqueryscan_references
1074 * Do set_plan_references processing on a SubqueryScan
1076 * We try to strip out the SubqueryScan entirely; if we can't, we have
1077 * to do the normal processing on it.
1080 set_subqueryscan_references(PlannerInfo
*root
,
1087 /* Need to look up the subquery's RelOptInfo, since we need its subroot */
1088 rel
= find_base_rel(root
, plan
->scan
.scanrelid
);
1090 /* Recursively process the subplan */
1091 plan
->subplan
= set_plan_references(rel
->subroot
, plan
->subplan
);
1093 if (trivial_subqueryscan(plan
))
1096 * We can omit the SubqueryScan node and just pull up the subplan.
1098 result
= clean_up_removed_plan_level((Plan
*) plan
, plan
->subplan
);
1103 * Keep the SubqueryScan node. We have to do the processing that
1104 * set_plan_references would otherwise have done on it. Notice we do
1105 * not do set_upper_references() here, because a SubqueryScan will
1106 * always have been created with correct references to its subplan's
1107 * outputs to begin with.
1109 plan
->scan
.scanrelid
+= rtoffset
;
1110 plan
->scan
.plan
.targetlist
=
1111 fix_scan_list(root
, plan
->scan
.plan
.targetlist
, rtoffset
);
1112 plan
->scan
.plan
.qual
=
1113 fix_scan_list(root
, plan
->scan
.plan
.qual
, rtoffset
);
1115 result
= (Plan
*) plan
;
1122 * trivial_subqueryscan
1123 * Detect whether a SubqueryScan can be deleted from the plan tree.
1125 * We can delete it if it has no qual to check and the targetlist just
1126 * regurgitates the output of the child plan.
1129 trivial_subqueryscan(SubqueryScan
*plan
)
1135 if (plan
->scan
.plan
.qual
!= NIL
)
1138 if (list_length(plan
->scan
.plan
.targetlist
) !=
1139 list_length(plan
->subplan
->targetlist
))
1140 return false; /* tlists not same length */
1143 forboth(lp
, plan
->scan
.plan
.targetlist
, lc
, plan
->subplan
->targetlist
)
1145 TargetEntry
*ptle
= (TargetEntry
*) lfirst(lp
);
1146 TargetEntry
*ctle
= (TargetEntry
*) lfirst(lc
);
1148 if (ptle
->resjunk
!= ctle
->resjunk
)
1149 return false; /* tlist doesn't match junk status */
1152 * We accept either a Var referencing the corresponding element of the
1153 * subplan tlist, or a Const equaling the subplan element. See
1154 * generate_setop_tlist() for motivation.
1156 if (ptle
->expr
&& IsA(ptle
->expr
, Var
))
1158 Var
*var
= (Var
*) ptle
->expr
;
1160 Assert(var
->varno
== plan
->scan
.scanrelid
);
1161 Assert(var
->varlevelsup
== 0);
1162 if (var
->varattno
!= attrno
)
1163 return false; /* out of order */
1165 else if (ptle
->expr
&& IsA(ptle
->expr
, Const
))
1167 if (!equal(ptle
->expr
, ctle
->expr
))
1180 * clean_up_removed_plan_level
1181 * Do necessary cleanup when we strip out a SubqueryScan, Append, etc
1183 * We are dropping the "parent" plan in favor of returning just its "child".
1184 * A few small tweaks are needed.
1187 clean_up_removed_plan_level(Plan
*parent
, Plan
*child
)
1190 * We have to be sure we don't lose any initplans, so move any that were
1191 * attached to the parent plan to the child. If we do move any, the child
1192 * is no longer parallel-safe.
1194 if (parent
->initPlan
)
1195 child
->parallel_safe
= false;
1198 * Attach plans this way so that parent's initplans are processed before
1199 * any pre-existing initplans of the child. Probably doesn't matter, but
1200 * let's preserve the ordering just in case.
1202 child
->initPlan
= list_concat(parent
->initPlan
,
1206 * We also have to transfer the parent's column labeling info into the
1207 * child, else columns sent to client will be improperly labeled if this
1208 * is the topmost plan level. resjunk and so on may be important too.
1210 apply_tlist_labeling(child
->targetlist
, parent
->targetlist
);
1216 * set_foreignscan_references
1217 * Do set_plan_references processing on a ForeignScan
1220 set_foreignscan_references(PlannerInfo
*root
,
1224 /* Adjust scanrelid if it's valid */
1225 if (fscan
->scan
.scanrelid
> 0)
1226 fscan
->scan
.scanrelid
+= rtoffset
;
1228 if (fscan
->fdw_scan_tlist
!= NIL
|| fscan
->scan
.scanrelid
== 0)
1231 * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1232 * foreign scan tuple
1234 indexed_tlist
*itlist
= build_tlist_index(fscan
->fdw_scan_tlist
);
1236 fscan
->scan
.plan
.targetlist
= (List
*)
1237 fix_upper_expr(root
,
1238 (Node
*) fscan
->scan
.plan
.targetlist
,
1242 fscan
->scan
.plan
.qual
= (List
*)
1243 fix_upper_expr(root
,
1244 (Node
*) fscan
->scan
.plan
.qual
,
1248 fscan
->fdw_exprs
= (List
*)
1249 fix_upper_expr(root
,
1250 (Node
*) fscan
->fdw_exprs
,
1254 fscan
->fdw_recheck_quals
= (List
*)
1255 fix_upper_expr(root
,
1256 (Node
*) fscan
->fdw_recheck_quals
,
1261 /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1262 fscan
->fdw_scan_tlist
=
1263 fix_scan_list(root
, fscan
->fdw_scan_tlist
, rtoffset
);
1268 * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
1271 fscan
->scan
.plan
.targetlist
=
1272 fix_scan_list(root
, fscan
->scan
.plan
.targetlist
, rtoffset
);
1273 fscan
->scan
.plan
.qual
=
1274 fix_scan_list(root
, fscan
->scan
.plan
.qual
, rtoffset
);
1276 fix_scan_list(root
, fscan
->fdw_exprs
, rtoffset
);
1277 fscan
->fdw_recheck_quals
=
1278 fix_scan_list(root
, fscan
->fdw_recheck_quals
, rtoffset
);
1281 fscan
->fs_relids
= offset_relid_set(fscan
->fs_relids
, rtoffset
);
1285 * set_customscan_references
1286 * Do set_plan_references processing on a CustomScan
1289 set_customscan_references(PlannerInfo
*root
,
1295 /* Adjust scanrelid if it's valid */
1296 if (cscan
->scan
.scanrelid
> 0)
1297 cscan
->scan
.scanrelid
+= rtoffset
;
1299 if (cscan
->custom_scan_tlist
!= NIL
|| cscan
->scan
.scanrelid
== 0)
1301 /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1302 indexed_tlist
*itlist
= build_tlist_index(cscan
->custom_scan_tlist
);
1304 cscan
->scan
.plan
.targetlist
= (List
*)
1305 fix_upper_expr(root
,
1306 (Node
*) cscan
->scan
.plan
.targetlist
,
1310 cscan
->scan
.plan
.qual
= (List
*)
1311 fix_upper_expr(root
,
1312 (Node
*) cscan
->scan
.plan
.qual
,
1316 cscan
->custom_exprs
= (List
*)
1317 fix_upper_expr(root
,
1318 (Node
*) cscan
->custom_exprs
,
1323 /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1324 cscan
->custom_scan_tlist
=
1325 fix_scan_list(root
, cscan
->custom_scan_tlist
, rtoffset
);
1329 /* Adjust tlist, qual, custom_exprs in the standard way */
1330 cscan
->scan
.plan
.targetlist
=
1331 fix_scan_list(root
, cscan
->scan
.plan
.targetlist
, rtoffset
);
1332 cscan
->scan
.plan
.qual
=
1333 fix_scan_list(root
, cscan
->scan
.plan
.qual
, rtoffset
);
1334 cscan
->custom_exprs
=
1335 fix_scan_list(root
, cscan
->custom_exprs
, rtoffset
);
1338 /* Adjust child plan-nodes recursively, if needed */
1339 foreach(lc
, cscan
->custom_plans
)
1341 lfirst(lc
) = set_plan_refs(root
, (Plan
*) lfirst(lc
), rtoffset
);
1344 cscan
->custom_relids
= offset_relid_set(cscan
->custom_relids
, rtoffset
);
1348 * set_append_references
1349 * Do set_plan_references processing on an Append
1351 * We try to strip out the Append entirely; if we can't, we have
1352 * to do the normal processing on it.
1355 set_append_references(PlannerInfo
*root
,
1362 * Append, like Sort et al, doesn't actually evaluate its targetlist or
1363 * check quals. If it's got exactly one child plan, then it's not doing
1364 * anything useful at all, and we can strip it out.
1366 Assert(aplan
->plan
.qual
== NIL
);
1368 /* First, we gotta recurse on the children */
1369 foreach(l
, aplan
->appendplans
)
1371 lfirst(l
) = set_plan_refs(root
, (Plan
*) lfirst(l
), rtoffset
);
1375 * See if it's safe to get rid of the Append entirely. For this to be
1376 * safe, there must be only one child plan and that child plan's parallel
1377 * awareness must match that of the Append's. The reason for the latter
1378 * is that the if the Append is parallel aware and the child is not then
1379 * the calling plan may execute the non-parallel aware child multiple
1382 if (list_length(aplan
->appendplans
) == 1 &&
1383 ((Plan
*) linitial(aplan
->appendplans
))->parallel_aware
== aplan
->plan
.parallel_aware
)
1384 return clean_up_removed_plan_level((Plan
*) aplan
,
1385 (Plan
*) linitial(aplan
->appendplans
));
1388 * Otherwise, clean up the Append as needed. It's okay to do this after
1389 * recursing to the children, because set_dummy_tlist_references doesn't
1392 set_dummy_tlist_references((Plan
*) aplan
, rtoffset
);
1394 aplan
->apprelids
= offset_relid_set(aplan
->apprelids
, rtoffset
);
1396 if (aplan
->part_prune_info
)
1398 foreach(l
, aplan
->part_prune_info
->prune_infos
)
1400 List
*prune_infos
= lfirst(l
);
1403 foreach(l2
, prune_infos
)
1405 PartitionedRelPruneInfo
*pinfo
= lfirst(l2
);
1407 pinfo
->rtindex
+= rtoffset
;
1412 /* We don't need to recurse to lefttree or righttree ... */
1413 Assert(aplan
->plan
.lefttree
== NULL
);
1414 Assert(aplan
->plan
.righttree
== NULL
);
1416 return (Plan
*) aplan
;
1420 * set_mergeappend_references
1421 * Do set_plan_references processing on a MergeAppend
1423 * We try to strip out the MergeAppend entirely; if we can't, we have
1424 * to do the normal processing on it.
1427 set_mergeappend_references(PlannerInfo
*root
,
1434 * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
1435 * or check quals. If it's got exactly one child plan, then it's not
1436 * doing anything useful at all, and we can strip it out.
1438 Assert(mplan
->plan
.qual
== NIL
);
1440 /* First, we gotta recurse on the children */
1441 foreach(l
, mplan
->mergeplans
)
1443 lfirst(l
) = set_plan_refs(root
, (Plan
*) lfirst(l
), rtoffset
);
1447 * See if it's safe to get rid of the MergeAppend entirely. For this to
1448 * be safe, there must be only one child plan and that child plan's
1449 * parallel awareness must match that of the MergeAppend's. The reason
1450 * for the latter is that the if the MergeAppend is parallel aware and the
1451 * child is not then the calling plan may execute the non-parallel aware
1452 * child multiple times.
1454 if (list_length(mplan
->mergeplans
) == 1 &&
1455 ((Plan
*) linitial(mplan
->mergeplans
))->parallel_aware
== mplan
->plan
.parallel_aware
)
1456 return clean_up_removed_plan_level((Plan
*) mplan
,
1457 (Plan
*) linitial(mplan
->mergeplans
));
1460 * Otherwise, clean up the MergeAppend as needed. It's okay to do this
1461 * after recursing to the children, because set_dummy_tlist_references
1462 * doesn't look at those.
1464 set_dummy_tlist_references((Plan
*) mplan
, rtoffset
);
1466 mplan
->apprelids
= offset_relid_set(mplan
->apprelids
, rtoffset
);
1468 if (mplan
->part_prune_info
)
1470 foreach(l
, mplan
->part_prune_info
->prune_infos
)
1472 List
*prune_infos
= lfirst(l
);
1475 foreach(l2
, prune_infos
)
1477 PartitionedRelPruneInfo
*pinfo
= lfirst(l2
);
1479 pinfo
->rtindex
+= rtoffset
;
1484 /* We don't need to recurse to lefttree or righttree ... */
1485 Assert(mplan
->plan
.lefttree
== NULL
);
1486 Assert(mplan
->plan
.righttree
== NULL
);
1488 return (Plan
*) mplan
;
1492 * set_hash_references
1493 * Do set_plan_references processing on a Hash node
1496 set_hash_references(PlannerInfo
*root
, Plan
*plan
, int rtoffset
)
1498 Hash
*hplan
= (Hash
*) plan
;
1499 Plan
*outer_plan
= plan
->lefttree
;
1500 indexed_tlist
*outer_itlist
;
1503 * Hash's hashkeys are used when feeding tuples into the hashtable,
1504 * therefore have them reference Hash's outer plan (which itself is the
1505 * inner plan of the HashJoin).
1507 outer_itlist
= build_tlist_index(outer_plan
->targetlist
);
1508 hplan
->hashkeys
= (List
*)
1509 fix_upper_expr(root
,
1510 (Node
*) hplan
->hashkeys
,
1515 /* Hash doesn't project */
1516 set_dummy_tlist_references(plan
, rtoffset
);
1518 /* Hash nodes don't have their own quals */
1519 Assert(plan
->qual
== NIL
);
1524 * Apply rtoffset to the members of a Relids set.
1527 offset_relid_set(Relids relids
, int rtoffset
)
1529 Relids result
= NULL
;
1532 /* If there's no offset to apply, we needn't recompute the value */
1536 while ((rtindex
= bms_next_member(relids
, rtindex
)) >= 0)
1537 result
= bms_add_member(result
, rtindex
+ rtoffset
);
1545 * fix_scan_expr and friends do this enough times that it's worth having
1546 * a bespoke routine instead of using the generic copyObject() function.
1551 Var
*newvar
= (Var
*) palloc(sizeof(Var
));
1559 * Do generic set_plan_references processing on an expression node
1561 * This is code that is common to all variants of expression-fixing.
1562 * We must look up operator opcode info for OpExpr and related nodes,
1563 * add OIDs from regclass Const nodes into root->glob->relationOids, and
1564 * add PlanInvalItems for user-defined functions into root->glob->invalItems.
1565 * We also fill in column index lists for GROUPING() expressions.
1567 * We assume it's okay to update opcode info in-place. So this could possibly
1568 * scribble on the planner's input data structures, but it's OK.
1571 fix_expr_common(PlannerInfo
*root
, Node
*node
)
1573 /* We assume callers won't call us on a NULL pointer */
1574 if (IsA(node
, Aggref
))
1576 record_plan_function_dependency(root
,
1577 ((Aggref
*) node
)->aggfnoid
);
1579 else if (IsA(node
, WindowFunc
))
1581 record_plan_function_dependency(root
,
1582 ((WindowFunc
*) node
)->winfnoid
);
1584 else if (IsA(node
, FuncExpr
))
1586 record_plan_function_dependency(root
,
1587 ((FuncExpr
*) node
)->funcid
);
1589 else if (IsA(node
, OpExpr
))
1591 set_opfuncid((OpExpr
*) node
);
1592 record_plan_function_dependency(root
,
1593 ((OpExpr
*) node
)->opfuncid
);
1595 else if (IsA(node
, DistinctExpr
))
1597 set_opfuncid((OpExpr
*) node
); /* rely on struct equivalence */
1598 record_plan_function_dependency(root
,
1599 ((DistinctExpr
*) node
)->opfuncid
);
1601 else if (IsA(node
, NullIfExpr
))
1603 set_opfuncid((OpExpr
*) node
); /* rely on struct equivalence */
1604 record_plan_function_dependency(root
,
1605 ((NullIfExpr
*) node
)->opfuncid
);
1607 else if (IsA(node
, ScalarArrayOpExpr
))
1609 set_sa_opfuncid((ScalarArrayOpExpr
*) node
);
1610 record_plan_function_dependency(root
,
1611 ((ScalarArrayOpExpr
*) node
)->opfuncid
);
1613 else if (IsA(node
, Const
))
1615 Const
*con
= (Const
*) node
;
1617 /* Check for regclass reference */
1618 if (ISREGCLASSCONST(con
))
1619 root
->glob
->relationOids
=
1620 lappend_oid(root
->glob
->relationOids
,
1621 DatumGetObjectId(con
->constvalue
));
1623 else if (IsA(node
, GroupingFunc
))
1625 GroupingFunc
*g
= (GroupingFunc
*) node
;
1626 AttrNumber
*grouping_map
= root
->grouping_map
;
1628 /* If there are no grouping sets, we don't need this. */
1630 Assert(grouping_map
|| g
->cols
== NIL
);
1637 foreach(lc
, g
->refs
)
1639 cols
= lappend_int(cols
, grouping_map
[lfirst_int(lc
)]);
1642 Assert(!g
->cols
|| equal(cols
, g
->cols
));
1652 * Do set_plan_references processing on a Param
1654 * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from
1655 * root->multiexpr_params; otherwise no change is needed.
1656 * Just for paranoia's sake, we make a copy of the node in either case.
1659 fix_param_node(PlannerInfo
*root
, Param
*p
)
1661 if (p
->paramkind
== PARAM_MULTIEXPR
)
1663 int subqueryid
= p
->paramid
>> 16;
1664 int colno
= p
->paramid
& 0xFFFF;
1667 if (subqueryid
<= 0 ||
1668 subqueryid
> list_length(root
->multiexpr_params
))
1669 elog(ERROR
, "unexpected PARAM_MULTIEXPR ID: %d", p
->paramid
);
1670 params
= (List
*) list_nth(root
->multiexpr_params
, subqueryid
- 1);
1671 if (colno
<= 0 || colno
> list_length(params
))
1672 elog(ERROR
, "unexpected PARAM_MULTIEXPR ID: %d", p
->paramid
);
1673 return copyObject(list_nth(params
, colno
- 1));
1675 return (Node
*) copyObject(p
);
1680 * Do set_plan_references processing on a scan-level expression
1682 * This consists of incrementing all Vars' varnos by rtoffset,
1683 * replacing PARAM_MULTIEXPR Params, expanding PlaceHolderVars,
1684 * replacing Aggref nodes that should be replaced by initplan output Params,
1685 * looking up operator opcode info for OpExpr and related nodes,
1686 * and adding OIDs from regclass Const nodes into root->glob->relationOids.
1689 fix_scan_expr(PlannerInfo
*root
, Node
*node
, int rtoffset
)
1691 fix_scan_expr_context context
;
1693 context
.root
= root
;
1694 context
.rtoffset
= rtoffset
;
1696 if (rtoffset
!= 0 ||
1697 root
->multiexpr_params
!= NIL
||
1698 root
->glob
->lastPHId
!= 0 ||
1699 root
->minmax_aggs
!= NIL
)
1701 return fix_scan_expr_mutator(node
, &context
);
1706 * If rtoffset == 0, we don't need to change any Vars, and if there
1707 * are no MULTIEXPR subqueries then we don't need to replace
1708 * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
1709 * we won't need to remove them, and if there are no minmax Aggrefs we
1710 * won't need to replace them. Then it's OK to just scribble on the
1711 * input node tree instead of copying (since the only change, filling
1712 * in any unset opfuncid fields, is harmless). This saves just enough
1713 * cycles to be noticeable on trivial queries.
1715 (void) fix_scan_expr_walker(node
, &context
);
1721 fix_scan_expr_mutator(Node
*node
, fix_scan_expr_context
*context
)
1727 Var
*var
= copyVar((Var
*) node
);
1729 Assert(var
->varlevelsup
== 0);
1732 * We should not see any Vars marked INNER_VAR or OUTER_VAR. But an
1733 * indexqual expression could contain INDEX_VAR Vars.
1735 Assert(var
->varno
!= INNER_VAR
);
1736 Assert(var
->varno
!= OUTER_VAR
);
1737 if (!IS_SPECIAL_VARNO(var
->varno
))
1738 var
->varno
+= context
->rtoffset
;
1739 if (var
->varnosyn
> 0)
1740 var
->varnosyn
+= context
->rtoffset
;
1741 return (Node
*) var
;
1743 if (IsA(node
, Param
))
1744 return fix_param_node(context
->root
, (Param
*) node
);
1745 if (IsA(node
, Aggref
))
1747 Aggref
*aggref
= (Aggref
*) node
;
1749 /* See if the Aggref should be replaced by a Param */
1750 if (context
->root
->minmax_aggs
!= NIL
&&
1751 list_length(aggref
->args
) == 1)
1753 TargetEntry
*curTarget
= (TargetEntry
*) linitial(aggref
->args
);
1756 foreach(lc
, context
->root
->minmax_aggs
)
1758 MinMaxAggInfo
*mminfo
= (MinMaxAggInfo
*) lfirst(lc
);
1760 if (mminfo
->aggfnoid
== aggref
->aggfnoid
&&
1761 equal(mminfo
->target
, curTarget
->expr
))
1762 return (Node
*) copyObject(mminfo
->param
);
1765 /* If no match, just fall through to process it normally */
1767 if (IsA(node
, CurrentOfExpr
))
1769 CurrentOfExpr
*cexpr
= (CurrentOfExpr
*) copyObject(node
);
1771 Assert(cexpr
->cvarno
!= INNER_VAR
);
1772 Assert(cexpr
->cvarno
!= OUTER_VAR
);
1773 if (!IS_SPECIAL_VARNO(cexpr
->cvarno
))
1774 cexpr
->cvarno
+= context
->rtoffset
;
1775 return (Node
*) cexpr
;
1777 if (IsA(node
, PlaceHolderVar
))
1779 /* At scan level, we should always just evaluate the contained expr */
1780 PlaceHolderVar
*phv
= (PlaceHolderVar
*) node
;
1782 return fix_scan_expr_mutator((Node
*) phv
->phexpr
, context
);
1784 fix_expr_common(context
->root
, node
);
1785 return expression_tree_mutator(node
, fix_scan_expr_mutator
,
1790 fix_scan_expr_walker(Node
*node
, fix_scan_expr_context
*context
)
1794 Assert(!IsA(node
, PlaceHolderVar
));
1795 fix_expr_common(context
->root
, node
);
1796 return expression_tree_walker(node
, fix_scan_expr_walker
,
1801 * set_join_references
1802 * Modify the target list and quals of a join node to reference its
1803 * subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting
1804 * attno values to the result domain number of either the corresponding
1805 * outer or inner join tuple item. Also perform opcode lookup for these
1806 * expressions, and add regclass OIDs to root->glob->relationOids.
1809 set_join_references(PlannerInfo
*root
, Join
*join
, int rtoffset
)
1811 Plan
*outer_plan
= join
->plan
.lefttree
;
1812 Plan
*inner_plan
= join
->plan
.righttree
;
1813 indexed_tlist
*outer_itlist
;
1814 indexed_tlist
*inner_itlist
;
1816 outer_itlist
= build_tlist_index(outer_plan
->targetlist
);
1817 inner_itlist
= build_tlist_index(inner_plan
->targetlist
);
1820 * First process the joinquals (including merge or hash clauses). These
1821 * are logically below the join so they can always use all values
1822 * available from the input tlists. It's okay to also handle
1823 * NestLoopParams now, because those couldn't refer to nullable
1826 join
->joinqual
= fix_join_expr(root
,
1833 /* Now do join-type-specific stuff */
1834 if (IsA(join
, NestLoop
))
1836 NestLoop
*nl
= (NestLoop
*) join
;
1839 foreach(lc
, nl
->nestParams
)
1841 NestLoopParam
*nlp
= (NestLoopParam
*) lfirst(lc
);
1843 nlp
->paramval
= (Var
*) fix_upper_expr(root
,
1844 (Node
*) nlp
->paramval
,
1848 /* Check we replaced any PlaceHolderVar with simple Var */
1849 if (!(IsA(nlp
->paramval
, Var
) &&
1850 nlp
->paramval
->varno
== OUTER_VAR
))
1851 elog(ERROR
, "NestLoopParam was not reduced to a simple Var");
1854 else if (IsA(join
, MergeJoin
))
1856 MergeJoin
*mj
= (MergeJoin
*) join
;
1858 mj
->mergeclauses
= fix_join_expr(root
,
1865 else if (IsA(join
, HashJoin
))
1867 HashJoin
*hj
= (HashJoin
*) join
;
1869 hj
->hashclauses
= fix_join_expr(root
,
1877 * HashJoin's hashkeys are used to look for matching tuples from its
1878 * outer plan (not the Hash node!) in the hashtable.
1880 hj
->hashkeys
= (List
*) fix_upper_expr(root
,
1881 (Node
*) hj
->hashkeys
,
1888 * Now we need to fix up the targetlist and qpqual, which are logically
1889 * above the join. This means they should not re-use any input expression
1890 * that was computed in the nullable side of an outer join. Vars and
1891 * PlaceHolderVars are fine, so we can implement this restriction just by
1892 * clearing has_non_vars in the indexed_tlist structs.
1894 * XXX This is a grotty workaround for the fact that we don't clearly
1895 * distinguish between a Var appearing below an outer join and the "same"
1896 * Var appearing above it. If we did, we'd not need to hack the matching
1899 switch (join
->jointype
)
1904 inner_itlist
->has_non_vars
= false;
1907 outer_itlist
->has_non_vars
= false;
1910 outer_itlist
->has_non_vars
= false;
1911 inner_itlist
->has_non_vars
= false;
1917 join
->plan
.targetlist
= fix_join_expr(root
,
1918 join
->plan
.targetlist
,
1923 join
->plan
.qual
= fix_join_expr(root
,
1930 pfree(outer_itlist
);
1931 pfree(inner_itlist
);
1935 * set_upper_references
1936 * Update the targetlist and quals of an upper-level plan node
1937 * to refer to the tuples returned by its lefttree subplan.
1938 * Also perform opcode lookup for these expressions, and
1939 * add regclass OIDs to root->glob->relationOids.
1941 * This is used for single-input plan types like Agg, Group, Result.
1943 * In most cases, we have to match up individual Vars in the tlist and
1944 * qual expressions with elements of the subplan's tlist (which was
1945 * generated by flattening these selfsame expressions, so it should have all
1946 * the required variables). There is an important exception, however:
1947 * depending on where we are in the plan tree, sort/group columns may have
1948 * been pushed into the subplan tlist unflattened. If these values are also
1949 * needed in the output then we want to reference the subplan tlist element
1950 * rather than recomputing the expression.
1953 set_upper_references(PlannerInfo
*root
, Plan
*plan
, int rtoffset
)
1955 Plan
*subplan
= plan
->lefttree
;
1956 indexed_tlist
*subplan_itlist
;
1957 List
*output_targetlist
;
1960 subplan_itlist
= build_tlist_index(subplan
->targetlist
);
1962 output_targetlist
= NIL
;
1963 foreach(l
, plan
->targetlist
)
1965 TargetEntry
*tle
= (TargetEntry
*) lfirst(l
);
1968 /* If it's a sort/group item, first try to match by sortref */
1969 if (tle
->ressortgroupref
!= 0)
1972 search_indexed_tlist_for_sortgroupref(tle
->expr
,
1973 tle
->ressortgroupref
,
1977 newexpr
= fix_upper_expr(root
,
1984 newexpr
= fix_upper_expr(root
,
1989 tle
= flatCopyTargetEntry(tle
);
1990 tle
->expr
= (Expr
*) newexpr
;
1991 output_targetlist
= lappend(output_targetlist
, tle
);
1993 plan
->targetlist
= output_targetlist
;
1995 plan
->qual
= (List
*)
1996 fix_upper_expr(root
,
1997 (Node
*) plan
->qual
,
2002 pfree(subplan_itlist
);
2006 * set_param_references
2007 * Initialize the initParam list in Gather or Gather merge node such that
2008 * it contains reference of all the params that needs to be evaluated
2009 * before execution of the node. It contains the initplan params that are
2010 * being passed to the plan nodes below it.
2013 set_param_references(PlannerInfo
*root
, Plan
*plan
)
2015 Assert(IsA(plan
, Gather
) || IsA(plan
, GatherMerge
));
2017 if (plan
->lefttree
->extParam
)
2020 Bitmapset
*initSetParam
= NULL
;
2023 for (proot
= root
; proot
!= NULL
; proot
= proot
->parent_root
)
2025 foreach(l
, proot
->init_plans
)
2027 SubPlan
*initsubplan
= (SubPlan
*) lfirst(l
);
2030 foreach(l2
, initsubplan
->setParam
)
2032 initSetParam
= bms_add_member(initSetParam
, lfirst_int(l2
));
2038 * Remember the list of all external initplan params that are used by
2039 * the children of Gather or Gather merge node.
2041 if (IsA(plan
, Gather
))
2042 ((Gather
*) plan
)->initParam
=
2043 bms_intersect(plan
->lefttree
->extParam
, initSetParam
);
2045 ((GatherMerge
*) plan
)->initParam
=
2046 bms_intersect(plan
->lefttree
->extParam
, initSetParam
);
2051 * Recursively scan an expression tree and convert Aggrefs to the proper
2052 * intermediate form for combining aggregates. This means (1) replacing each
2053 * one's argument list with a single argument that is the original Aggref
2054 * modified to show partial aggregation and (2) changing the upper Aggref to
2055 * show combining aggregation.
2057 * After this step, set_upper_references will replace the partial Aggrefs
2058 * with Vars referencing the lower Agg plan node's outputs, so that the final
2059 * form seen by the executor is a combining Aggref with a Var as input.
2061 * It's rather messy to postpone this step until setrefs.c; ideally it'd be
2062 * done in createplan.c. The difficulty is that once we modify the Aggref
2063 * expressions, they will no longer be equal() to their original form and
2064 * so cross-plan-node-level matches will fail. So this has to happen after
2065 * the plan node above the Agg has resolved its subplan references.
2068 convert_combining_aggrefs(Node
*node
, void *context
)
2072 if (IsA(node
, Aggref
))
2074 Aggref
*orig_agg
= (Aggref
*) node
;
2078 /* Assert we've not chosen to partial-ize any unsupported cases */
2079 Assert(orig_agg
->aggorder
== NIL
);
2080 Assert(orig_agg
->aggdistinct
== NIL
);
2083 * Since aggregate calls can't be nested, we needn't recurse into the
2084 * arguments. But for safety, flat-copy the Aggref node itself rather
2085 * than modifying it in-place.
2087 child_agg
= makeNode(Aggref
);
2088 memcpy(child_agg
, orig_agg
, sizeof(Aggref
));
2091 * For the parent Aggref, we want to copy all the fields of the
2092 * original aggregate *except* the args list, which we'll replace
2093 * below, and the aggfilter expression, which should be applied only
2094 * by the child not the parent. Rather than explicitly knowing about
2095 * all the other fields here, we can momentarily modify child_agg to
2096 * provide a suitable source for copyObject.
2098 child_agg
->args
= NIL
;
2099 child_agg
->aggfilter
= NULL
;
2100 parent_agg
= copyObject(child_agg
);
2101 child_agg
->args
= orig_agg
->args
;
2102 child_agg
->aggfilter
= orig_agg
->aggfilter
;
2105 * Now, set up child_agg to represent the first phase of partial
2106 * aggregation. For now, assume serialization is required.
2108 mark_partial_aggref(child_agg
, AGGSPLIT_INITIAL_SERIAL
);
2111 * And set up parent_agg to represent the second phase.
2113 parent_agg
->args
= list_make1(makeTargetEntry((Expr
*) child_agg
,
2115 mark_partial_aggref(parent_agg
, AGGSPLIT_FINAL_DESERIAL
);
2117 return (Node
*) parent_agg
;
2119 return expression_tree_mutator(node
, convert_combining_aggrefs
,
2124 * set_dummy_tlist_references
2125 * Replace the targetlist of an upper-level plan node with a simple
2126 * list of OUTER_VAR references to its child.
2128 * This is used for plan types like Sort and Append that don't evaluate
2129 * their targetlists. Although the executor doesn't care at all what's in
2130 * the tlist, EXPLAIN needs it to be realistic.
2132 * Note: we could almost use set_upper_references() here, but it fails for
2133 * Append for lack of a lefttree subplan. Single-purpose code is faster
2137 set_dummy_tlist_references(Plan
*plan
, int rtoffset
)
2139 List
*output_targetlist
;
2142 output_targetlist
= NIL
;
2143 foreach(l
, plan
->targetlist
)
2145 TargetEntry
*tle
= (TargetEntry
*) lfirst(l
);
2146 Var
*oldvar
= (Var
*) tle
->expr
;
2150 * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
2151 * as Consts, not Vars referencing Consts. Here, there's no speed
2152 * advantage to be had, but it makes EXPLAIN output look cleaner, and
2153 * again it avoids confusing the executor.
2155 if (IsA(oldvar
, Const
))
2157 /* just reuse the existing TLE node */
2158 output_targetlist
= lappend(output_targetlist
, tle
);
2162 newvar
= makeVar(OUTER_VAR
,
2164 exprType((Node
*) oldvar
),
2165 exprTypmod((Node
*) oldvar
),
2166 exprCollation((Node
*) oldvar
),
2168 if (IsA(oldvar
, Var
) &&
2169 oldvar
->varnosyn
> 0)
2171 newvar
->varnosyn
= oldvar
->varnosyn
+ rtoffset
;
2172 newvar
->varattnosyn
= oldvar
->varattnosyn
;
2176 newvar
->varnosyn
= 0; /* wasn't ever a plain Var */
2177 newvar
->varattnosyn
= 0;
2180 tle
= flatCopyTargetEntry(tle
);
2181 tle
->expr
= (Expr
*) newvar
;
2182 output_targetlist
= lappend(output_targetlist
, tle
);
2184 plan
->targetlist
= output_targetlist
;
2186 /* We don't touch plan->qual here */
2191 * build_tlist_index --- build an index data structure for a child tlist
2193 * In most cases, subplan tlists will be "flat" tlists with only Vars,
2194 * so we try to optimize that case by extracting information about Vars
2195 * in advance. Matching a parent tlist to a child is still an O(N^2)
2196 * operation, but at least with a much smaller constant factor than plain
2197 * tlist_member() searches.
2199 * The result of this function is an indexed_tlist struct to pass to
2200 * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
2201 * When done, the indexed_tlist may be freed with a single pfree().
2203 static indexed_tlist
*
2204 build_tlist_index(List
*tlist
)
2206 indexed_tlist
*itlist
;
2210 /* Create data structure with enough slots for all tlist entries */
2211 itlist
= (indexed_tlist
*)
2212 palloc(offsetof(indexed_tlist
, vars
) +
2213 list_length(tlist
) * sizeof(tlist_vinfo
));
2215 itlist
->tlist
= tlist
;
2216 itlist
->has_ph_vars
= false;
2217 itlist
->has_non_vars
= false;
2219 /* Find the Vars and fill in the index array */
2220 vinfo
= itlist
->vars
;
2223 TargetEntry
*tle
= (TargetEntry
*) lfirst(l
);
2225 if (tle
->expr
&& IsA(tle
->expr
, Var
))
2227 Var
*var
= (Var
*) tle
->expr
;
2229 vinfo
->varno
= var
->varno
;
2230 vinfo
->varattno
= var
->varattno
;
2231 vinfo
->resno
= tle
->resno
;
2234 else if (tle
->expr
&& IsA(tle
->expr
, PlaceHolderVar
))
2235 itlist
->has_ph_vars
= true;
2237 itlist
->has_non_vars
= true;
2240 itlist
->num_vars
= (vinfo
- itlist
->vars
);
2246 * build_tlist_index_other_vars --- build a restricted tlist index
2248 * This is like build_tlist_index, but we only index tlist entries that
2249 * are Vars belonging to some rel other than the one specified. We will set
2250 * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
2251 * (so nothing other than Vars and PlaceHolderVars can be matched).
2253 static indexed_tlist
*
2254 build_tlist_index_other_vars(List
*tlist
, Index ignore_rel
)
2256 indexed_tlist
*itlist
;
2260 /* Create data structure with enough slots for all tlist entries */
2261 itlist
= (indexed_tlist
*)
2262 palloc(offsetof(indexed_tlist
, vars
) +
2263 list_length(tlist
) * sizeof(tlist_vinfo
));
2265 itlist
->tlist
= tlist
;
2266 itlist
->has_ph_vars
= false;
2267 itlist
->has_non_vars
= false;
2269 /* Find the desired Vars and fill in the index array */
2270 vinfo
= itlist
->vars
;
2273 TargetEntry
*tle
= (TargetEntry
*) lfirst(l
);
2275 if (tle
->expr
&& IsA(tle
->expr
, Var
))
2277 Var
*var
= (Var
*) tle
->expr
;
2279 if (var
->varno
!= ignore_rel
)
2281 vinfo
->varno
= var
->varno
;
2282 vinfo
->varattno
= var
->varattno
;
2283 vinfo
->resno
= tle
->resno
;
2287 else if (tle
->expr
&& IsA(tle
->expr
, PlaceHolderVar
))
2288 itlist
->has_ph_vars
= true;
2291 itlist
->num_vars
= (vinfo
- itlist
->vars
);
2297 * search_indexed_tlist_for_var --- find a Var in an indexed tlist
2299 * If a match is found, return a copy of the given Var with suitably
2300 * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
2301 * Also ensure that varnosyn is incremented by rtoffset.
2302 * If no match, return NULL.
2305 search_indexed_tlist_for_var(Var
*var
, indexed_tlist
*itlist
,
2306 Index newvarno
, int rtoffset
)
2308 Index varno
= var
->varno
;
2309 AttrNumber varattno
= var
->varattno
;
2313 vinfo
= itlist
->vars
;
2314 i
= itlist
->num_vars
;
2317 if (vinfo
->varno
== varno
&& vinfo
->varattno
== varattno
)
2320 Var
*newvar
= copyVar(var
);
2322 newvar
->varno
= newvarno
;
2323 newvar
->varattno
= vinfo
->resno
;
2324 if (newvar
->varnosyn
> 0)
2325 newvar
->varnosyn
+= rtoffset
;
2330 return NULL
; /* no match */
2334 * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
2336 * If a match is found, return a Var constructed to reference the tlist item.
2337 * If no match, return NULL.
2339 * NOTE: it is a waste of time to call this unless itlist->has_ph_vars or
2340 * itlist->has_non_vars. Furthermore, set_join_references() relies on being
2341 * able to prevent matching of non-Vars by clearing itlist->has_non_vars,
2342 * so there's a correctness reason not to call it unless that's set.
2345 search_indexed_tlist_for_non_var(Expr
*node
,
2346 indexed_tlist
*itlist
, Index newvarno
)
2351 * If it's a simple Const, replacing it with a Var is silly, even if there
2352 * happens to be an identical Const below; a Var is more expensive to
2353 * execute than a Const. What's more, replacing it could confuse some
2354 * places in the executor that expect to see simple Consts for, eg,
2357 if (IsA(node
, Const
))
2360 tle
= tlist_member(node
, itlist
->tlist
);
2363 /* Found a matching subplan output expression */
2366 newvar
= makeVarFromTargetEntry(newvarno
, tle
);
2367 newvar
->varnosyn
= 0; /* wasn't ever a plain Var */
2368 newvar
->varattnosyn
= 0;
2371 return NULL
; /* no match */
2375 * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
2377 * If a match is found, return a Var constructed to reference the tlist item.
2378 * If no match, return NULL.
2380 * This is needed to ensure that we select the right subplan TLE in cases
2381 * where there are multiple textually-equal()-but-volatile sort expressions.
2382 * And it's also faster than search_indexed_tlist_for_non_var.
2385 search_indexed_tlist_for_sortgroupref(Expr
*node
,
2387 indexed_tlist
*itlist
,
2392 foreach(lc
, itlist
->tlist
)
2394 TargetEntry
*tle
= (TargetEntry
*) lfirst(lc
);
2396 /* The equal() check should be redundant, but let's be paranoid */
2397 if (tle
->ressortgroupref
== sortgroupref
&&
2398 equal(node
, tle
->expr
))
2400 /* Found a matching subplan output expression */
2403 newvar
= makeVarFromTargetEntry(newvarno
, tle
);
2404 newvar
->varnosyn
= 0; /* wasn't ever a plain Var */
2405 newvar
->varattnosyn
= 0;
2409 return NULL
; /* no match */
2414 * Create a new set of targetlist entries or join qual clauses by
2415 * changing the varno/varattno values of variables in the clauses
2416 * to reference target list values from the outer and inner join
2417 * relation target lists. Also perform opcode lookup and add
2418 * regclass OIDs to root->glob->relationOids.
2420 * This is used in three different scenarios:
2421 * 1) a normal join clause, where all the Vars in the clause *must* be
2422 * replaced by OUTER_VAR or INNER_VAR references. In this case
2423 * acceptable_rel should be zero so that any failure to match a Var will be
2424 * reported as an error.
2425 * 2) RETURNING clauses, which may contain both Vars of the target relation
2426 * and Vars of other relations. In this case we want to replace the
2427 * other-relation Vars by OUTER_VAR references, while leaving target Vars
2428 * alone. Thus inner_itlist = NULL and acceptable_rel = the ID of the
2429 * target relation should be passed.
2430 * 3) ON CONFLICT UPDATE SET/WHERE clauses. Here references to EXCLUDED are
2431 * to be replaced with INNER_VAR references, while leaving target Vars (the
2432 * to-be-updated relation) alone. Correspondingly inner_itlist is to be
2433 * EXCLUDED elements, outer_itlist = NULL and acceptable_rel the target
2436 * 'clauses' is the targetlist or list of join clauses
2437 * 'outer_itlist' is the indexed target list of the outer join relation,
2439 * 'inner_itlist' is the indexed target list of the inner join relation,
2441 * 'acceptable_rel' is either zero or the rangetable index of a relation
2442 * whose Vars may appear in the clause without provoking an error
2443 * 'rtoffset': how much to increment varnos by
2445 * Returns the new expression tree. The original clause structure is
2449 fix_join_expr(PlannerInfo
*root
,
2451 indexed_tlist
*outer_itlist
,
2452 indexed_tlist
*inner_itlist
,
2453 Index acceptable_rel
,
2456 fix_join_expr_context context
;
2458 context
.root
= root
;
2459 context
.outer_itlist
= outer_itlist
;
2460 context
.inner_itlist
= inner_itlist
;
2461 context
.acceptable_rel
= acceptable_rel
;
2462 context
.rtoffset
= rtoffset
;
2463 return (List
*) fix_join_expr_mutator((Node
*) clauses
, &context
);
2467 fix_join_expr_mutator(Node
*node
, fix_join_expr_context
*context
)
2475 Var
*var
= (Var
*) node
;
2477 /* Look for the var in the input tlists, first in the outer */
2478 if (context
->outer_itlist
)
2480 newvar
= search_indexed_tlist_for_var(var
,
2481 context
->outer_itlist
,
2485 return (Node
*) newvar
;
2488 /* then in the inner. */
2489 if (context
->inner_itlist
)
2491 newvar
= search_indexed_tlist_for_var(var
,
2492 context
->inner_itlist
,
2496 return (Node
*) newvar
;
2499 /* If it's for acceptable_rel, adjust and return it */
2500 if (var
->varno
== context
->acceptable_rel
)
2503 var
->varno
+= context
->rtoffset
;
2504 if (var
->varnosyn
> 0)
2505 var
->varnosyn
+= context
->rtoffset
;
2506 return (Node
*) var
;
2509 /* No referent found for Var */
2510 elog(ERROR
, "variable not found in subplan target lists");
2512 if (IsA(node
, PlaceHolderVar
))
2514 PlaceHolderVar
*phv
= (PlaceHolderVar
*) node
;
2516 /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2517 if (context
->outer_itlist
&& context
->outer_itlist
->has_ph_vars
)
2519 newvar
= search_indexed_tlist_for_non_var((Expr
*) phv
,
2520 context
->outer_itlist
,
2523 return (Node
*) newvar
;
2525 if (context
->inner_itlist
&& context
->inner_itlist
->has_ph_vars
)
2527 newvar
= search_indexed_tlist_for_non_var((Expr
*) phv
,
2528 context
->inner_itlist
,
2531 return (Node
*) newvar
;
2534 /* If not supplied by input plans, evaluate the contained expr */
2535 return fix_join_expr_mutator((Node
*) phv
->phexpr
, context
);
2537 /* Try matching more complex expressions too, if tlists have any */
2538 if (context
->outer_itlist
&& context
->outer_itlist
->has_non_vars
)
2540 newvar
= search_indexed_tlist_for_non_var((Expr
*) node
,
2541 context
->outer_itlist
,
2544 return (Node
*) newvar
;
2546 if (context
->inner_itlist
&& context
->inner_itlist
->has_non_vars
)
2548 newvar
= search_indexed_tlist_for_non_var((Expr
*) node
,
2549 context
->inner_itlist
,
2552 return (Node
*) newvar
;
2554 /* Special cases (apply only AFTER failing to match to lower tlist) */
2555 if (IsA(node
, Param
))
2556 return fix_param_node(context
->root
, (Param
*) node
);
2557 fix_expr_common(context
->root
, node
);
2558 return expression_tree_mutator(node
,
2559 fix_join_expr_mutator
,
2565 * Modifies an expression tree so that all Var nodes reference outputs
2566 * of a subplan. Also looks for Aggref nodes that should be replaced
2567 * by initplan output Params. Also performs opcode lookup, and adds
2568 * regclass OIDs to root->glob->relationOids.
2570 * This is used to fix up target and qual expressions of non-join upper-level
2571 * plan nodes, as well as index-only scan nodes.
2573 * An error is raised if no matching var can be found in the subplan tlist
2574 * --- so this routine should only be applied to nodes whose subplans'
2575 * targetlists were generated by flattening the expressions used in the
2578 * If itlist->has_non_vars is true, then we try to match whole subexpressions
2579 * against elements of the subplan tlist, so that we can avoid recomputing
2580 * expressions that were already computed by the subplan. (This is relatively
2581 * expensive, so we don't want to try it in the common case where the
2582 * subplan tlist is just a flattened list of Vars.)
2584 * 'node': the tree to be fixed (a target item or qual)
2585 * 'subplan_itlist': indexed target list for subplan (or index)
2586 * 'newvarno': varno to use for Vars referencing tlist elements
2587 * 'rtoffset': how much to increment varnos by
2589 * The resulting tree is a copy of the original in which all Var nodes have
2590 * varno = newvarno, varattno = resno of corresponding targetlist element.
2591 * The original tree is not modified.
2594 fix_upper_expr(PlannerInfo
*root
,
2596 indexed_tlist
*subplan_itlist
,
2600 fix_upper_expr_context context
;
2602 context
.root
= root
;
2603 context
.subplan_itlist
= subplan_itlist
;
2604 context
.newvarno
= newvarno
;
2605 context
.rtoffset
= rtoffset
;
2606 return fix_upper_expr_mutator(node
, &context
);
2610 fix_upper_expr_mutator(Node
*node
, fix_upper_expr_context
*context
)
2618 Var
*var
= (Var
*) node
;
2620 newvar
= search_indexed_tlist_for_var(var
,
2621 context
->subplan_itlist
,
2625 elog(ERROR
, "variable not found in subplan target list");
2626 return (Node
*) newvar
;
2628 if (IsA(node
, PlaceHolderVar
))
2630 PlaceHolderVar
*phv
= (PlaceHolderVar
*) node
;
2632 /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2633 if (context
->subplan_itlist
->has_ph_vars
)
2635 newvar
= search_indexed_tlist_for_non_var((Expr
*) phv
,
2636 context
->subplan_itlist
,
2639 return (Node
*) newvar
;
2641 /* If not supplied by input plan, evaluate the contained expr */
2642 return fix_upper_expr_mutator((Node
*) phv
->phexpr
, context
);
2644 /* Try matching more complex expressions too, if tlist has any */
2645 if (context
->subplan_itlist
->has_non_vars
)
2647 newvar
= search_indexed_tlist_for_non_var((Expr
*) node
,
2648 context
->subplan_itlist
,
2651 return (Node
*) newvar
;
2653 /* Special cases (apply only AFTER failing to match to lower tlist) */
2654 if (IsA(node
, Param
))
2655 return fix_param_node(context
->root
, (Param
*) node
);
2656 if (IsA(node
, Aggref
))
2658 Aggref
*aggref
= (Aggref
*) node
;
2660 /* See if the Aggref should be replaced by a Param */
2661 if (context
->root
->minmax_aggs
!= NIL
&&
2662 list_length(aggref
->args
) == 1)
2664 TargetEntry
*curTarget
= (TargetEntry
*) linitial(aggref
->args
);
2667 foreach(lc
, context
->root
->minmax_aggs
)
2669 MinMaxAggInfo
*mminfo
= (MinMaxAggInfo
*) lfirst(lc
);
2671 if (mminfo
->aggfnoid
== aggref
->aggfnoid
&&
2672 equal(mminfo
->target
, curTarget
->expr
))
2673 return (Node
*) copyObject(mminfo
->param
);
2676 /* If no match, just fall through to process it normally */
2678 fix_expr_common(context
->root
, node
);
2679 return expression_tree_mutator(node
,
2680 fix_upper_expr_mutator
,
2685 * set_returning_clause_references
2686 * Perform setrefs.c's work on a RETURNING targetlist
2688 * If the query involves more than just the result table, we have to
2689 * adjust any Vars that refer to other tables to reference junk tlist
2690 * entries in the top subplan's targetlist. Vars referencing the result
2691 * table should be left alone, however (the executor will evaluate them
2692 * using the actual heap tuple, after firing triggers if any). In the
2693 * adjusted RETURNING list, result-table Vars will have their original
2694 * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
2696 * We also must perform opcode lookup and add regclass OIDs to
2697 * root->glob->relationOids.
2699 * 'rlist': the RETURNING targetlist to be fixed
2700 * 'topplan': the top subplan node that will be just below the ModifyTable
2701 * node (note it's not yet passed through set_plan_refs)
2702 * 'resultRelation': RT index of the associated result relation
2703 * 'rtoffset': how much to increment varnos by
2705 * Note: the given 'root' is for the parent query level, not the 'topplan'.
2706 * This does not matter currently since we only access the dependency-item
2707 * lists in root->glob, but it would need some hacking if we wanted a root
2708 * that actually matches the subplan.
2710 * Note: resultRelation is not yet adjusted by rtoffset.
2713 set_returning_clause_references(PlannerInfo
*root
,
2716 Index resultRelation
,
2719 indexed_tlist
*itlist
;
2722 * We can perform the desired Var fixup by abusing the fix_join_expr
2723 * machinery that formerly handled inner indexscan fixup. We search the
2724 * top plan's targetlist for Vars of non-result relations, and use
2725 * fix_join_expr to convert RETURNING Vars into references to those tlist
2726 * entries, while leaving result-rel Vars as-is.
2728 * PlaceHolderVars will also be sought in the targetlist, but no
2729 * more-complex expressions will be. Note that it is not possible for a
2730 * PlaceHolderVar to refer to the result relation, since the result is
2731 * never below an outer join. If that case could happen, we'd have to be
2732 * prepared to pick apart the PlaceHolderVar and evaluate its contained
2733 * expression instead.
2735 itlist
= build_tlist_index_other_vars(topplan
->targetlist
, resultRelation
);
2737 rlist
= fix_join_expr(root
,
2750 /*****************************************************************************
2751 * QUERY DEPENDENCY MANAGEMENT
2752 *****************************************************************************/
2755 * record_plan_function_dependency
2756 * Mark the current plan as depending on a particular function.
2758 * This is exported so that the function-inlining code can record a
2759 * dependency on a function that it's removed from the plan tree.
2762 record_plan_function_dependency(PlannerInfo
*root
, Oid funcid
)
2765 * For performance reasons, we don't bother to track built-in functions;
2766 * we just assume they'll never change (or at least not in ways that'd
2767 * invalidate plans using them). For this purpose we can consider a
2768 * built-in function to be one with OID less than FirstBootstrapObjectId.
2769 * Note that the OID generator guarantees never to generate such an OID
2770 * after startup, even at OID wraparound.
2772 if (funcid
>= (Oid
) FirstBootstrapObjectId
)
2774 PlanInvalItem
*inval_item
= makeNode(PlanInvalItem
);
2777 * It would work to use any syscache on pg_proc, but the easiest is
2778 * PROCOID since we already have the function's OID at hand. Note
2779 * that plancache.c knows we use PROCOID.
2781 inval_item
->cacheId
= PROCOID
;
2782 inval_item
->hashValue
= GetSysCacheHashValue1(PROCOID
,
2783 ObjectIdGetDatum(funcid
));
2785 root
->glob
->invalItems
= lappend(root
->glob
->invalItems
, inval_item
);
2790 * record_plan_type_dependency
2791 * Mark the current plan as depending on a particular type.
2793 * This is exported so that eval_const_expressions can record a
2794 * dependency on a domain that it's removed a CoerceToDomain node for.
2796 * We don't currently need to record dependencies on domains that the
2797 * plan contains CoerceToDomain nodes for, though that might change in
2798 * future. Hence, this isn't actually called in this module, though
2799 * someday fix_expr_common might call it.
2802 record_plan_type_dependency(PlannerInfo
*root
, Oid typid
)
2805 * As in record_plan_function_dependency, ignore the possibility that
2806 * someone would change a built-in domain.
2808 if (typid
>= (Oid
) FirstBootstrapObjectId
)
2810 PlanInvalItem
*inval_item
= makeNode(PlanInvalItem
);
2813 * It would work to use any syscache on pg_type, but the easiest is
2814 * TYPEOID since we already have the type's OID at hand. Note that
2815 * plancache.c knows we use TYPEOID.
2817 inval_item
->cacheId
= TYPEOID
;
2818 inval_item
->hashValue
= GetSysCacheHashValue1(TYPEOID
,
2819 ObjectIdGetDatum(typid
));
2821 root
->glob
->invalItems
= lappend(root
->glob
->invalItems
, inval_item
);
2826 * extract_query_dependencies
2827 * Given a rewritten, but not yet planned, query or queries
2828 * (i.e. a Query node or list of Query nodes), extract dependencies
2829 * just as set_plan_references would do. Also detect whether any
2830 * rewrite steps were affected by RLS.
2832 * This is needed by plancache.c to handle invalidation of cached unplanned
2835 * Note: this does not go through eval_const_expressions, and hence doesn't
2836 * reflect its additions of inlined functions and elided CoerceToDomain nodes
2837 * to the invalItems list. This is obviously OK for functions, since we'll
2838 * see them in the original query tree anyway. For domains, it's OK because
2839 * we don't care about domains unless they get elided. That is, a plan might
2840 * have domain dependencies that the query tree doesn't.
2843 extract_query_dependencies(Node
*query
,
2844 List
**relationOids
,
2846 bool *hasRowSecurity
)
2851 /* Make up dummy planner state so we can use this module's machinery */
2852 MemSet(&glob
, 0, sizeof(glob
));
2853 glob
.type
= T_PlannerGlobal
;
2854 glob
.relationOids
= NIL
;
2855 glob
.invalItems
= NIL
;
2856 /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
2857 glob
.dependsOnRole
= false;
2859 MemSet(&root
, 0, sizeof(root
));
2860 root
.type
= T_PlannerInfo
;
2863 (void) extract_query_dependencies_walker(query
, &root
);
2865 *relationOids
= glob
.relationOids
;
2866 *invalItems
= glob
.invalItems
;
2867 *hasRowSecurity
= glob
.dependsOnRole
;
2871 * Tree walker for extract_query_dependencies.
2873 * This is exported so that expression_planner_with_deps can call it on
2874 * simple expressions (post-planning, not before planning, in that case).
2875 * In that usage, glob.dependsOnRole isn't meaningful, but the relationOids
2876 * and invalItems lists are added to as needed.
2879 extract_query_dependencies_walker(Node
*node
, PlannerInfo
*context
)
2883 Assert(!IsA(node
, PlaceHolderVar
));
2884 if (IsA(node
, Query
))
2886 Query
*query
= (Query
*) node
;
2889 if (query
->commandType
== CMD_UTILITY
)
2892 * This logic must handle any utility command for which parse
2893 * analysis was nontrivial (cf. stmt_requires_parse_analysis).
2895 * Notably, CALL requires its own processing.
2897 if (IsA(query
->utilityStmt
, CallStmt
))
2899 CallStmt
*callstmt
= (CallStmt
*) query
->utilityStmt
;
2901 /* We need not examine funccall, just the transformed exprs */
2902 (void) extract_query_dependencies_walker((Node
*) callstmt
->funcexpr
,
2908 * Ignore other utility statements, except those (such as EXPLAIN)
2909 * that contain a parsed-but-not-planned query. For those, we
2910 * just need to transfer our attention to the contained query.
2912 query
= UtilityContainsQuery(query
->utilityStmt
);
2917 /* Remember if any Query has RLS quals applied by rewriter */
2918 if (query
->hasRowSecurity
)
2919 context
->glob
->dependsOnRole
= true;
2921 /* Collect relation OIDs in this Query's rtable */
2922 foreach(lc
, query
->rtable
)
2924 RangeTblEntry
*rte
= (RangeTblEntry
*) lfirst(lc
);
2926 if (rte
->rtekind
== RTE_RELATION
)
2927 context
->glob
->relationOids
=
2928 lappend_oid(context
->glob
->relationOids
, rte
->relid
);
2929 else if (rte
->rtekind
== RTE_NAMEDTUPLESTORE
&&
2930 OidIsValid(rte
->relid
))
2931 context
->glob
->relationOids
=
2932 lappend_oid(context
->glob
->relationOids
,
2936 /* And recurse into the query's subexpressions */
2937 return query_tree_walker(query
, extract_query_dependencies_walker
,
2938 (void *) context
, 0);
2940 /* Extract function dependencies and check for regclass Consts */
2941 fix_expr_common(context
, node
);
2942 return expression_tree_walker(node
, extract_query_dependencies_walker
,