1/*-------------------------------------------------------------------------
2 *
3 * setrefs.c
4 * Post-processing of a completed plan tree: fix references to subplan
5 * vars, compute regproc values for operators, etc
6 *
7 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/backend/optimizer/plan/setrefs.c
13 *
14 *-------------------------------------------------------------------------
15 */
16#include "postgres.h"
17
18#include "access/transam.h"
19#include "catalog/pg_type.h"
20#include "nodes/makefuncs.h"
21#include "nodes/nodeFuncs.h"
22#include "optimizer/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"
30
31
32typedef struct
33{
34 Index varno; /* RT index of Var */
35 AttrNumber varattno; /* attr number of Var */
36 AttrNumber resno; /* TLE position of Var */
37} tlist_vinfo;
38
39typedef struct
40{
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 */
46} indexed_tlist;
47
48typedef struct
49{
50 PlannerInfo *root;
51 int rtoffset;
52} fix_scan_expr_context;
53
54typedef struct
55{
56 PlannerInfo *root;
57 indexed_tlist *outer_itlist;
58 indexed_tlist *inner_itlist;
59 Index acceptable_rel;
60 int rtoffset;
61} fix_join_expr_context;
62
63typedef struct
64{
65 PlannerInfo *root;
66 indexed_tlist *subplan_itlist;
67 Index newvarno;
68 int rtoffset;
69} fix_upper_expr_context;
70
71/*
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.)
77 */
78#define ISREGCLASSCONST(con) \
79 (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
80 !(con)->constisnull)
81
82#define fix_scan_list(root, lst, rtoffset) \
83 ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))
84
85static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing);
86static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
87static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob);
88static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte);
89static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
90static Plan *set_indexonlyscan_references(PlannerInfo *root,
91 IndexOnlyScan *plan,
92 int rtoffset);
93static Plan *set_subqueryscan_references(PlannerInfo *root,
94 SubqueryScan *plan,
95 int rtoffset);
96static bool trivial_subqueryscan(SubqueryScan *plan);
97static Plan *clean_up_removed_plan_level(Plan *parent, Plan *child);
98static void set_foreignscan_references(PlannerInfo *root,
99 ForeignScan *fscan,
100 int rtoffset);
101static void set_customscan_references(PlannerInfo *root,
102 CustomScan *cscan,
103 int rtoffset);
104static Plan *set_append_references(PlannerInfo *root,
105 Append *aplan,
106 int rtoffset);
107static Plan *set_mergeappend_references(PlannerInfo *root,
108 MergeAppend *mplan,
109 int rtoffset);
110static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset);
111static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
112static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
113static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
114static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
115static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset);
116static void set_param_references(PlannerInfo *root, Plan *plan);
117static Node *convert_combining_aggrefs(Node *node, void *context);
118static void set_dummy_tlist_references(Plan *plan, int rtoffset);
119static indexed_tlist *build_tlist_index(List *tlist);
120static Var *search_indexed_tlist_for_var(Var *var,
121 indexed_tlist *itlist,
122 Index newvarno,
123 int rtoffset);
124static Var *search_indexed_tlist_for_non_var(Expr *node,
125 indexed_tlist *itlist,
126 Index newvarno);
127static Var *search_indexed_tlist_for_sortgroupref(Expr *node,
128 Index sortgroupref,
129 indexed_tlist *itlist,
130 Index newvarno);
131static List *fix_join_expr(PlannerInfo *root,
132 List *clauses,
133 indexed_tlist *outer_itlist,
134 indexed_tlist *inner_itlist,
135 Index acceptable_rel, int rtoffset);
136static Node *fix_join_expr_mutator(Node *node,
137 fix_join_expr_context *context);
138static Node *fix_upper_expr(PlannerInfo *root,
139 Node *node,
140 indexed_tlist *subplan_itlist,
141 Index newvarno,
142 int rtoffset);
143static Node *fix_upper_expr_mutator(Node *node,
144 fix_upper_expr_context *context);
145static List *set_returning_clause_references(PlannerInfo *root,
146 List *rlist,
147 Plan *topplan,
148 Index resultRelation,
149 int rtoffset);
150
151
152/*****************************************************************************
153 *
154 * SUBPLAN REFERENCES
155 *
156 *****************************************************************************/
157
158/*
159 * set_plan_references
160 *
161 * This is the final processing pass of the planner/optimizer. The plan
162 * tree is complete; we just have to adjust some representational details
163 * for the convenience of the executor:
164 *
165 * 1. We flatten the various subquery rangetables into a single list, and
166 * zero out RangeTblEntry fields that are not useful to the executor.
167 *
168 * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
169 *
170 * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
171 * subplans.
172 *
173 * 4. Aggrefs in Agg plan nodes need to be adjusted in some cases involving
174 * partial aggregation or minmax aggregate optimization.
175 *
176 * 5. PARAM_MULTIEXPR Params are replaced by regular PARAM_EXEC Params,
177 * now that we have finished planning all MULTIEXPR subplans.
178 *
179 * 6. We compute regproc OIDs for operators (ie, we look up the function
180 * that implements each op).
181 *
182 * 7. We create lists of specific objects that the plan depends on.
183 * This will be used by plancache.c to drive invalidation of cached plans.
184 * Relation dependencies are represented by OIDs, and everything else by
185 * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
186 * Currently, relations, user-defined functions, and domains are the only
187 * types of objects that are explicitly tracked this way.
188 *
189 * 8. We assign every plan node in the tree a unique ID.
190 *
191 * We also perform one final optimization step, which is to delete
192 * SubqueryScan, Append, and MergeAppend plan nodes that aren't doing
193 * anything useful. The reason for doing this last is that
194 * it can't readily be done before set_plan_references, because it would
195 * break set_upper_references: the Vars in the child plan's top tlist
196 * wouldn't match up with the Vars in the outer plan tree. A SubqueryScan
197 * serves a necessary function as a buffer between outer query and subquery
198 * variable numbering ... but after we've flattened the rangetable this is
199 * no longer a problem, since then there's only one rtindex namespace.
200 * Likewise, Append and MergeAppend buffer between the parent and child vars
201 * of an appendrel, but we don't need to worry about that once we've done
202 * set_plan_references.
203 *
204 * set_plan_references recursively traverses the whole plan tree.
205 *
206 * The return value is normally the same Plan node passed in, but can be
207 * different when the passed-in Plan is a node we decide isn't needed.
208 *
209 * The flattened rangetable entries are appended to root->glob->finalrtable.
210 * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the
211 * RT indexes of ModifyTable result relations to root->glob->resultRelations.
212 * Plan dependencies are appended to root->glob->relationOids (for relations)
213 * and root->glob->invalItems (for everything else).
214 *
215 * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
216 * to process targetlist and qual expressions. We can assume that the Plan
217 * nodes were just built by the planner and are not multiply referenced, but
218 * it's not so safe to assume that for expression tree nodes.
219 */
220Plan *
221set_plan_references(PlannerInfo *root, Plan *plan)
222{
223 PlannerGlobal *glob = root->glob;
224 int rtoffset = list_length(glob->finalrtable);
225 ListCell *lc;
226
227 /*
228 * Add all the query's RTEs to the flattened rangetable. The live ones
229 * will have their rangetable indexes increased by rtoffset. (Additional
230 * RTEs, not referenced by the Plan tree, might get added after those.)
231 */
232 add_rtes_to_flat_rtable(root, false);
233
234 /*
235 * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
236 */
237 foreach(lc, root->rowMarks)
238 {
239 PlanRowMark *rc = lfirst_node(PlanRowMark, lc);
240 PlanRowMark *newrc;
241
242 /* flat copy is enough since all fields are scalars */
243 newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
244 memcpy(newrc, rc, sizeof(PlanRowMark));
245
246 /* adjust indexes ... but *not* the rowmarkId */
247 newrc->rti += rtoffset;
248 newrc->prti += rtoffset;
249
250 glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
251 }
252
253 /* Now fix the Plan tree */
254 return set_plan_refs(root, plan, rtoffset);
255}
256
257/*
258 * Extract RangeTblEntries from the plan's rangetable, and add to flat rtable
259 *
260 * This can recurse into subquery plans; "recursing" is true if so.
261 */
262static void
263add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
264{
265 PlannerGlobal *glob = root->glob;
266 Index rti;
267 ListCell *lc;
268
269 /*
270 * Add the query's own RTEs to the flattened rangetable.
271 *
272 * At top level, we must add all RTEs so that their indexes in the
273 * flattened rangetable match up with their original indexes. When
274 * recursing, we only care about extracting relation RTEs.
275 */
276 foreach(lc, root->parse->rtable)
277 {
278 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
279
280 if (!recursing || rte->rtekind == RTE_RELATION)
281 add_rte_to_flat_rtable(glob, rte);
282 }
283
284 /*
285 * If there are any dead subqueries, they are not referenced in the Plan
286 * tree, so we must add RTEs contained in them to the flattened rtable
287 * separately. (If we failed to do this, the executor would not perform
288 * expected permission checks for tables mentioned in such subqueries.)
289 *
290 * Note: this pass over the rangetable can't be combined with the previous
291 * one, because that would mess up the numbering of the live RTEs in the
292 * flattened rangetable.
293 */
294 rti = 1;
295 foreach(lc, root->parse->rtable)
296 {
297 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
298
299 /*
300 * We should ignore inheritance-parent RTEs: their contents have been
301 * pulled up into our rangetable already. Also ignore any subquery
302 * RTEs without matching RelOptInfos, as they likewise have been
303 * pulled up.
304 */
305 if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
306 rti < root->simple_rel_array_size)
307 {
308 RelOptInfo *rel = root->simple_rel_array[rti];
309
310 if (rel != NULL)
311 {
312 Assert(rel->relid == rti); /* sanity check on array */
313
314 /*
315 * The subquery might never have been planned at all, if it
316 * was excluded on the basis of self-contradictory constraints
317 * in our query level. In this case apply
318 * flatten_unplanned_rtes.
319 *
320 * If it was planned but the result rel is dummy, we assume
321 * that it has been omitted from our plan tree (see
322 * set_subquery_pathlist), and recurse to pull up its RTEs.
323 *
324 * Otherwise, it should be represented by a SubqueryScan node
325 * somewhere in our plan tree, and we'll pull up its RTEs when
326 * we process that plan node.
327 *
328 * However, if we're recursing, then we should pull up RTEs
329 * whether the subquery is dummy or not, because we've found
330 * that some upper query level is treating this one as dummy,
331 * and so we won't scan this level's plan tree at all.
332 */
333 if (rel->subroot == NULL)
334 flatten_unplanned_rtes(glob, rte);
335 else if (recursing ||
336 IS_DUMMY_REL(fetch_upper_rel(rel->subroot,
337 UPPERREL_FINAL, NULL)))
338 add_rtes_to_flat_rtable(rel->subroot, true);
339 }
340 }
341 rti++;
342 }
343}
344
345/*
346 * Extract RangeTblEntries from a subquery that was never planned at all
347 */
348static void
349flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
350{
351 /* Use query_tree_walker to find all RTEs in the parse tree */
352 (void) query_tree_walker(rte->subquery,
353 flatten_rtes_walker,
354 (void *) glob,
355 QTW_EXAMINE_RTES_BEFORE);
356}
357
358static bool
359flatten_rtes_walker(Node *node, PlannerGlobal *glob)
360{
361 if (node == NULL)
362 return false;
363 if (IsA(node, RangeTblEntry))
364 {
365 RangeTblEntry *rte = (RangeTblEntry *) node;
366
367 /* As above, we need only save relation RTEs */
368 if (rte->rtekind == RTE_RELATION)
369 add_rte_to_flat_rtable(glob, rte);
370 return false;
371 }
372 if (IsA(node, Query))
373 {
374 /* Recurse into subselects */
375 return query_tree_walker((Query *) node,
376 flatten_rtes_walker,
377 (void *) glob,
378 QTW_EXAMINE_RTES_BEFORE);
379 }
380 return expression_tree_walker(node, flatten_rtes_walker,
381 (void *) glob);
382}
383
384/*
385 * Add (a copy of) the given RTE to the final rangetable
386 *
387 * In the flat rangetable, we zero out substructure pointers that are not
388 * needed by the executor; this reduces the storage space and copying cost
389 * for cached plans. We keep only the ctename, alias and eref Alias fields,
390 * which are needed by EXPLAIN, and the selectedCols, insertedCols and
391 * updatedCols bitmaps, which are needed for executor-startup permissions
392 * checking and for trigger event checking.
393 */
394static void
395add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
396{
397 RangeTblEntry *newrte;
398
399 /* flat copy to duplicate all the scalar fields */
400 newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
401 memcpy(newrte, rte, sizeof(RangeTblEntry));
402
403 /* zap unneeded sub-structure */
404 newrte->tablesample = NULL;
405 newrte->subquery = NULL;
406 newrte->joinaliasvars = NIL;
407 newrte->functions = NIL;
408 newrte->tablefunc = NULL;
409 newrte->values_lists = NIL;
410 newrte->coltypes = NIL;
411 newrte->coltypmods = NIL;
412 newrte->colcollations = NIL;
413 newrte->securityQuals = NIL;
414
415 glob->finalrtable = lappend(glob->finalrtable, newrte);
416
417 /*
418 * Check for RT index overflow; it's very unlikely, but if it did happen,
419 * the executor would get confused by varnos that match the special varno
420 * values.
421 */
422 if (IS_SPECIAL_VARNO(list_length(glob->finalrtable)))
423 ereport(ERROR,
424 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
425 errmsg("too many range table entries")));
426
427 /*
428 * If it's a plain relation RTE, add the table to relationOids.
429 *
430 * We do this even though the RTE might be unreferenced in the plan tree;
431 * this would correspond to cases such as views that were expanded, child
432 * tables that were eliminated by constraint exclusion, etc. Schema
433 * invalidation on such a rel must still force rebuilding of the plan.
434 *
435 * Note we don't bother to avoid making duplicate list entries. We could,
436 * but it would probably cost more cycles than it would save.
437 */
438 if (newrte->rtekind == RTE_RELATION)
439 glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
440}
441
442/*
443 * set_plan_refs: recurse through the Plan nodes of a single subquery level
444 */
445static Plan *
446set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
447{
448 ListCell *l;
449
450 if (plan == NULL)
451 return NULL;
452
453 /* Assign this node a unique ID. */
454 plan->plan_node_id = root->glob->lastPlanNodeId++;
455
456 /*
457 * Plan-type-specific fixes
458 */
459 switch (nodeTag(plan))
460 {
461 case T_SeqScan:
462 {
463 SeqScan *splan = (SeqScan *) plan;
464
465 splan->scanrelid += rtoffset;
466 splan->plan.targetlist =
467 fix_scan_list(root, splan->plan.targetlist, rtoffset);
468 splan->plan.qual =
469 fix_scan_list(root, splan->plan.qual, rtoffset);
470 }
471 break;
472 case T_SampleScan:
473 {
474 SampleScan *splan = (SampleScan *) plan;
475
476 splan->scan.scanrelid += rtoffset;
477 splan->scan.plan.targetlist =
478 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
479 splan->scan.plan.qual =
480 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
481 splan->tablesample = (TableSampleClause *)
482 fix_scan_expr(root, (Node *) splan->tablesample, rtoffset);
483 }
484 break;
485 case T_IndexScan:
486 {
487 IndexScan *splan = (IndexScan *) plan;
488
489 splan->scan.scanrelid += rtoffset;
490 splan->scan.plan.targetlist =
491 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
492 splan->scan.plan.qual =
493 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
494 splan->indexqual =
495 fix_scan_list(root, splan->indexqual, rtoffset);
496 splan->indexqualorig =
497 fix_scan_list(root, splan->indexqualorig, rtoffset);
498 splan->indexorderby =
499 fix_scan_list(root, splan->indexorderby, rtoffset);
500 splan->indexorderbyorig =
501 fix_scan_list(root, splan->indexorderbyorig, rtoffset);
502 }
503 break;
504 case T_IndexOnlyScan:
505 {
506 IndexOnlyScan *splan = (IndexOnlyScan *) plan;
507
508 return set_indexonlyscan_references(root, splan, rtoffset);
509 }
510 break;
511 case T_BitmapIndexScan:
512 {
513 BitmapIndexScan *splan = (BitmapIndexScan *) plan;
514
515 splan->scan.scanrelid += rtoffset;
516 /* no need to fix targetlist and qual */
517 Assert(splan->scan.plan.targetlist == NIL);
518 Assert(splan->scan.plan.qual == NIL);
519 splan->indexqual =
520 fix_scan_list(root, splan->indexqual, rtoffset);
521 splan->indexqualorig =
522 fix_scan_list(root, splan->indexqualorig, rtoffset);
523 }
524 break;
525 case T_BitmapHeapScan:
526 {
527 BitmapHeapScan *splan = (BitmapHeapScan *) plan;
528
529 splan->scan.scanrelid += rtoffset;
530 splan->scan.plan.targetlist =
531 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
532 splan->scan.plan.qual =
533 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
534 splan->bitmapqualorig =
535 fix_scan_list(root, splan->bitmapqualorig, rtoffset);
536 }
537 break;
538 case T_TidScan:
539 {
540 TidScan *splan = (TidScan *) plan;
541
542 splan->scan.scanrelid += rtoffset;
543 splan->scan.plan.targetlist =
544 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
545 splan->scan.plan.qual =
546 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
547 splan->tidquals =
548 fix_scan_list(root, splan->tidquals, rtoffset);
549 }
550 break;
551 case T_SubqueryScan:
552 /* Needs special treatment, see comments below */
553 return set_subqueryscan_references(root,
554 (SubqueryScan *) plan,
555 rtoffset);
556 case T_FunctionScan:
557 {
558 FunctionScan *splan = (FunctionScan *) plan;
559
560 splan->scan.scanrelid += rtoffset;
561 splan->scan.plan.targetlist =
562 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
563 splan->scan.plan.qual =
564 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
565 splan->functions =
566 fix_scan_list(root, splan->functions, rtoffset);
567 }
568 break;
569 case T_TableFuncScan:
570 {
571 TableFuncScan *splan = (TableFuncScan *) plan;
572
573 splan->scan.scanrelid += rtoffset;
574 splan->scan.plan.targetlist =
575 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
576 splan->scan.plan.qual =
577 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
578 splan->tablefunc = (TableFunc *)
579 fix_scan_expr(root, (Node *) splan->tablefunc, rtoffset);
580 }
581 break;
582 case T_ValuesScan:
583 {
584 ValuesScan *splan = (ValuesScan *) plan;
585
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);
591 splan->values_lists =
592 fix_scan_list(root, splan->values_lists, rtoffset);
593 }
594 break;
595 case T_CteScan:
596 {
597 CteScan *splan = (CteScan *) plan;
598
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 }
605 break;
606 case T_NamedTuplestoreScan:
607 {
608 NamedTuplestoreScan *splan = (NamedTuplestoreScan *) plan;
609
610 splan->scan.scanrelid += rtoffset;
611 splan->scan.plan.targetlist =
612 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
613 splan->scan.plan.qual =
614 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
615 }
616 break;
617 case T_WorkTableScan:
618 {
619 WorkTableScan *splan = (WorkTableScan *) plan;
620
621 splan->scan.scanrelid += rtoffset;
622 splan->scan.plan.targetlist =
623 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
624 splan->scan.plan.qual =
625 fix_scan_list(root, splan->scan.plan.qual, rtoffset);
626 }
627 break;
628 case T_ForeignScan:
629 set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
630 break;
631 case T_CustomScan:
632 set_customscan_references(root, (CustomScan *) plan, rtoffset);
633 break;
634
635 case T_NestLoop:
636 case T_MergeJoin:
637 case T_HashJoin:
638 set_join_references(root, (Join *) plan, rtoffset);
639 break;
640
641 case T_Gather:
642 case T_GatherMerge:
643 {
644 set_upper_references(root, plan, rtoffset);
645 set_param_references(root, plan);
646 }
647 break;
648
649 case T_Hash:
650 set_hash_references(root, plan, rtoffset);
651 break;
652
653 case T_Material:
654 case T_Sort:
655 case T_Unique:
656 case T_SetOp:
657
658 /*
659 * These plan types don't actually bother to evaluate their
660 * targetlists, because they just return their unmodified input
661 * tuples. Even though the targetlist won't be used by the
662 * executor, we fix it up for possible use by EXPLAIN (not to
663 * mention ease of debugging --- wrong varnos are very confusing).
664 */
665 set_dummy_tlist_references(plan, rtoffset);
666
667 /*
668 * Since these plan types don't check quals either, we should not
669 * find any qual expression attached to them.
670 */
671 Assert(plan->qual == NIL);
672 break;
673 case T_LockRows:
674 {
675 LockRows *splan = (LockRows *) plan;
676
677 /*
678 * Like the plan types above, LockRows doesn't evaluate its
679 * tlist or quals. But we have to fix up the RT indexes in
680 * its rowmarks.
681 */
682 set_dummy_tlist_references(plan, rtoffset);
683 Assert(splan->plan.qual == NIL);
684
685 foreach(l, splan->rowMarks)
686 {
687 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
688
689 rc->rti += rtoffset;
690 rc->prti += rtoffset;
691 }
692 }
693 break;
694 case T_Limit:
695 {
696 Limit *splan = (Limit *) plan;
697
698 /*
699 * Like the plan types above, Limit doesn't evaluate its tlist
700 * or quals. It does have live expressions for limit/offset,
701 * however; and those cannot contain subplan variable refs, so
702 * fix_scan_expr works for them.
703 */
704 set_dummy_tlist_references(plan, rtoffset);
705 Assert(splan->plan.qual == NIL);
706
707 splan->limitOffset =
708 fix_scan_expr(root, splan->limitOffset, rtoffset);
709 splan->limitCount =
710 fix_scan_expr(root, splan->limitCount, rtoffset);
711 }
712 break;
713 case T_Agg:
714 {
715 Agg *agg = (Agg *) plan;
716
717 /*
718 * If this node is combining partial-aggregation results, we
719 * must convert its Aggrefs to contain references to the
720 * partial-aggregate subexpressions that will be available
721 * from the child plan node.
722 */
723 if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
724 {
725 plan->targetlist = (List *)
726 convert_combining_aggrefs((Node *) plan->targetlist,
727 NULL);
728 plan->qual = (List *)
729 convert_combining_aggrefs((Node *) plan->qual,
730 NULL);
731 }
732
733 set_upper_references(root, plan, rtoffset);
734 }
735 break;
736 case T_Group:
737 set_upper_references(root, plan, rtoffset);
738 break;
739 case T_WindowAgg:
740 {
741 WindowAgg *wplan = (WindowAgg *) plan;
742
743 set_upper_references(root, plan, rtoffset);
744
745 /*
746 * Like Limit node limit/offset expressions, WindowAgg has
747 * frame offset expressions, which cannot contain subplan
748 * variable refs, so fix_scan_expr works for them.
749 */
750 wplan->startOffset =
751 fix_scan_expr(root, wplan->startOffset, rtoffset);
752 wplan->endOffset =
753 fix_scan_expr(root, wplan->endOffset, rtoffset);
754 }
755 break;
756 case T_Result:
757 {
758 Result *splan = (Result *) plan;
759
760 /*
761 * Result may or may not have a subplan; if not, it's more
762 * like a scan node than an upper node.
763 */
764 if (splan->plan.lefttree != NULL)
765 set_upper_references(root, plan, rtoffset);
766 else
767 {
768 splan->plan.targetlist =
769 fix_scan_list(root, splan->plan.targetlist, rtoffset);
770 splan->plan.qual =
771 fix_scan_list(root, splan->plan.qual, rtoffset);
772 }
773 /* resconstantqual can't contain any subplan variable refs */
774 splan->resconstantqual =
775 fix_scan_expr(root, splan->resconstantqual, rtoffset);
776 }
777 break;
778 case T_ProjectSet:
779 set_upper_references(root, plan, rtoffset);
780 break;
781 case T_ModifyTable:
782 {
783 ModifyTable *splan = (ModifyTable *) plan;
784
785 Assert(splan->plan.targetlist == NIL);
786 Assert(splan->plan.qual == NIL);
787
788 splan->withCheckOptionLists =
789 fix_scan_list(root, splan->withCheckOptionLists, rtoffset);
790
791 if (splan->returningLists)
792 {
793 List *newRL = NIL;
794 ListCell *lcrl,
795 *lcrr,
796 *lcp;
797
798 /*
799 * Pass each per-subplan returningList through
800 * set_returning_clause_references().
801 */
802 Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
803 Assert(list_length(splan->returningLists) == list_length(splan->plans));
804 forthree(lcrl, splan->returningLists,
805 lcrr, splan->resultRelations,
806 lcp, splan->plans)
807 {
808 List *rlist = (List *) lfirst(lcrl);
809 Index resultrel = lfirst_int(lcrr);
810 Plan *subplan = (Plan *) lfirst(lcp);
811
812 rlist = set_returning_clause_references(root,
813 rlist,
814 subplan,
815 resultrel,
816 rtoffset);
817 newRL = lappend(newRL, rlist);
818 }
819 splan->returningLists = newRL;
820
821 /*
822 * Set up the visible plan targetlist as being the same as
823 * the first RETURNING list. This is for the use of
824 * EXPLAIN; the executor won't pay any attention to the
825 * targetlist. We postpone this step until here so that
826 * we don't have to do set_returning_clause_references()
827 * twice on identical targetlists.
828 */
829 splan->plan.targetlist = copyObject(linitial(newRL));
830 }
831
832 /*
833 * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
834 * join', where the inner side is the EXCLUDED tuple.
835 * Therefore use fix_join_expr to setup the relevant variables
836 * to INNER_VAR. We explicitly don't create any OUTER_VARs as
837 * those are already used by RETURNING and it seems better to
838 * be non-conflicting.
839 */
840 if (splan->onConflictSet)
841 {
842 indexed_tlist *itlist;
843
844 itlist = build_tlist_index(splan->exclRelTlist);
845
846 splan->onConflictSet =
847 fix_join_expr(root, splan->onConflictSet,
848 NULL, itlist,
849 linitial_int(splan->resultRelations),
850 rtoffset);
851
852 splan->onConflictWhere = (Node *)
853 fix_join_expr(root, (List *) splan->onConflictWhere,
854 NULL, itlist,
855 linitial_int(splan->resultRelations),
856 rtoffset);
857
858 pfree(itlist);
859
860 splan->exclRelTlist =
861 fix_scan_list(root, splan->exclRelTlist, rtoffset);
862 }
863
864 splan->nominalRelation += rtoffset;
865 if (splan->rootRelation)
866 splan->rootRelation += rtoffset;
867 splan->exclRelRTI += rtoffset;
868
869 foreach(l, splan->resultRelations)
870 {
871 lfirst_int(l) += rtoffset;
872 }
873 foreach(l, splan->rowMarks)
874 {
875 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
876
877 rc->rti += rtoffset;
878 rc->prti += rtoffset;
879 }
880 foreach(l, splan->plans)
881 {
882 lfirst(l) = set_plan_refs(root,
883 (Plan *) lfirst(l),
884 rtoffset);
885 }
886
887 /*
888 * Append this ModifyTable node's final result relation RT
889 * index(es) to the global list for the plan, and set its
890 * resultRelIndex to reflect their starting position in the
891 * global list.
892 */
893 splan->resultRelIndex = list_length(root->glob->resultRelations);
894 root->glob->resultRelations =
895 list_concat(root->glob->resultRelations,
896 list_copy(splan->resultRelations));
897
898 /*
899 * If the main target relation is a partitioned table, also
900 * add the partition root's RT index to rootResultRelations,
901 * and remember its index in that list in rootResultRelIndex.
902 */
903 if (splan->rootRelation)
904 {
905 splan->rootResultRelIndex =
906 list_length(root->glob->rootResultRelations);
907 root->glob->rootResultRelations =
908 lappend_int(root->glob->rootResultRelations,
909 splan->rootRelation);
910 }
911 }
912 break;
913 case T_Append:
914 /* Needs special treatment, see comments below */
915 return set_append_references(root,
916 (Append *) plan,
917 rtoffset);
918 case T_MergeAppend:
919 /* Needs special treatment, see comments below */
920 return set_mergeappend_references(root,
921 (MergeAppend *) plan,
922 rtoffset);
923 case T_RecursiveUnion:
924 /* This doesn't evaluate targetlist or check quals either */
925 set_dummy_tlist_references(plan, rtoffset);
926 Assert(plan->qual == NIL);
927 break;
928 case T_BitmapAnd:
929 {
930 BitmapAnd *splan = (BitmapAnd *) plan;
931
932 /* BitmapAnd works like Append, but has no tlist */
933 Assert(splan->plan.targetlist == NIL);
934 Assert(splan->plan.qual == NIL);
935 foreach(l, splan->bitmapplans)
936 {
937 lfirst(l) = set_plan_refs(root,
938 (Plan *) lfirst(l),
939 rtoffset);
940 }
941 }
942 break;
943 case T_BitmapOr:
944 {
945 BitmapOr *splan = (BitmapOr *) plan;
946
947 /* BitmapOr works like Append, but has no tlist */
948 Assert(splan->plan.targetlist == NIL);
949 Assert(splan->plan.qual == NIL);
950 foreach(l, splan->bitmapplans)
951 {
952 lfirst(l) = set_plan_refs(root,
953 (Plan *) lfirst(l),
954 rtoffset);
955 }
956 }
957 break;
958 default:
959 elog(ERROR, "unrecognized node type: %d",
960 (int) nodeTag(plan));
961 break;
962 }
963
964 /*
965 * Now recurse into child plans, if any
966 *
967 * NOTE: it is essential that we recurse into child plans AFTER we set
968 * subplan references in this plan's tlist and quals. If we did the
969 * reference-adjustments bottom-up, then we would fail to match this
970 * plan's var nodes against the already-modified nodes of the children.
971 */
972 plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
973 plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
974
975 return plan;
976}
977
978/*
979 * set_indexonlyscan_references
980 * Do set_plan_references processing on an IndexOnlyScan
981 *
982 * This is unlike the handling of a plain IndexScan because we have to
983 * convert Vars referencing the heap into Vars referencing the index.
984 * We can use the fix_upper_expr machinery for that, by working from a
985 * targetlist describing the index columns.
986 */
987static Plan *
988set_indexonlyscan_references(PlannerInfo *root,
989 IndexOnlyScan *plan,
990 int rtoffset)
991{
992 indexed_tlist *index_itlist;
993
994 index_itlist = build_tlist_index(plan->indextlist);
995
996 plan->scan.scanrelid += rtoffset;
997 plan->scan.plan.targetlist = (List *)
998 fix_upper_expr(root,
999 (Node *) plan->scan.plan.targetlist,
1000 index_itlist,
1001 INDEX_VAR,
1002 rtoffset);
1003 plan->scan.plan.qual = (List *)
1004 fix_upper_expr(root,
1005 (Node *) plan->scan.plan.qual,
1006 index_itlist,
1007 INDEX_VAR,
1008 rtoffset);
1009 /* indexqual is already transformed to reference index columns */
1010 plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset);
1011 /* indexorderby is already transformed to reference index columns */
1012 plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset);
1013 /* indextlist must NOT be transformed to reference index columns */
1014 plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset);
1015
1016 pfree(index_itlist);
1017
1018 return (Plan *) plan;
1019}
1020
1021/*
1022 * set_subqueryscan_references
1023 * Do set_plan_references processing on a SubqueryScan
1024 *
1025 * We try to strip out the SubqueryScan entirely; if we can't, we have
1026 * to do the normal processing on it.
1027 */
1028static Plan *
1029set_subqueryscan_references(PlannerInfo *root,
1030 SubqueryScan *plan,
1031 int rtoffset)
1032{
1033 RelOptInfo *rel;
1034 Plan *result;
1035
1036 /* Need to look up the subquery's RelOptInfo, since we need its subroot */
1037 rel = find_base_rel(root, plan->scan.scanrelid);
1038
1039 /* Recursively process the subplan */
1040 plan->subplan = set_plan_references(rel->subroot, plan->subplan);
1041
1042 if (trivial_subqueryscan(plan))
1043 {
1044 /*
1045 * We can omit the SubqueryScan node and just pull up the subplan.
1046 */
1047 result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
1048 }
1049 else
1050 {
1051 /*
1052 * Keep the SubqueryScan node. We have to do the processing that
1053 * set_plan_references would otherwise have done on it. Notice we do
1054 * not do set_upper_references() here, because a SubqueryScan will
1055 * always have been created with correct references to its subplan's
1056 * outputs to begin with.
1057 */
1058 plan->scan.scanrelid += rtoffset;
1059 plan->scan.plan.targetlist =
1060 fix_scan_list(root, plan->scan.plan.targetlist, rtoffset);
1061 plan->scan.plan.qual =
1062 fix_scan_list(root, plan->scan.plan.qual, rtoffset);
1063
1064 result = (Plan *) plan;
1065 }
1066
1067 return result;
1068}
1069
1070/*
1071 * trivial_subqueryscan
1072 * Detect whether a SubqueryScan can be deleted from the plan tree.
1073 *
1074 * We can delete it if it has no qual to check and the targetlist just
1075 * regurgitates the output of the child plan.
1076 */
1077static bool
1078trivial_subqueryscan(SubqueryScan *plan)
1079{
1080 int attrno;
1081 ListCell *lp,
1082 *lc;
1083
1084 if (plan->scan.plan.qual != NIL)
1085 return false;
1086
1087 if (list_length(plan->scan.plan.targetlist) !=
1088 list_length(plan->subplan->targetlist))
1089 return false; /* tlists not same length */
1090
1091 attrno = 1;
1092 forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1093 {
1094 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1095 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1096
1097 if (ptle->resjunk != ctle->resjunk)
1098 return false; /* tlist doesn't match junk status */
1099
1100 /*
1101 * We accept either a Var referencing the corresponding element of the
1102 * subplan tlist, or a Const equaling the subplan element. See
1103 * generate_setop_tlist() for motivation.
1104 */
1105 if (ptle->expr && IsA(ptle->expr, Var))
1106 {
1107 Var *var = (Var *) ptle->expr;
1108
1109 Assert(var->varno == plan->scan.scanrelid);
1110 Assert(var->varlevelsup == 0);
1111 if (var->varattno != attrno)
1112 return false; /* out of order */
1113 }
1114 else if (ptle->expr && IsA(ptle->expr, Const))
1115 {
1116 if (!equal(ptle->expr, ctle->expr))
1117 return false;
1118 }
1119 else
1120 return false;
1121
1122 attrno++;
1123 }
1124
1125 return true;
1126}
1127
1128/*
1129 * clean_up_removed_plan_level
1130 * Do necessary cleanup when we strip out a SubqueryScan, Append, etc
1131 *
1132 * We are dropping the "parent" plan in favor of returning just its "child".
1133 * A few small tweaks are needed.
1134 */
1135static Plan *
1136clean_up_removed_plan_level(Plan *parent, Plan *child)
1137{
1138 /* We have to be sure we don't lose any initplans */
1139 child->initPlan = list_concat(parent->initPlan,
1140 child->initPlan);
1141
1142 /*
1143 * We also have to transfer the parent's column labeling info into the
1144 * child, else columns sent to client will be improperly labeled if this
1145 * is the topmost plan level. resjunk and so on may be important too.
1146 */
1147 apply_tlist_labeling(child->targetlist, parent->targetlist);
1148
1149 return child;
1150}
1151
1152/*
1153 * set_foreignscan_references
1154 * Do set_plan_references processing on a ForeignScan
1155 */
1156static void
1157set_foreignscan_references(PlannerInfo *root,
1158 ForeignScan *fscan,
1159 int rtoffset)
1160{
1161 /* Adjust scanrelid if it's valid */
1162 if (fscan->scan.scanrelid > 0)
1163 fscan->scan.scanrelid += rtoffset;
1164
1165 if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
1166 {
1167 /*
1168 * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1169 * foreign scan tuple
1170 */
1171 indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist);
1172
1173 fscan->scan.plan.targetlist = (List *)
1174 fix_upper_expr(root,
1175 (Node *) fscan->scan.plan.targetlist,
1176 itlist,
1177 INDEX_VAR,
1178 rtoffset);
1179 fscan->scan.plan.qual = (List *)
1180 fix_upper_expr(root,
1181 (Node *) fscan->scan.plan.qual,
1182 itlist,
1183 INDEX_VAR,
1184 rtoffset);
1185 fscan->fdw_exprs = (List *)
1186 fix_upper_expr(root,
1187 (Node *) fscan->fdw_exprs,
1188 itlist,
1189 INDEX_VAR,
1190 rtoffset);
1191 fscan->fdw_recheck_quals = (List *)
1192 fix_upper_expr(root,
1193 (Node *) fscan->fdw_recheck_quals,
1194 itlist,
1195 INDEX_VAR,
1196 rtoffset);
1197 pfree(itlist);
1198 /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1199 fscan->fdw_scan_tlist =
1200 fix_scan_list(root, fscan->fdw_scan_tlist, rtoffset);
1201 }
1202 else
1203 {
1204 /*
1205 * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
1206 * way
1207 */
1208 fscan->scan.plan.targetlist =
1209 fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset);
1210 fscan->scan.plan.qual =
1211 fix_scan_list(root, fscan->scan.plan.qual, rtoffset);
1212 fscan->fdw_exprs =
1213 fix_scan_list(root, fscan->fdw_exprs, rtoffset);
1214 fscan->fdw_recheck_quals =
1215 fix_scan_list(root, fscan->fdw_recheck_quals, rtoffset);
1216 }
1217
1218 /* Adjust fs_relids if needed */
1219 if (rtoffset > 0)
1220 {
1221 Bitmapset *tempset = NULL;
1222 int x = -1;
1223
1224 while ((x = bms_next_member(fscan->fs_relids, x)) >= 0)
1225 tempset = bms_add_member(tempset, x + rtoffset);
1226 fscan->fs_relids = tempset;
1227 }
1228}
1229
1230/*
1231 * set_customscan_references
1232 * Do set_plan_references processing on a CustomScan
1233 */
1234static void
1235set_customscan_references(PlannerInfo *root,
1236 CustomScan *cscan,
1237 int rtoffset)
1238{
1239 ListCell *lc;
1240
1241 /* Adjust scanrelid if it's valid */
1242 if (cscan->scan.scanrelid > 0)
1243 cscan->scan.scanrelid += rtoffset;
1244
1245 if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
1246 {
1247 /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1248 indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist);
1249
1250 cscan->scan.plan.targetlist = (List *)
1251 fix_upper_expr(root,
1252 (Node *) cscan->scan.plan.targetlist,
1253 itlist,
1254 INDEX_VAR,
1255 rtoffset);
1256 cscan->scan.plan.qual = (List *)
1257 fix_upper_expr(root,
1258 (Node *) cscan->scan.plan.qual,
1259 itlist,
1260 INDEX_VAR,
1261 rtoffset);
1262 cscan->custom_exprs = (List *)
1263 fix_upper_expr(root,
1264 (Node *) cscan->custom_exprs,
1265 itlist,
1266 INDEX_VAR,
1267 rtoffset);
1268 pfree(itlist);
1269 /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1270 cscan->custom_scan_tlist =
1271 fix_scan_list(root, cscan->custom_scan_tlist, rtoffset);
1272 }
1273 else
1274 {
1275 /* Adjust tlist, qual, custom_exprs in the standard way */
1276 cscan->scan.plan.targetlist =
1277 fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
1278 cscan->scan.plan.qual =
1279 fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
1280 cscan->custom_exprs =
1281 fix_scan_list(root, cscan->custom_exprs, rtoffset);
1282 }
1283
1284 /* Adjust child plan-nodes recursively, if needed */
1285 foreach(lc, cscan->custom_plans)
1286 {
1287 lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
1288 }
1289
1290 /* Adjust custom_relids if needed */
1291 if (rtoffset > 0)
1292 {
1293 Bitmapset *tempset = NULL;
1294 int x = -1;
1295
1296 while ((x = bms_next_member(cscan->custom_relids, x)) >= 0)
1297 tempset = bms_add_member(tempset, x + rtoffset);
1298 cscan->custom_relids = tempset;
1299 }
1300}
1301
1302/*
1303 * set_append_references
1304 * Do set_plan_references processing on an Append
1305 *
1306 * We try to strip out the Append entirely; if we can't, we have
1307 * to do the normal processing on it.
1308 */
1309static Plan *
1310set_append_references(PlannerInfo *root,
1311 Append *aplan,
1312 int rtoffset)
1313{
1314 ListCell *l;
1315
1316 /*
1317 * Append, like Sort et al, doesn't actually evaluate its targetlist or
1318 * check quals. If it's got exactly one child plan, then it's not doing
1319 * anything useful at all, and we can strip it out.
1320 */
1321 Assert(aplan->plan.qual == NIL);
1322
1323 /* First, we gotta recurse on the children */
1324 foreach(l, aplan->appendplans)
1325 {
1326 lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1327 }
1328
1329 /* Now, if there's just one, forget the Append and return that child */
1330 if (list_length(aplan->appendplans) == 1)
1331 return clean_up_removed_plan_level((Plan *) aplan,
1332 (Plan *) linitial(aplan->appendplans));
1333
1334 /*
1335 * Otherwise, clean up the Append as needed. It's okay to do this after
1336 * recursing to the children, because set_dummy_tlist_references doesn't
1337 * look at those.
1338 */
1339 set_dummy_tlist_references((Plan *) aplan, rtoffset);
1340
1341 if (aplan->part_prune_info)
1342 {
1343 foreach(l, aplan->part_prune_info->prune_infos)
1344 {
1345 List *prune_infos = lfirst(l);
1346 ListCell *l2;
1347
1348 foreach(l2, prune_infos)
1349 {
1350 PartitionedRelPruneInfo *pinfo = lfirst(l2);
1351
1352 pinfo->rtindex += rtoffset;
1353 }
1354 }
1355 }
1356
1357 /* We don't need to recurse to lefttree or righttree ... */
1358 Assert(aplan->plan.lefttree == NULL);
1359 Assert(aplan->plan.righttree == NULL);
1360
1361 return (Plan *) aplan;
1362}
1363
1364/*
1365 * set_mergeappend_references
1366 * Do set_plan_references processing on a MergeAppend
1367 *
1368 * We try to strip out the MergeAppend entirely; if we can't, we have
1369 * to do the normal processing on it.
1370 */
1371static Plan *
1372set_mergeappend_references(PlannerInfo *root,
1373 MergeAppend *mplan,
1374 int rtoffset)
1375{
1376 ListCell *l;
1377
1378 /*
1379 * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
1380 * or check quals. If it's got exactly one child plan, then it's not
1381 * doing anything useful at all, and we can strip it out.
1382 */
1383 Assert(mplan->plan.qual == NIL);
1384
1385 /* First, we gotta recurse on the children */
1386 foreach(l, mplan->mergeplans)
1387 {
1388 lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1389 }
1390
1391 /* Now, if there's just one, forget the MergeAppend and return that child */
1392 if (list_length(mplan->mergeplans) == 1)
1393 return clean_up_removed_plan_level((Plan *) mplan,
1394 (Plan *) linitial(mplan->mergeplans));
1395
1396 /*
1397 * Otherwise, clean up the MergeAppend as needed. It's okay to do this
1398 * after recursing to the children, because set_dummy_tlist_references
1399 * doesn't look at those.
1400 */
1401 set_dummy_tlist_references((Plan *) mplan, rtoffset);
1402
1403 if (mplan->part_prune_info)
1404 {
1405 foreach(l, mplan->part_prune_info->prune_infos)
1406 {
1407 List *prune_infos = lfirst(l);
1408 ListCell *l2;
1409
1410 foreach(l2, prune_infos)
1411 {
1412 PartitionedRelPruneInfo *pinfo = lfirst(l2);
1413
1414 pinfo->rtindex += rtoffset;
1415 }
1416 }
1417 }
1418
1419 /* We don't need to recurse to lefttree or righttree ... */
1420 Assert(mplan->plan.lefttree == NULL);
1421 Assert(mplan->plan.righttree == NULL);
1422
1423 return (Plan *) mplan;
1424}
1425
1426/*
1427 * set_hash_references
1428 * Do set_plan_references processing on a Hash node
1429 */
1430static void
1431set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
1432{
1433 Hash *hplan = (Hash *) plan;
1434 Plan *outer_plan = plan->lefttree;
1435 indexed_tlist *outer_itlist;
1436
1437 /*
1438 * Hash's hashkeys are used when feeding tuples into the hashtable,
1439 * therefore have them reference Hash's outer plan (which itself is the
1440 * inner plan of the HashJoin).
1441 */
1442 outer_itlist = build_tlist_index(outer_plan->targetlist);
1443 hplan->hashkeys = (List *)
1444 fix_upper_expr(root,
1445 (Node *) hplan->hashkeys,
1446 outer_itlist,
1447 OUTER_VAR,
1448 rtoffset);
1449
1450 /* Hash doesn't project */
1451 set_dummy_tlist_references(plan, rtoffset);
1452
1453 /* Hash nodes don't have their own quals */
1454 Assert(plan->qual == NIL);
1455}
1456
1457/*
1458 * copyVar
1459 * Copy a Var node.
1460 *
1461 * fix_scan_expr and friends do this enough times that it's worth having
1462 * a bespoke routine instead of using the generic copyObject() function.
1463 */
1464static inline Var *
1465copyVar(Var *var)
1466{
1467 Var *newvar = (Var *) palloc(sizeof(Var));
1468
1469 *newvar = *var;
1470 return newvar;
1471}
1472
1473/*
1474 * fix_expr_common
1475 * Do generic set_plan_references processing on an expression node
1476 *
1477 * This is code that is common to all variants of expression-fixing.
1478 * We must look up operator opcode info for OpExpr and related nodes,
1479 * add OIDs from regclass Const nodes into root->glob->relationOids, and
1480 * add PlanInvalItems for user-defined functions into root->glob->invalItems.
1481 * We also fill in column index lists for GROUPING() expressions.
1482 *
1483 * We assume it's okay to update opcode info in-place. So this could possibly
1484 * scribble on the planner's input data structures, but it's OK.
1485 */
1486static void
1487fix_expr_common(PlannerInfo *root, Node *node)
1488{
1489 /* We assume callers won't call us on a NULL pointer */
1490 if (IsA(node, Aggref))
1491 {
1492 record_plan_function_dependency(root,
1493 ((Aggref *) node)->aggfnoid);
1494 }
1495 else if (IsA(node, WindowFunc))
1496 {
1497 record_plan_function_dependency(root,
1498 ((WindowFunc *) node)->winfnoid);
1499 }
1500 else if (IsA(node, FuncExpr))
1501 {
1502 record_plan_function_dependency(root,
1503 ((FuncExpr *) node)->funcid);
1504 }
1505 else if (IsA(node, OpExpr))
1506 {
1507 set_opfuncid((OpExpr *) node);
1508 record_plan_function_dependency(root,
1509 ((OpExpr *) node)->opfuncid);
1510 }
1511 else if (IsA(node, DistinctExpr))
1512 {
1513 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1514 record_plan_function_dependency(root,
1515 ((DistinctExpr *) node)->opfuncid);
1516 }
1517 else if (IsA(node, NullIfExpr))
1518 {
1519 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1520 record_plan_function_dependency(root,
1521 ((NullIfExpr *) node)->opfuncid);
1522 }
1523 else if (IsA(node, ScalarArrayOpExpr))
1524 {
1525 set_sa_opfuncid((ScalarArrayOpExpr *) node);
1526 record_plan_function_dependency(root,
1527 ((ScalarArrayOpExpr *) node)->opfuncid);
1528 }
1529 else if (IsA(node, Const))
1530 {
1531 Const *con = (Const *) node;
1532
1533 /* Check for regclass reference */
1534 if (ISREGCLASSCONST(con))
1535 root->glob->relationOids =
1536 lappend_oid(root->glob->relationOids,
1537 DatumGetObjectId(con->constvalue));
1538 }
1539 else if (IsA(node, GroupingFunc))
1540 {
1541 GroupingFunc *g = (GroupingFunc *) node;
1542 AttrNumber *grouping_map = root->grouping_map;
1543
1544 /* If there are no grouping sets, we don't need this. */
1545
1546 Assert(grouping_map || g->cols == NIL);
1547
1548 if (grouping_map)
1549 {
1550 ListCell *lc;
1551 List *cols = NIL;
1552
1553 foreach(lc, g->refs)
1554 {
1555 cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
1556 }
1557
1558 Assert(!g->cols || equal(cols, g->cols));
1559
1560 if (!g->cols)
1561 g->cols = cols;
1562 }
1563 }
1564}
1565
1566/*
1567 * fix_param_node
1568 * Do set_plan_references processing on a Param
1569 *
1570 * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from
1571 * root->multiexpr_params; otherwise no change is needed.
1572 * Just for paranoia's sake, we make a copy of the node in either case.
1573 */
1574static Node *
1575fix_param_node(PlannerInfo *root, Param *p)
1576{
1577 if (p->paramkind == PARAM_MULTIEXPR)
1578 {
1579 int subqueryid = p->paramid >> 16;
1580 int colno = p->paramid & 0xFFFF;
1581 List *params;
1582
1583 if (subqueryid <= 0 ||
1584 subqueryid > list_length(root->multiexpr_params))
1585 elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1586 params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
1587 if (colno <= 0 || colno > list_length(params))
1588 elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1589 return copyObject(list_nth(params, colno - 1));
1590 }
1591 return (Node *) copyObject(p);
1592}
1593
1594/*
1595 * fix_scan_expr
1596 * Do set_plan_references processing on a scan-level expression
1597 *
1598 * This consists of incrementing all Vars' varnos by rtoffset,
1599 * replacing PARAM_MULTIEXPR Params, expanding PlaceHolderVars,
1600 * replacing Aggref nodes that should be replaced by initplan output Params,
1601 * looking up operator opcode info for OpExpr and related nodes,
1602 * and adding OIDs from regclass Const nodes into root->glob->relationOids.
1603 */
1604static Node *
1605fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
1606{
1607 fix_scan_expr_context context;
1608
1609 context.root = root;
1610 context.rtoffset = rtoffset;
1611
1612 if (rtoffset != 0 ||
1613 root->multiexpr_params != NIL ||
1614 root->glob->lastPHId != 0 ||
1615 root->minmax_aggs != NIL)
1616 {
1617 return fix_scan_expr_mutator(node, &context);
1618 }
1619 else
1620 {
1621 /*
1622 * If rtoffset == 0, we don't need to change any Vars, and if there
1623 * are no MULTIEXPR subqueries then we don't need to replace
1624 * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
1625 * we won't need to remove them, and if there are no minmax Aggrefs we
1626 * won't need to replace them. Then it's OK to just scribble on the
1627 * input node tree instead of copying (since the only change, filling
1628 * in any unset opfuncid fields, is harmless). This saves just enough
1629 * cycles to be noticeable on trivial queries.
1630 */
1631 (void) fix_scan_expr_walker(node, &context);
1632 return node;
1633 }
1634}
1635
1636static Node *
1637fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
1638{
1639 if (node == NULL)
1640 return NULL;
1641 if (IsA(node, Var))
1642 {
1643 Var *var = copyVar((Var *) node);
1644
1645 Assert(var->varlevelsup == 0);
1646
1647 /*
1648 * We should not see any Vars marked INNER_VAR or OUTER_VAR. But an
1649 * indexqual expression could contain INDEX_VAR Vars.
1650 */
1651 Assert(var->varno != INNER_VAR);
1652 Assert(var->varno != OUTER_VAR);
1653 if (!IS_SPECIAL_VARNO(var->varno))
1654 var->varno += context->rtoffset;
1655 if (var->varnoold > 0)
1656 var->varnoold += context->rtoffset;
1657 return (Node *) var;
1658 }
1659 if (IsA(node, Param))
1660 return fix_param_node(context->root, (Param *) node);
1661 if (IsA(node, Aggref))
1662 {
1663 Aggref *aggref = (Aggref *) node;
1664
1665 /* See if the Aggref should be replaced by a Param */
1666 if (context->root->minmax_aggs != NIL &&
1667 list_length(aggref->args) == 1)
1668 {
1669 TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
1670 ListCell *lc;
1671
1672 foreach(lc, context->root->minmax_aggs)
1673 {
1674 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
1675
1676 if (mminfo->aggfnoid == aggref->aggfnoid &&
1677 equal(mminfo->target, curTarget->expr))
1678 return (Node *) copyObject(mminfo->param);
1679 }
1680 }
1681 /* If no match, just fall through to process it normally */
1682 }
1683 if (IsA(node, CurrentOfExpr))
1684 {
1685 CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
1686
1687 Assert(cexpr->cvarno != INNER_VAR);
1688 Assert(cexpr->cvarno != OUTER_VAR);
1689 if (!IS_SPECIAL_VARNO(cexpr->cvarno))
1690 cexpr->cvarno += context->rtoffset;
1691 return (Node *) cexpr;
1692 }
1693 if (IsA(node, PlaceHolderVar))
1694 {
1695 /* At scan level, we should always just evaluate the contained expr */
1696 PlaceHolderVar *phv = (PlaceHolderVar *) node;
1697
1698 return fix_scan_expr_mutator((Node *) phv->phexpr, context);
1699 }
1700 fix_expr_common(context->root, node);
1701 return expression_tree_mutator(node, fix_scan_expr_mutator,
1702 (void *) context);
1703}
1704
1705static bool
1706fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
1707{
1708 if (node == NULL)
1709 return false;
1710 Assert(!IsA(node, PlaceHolderVar));
1711 fix_expr_common(context->root, node);
1712 return expression_tree_walker(node, fix_scan_expr_walker,
1713 (void *) context);
1714}
1715
1716/*
1717 * set_join_references
1718 * Modify the target list and quals of a join node to reference its
1719 * subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting
1720 * attno values to the result domain number of either the corresponding
1721 * outer or inner join tuple item. Also perform opcode lookup for these
1722 * expressions, and add regclass OIDs to root->glob->relationOids.
1723 */
1724static void
1725set_join_references(PlannerInfo *root, Join *join, int rtoffset)
1726{
1727 Plan *outer_plan = join->plan.lefttree;
1728 Plan *inner_plan = join->plan.righttree;
1729 indexed_tlist *outer_itlist;
1730 indexed_tlist *inner_itlist;
1731
1732 outer_itlist = build_tlist_index(outer_plan->targetlist);
1733 inner_itlist = build_tlist_index(inner_plan->targetlist);
1734
1735 /*
1736 * First process the joinquals (including merge or hash clauses). These
1737 * are logically below the join so they can always use all values
1738 * available from the input tlists. It's okay to also handle
1739 * NestLoopParams now, because those couldn't refer to nullable
1740 * subexpressions.
1741 */
1742 join->joinqual = fix_join_expr(root,
1743 join->joinqual,
1744 outer_itlist,
1745 inner_itlist,
1746 (Index) 0,
1747 rtoffset);
1748
1749 /* Now do join-type-specific stuff */
1750 if (IsA(join, NestLoop))
1751 {
1752 NestLoop *nl = (NestLoop *) join;
1753 ListCell *lc;
1754
1755 foreach(lc, nl->nestParams)
1756 {
1757 NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
1758
1759 nlp->paramval = (Var *) fix_upper_expr(root,
1760 (Node *) nlp->paramval,
1761 outer_itlist,
1762 OUTER_VAR,
1763 rtoffset);
1764 /* Check we replaced any PlaceHolderVar with simple Var */
1765 if (!(IsA(nlp->paramval, Var) &&
1766 nlp->paramval->varno == OUTER_VAR))
1767 elog(ERROR, "NestLoopParam was not reduced to a simple Var");
1768 }
1769 }
1770 else if (IsA(join, MergeJoin))
1771 {
1772 MergeJoin *mj = (MergeJoin *) join;
1773
1774 mj->mergeclauses = fix_join_expr(root,
1775 mj->mergeclauses,
1776 outer_itlist,
1777 inner_itlist,
1778 (Index) 0,
1779 rtoffset);
1780 }
1781 else if (IsA(join, HashJoin))
1782 {
1783 HashJoin *hj = (HashJoin *) join;
1784
1785 hj->hashclauses = fix_join_expr(root,
1786 hj->hashclauses,
1787 outer_itlist,
1788 inner_itlist,
1789 (Index) 0,
1790 rtoffset);
1791
1792 /*
1793 * HashJoin's hashkeys are used to look for matching tuples from its
1794 * outer plan (not the Hash node!) in the hashtable.
1795 */
1796 hj->hashkeys = (List *) fix_upper_expr(root,
1797 (Node *) hj->hashkeys,
1798 outer_itlist,
1799 OUTER_VAR,
1800 rtoffset);
1801 }
1802
1803 /*
1804 * Now we need to fix up the targetlist and qpqual, which are logically
1805 * above the join. This means they should not re-use any input expression
1806 * that was computed in the nullable side of an outer join. Vars and
1807 * PlaceHolderVars are fine, so we can implement this restriction just by
1808 * clearing has_non_vars in the indexed_tlist structs.
1809 *
1810 * XXX This is a grotty workaround for the fact that we don't clearly
1811 * distinguish between a Var appearing below an outer join and the "same"
1812 * Var appearing above it. If we did, we'd not need to hack the matching
1813 * rules this way.
1814 */
1815 switch (join->jointype)
1816 {
1817 case JOIN_LEFT:
1818 case JOIN_SEMI:
1819 case JOIN_ANTI:
1820 inner_itlist->has_non_vars = false;
1821 break;
1822 case JOIN_RIGHT:
1823 outer_itlist->has_non_vars = false;
1824 break;
1825 case JOIN_FULL:
1826 outer_itlist->has_non_vars = false;
1827 inner_itlist->has_non_vars = false;
1828 break;
1829 default:
1830 break;
1831 }
1832
1833 join->plan.targetlist = fix_join_expr(root,
1834 join->plan.targetlist,
1835 outer_itlist,
1836 inner_itlist,
1837 (Index) 0,
1838 rtoffset);
1839 join->plan.qual = fix_join_expr(root,
1840 join->plan.qual,
1841 outer_itlist,
1842 inner_itlist,
1843 (Index) 0,
1844 rtoffset);
1845
1846 pfree(outer_itlist);
1847 pfree(inner_itlist);
1848}
1849
1850/*
1851 * set_upper_references
1852 * Update the targetlist and quals of an upper-level plan node
1853 * to refer to the tuples returned by its lefttree subplan.
1854 * Also perform opcode lookup for these expressions, and
1855 * add regclass OIDs to root->glob->relationOids.
1856 *
1857 * This is used for single-input plan types like Agg, Group, Result.
1858 *
1859 * In most cases, we have to match up individual Vars in the tlist and
1860 * qual expressions with elements of the subplan's tlist (which was
1861 * generated by flattening these selfsame expressions, so it should have all
1862 * the required variables). There is an important exception, however:
1863 * depending on where we are in the plan tree, sort/group columns may have
1864 * been pushed into the subplan tlist unflattened. If these values are also
1865 * needed in the output then we want to reference the subplan tlist element
1866 * rather than recomputing the expression.
1867 */
1868static void
1869set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
1870{
1871 Plan *subplan = plan->lefttree;
1872 indexed_tlist *subplan_itlist;
1873 List *output_targetlist;
1874 ListCell *l;
1875
1876 subplan_itlist = build_tlist_index(subplan->targetlist);
1877
1878 output_targetlist = NIL;
1879 foreach(l, plan->targetlist)
1880 {
1881 TargetEntry *tle = (TargetEntry *) lfirst(l);
1882 Node *newexpr;
1883
1884 /* If it's a sort/group item, first try to match by sortref */
1885 if (tle->ressortgroupref != 0)
1886 {
1887 newexpr = (Node *)
1888 search_indexed_tlist_for_sortgroupref(tle->expr,
1889 tle->ressortgroupref,
1890 subplan_itlist,
1891 OUTER_VAR);
1892 if (!newexpr)
1893 newexpr = fix_upper_expr(root,
1894 (Node *) tle->expr,
1895 subplan_itlist,
1896 OUTER_VAR,
1897 rtoffset);
1898 }
1899 else
1900 newexpr = fix_upper_expr(root,
1901 (Node *) tle->expr,
1902 subplan_itlist,
1903 OUTER_VAR,
1904 rtoffset);
1905 tle = flatCopyTargetEntry(tle);
1906 tle->expr = (Expr *) newexpr;
1907 output_targetlist = lappend(output_targetlist, tle);
1908 }
1909 plan->targetlist = output_targetlist;
1910
1911 plan->qual = (List *)
1912 fix_upper_expr(root,
1913 (Node *) plan->qual,
1914 subplan_itlist,
1915 OUTER_VAR,
1916 rtoffset);
1917
1918 pfree(subplan_itlist);
1919}
1920
1921/*
1922 * set_param_references
1923 * Initialize the initParam list in Gather or Gather merge node such that
1924 * it contains reference of all the params that needs to be evaluated
1925 * before execution of the node. It contains the initplan params that are
1926 * being passed to the plan nodes below it.
1927 */
1928static void
1929set_param_references(PlannerInfo *root, Plan *plan)
1930{
1931 Assert(IsA(plan, Gather) ||IsA(plan, GatherMerge));
1932
1933 if (plan->lefttree->extParam)
1934 {
1935 PlannerInfo *proot;
1936 Bitmapset *initSetParam = NULL;
1937 ListCell *l;
1938
1939 for (proot = root; proot != NULL; proot = proot->parent_root)
1940 {
1941 foreach(l, proot->init_plans)
1942 {
1943 SubPlan *initsubplan = (SubPlan *) lfirst(l);
1944 ListCell *l2;
1945
1946 foreach(l2, initsubplan->setParam)
1947 {
1948 initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
1949 }
1950 }
1951 }
1952
1953 /*
1954 * Remember the list of all external initplan params that are used by
1955 * the children of Gather or Gather merge node.
1956 */
1957 if (IsA(plan, Gather))
1958 ((Gather *) plan)->initParam =
1959 bms_intersect(plan->lefttree->extParam, initSetParam);
1960 else
1961 ((GatherMerge *) plan)->initParam =
1962 bms_intersect(plan->lefttree->extParam, initSetParam);
1963 }
1964}
1965
1966/*
1967 * Recursively scan an expression tree and convert Aggrefs to the proper
1968 * intermediate form for combining aggregates. This means (1) replacing each
1969 * one's argument list with a single argument that is the original Aggref
1970 * modified to show partial aggregation and (2) changing the upper Aggref to
1971 * show combining aggregation.
1972 *
1973 * After this step, set_upper_references will replace the partial Aggrefs
1974 * with Vars referencing the lower Agg plan node's outputs, so that the final
1975 * form seen by the executor is a combining Aggref with a Var as input.
1976 *
1977 * It's rather messy to postpone this step until setrefs.c; ideally it'd be
1978 * done in createplan.c. The difficulty is that once we modify the Aggref
1979 * expressions, they will no longer be equal() to their original form and
1980 * so cross-plan-node-level matches will fail. So this has to happen after
1981 * the plan node above the Agg has resolved its subplan references.
1982 */
1983static Node *
1984convert_combining_aggrefs(Node *node, void *context)
1985{
1986 if (node == NULL)
1987 return NULL;
1988 if (IsA(node, Aggref))
1989 {
1990 Aggref *orig_agg = (Aggref *) node;
1991 Aggref *child_agg;
1992 Aggref *parent_agg;
1993
1994 /* Assert we've not chosen to partial-ize any unsupported cases */
1995 Assert(orig_agg->aggorder == NIL);
1996 Assert(orig_agg->aggdistinct == NIL);
1997
1998 /*
1999 * Since aggregate calls can't be nested, we needn't recurse into the
2000 * arguments. But for safety, flat-copy the Aggref node itself rather
2001 * than modifying it in-place.
2002 */
2003 child_agg = makeNode(Aggref);
2004 memcpy(child_agg, orig_agg, sizeof(Aggref));
2005
2006 /*
2007 * For the parent Aggref, we want to copy all the fields of the
2008 * original aggregate *except* the args list, which we'll replace
2009 * below, and the aggfilter expression, which should be applied only
2010 * by the child not the parent. Rather than explicitly knowing about
2011 * all the other fields here, we can momentarily modify child_agg to
2012 * provide a suitable source for copyObject.
2013 */
2014 child_agg->args = NIL;
2015 child_agg->aggfilter = NULL;
2016 parent_agg = copyObject(child_agg);
2017 child_agg->args = orig_agg->args;
2018 child_agg->aggfilter = orig_agg->aggfilter;
2019
2020 /*
2021 * Now, set up child_agg to represent the first phase of partial
2022 * aggregation. For now, assume serialization is required.
2023 */
2024 mark_partial_aggref(child_agg, AGGSPLIT_INITIAL_SERIAL);
2025
2026 /*
2027 * And set up parent_agg to represent the second phase.
2028 */
2029 parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
2030 1, NULL, false));
2031 mark_partial_aggref(parent_agg, AGGSPLIT_FINAL_DESERIAL);
2032
2033 return (Node *) parent_agg;
2034 }
2035 return expression_tree_mutator(node, convert_combining_aggrefs,
2036 (void *) context);
2037}
2038
2039/*
2040 * set_dummy_tlist_references
2041 * Replace the targetlist of an upper-level plan node with a simple
2042 * list of OUTER_VAR references to its child.
2043 *
2044 * This is used for plan types like Sort and Append that don't evaluate
2045 * their targetlists. Although the executor doesn't care at all what's in
2046 * the tlist, EXPLAIN needs it to be realistic.
2047 *
2048 * Note: we could almost use set_upper_references() here, but it fails for
2049 * Append for lack of a lefttree subplan. Single-purpose code is faster
2050 * anyway.
2051 */
2052static void
2053set_dummy_tlist_references(Plan *plan, int rtoffset)
2054{
2055 List *output_targetlist;
2056 ListCell *l;
2057
2058 output_targetlist = NIL;
2059 foreach(l, plan->targetlist)
2060 {
2061 TargetEntry *tle = (TargetEntry *) lfirst(l);
2062 Var *oldvar = (Var *) tle->expr;
2063 Var *newvar;
2064
2065 /*
2066 * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
2067 * as Consts, not Vars referencing Consts. Here, there's no speed
2068 * advantage to be had, but it makes EXPLAIN output look cleaner, and
2069 * again it avoids confusing the executor.
2070 */
2071 if (IsA(oldvar, Const))
2072 {
2073 /* just reuse the existing TLE node */
2074 output_targetlist = lappend(output_targetlist, tle);
2075 continue;
2076 }
2077
2078 newvar = makeVar(OUTER_VAR,
2079 tle->resno,
2080 exprType((Node *) oldvar),
2081 exprTypmod((Node *) oldvar),
2082 exprCollation((Node *) oldvar),
2083 0);
2084 if (IsA(oldvar, Var))
2085 {
2086 newvar->varnoold = oldvar->varno + rtoffset;
2087 newvar->varoattno = oldvar->varattno;
2088 }
2089 else
2090 {
2091 newvar->varnoold = 0; /* wasn't ever a plain Var */
2092 newvar->varoattno = 0;
2093 }
2094
2095 tle = flatCopyTargetEntry(tle);
2096 tle->expr = (Expr *) newvar;
2097 output_targetlist = lappend(output_targetlist, tle);
2098 }
2099 plan->targetlist = output_targetlist;
2100
2101 /* We don't touch plan->qual here */
2102}
2103
2104
2105/*
2106 * build_tlist_index --- build an index data structure for a child tlist
2107 *
2108 * In most cases, subplan tlists will be "flat" tlists with only Vars,
2109 * so we try to optimize that case by extracting information about Vars
2110 * in advance. Matching a parent tlist to a child is still an O(N^2)
2111 * operation, but at least with a much smaller constant factor than plain
2112 * tlist_member() searches.
2113 *
2114 * The result of this function is an indexed_tlist struct to pass to
2115 * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
2116 * When done, the indexed_tlist may be freed with a single pfree().
2117 */
2118static indexed_tlist *
2119build_tlist_index(List *tlist)
2120{
2121 indexed_tlist *itlist;
2122 tlist_vinfo *vinfo;
2123 ListCell *l;
2124
2125 /* Create data structure with enough slots for all tlist entries */
2126 itlist = (indexed_tlist *)
2127 palloc(offsetof(indexed_tlist, vars) +
2128 list_length(tlist) * sizeof(tlist_vinfo));
2129
2130 itlist->tlist = tlist;
2131 itlist->has_ph_vars = false;
2132 itlist->has_non_vars = false;
2133
2134 /* Find the Vars and fill in the index array */
2135 vinfo = itlist->vars;
2136 foreach(l, tlist)
2137 {
2138 TargetEntry *tle = (TargetEntry *) lfirst(l);
2139
2140 if (tle->expr && IsA(tle->expr, Var))
2141 {
2142 Var *var = (Var *) tle->expr;
2143
2144 vinfo->varno = var->varno;
2145 vinfo->varattno = var->varattno;
2146 vinfo->resno = tle->resno;
2147 vinfo++;
2148 }
2149 else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2150 itlist->has_ph_vars = true;
2151 else
2152 itlist->has_non_vars = true;
2153 }
2154
2155 itlist->num_vars = (vinfo - itlist->vars);
2156
2157 return itlist;
2158}
2159
2160/*
2161 * build_tlist_index_other_vars --- build a restricted tlist index
2162 *
2163 * This is like build_tlist_index, but we only index tlist entries that
2164 * are Vars belonging to some rel other than the one specified. We will set
2165 * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
2166 * (so nothing other than Vars and PlaceHolderVars can be matched).
2167 */
2168static indexed_tlist *
2169build_tlist_index_other_vars(List *tlist, Index ignore_rel)
2170{
2171 indexed_tlist *itlist;
2172 tlist_vinfo *vinfo;
2173 ListCell *l;
2174
2175 /* Create data structure with enough slots for all tlist entries */
2176 itlist = (indexed_tlist *)
2177 palloc(offsetof(indexed_tlist, vars) +
2178 list_length(tlist) * sizeof(tlist_vinfo));
2179
2180 itlist->tlist = tlist;
2181 itlist->has_ph_vars = false;
2182 itlist->has_non_vars = false;
2183
2184 /* Find the desired Vars and fill in the index array */
2185 vinfo = itlist->vars;
2186 foreach(l, tlist)
2187 {
2188 TargetEntry *tle = (TargetEntry *) lfirst(l);
2189
2190 if (tle->expr && IsA(tle->expr, Var))
2191 {
2192 Var *var = (Var *) tle->expr;
2193
2194 if (var->varno != ignore_rel)
2195 {
2196 vinfo->varno = var->varno;
2197 vinfo->varattno = var->varattno;
2198 vinfo->resno = tle->resno;
2199 vinfo++;
2200 }
2201 }
2202 else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2203 itlist->has_ph_vars = true;
2204 }
2205
2206 itlist->num_vars = (vinfo - itlist->vars);
2207
2208 return itlist;
2209}
2210
2211/*
2212 * search_indexed_tlist_for_var --- find a Var in an indexed tlist
2213 *
2214 * If a match is found, return a copy of the given Var with suitably
2215 * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
2216 * Also ensure that varnoold is incremented by rtoffset.
2217 * If no match, return NULL.
2218 */
2219static Var *
2220search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
2221 Index newvarno, int rtoffset)
2222{
2223 Index varno = var->varno;
2224 AttrNumber varattno = var->varattno;
2225 tlist_vinfo *vinfo;
2226 int i;
2227
2228 vinfo = itlist->vars;
2229 i = itlist->num_vars;
2230 while (i-- > 0)
2231 {
2232 if (vinfo->varno == varno && vinfo->varattno == varattno)
2233 {
2234 /* Found a match */
2235 Var *newvar = copyVar(var);
2236
2237 newvar->varno = newvarno;
2238 newvar->varattno = vinfo->resno;
2239 if (newvar->varnoold > 0)
2240 newvar->varnoold += rtoffset;
2241 return newvar;
2242 }
2243 vinfo++;
2244 }
2245 return NULL; /* no match */
2246}
2247
2248/*
2249 * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
2250 *
2251 * If a match is found, return a Var constructed to reference the tlist item.
2252 * If no match, return NULL.
2253 *
2254 * NOTE: it is a waste of time to call this unless itlist->has_ph_vars or
2255 * itlist->has_non_vars. Furthermore, set_join_references() relies on being
2256 * able to prevent matching of non-Vars by clearing itlist->has_non_vars,
2257 * so there's a correctness reason not to call it unless that's set.
2258 */
2259static Var *
2260search_indexed_tlist_for_non_var(Expr *node,
2261 indexed_tlist *itlist, Index newvarno)
2262{
2263 TargetEntry *tle;
2264
2265 /*
2266 * If it's a simple Const, replacing it with a Var is silly, even if there
2267 * happens to be an identical Const below; a Var is more expensive to
2268 * execute than a Const. What's more, replacing it could confuse some
2269 * places in the executor that expect to see simple Consts for, eg,
2270 * dropped columns.
2271 */
2272 if (IsA(node, Const))
2273 return NULL;
2274
2275 tle = tlist_member(node, itlist->tlist);
2276 if (tle)
2277 {
2278 /* Found a matching subplan output expression */
2279 Var *newvar;
2280
2281 newvar = makeVarFromTargetEntry(newvarno, tle);
2282 newvar->varnoold = 0; /* wasn't ever a plain Var */
2283 newvar->varoattno = 0;
2284 return newvar;
2285 }
2286 return NULL; /* no match */
2287}
2288
2289/*
2290 * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
2291 *
2292 * If a match is found, return a Var constructed to reference the tlist item.
2293 * If no match, return NULL.
2294 *
2295 * This is needed to ensure that we select the right subplan TLE in cases
2296 * where there are multiple textually-equal()-but-volatile sort expressions.
2297 * And it's also faster than search_indexed_tlist_for_non_var.
2298 */
2299static Var *
2300search_indexed_tlist_for_sortgroupref(Expr *node,
2301 Index sortgroupref,
2302 indexed_tlist *itlist,
2303 Index newvarno)
2304{
2305 ListCell *lc;
2306
2307 foreach(lc, itlist->tlist)
2308 {
2309 TargetEntry *tle = (TargetEntry *) lfirst(lc);
2310
2311 /* The equal() check should be redundant, but let's be paranoid */
2312 if (tle->ressortgroupref == sortgroupref &&
2313 equal(node, tle->expr))
2314 {
2315 /* Found a matching subplan output expression */
2316 Var *newvar;
2317
2318 newvar = makeVarFromTargetEntry(newvarno, tle);
2319 newvar->varnoold = 0; /* wasn't ever a plain Var */
2320 newvar->varoattno = 0;
2321 return newvar;
2322 }
2323 }
2324 return NULL; /* no match */
2325}
2326
2327/*
2328 * fix_join_expr
2329 * Create a new set of targetlist entries or join qual clauses by
2330 * changing the varno/varattno values of variables in the clauses
2331 * to reference target list values from the outer and inner join
2332 * relation target lists. Also perform opcode lookup and add
2333 * regclass OIDs to root->glob->relationOids.
2334 *
2335 * This is used in three different scenarios:
2336 * 1) a normal join clause, where all the Vars in the clause *must* be
2337 * replaced by OUTER_VAR or INNER_VAR references. In this case
2338 * acceptable_rel should be zero so that any failure to match a Var will be
2339 * reported as an error.
2340 * 2) RETURNING clauses, which may contain both Vars of the target relation
2341 * and Vars of other relations. In this case we want to replace the
2342 * other-relation Vars by OUTER_VAR references, while leaving target Vars
2343 * alone. Thus inner_itlist = NULL and acceptable_rel = the ID of the
2344 * target relation should be passed.
2345 * 3) ON CONFLICT UPDATE SET/WHERE clauses. Here references to EXCLUDED are
2346 * to be replaced with INNER_VAR references, while leaving target Vars (the
2347 * to-be-updated relation) alone. Correspondingly inner_itlist is to be
2348 * EXCLUDED elements, outer_itlist = NULL and acceptable_rel the target
2349 * relation.
2350 *
2351 * 'clauses' is the targetlist or list of join clauses
2352 * 'outer_itlist' is the indexed target list of the outer join relation,
2353 * or NULL
2354 * 'inner_itlist' is the indexed target list of the inner join relation,
2355 * or NULL
2356 * 'acceptable_rel' is either zero or the rangetable index of a relation
2357 * whose Vars may appear in the clause without provoking an error
2358 * 'rtoffset': how much to increment varnoold by
2359 *
2360 * Returns the new expression tree. The original clause structure is
2361 * not modified.
2362 */
2363static List *
2364fix_join_expr(PlannerInfo *root,
2365 List *clauses,
2366 indexed_tlist *outer_itlist,
2367 indexed_tlist *inner_itlist,
2368 Index acceptable_rel,
2369 int rtoffset)
2370{
2371 fix_join_expr_context context;
2372
2373 context.root = root;
2374 context.outer_itlist = outer_itlist;
2375 context.inner_itlist = inner_itlist;
2376 context.acceptable_rel = acceptable_rel;
2377 context.rtoffset = rtoffset;
2378 return (List *) fix_join_expr_mutator((Node *) clauses, &context);
2379}
2380
2381static Node *
2382fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
2383{
2384 Var *newvar;
2385
2386 if (node == NULL)
2387 return NULL;
2388 if (IsA(node, Var))
2389 {
2390 Var *var = (Var *) node;
2391
2392 /* Look for the var in the input tlists, first in the outer */
2393 if (context->outer_itlist)
2394 {
2395 newvar = search_indexed_tlist_for_var(var,
2396 context->outer_itlist,
2397 OUTER_VAR,
2398 context->rtoffset);
2399 if (newvar)
2400 return (Node *) newvar;
2401 }
2402
2403 /* then in the inner. */
2404 if (context->inner_itlist)
2405 {
2406 newvar = search_indexed_tlist_for_var(var,
2407 context->inner_itlist,
2408 INNER_VAR,
2409 context->rtoffset);
2410 if (newvar)
2411 return (Node *) newvar;
2412 }
2413
2414 /* If it's for acceptable_rel, adjust and return it */
2415 if (var->varno == context->acceptable_rel)
2416 {
2417 var = copyVar(var);
2418 var->varno += context->rtoffset;
2419 if (var->varnoold > 0)
2420 var->varnoold += context->rtoffset;
2421 return (Node *) var;
2422 }
2423
2424 /* No referent found for Var */
2425 elog(ERROR, "variable not found in subplan target lists");
2426 }
2427 if (IsA(node, PlaceHolderVar))
2428 {
2429 PlaceHolderVar *phv = (PlaceHolderVar *) node;
2430
2431 /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2432 if (context->outer_itlist && context->outer_itlist->has_ph_vars)
2433 {
2434 newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2435 context->outer_itlist,
2436 OUTER_VAR);
2437 if (newvar)
2438 return (Node *) newvar;
2439 }
2440 if (context->inner_itlist && context->inner_itlist->has_ph_vars)
2441 {
2442 newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2443 context->inner_itlist,
2444 INNER_VAR);
2445 if (newvar)
2446 return (Node *) newvar;
2447 }
2448
2449 /* If not supplied by input plans, evaluate the contained expr */
2450 return fix_join_expr_mutator((Node *) phv->phexpr, context);
2451 }
2452 /* Try matching more complex expressions too, if tlists have any */
2453 if (context->outer_itlist && context->outer_itlist->has_non_vars)
2454 {
2455 newvar = search_indexed_tlist_for_non_var((Expr *) node,
2456 context->outer_itlist,
2457 OUTER_VAR);
2458 if (newvar)
2459 return (Node *) newvar;
2460 }
2461 if (context->inner_itlist && context->inner_itlist->has_non_vars)
2462 {
2463 newvar = search_indexed_tlist_for_non_var((Expr *) node,
2464 context->inner_itlist,
2465 INNER_VAR);
2466 if (newvar)
2467 return (Node *) newvar;
2468 }
2469 /* Special cases (apply only AFTER failing to match to lower tlist) */
2470 if (IsA(node, Param))
2471 return fix_param_node(context->root, (Param *) node);
2472 fix_expr_common(context->root, node);
2473 return expression_tree_mutator(node,
2474 fix_join_expr_mutator,
2475 (void *) context);
2476}
2477
2478/*
2479 * fix_upper_expr
2480 * Modifies an expression tree so that all Var nodes reference outputs
2481 * of a subplan. Also looks for Aggref nodes that should be replaced
2482 * by initplan output Params. Also performs opcode lookup, and adds
2483 * regclass OIDs to root->glob->relationOids.
2484 *
2485 * This is used to fix up target and qual expressions of non-join upper-level
2486 * plan nodes, as well as index-only scan nodes.
2487 *
2488 * An error is raised if no matching var can be found in the subplan tlist
2489 * --- so this routine should only be applied to nodes whose subplans'
2490 * targetlists were generated by flattening the expressions used in the
2491 * parent node.
2492 *
2493 * If itlist->has_non_vars is true, then we try to match whole subexpressions
2494 * against elements of the subplan tlist, so that we can avoid recomputing
2495 * expressions that were already computed by the subplan. (This is relatively
2496 * expensive, so we don't want to try it in the common case where the
2497 * subplan tlist is just a flattened list of Vars.)
2498 *
2499 * 'node': the tree to be fixed (a target item or qual)
2500 * 'subplan_itlist': indexed target list for subplan (or index)
2501 * 'newvarno': varno to use for Vars referencing tlist elements
2502 * 'rtoffset': how much to increment varnoold by
2503 *
2504 * The resulting tree is a copy of the original in which all Var nodes have
2505 * varno = newvarno, varattno = resno of corresponding targetlist element.
2506 * The original tree is not modified.
2507 */
2508static Node *
2509fix_upper_expr(PlannerInfo *root,
2510 Node *node,
2511 indexed_tlist *subplan_itlist,
2512 Index newvarno,
2513 int rtoffset)
2514{
2515 fix_upper_expr_context context;
2516
2517 context.root = root;
2518 context.subplan_itlist = subplan_itlist;
2519 context.newvarno = newvarno;
2520 context.rtoffset = rtoffset;
2521 return fix_upper_expr_mutator(node, &context);
2522}
2523
2524static Node *
2525fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
2526{
2527 Var *newvar;
2528
2529 if (node == NULL)
2530 return NULL;
2531 if (IsA(node, Var))
2532 {
2533 Var *var = (Var *) node;
2534
2535 newvar = search_indexed_tlist_for_var(var,
2536 context->subplan_itlist,
2537 context->newvarno,
2538 context->rtoffset);
2539 if (!newvar)
2540 elog(ERROR, "variable not found in subplan target list");
2541 return (Node *) newvar;
2542 }
2543 if (IsA(node, PlaceHolderVar))
2544 {
2545 PlaceHolderVar *phv = (PlaceHolderVar *) node;
2546
2547 /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2548 if (context->subplan_itlist->has_ph_vars)
2549 {
2550 newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2551 context->subplan_itlist,
2552 context->newvarno);
2553 if (newvar)
2554 return (Node *) newvar;
2555 }
2556 /* If not supplied by input plan, evaluate the contained expr */
2557 return fix_upper_expr_mutator((Node *) phv->phexpr, context);
2558 }
2559 /* Try matching more complex expressions too, if tlist has any */
2560 if (context->subplan_itlist->has_non_vars)
2561 {
2562 newvar = search_indexed_tlist_for_non_var((Expr *) node,
2563 context->subplan_itlist,
2564 context->newvarno);
2565 if (newvar)
2566 return (Node *) newvar;
2567 }
2568 /* Special cases (apply only AFTER failing to match to lower tlist) */
2569 if (IsA(node, Param))
2570 return fix_param_node(context->root, (Param *) node);
2571 if (IsA(node, Aggref))
2572 {
2573 Aggref *aggref = (Aggref *) node;
2574
2575 /* See if the Aggref should be replaced by a Param */
2576 if (context->root->minmax_aggs != NIL &&
2577 list_length(aggref->args) == 1)
2578 {
2579 TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
2580 ListCell *lc;
2581
2582 foreach(lc, context->root->minmax_aggs)
2583 {
2584 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
2585
2586 if (mminfo->aggfnoid == aggref->aggfnoid &&
2587 equal(mminfo->target, curTarget->expr))
2588 return (Node *) copyObject(mminfo->param);
2589 }
2590 }
2591 /* If no match, just fall through to process it normally */
2592 }
2593 fix_expr_common(context->root, node);
2594 return expression_tree_mutator(node,
2595 fix_upper_expr_mutator,
2596 (void *) context);
2597}
2598
2599/*
2600 * set_returning_clause_references
2601 * Perform setrefs.c's work on a RETURNING targetlist
2602 *
2603 * If the query involves more than just the result table, we have to
2604 * adjust any Vars that refer to other tables to reference junk tlist
2605 * entries in the top subplan's targetlist. Vars referencing the result
2606 * table should be left alone, however (the executor will evaluate them
2607 * using the actual heap tuple, after firing triggers if any). In the
2608 * adjusted RETURNING list, result-table Vars will have their original
2609 * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
2610 *
2611 * We also must perform opcode lookup and add regclass OIDs to
2612 * root->glob->relationOids.
2613 *
2614 * 'rlist': the RETURNING targetlist to be fixed
2615 * 'topplan': the top subplan node that will be just below the ModifyTable
2616 * node (note it's not yet passed through set_plan_refs)
2617 * 'resultRelation': RT index of the associated result relation
2618 * 'rtoffset': how much to increment varnos by
2619 *
2620 * Note: the given 'root' is for the parent query level, not the 'topplan'.
2621 * This does not matter currently since we only access the dependency-item
2622 * lists in root->glob, but it would need some hacking if we wanted a root
2623 * that actually matches the subplan.
2624 *
2625 * Note: resultRelation is not yet adjusted by rtoffset.
2626 */
2627static List *
2628set_returning_clause_references(PlannerInfo *root,
2629 List *rlist,
2630 Plan *topplan,
2631 Index resultRelation,
2632 int rtoffset)
2633{
2634 indexed_tlist *itlist;
2635
2636 /*
2637 * We can perform the desired Var fixup by abusing the fix_join_expr
2638 * machinery that formerly handled inner indexscan fixup. We search the
2639 * top plan's targetlist for Vars of non-result relations, and use
2640 * fix_join_expr to convert RETURNING Vars into references to those tlist
2641 * entries, while leaving result-rel Vars as-is.
2642 *
2643 * PlaceHolderVars will also be sought in the targetlist, but no
2644 * more-complex expressions will be. Note that it is not possible for a
2645 * PlaceHolderVar to refer to the result relation, since the result is
2646 * never below an outer join. If that case could happen, we'd have to be
2647 * prepared to pick apart the PlaceHolderVar and evaluate its contained
2648 * expression instead.
2649 */
2650 itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
2651
2652 rlist = fix_join_expr(root,
2653 rlist,
2654 itlist,
2655 NULL,
2656 resultRelation,
2657 rtoffset);
2658
2659 pfree(itlist);
2660
2661 return rlist;
2662}
2663
2664
2665/*****************************************************************************
2666 * QUERY DEPENDENCY MANAGEMENT
2667 *****************************************************************************/
2668
2669/*
2670 * record_plan_function_dependency
2671 * Mark the current plan as depending on a particular function.
2672 *
2673 * This is exported so that the function-inlining code can record a
2674 * dependency on a function that it's removed from the plan tree.
2675 */
2676void
2677record_plan_function_dependency(PlannerInfo *root, Oid funcid)
2678{
2679 /*
2680 * For performance reasons, we don't bother to track built-in functions;
2681 * we just assume they'll never change (or at least not in ways that'd
2682 * invalidate plans using them). For this purpose we can consider a
2683 * built-in function to be one with OID less than FirstBootstrapObjectId.
2684 * Note that the OID generator guarantees never to generate such an OID
2685 * after startup, even at OID wraparound.
2686 */
2687 if (funcid >= (Oid) FirstBootstrapObjectId)
2688 {
2689 PlanInvalItem *inval_item = makeNode(PlanInvalItem);
2690
2691 /*
2692 * It would work to use any syscache on pg_proc, but the easiest is
2693 * PROCOID since we already have the function's OID at hand. Note
2694 * that plancache.c knows we use PROCOID.
2695 */
2696 inval_item->cacheId = PROCOID;
2697 inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
2698 ObjectIdGetDatum(funcid));
2699
2700 root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
2701 }
2702}
2703
2704/*
2705 * record_plan_type_dependency
2706 * Mark the current plan as depending on a particular type.
2707 *
2708 * This is exported so that eval_const_expressions can record a
2709 * dependency on a domain that it's removed a CoerceToDomain node for.
2710 *
2711 * We don't currently need to record dependencies on domains that the
2712 * plan contains CoerceToDomain nodes for, though that might change in
2713 * future. Hence, this isn't actually called in this module, though
2714 * someday fix_expr_common might call it.
2715 */
2716void
2717record_plan_type_dependency(PlannerInfo *root, Oid typid)
2718{
2719 /*
2720 * As in record_plan_function_dependency, ignore the possibility that
2721 * someone would change a built-in domain.
2722 */
2723 if (typid >= (Oid) FirstBootstrapObjectId)
2724 {
2725 PlanInvalItem *inval_item = makeNode(PlanInvalItem);
2726
2727 /*
2728 * It would work to use any syscache on pg_type, but the easiest is
2729 * TYPEOID since we already have the type's OID at hand. Note that
2730 * plancache.c knows we use TYPEOID.
2731 */
2732 inval_item->cacheId = TYPEOID;
2733 inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
2734 ObjectIdGetDatum(typid));
2735
2736 root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
2737 }
2738}
2739
2740/*
2741 * extract_query_dependencies
2742 * Given a rewritten, but not yet planned, query or queries
2743 * (i.e. a Query node or list of Query nodes), extract dependencies
2744 * just as set_plan_references would do. Also detect whether any
2745 * rewrite steps were affected by RLS.
2746 *
2747 * This is needed by plancache.c to handle invalidation of cached unplanned
2748 * queries.
2749 *
2750 * Note: this does not go through eval_const_expressions, and hence doesn't
2751 * reflect its additions of inlined functions and elided CoerceToDomain nodes
2752 * to the invalItems list. This is obviously OK for functions, since we'll
2753 * see them in the original query tree anyway. For domains, it's OK because
2754 * we don't care about domains unless they get elided. That is, a plan might
2755 * have domain dependencies that the query tree doesn't.
2756 */
2757void
2758extract_query_dependencies(Node *query,
2759 List **relationOids,
2760 List **invalItems,
2761 bool *hasRowSecurity)
2762{
2763 PlannerGlobal glob;
2764 PlannerInfo root;
2765
2766 /* Make up dummy planner state so we can use this module's machinery */
2767 MemSet(&glob, 0, sizeof(glob));
2768 glob.type = T_PlannerGlobal;
2769 glob.relationOids = NIL;
2770 glob.invalItems = NIL;
2771 /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
2772 glob.dependsOnRole = false;
2773
2774 MemSet(&root, 0, sizeof(root));
2775 root.type = T_PlannerInfo;
2776 root.glob = &glob;
2777
2778 (void) extract_query_dependencies_walker(query, &root);
2779
2780 *relationOids = glob.relationOids;
2781 *invalItems = glob.invalItems;
2782 *hasRowSecurity = glob.dependsOnRole;
2783}
2784
2785/*
2786 * Tree walker for extract_query_dependencies.
2787 *
2788 * This is exported so that expression_planner_with_deps can call it on
2789 * simple expressions (post-planning, not before planning, in that case).
2790 * In that usage, glob.dependsOnRole isn't meaningful, but the relationOids
2791 * and invalItems lists are added to as needed.
2792 */
2793bool
2794extract_query_dependencies_walker(Node *node, PlannerInfo *context)
2795{
2796 if (node == NULL)
2797 return false;
2798 Assert(!IsA(node, PlaceHolderVar));
2799 if (IsA(node, Query))
2800 {
2801 Query *query = (Query *) node;
2802 ListCell *lc;
2803
2804 if (query->commandType == CMD_UTILITY)
2805 {
2806 /*
2807 * Ignore utility statements, except those (such as EXPLAIN) that
2808 * contain a parsed-but-not-planned query.
2809 */
2810 query = UtilityContainsQuery(query->utilityStmt);
2811 if (query == NULL)
2812 return false;
2813 }
2814
2815 /* Remember if any Query has RLS quals applied by rewriter */
2816 if (query->hasRowSecurity)
2817 context->glob->dependsOnRole = true;
2818
2819 /* Collect relation OIDs in this Query's rtable */
2820 foreach(lc, query->rtable)
2821 {
2822 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2823
2824 if (rte->rtekind == RTE_RELATION)
2825 context->glob->relationOids =
2826 lappend_oid(context->glob->relationOids, rte->relid);
2827 else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
2828 OidIsValid(rte->relid))
2829 context->glob->relationOids =
2830 lappend_oid(context->glob->relationOids,
2831 rte->relid);
2832 }
2833
2834 /* And recurse into the query's subexpressions */
2835 return query_tree_walker(query, extract_query_dependencies_walker,
2836 (void *) context, 0);
2837 }
2838 /* Extract function dependencies and check for regclass Consts */
2839 fix_expr_common(context, node);
2840 return expression_tree_walker(node, extract_query_dependencies_walker,
2841 (void *) context);
2842}
2843