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