PostgreSQL Source Code  git master
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-2023, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  * src/backend/optimizer/plan/setrefs.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 
18 #include "access/transam.h"
19 #include "catalog/pg_type.h"
20 #include "nodes/makefuncs.h"
21 #include "nodes/nodeFuncs.h"
22 #include "optimizer/optimizer.h"
23 #include "optimizer/pathnode.h"
24 #include "optimizer/planmain.h"
25 #include "optimizer/planner.h"
26 #include "optimizer/tlist.h"
27 #include "parser/parse_relation.h"
28 #include "tcop/utility.h"
29 #include "utils/lsyscache.h"
30 #include "utils/syscache.h"
31 
32 
33 typedef enum
34 {
35  NRM_EQUAL, /* expect exact match of nullingrels */
36  NRM_SUBSET, /* actual Var may have a subset of input */
37  NRM_SUPERSET /* actual Var may have a superset of input */
39 
40 typedef struct
41 {
42  int varno; /* RT index of Var */
43  AttrNumber varattno; /* attr number of Var */
44  AttrNumber resno; /* TLE position of Var */
45 #ifdef USE_ASSERT_CHECKING
46  Bitmapset *varnullingrels; /* Var's varnullingrels */
47 #endif
48 } tlist_vinfo;
49 
50 typedef struct
51 {
52  List *tlist; /* underlying target list */
53  int num_vars; /* number of plain Var tlist entries */
54  bool has_ph_vars; /* are there PlaceHolderVar entries? */
55  bool has_non_vars; /* are there other entries? */
56  tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]; /* has num_vars entries */
58 
59 typedef struct
60 {
62  int rtoffset;
63  double num_exec;
65 
66 typedef struct
67 {
72  int rtoffset;
74  double num_exec;
76 
77 typedef struct
78 {
81  int newvarno;
82  int rtoffset;
84  double num_exec;
86 
87 typedef struct
88 {
91  int newvarno;
93 
94 /* Context info for flatten_rtes_walker() */
95 typedef struct
96 {
100 
101 /*
102  * Selecting the best alternative in an AlternativeSubPlan expression requires
103  * estimating how many times that expression will be evaluated. For an
104  * expression in a plan node's targetlist, the plan's estimated number of
105  * output rows is clearly what to use, but for an expression in a qual it's
106  * far less clear. Since AlternativeSubPlans aren't heavily used, we don't
107  * want to expend a lot of cycles making such estimates. What we use is twice
108  * the number of output rows. That's not entirely unfounded: we know that
109  * clause_selectivity() would fall back to a default selectivity estimate
110  * of 0.5 for any SubPlan, so if the qual containing the SubPlan is the last
111  * to be applied (which it likely would be, thanks to order_qual_clauses()),
112  * this matches what we could have estimated in a far more laborious fashion.
113  * Obviously there are many other scenarios, but it's probably not worth the
114  * trouble to try to improve on this estimate, especially not when we don't
115  * have a better estimate for the selectivity of the SubPlan qual itself.
116  */
117 #define NUM_EXEC_TLIST(parentplan) ((parentplan)->plan_rows)
118 #define NUM_EXEC_QUAL(parentplan) ((parentplan)->plan_rows * 2.0)
119 
120 /*
121  * Check if a Const node is a regclass value. We accept plain OID too,
122  * since a regclass Const will get folded to that type if it's an argument
123  * to oideq or similar operators. (This might result in some extraneous
124  * values in a plan's list of relation dependencies, but the worst result
125  * would be occasional useless replans.)
126  */
127 #define ISREGCLASSCONST(con) \
128  (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
129  !(con)->constisnull)
130 
131 #define fix_scan_list(root, lst, rtoffset, num_exec) \
132  ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))
133 
134 static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing);
135 static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
136 static bool flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt);
137 static void add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
138  RangeTblEntry *rte);
139 static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
141  IndexOnlyScan *plan,
142  int rtoffset);
144  SubqueryScan *plan,
145  int rtoffset);
146 static Plan *clean_up_removed_plan_level(Plan *parent, Plan *child);
147 static void set_foreignscan_references(PlannerInfo *root,
148  ForeignScan *fscan,
149  int rtoffset);
150 static void set_customscan_references(PlannerInfo *root,
151  CustomScan *cscan,
152  int rtoffset);
154  Append *aplan,
155  int rtoffset);
157  MergeAppend *mplan,
158  int rtoffset);
159 static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset);
160 static Relids offset_relid_set(Relids relids, int rtoffset);
161 static Node *fix_scan_expr(PlannerInfo *root, Node *node,
162  int rtoffset, double num_exec);
163 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
164 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
165 static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
166 static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset);
167 static void set_param_references(PlannerInfo *root, Plan *plan);
168 static Node *convert_combining_aggrefs(Node *node, void *context);
169 static void set_dummy_tlist_references(Plan *plan, int rtoffset);
170 static indexed_tlist *build_tlist_index(List *tlist);
172  indexed_tlist *itlist,
173  int newvarno,
174  int rtoffset,
175  NullingRelsMatch nrm_match);
177  indexed_tlist *itlist,
178  int newvarno,
179  NullingRelsMatch nrm_match);
181  indexed_tlist *itlist,
182  int newvarno);
184  Index sortgroupref,
185  indexed_tlist *itlist,
186  int newvarno);
187 static List *fix_join_expr(PlannerInfo *root,
188  List *clauses,
189  indexed_tlist *outer_itlist,
190  indexed_tlist *inner_itlist,
191  Index acceptable_rel,
192  int rtoffset,
193  NullingRelsMatch nrm_match,
194  double num_exec);
195 static Node *fix_join_expr_mutator(Node *node,
196  fix_join_expr_context *context);
197 static Node *fix_upper_expr(PlannerInfo *root,
198  Node *node,
199  indexed_tlist *subplan_itlist,
200  int newvarno,
201  int rtoffset,
202  NullingRelsMatch nrm_match,
203  double num_exec);
204 static Node *fix_upper_expr_mutator(Node *node,
205  fix_upper_expr_context *context);
207  List *rlist,
208  Plan *topplan,
209  Index resultRelation,
210  int rtoffset);
212  List *runcondition,
213  Plan *plan);
214 
215 
216 /*****************************************************************************
217  *
218  * SUBPLAN REFERENCES
219  *
220  *****************************************************************************/
221 
222 /*
223  * set_plan_references
224  *
225  * This is the final processing pass of the planner/optimizer. The plan
226  * tree is complete; we just have to adjust some representational details
227  * for the convenience of the executor:
228  *
229  * 1. We flatten the various subquery rangetables into a single list, and
230  * zero out RangeTblEntry fields that are not useful to the executor.
231  *
232  * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
233  *
234  * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
235  * subplans.
236  *
237  * 4. Aggrefs in Agg plan nodes need to be adjusted in some cases involving
238  * partial aggregation or minmax aggregate optimization.
239  *
240  * 5. PARAM_MULTIEXPR Params are replaced by regular PARAM_EXEC Params,
241  * now that we have finished planning all MULTIEXPR subplans.
242  *
243  * 6. AlternativeSubPlan expressions are replaced by just one of their
244  * alternatives, using an estimate of how many times they'll be executed.
245  *
246  * 7. We compute regproc OIDs for operators (ie, we look up the function
247  * that implements each op).
248  *
249  * 8. We create lists of specific objects that the plan depends on.
250  * This will be used by plancache.c to drive invalidation of cached plans.
251  * Relation dependencies are represented by OIDs, and everything else by
252  * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
253  * Currently, relations, user-defined functions, and domains are the only
254  * types of objects that are explicitly tracked this way.
255  *
256  * 9. We assign every plan node in the tree a unique ID.
257  *
258  * We also perform one final optimization step, which is to delete
259  * SubqueryScan, Append, and MergeAppend plan nodes that aren't doing
260  * anything useful. The reason for doing this last is that
261  * it can't readily be done before set_plan_references, because it would
262  * break set_upper_references: the Vars in the child plan's top tlist
263  * wouldn't match up with the Vars in the outer plan tree. A SubqueryScan
264  * serves a necessary function as a buffer between outer query and subquery
265  * variable numbering ... but after we've flattened the rangetable this is
266  * no longer a problem, since then there's only one rtindex namespace.
267  * Likewise, Append and MergeAppend buffer between the parent and child vars
268  * of an appendrel, but we don't need to worry about that once we've done
269  * set_plan_references.
270  *
271  * set_plan_references recursively traverses the whole plan tree.
272  *
273  * The return value is normally the same Plan node passed in, but can be
274  * different when the passed-in Plan is a node we decide isn't needed.
275  *
276  * The flattened rangetable entries are appended to root->glob->finalrtable.
277  * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the
278  * RT indexes of ModifyTable result relations to root->glob->resultRelations,
279  * and flattened AppendRelInfos are appended to root->glob->appendRelations.
280  * Plan dependencies are appended to root->glob->relationOids (for relations)
281  * and root->glob->invalItems (for everything else).
282  *
283  * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
284  * to process targetlist and qual expressions. We can assume that the Plan
285  * nodes were just built by the planner and are not multiply referenced, but
286  * it's not so safe to assume that for expression tree nodes.
287  */
288 Plan *
290 {
291  Plan *result;
292  PlannerGlobal *glob = root->glob;
293  int rtoffset = list_length(glob->finalrtable);
294  ListCell *lc;
295 
296  /*
297  * Add all the query's RTEs to the flattened rangetable. The live ones
298  * will have their rangetable indexes increased by rtoffset. (Additional
299  * RTEs, not referenced by the Plan tree, might get added after those.)
300  */
301  add_rtes_to_flat_rtable(root, false);
302 
303  /*
304  * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
305  */
306  foreach(lc, root->rowMarks)
307  {
309  PlanRowMark *newrc;
310 
311  /* flat copy is enough since all fields are scalars */
312  newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
313  memcpy(newrc, rc, sizeof(PlanRowMark));
314 
315  /* adjust indexes ... but *not* the rowmarkId */
316  newrc->rti += rtoffset;
317  newrc->prti += rtoffset;
318 
319  glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
320  }
321 
322  /*
323  * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
324  * We assume the AppendRelInfos were built during planning and don't need
325  * to be copied.
326  */
327  foreach(lc, root->append_rel_list)
328  {
329  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
330 
331  /* adjust RT indexes */
332  appinfo->parent_relid += rtoffset;
333  appinfo->child_relid += rtoffset;
334 
335  /*
336  * Rather than adjust the translated_vars entries, just drop 'em.
337  * Neither the executor nor EXPLAIN currently need that data.
338  */
339  appinfo->translated_vars = NIL;
340 
341  glob->appendRelations = lappend(glob->appendRelations, appinfo);
342  }
343 
344  /* If needed, create workspace for processing AlternativeSubPlans */
345  if (root->hasAlternativeSubPlans)
346  {
347  root->isAltSubplan = (bool *)
348  palloc0(list_length(glob->subplans) * sizeof(bool));
349  root->isUsedSubplan = (bool *)
350  palloc0(list_length(glob->subplans) * sizeof(bool));
351  }
352 
353  /* Now fix the Plan tree */
354  result = set_plan_refs(root, plan, rtoffset);
355 
356  /*
357  * If we have AlternativeSubPlans, it is likely that we now have some
358  * unreferenced subplans in glob->subplans. To avoid expending cycles on
359  * those subplans later, get rid of them by setting those list entries to
360  * NULL. (Note: we can't do this immediately upon processing an
361  * AlternativeSubPlan, because there may be multiple copies of the
362  * AlternativeSubPlan, and they can get resolved differently.)
363  */
364  if (root->hasAlternativeSubPlans)
365  {
366  foreach(lc, glob->subplans)
367  {
368  int ndx = foreach_current_index(lc);
369 
370  /*
371  * If it was used by some AlternativeSubPlan in this query level,
372  * but wasn't selected as best by any AlternativeSubPlan, then we
373  * don't need it. Do not touch subplans that aren't parts of
374  * AlternativeSubPlans.
375  */
376  if (root->isAltSubplan[ndx] && !root->isUsedSubplan[ndx])
377  lfirst(lc) = NULL;
378  }
379  }
380 
381  /* Also fix up the information in PartitionPruneInfos. */
382  foreach(lc, root->partPruneInfos)
383  {
384  PartitionPruneInfo *pruneinfo = lfirst(lc);
385  ListCell *l;
386 
387  pruneinfo->root_parent_relids =
388  offset_relid_set(pruneinfo->root_parent_relids, rtoffset);
389  foreach(l, pruneinfo->prune_infos)
390  {
391  List *prune_infos = lfirst(l);
392  ListCell *l2;
393 
394  foreach(l2, prune_infos)
395  {
396  PartitionedRelPruneInfo *pinfo = lfirst(l2);
397 
398  /* RT index of the table to which the pinfo belongs. */
399  pinfo->rtindex += rtoffset;
400  }
401  }
402 
403  glob->partPruneInfos = lappend(glob->partPruneInfos, pruneinfo);
404  }
405 
406  return result;
407 }
408 
409 /*
410  * Extract RangeTblEntries from the plan's rangetable, and add to flat rtable
411  *
412  * This can recurse into subquery plans; "recursing" is true if so.
413  *
414  * This also seems like a good place to add the query's RTEPermissionInfos to
415  * the flat rteperminfos.
416  */
417 static void
418 add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
419 {
420  PlannerGlobal *glob = root->glob;
421  Index rti;
422  ListCell *lc;
423 
424  /*
425  * Add the query's own RTEs to the flattened rangetable.
426  *
427  * At top level, we must add all RTEs so that their indexes in the
428  * flattened rangetable match up with their original indexes. When
429  * recursing, we only care about extracting relation RTEs (and subquery
430  * RTEs that were once relation RTEs).
431  */
432  foreach(lc, root->parse->rtable)
433  {
434  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
435 
436  if (!recursing || rte->rtekind == RTE_RELATION ||
437  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))
438  add_rte_to_flat_rtable(glob, root->parse->rteperminfos, rte);
439  }
440 
441  /*
442  * If there are any dead subqueries, they are not referenced in the Plan
443  * tree, so we must add RTEs contained in them to the flattened rtable
444  * separately. (If we failed to do this, the executor would not perform
445  * expected permission checks for tables mentioned in such subqueries.)
446  *
447  * Note: this pass over the rangetable can't be combined with the previous
448  * one, because that would mess up the numbering of the live RTEs in the
449  * flattened rangetable.
450  */
451  rti = 1;
452  foreach(lc, root->parse->rtable)
453  {
454  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
455 
456  /*
457  * We should ignore inheritance-parent RTEs: their contents have been
458  * pulled up into our rangetable already. Also ignore any subquery
459  * RTEs without matching RelOptInfos, as they likewise have been
460  * pulled up.
461  */
462  if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
463  rti < root->simple_rel_array_size)
464  {
465  RelOptInfo *rel = root->simple_rel_array[rti];
466 
467  if (rel != NULL)
468  {
469  Assert(rel->relid == rti); /* sanity check on array */
470 
471  /*
472  * The subquery might never have been planned at all, if it
473  * was excluded on the basis of self-contradictory constraints
474  * in our query level. In this case apply
475  * flatten_unplanned_rtes.
476  *
477  * If it was planned but the result rel is dummy, we assume
478  * that it has been omitted from our plan tree (see
479  * set_subquery_pathlist), and recurse to pull up its RTEs.
480  *
481  * Otherwise, it should be represented by a SubqueryScan node
482  * somewhere in our plan tree, and we'll pull up its RTEs when
483  * we process that plan node.
484  *
485  * However, if we're recursing, then we should pull up RTEs
486  * whether the subquery is dummy or not, because we've found
487  * that some upper query level is treating this one as dummy,
488  * and so we won't scan this level's plan tree at all.
489  */
490  if (rel->subroot == NULL)
491  flatten_unplanned_rtes(glob, rte);
492  else if (recursing ||
494  UPPERREL_FINAL, NULL)))
495  add_rtes_to_flat_rtable(rel->subroot, true);
496  }
497  }
498  rti++;
499  }
500 }
501 
502 /*
503  * Extract RangeTblEntries from a subquery that was never planned at all
504  */
505 
506 static void
508 {
509  flatten_rtes_walker_context cxt = {glob, rte->subquery};
510 
511  /* Use query_tree_walker to find all RTEs in the parse tree */
512  (void) query_tree_walker(rte->subquery,
514  (void *) &cxt,
516 }
517 
518 static bool
520 {
521  if (node == NULL)
522  return false;
523  if (IsA(node, RangeTblEntry))
524  {
525  RangeTblEntry *rte = (RangeTblEntry *) node;
526 
527  /* As above, we need only save relation RTEs and former relations */
528  if (rte->rtekind == RTE_RELATION ||
529  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))
530  add_rte_to_flat_rtable(cxt->glob, cxt->query->rteperminfos, rte);
531  return false;
532  }
533  if (IsA(node, Query))
534  {
535  /*
536  * Recurse into subselects. Must update cxt->query to this query so
537  * that the rtable and rteperminfos correspond with each other.
538  */
539  Query *save_query = cxt->query;
540  bool result;
541 
542  cxt->query = (Query *) node;
543  result = query_tree_walker((Query *) node,
545  (void *) cxt,
547  cxt->query = save_query;
548  return result;
549  }
551  (void *) cxt);
552 }
553 
554 /*
555  * Add (a copy of) the given RTE to the final rangetable and also the
556  * corresponding RTEPermissionInfo, if any, to final rteperminfos.
557  *
558  * In the flat rangetable, we zero out substructure pointers that are not
559  * needed by the executor; this reduces the storage space and copying cost
560  * for cached plans. We keep only the ctename, alias, eref Alias fields,
561  * which are needed by EXPLAIN, and perminfoindex which is needed by the
562  * executor to fetch the RTE's RTEPermissionInfo.
563  */
564 static void
566  RangeTblEntry *rte)
567 {
568  RangeTblEntry *newrte;
569 
570  /* flat copy to duplicate all the scalar fields */
571  newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
572  memcpy(newrte, rte, sizeof(RangeTblEntry));
573 
574  /* zap unneeded sub-structure */
575  newrte->tablesample = NULL;
576  newrte->subquery = NULL;
577  newrte->joinaliasvars = NIL;
578  newrte->joinleftcols = NIL;
579  newrte->joinrightcols = NIL;
580  newrte->join_using_alias = NULL;
581  newrte->functions = NIL;
582  newrte->tablefunc = NULL;
583  newrte->values_lists = NIL;
584  newrte->coltypes = NIL;
585  newrte->coltypmods = NIL;
586  newrte->colcollations = NIL;
587  newrte->securityQuals = NIL;
588 
589  glob->finalrtable = lappend(glob->finalrtable, newrte);
590 
591  /*
592  * If it's a plain relation RTE (or a subquery that was once a view
593  * reference), add the relation OID to relationOids.
594  *
595  * We do this even though the RTE might be unreferenced in the plan tree;
596  * this would correspond to cases such as views that were expanded, child
597  * tables that were eliminated by constraint exclusion, etc. Schema
598  * invalidation on such a rel must still force rebuilding of the plan.
599  *
600  * Note we don't bother to avoid making duplicate list entries. We could,
601  * but it would probably cost more cycles than it would save.
602  */
603  if (newrte->rtekind == RTE_RELATION ||
604  (newrte->rtekind == RTE_SUBQUERY && OidIsValid(newrte->relid)))
605  glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
606 
607  /*
608  * Add a copy of the RTEPermissionInfo, if any, corresponding to this RTE
609  * to the flattened global list.
610  */
611  if (rte->perminfoindex > 0)
612  {
613  RTEPermissionInfo *perminfo;
614  RTEPermissionInfo *newperminfo;
615 
616  /* Get the existing one from this query's rteperminfos. */
617  perminfo = getRTEPermissionInfo(rteperminfos, newrte);
618 
619  /*
620  * Add a new one to finalrteperminfos and copy the contents of the
621  * existing one into it. Note that addRTEPermissionInfo() also
622  * updates newrte->perminfoindex to point to newperminfo in
623  * finalrteperminfos.
624  */
625  newrte->perminfoindex = 0; /* expected by addRTEPermissionInfo() */
626  newperminfo = addRTEPermissionInfo(&glob->finalrteperminfos, newrte);
627  memcpy(newperminfo, perminfo, sizeof(RTEPermissionInfo));
628  }
629 }
630 
631 /*
632  * set_plan_refs: recurse through the Plan nodes of a single subquery level
633  */
634 static Plan *
635 set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
636 {
637  ListCell *l;
638 
639  if (plan == NULL)
640  return NULL;
641 
642  /* Assign this node a unique ID. */
643  plan->plan_node_id = root->glob->lastPlanNodeId++;
644 
645  /*
646  * Plan-type-specific fixes
647  */
648  switch (nodeTag(plan))
649  {
650  case T_SeqScan:
651  {
652  SeqScan *splan = (SeqScan *) plan;
653 
654  splan->scan.scanrelid += rtoffset;
655  splan->scan.plan.targetlist =
656  fix_scan_list(root, splan->scan.plan.targetlist,
657  rtoffset, NUM_EXEC_TLIST(plan));
658  splan->scan.plan.qual =
659  fix_scan_list(root, splan->scan.plan.qual,
660  rtoffset, NUM_EXEC_QUAL(plan));
661  }
662  break;
663  case T_SampleScan:
664  {
665  SampleScan *splan = (SampleScan *) plan;
666 
667  splan->scan.scanrelid += rtoffset;
668  splan->scan.plan.targetlist =
669  fix_scan_list(root, splan->scan.plan.targetlist,
670  rtoffset, NUM_EXEC_TLIST(plan));
671  splan->scan.plan.qual =
672  fix_scan_list(root, splan->scan.plan.qual,
673  rtoffset, NUM_EXEC_QUAL(plan));
674  splan->tablesample = (TableSampleClause *)
675  fix_scan_expr(root, (Node *) splan->tablesample,
676  rtoffset, 1);
677  }
678  break;
679  case T_IndexScan:
680  {
681  IndexScan *splan = (IndexScan *) plan;
682 
683  splan->scan.scanrelid += rtoffset;
684  splan->scan.plan.targetlist =
685  fix_scan_list(root, splan->scan.plan.targetlist,
686  rtoffset, NUM_EXEC_TLIST(plan));
687  splan->scan.plan.qual =
688  fix_scan_list(root, splan->scan.plan.qual,
689  rtoffset, NUM_EXEC_QUAL(plan));
690  splan->indexqual =
691  fix_scan_list(root, splan->indexqual,
692  rtoffset, 1);
693  splan->indexqualorig =
694  fix_scan_list(root, splan->indexqualorig,
695  rtoffset, NUM_EXEC_QUAL(plan));
696  splan->indexorderby =
697  fix_scan_list(root, splan->indexorderby,
698  rtoffset, 1);
699  splan->indexorderbyorig =
700  fix_scan_list(root, splan->indexorderbyorig,
701  rtoffset, NUM_EXEC_QUAL(plan));
702  }
703  break;
704  case T_IndexOnlyScan:
705  {
706  IndexOnlyScan *splan = (IndexOnlyScan *) plan;
707 
708  return set_indexonlyscan_references(root, splan, rtoffset);
709  }
710  break;
711  case T_BitmapIndexScan:
712  {
714 
715  splan->scan.scanrelid += rtoffset;
716  /* no need to fix targetlist and qual */
717  Assert(splan->scan.plan.targetlist == NIL);
718  Assert(splan->scan.plan.qual == NIL);
719  splan->indexqual =
720  fix_scan_list(root, splan->indexqual, rtoffset, 1);
721  splan->indexqualorig =
722  fix_scan_list(root, splan->indexqualorig,
723  rtoffset, NUM_EXEC_QUAL(plan));
724  }
725  break;
726  case T_BitmapHeapScan:
727  {
728  BitmapHeapScan *splan = (BitmapHeapScan *) plan;
729 
730  splan->scan.scanrelid += rtoffset;
731  splan->scan.plan.targetlist =
732  fix_scan_list(root, splan->scan.plan.targetlist,
733  rtoffset, NUM_EXEC_TLIST(plan));
734  splan->scan.plan.qual =
735  fix_scan_list(root, splan->scan.plan.qual,
736  rtoffset, NUM_EXEC_QUAL(plan));
737  splan->bitmapqualorig =
738  fix_scan_list(root, splan->bitmapqualorig,
739  rtoffset, NUM_EXEC_QUAL(plan));
740  }
741  break;
742  case T_TidScan:
743  {
744  TidScan *splan = (TidScan *) plan;
745 
746  splan->scan.scanrelid += rtoffset;
747  splan->scan.plan.targetlist =
748  fix_scan_list(root, splan->scan.plan.targetlist,
749  rtoffset, NUM_EXEC_TLIST(plan));
750  splan->scan.plan.qual =
751  fix_scan_list(root, splan->scan.plan.qual,
752  rtoffset, NUM_EXEC_QUAL(plan));
753  splan->tidquals =
754  fix_scan_list(root, splan->tidquals,
755  rtoffset, 1);
756  }
757  break;
758  case T_TidRangeScan:
759  {
760  TidRangeScan *splan = (TidRangeScan *) plan;
761 
762  splan->scan.scanrelid += rtoffset;
763  splan->scan.plan.targetlist =
764  fix_scan_list(root, splan->scan.plan.targetlist,
765  rtoffset, NUM_EXEC_TLIST(plan));
766  splan->scan.plan.qual =
767  fix_scan_list(root, splan->scan.plan.qual,
768  rtoffset, NUM_EXEC_QUAL(plan));
769  splan->tidrangequals =
770  fix_scan_list(root, splan->tidrangequals,
771  rtoffset, 1);
772  }
773  break;
774  case T_SubqueryScan:
775  /* Needs special treatment, see comments below */
776  return set_subqueryscan_references(root,
777  (SubqueryScan *) plan,
778  rtoffset);
779  case T_FunctionScan:
780  {
781  FunctionScan *splan = (FunctionScan *) plan;
782 
783  splan->scan.scanrelid += rtoffset;
784  splan->scan.plan.targetlist =
785  fix_scan_list(root, splan->scan.plan.targetlist,
786  rtoffset, NUM_EXEC_TLIST(plan));
787  splan->scan.plan.qual =
788  fix_scan_list(root, splan->scan.plan.qual,
789  rtoffset, NUM_EXEC_QUAL(plan));
790  splan->functions =
791  fix_scan_list(root, splan->functions, rtoffset, 1);
792  }
793  break;
794  case T_TableFuncScan:
795  {
796  TableFuncScan *splan = (TableFuncScan *) plan;
797 
798  splan->scan.scanrelid += rtoffset;
799  splan->scan.plan.targetlist =
800  fix_scan_list(root, splan->scan.plan.targetlist,
801  rtoffset, NUM_EXEC_TLIST(plan));
802  splan->scan.plan.qual =
803  fix_scan_list(root, splan->scan.plan.qual,
804  rtoffset, NUM_EXEC_QUAL(plan));
805  splan->tablefunc = (TableFunc *)
806  fix_scan_expr(root, (Node *) splan->tablefunc,
807  rtoffset, 1);
808  }
809  break;
810  case T_ValuesScan:
811  {
812  ValuesScan *splan = (ValuesScan *) plan;
813 
814  splan->scan.scanrelid += rtoffset;
815  splan->scan.plan.targetlist =
816  fix_scan_list(root, splan->scan.plan.targetlist,
817  rtoffset, NUM_EXEC_TLIST(plan));
818  splan->scan.plan.qual =
819  fix_scan_list(root, splan->scan.plan.qual,
820  rtoffset, NUM_EXEC_QUAL(plan));
821  splan->values_lists =
822  fix_scan_list(root, splan->values_lists,
823  rtoffset, 1);
824  }
825  break;
826  case T_CteScan:
827  {
828  CteScan *splan = (CteScan *) plan;
829 
830  splan->scan.scanrelid += rtoffset;
831  splan->scan.plan.targetlist =
832  fix_scan_list(root, splan->scan.plan.targetlist,
833  rtoffset, NUM_EXEC_TLIST(plan));
834  splan->scan.plan.qual =
835  fix_scan_list(root, splan->scan.plan.qual,
836  rtoffset, NUM_EXEC_QUAL(plan));
837  }
838  break;
839  case T_NamedTuplestoreScan:
840  {
842 
843  splan->scan.scanrelid += rtoffset;
844  splan->scan.plan.targetlist =
845  fix_scan_list(root, splan->scan.plan.targetlist,
846  rtoffset, NUM_EXEC_TLIST(plan));
847  splan->scan.plan.qual =
848  fix_scan_list(root, splan->scan.plan.qual,
849  rtoffset, NUM_EXEC_QUAL(plan));
850  }
851  break;
852  case T_WorkTableScan:
853  {
854  WorkTableScan *splan = (WorkTableScan *) plan;
855 
856  splan->scan.scanrelid += rtoffset;
857  splan->scan.plan.targetlist =
858  fix_scan_list(root, splan->scan.plan.targetlist,
859  rtoffset, NUM_EXEC_TLIST(plan));
860  splan->scan.plan.qual =
861  fix_scan_list(root, splan->scan.plan.qual,
862  rtoffset, NUM_EXEC_QUAL(plan));
863  }
864  break;
865  case T_ForeignScan:
866  set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
867  break;
868  case T_CustomScan:
869  set_customscan_references(root, (CustomScan *) plan, rtoffset);
870  break;
871 
872  case T_NestLoop:
873  case T_MergeJoin:
874  case T_HashJoin:
875  set_join_references(root, (Join *) plan, rtoffset);
876  break;
877 
878  case T_Gather:
879  case T_GatherMerge:
880  {
881  set_upper_references(root, plan, rtoffset);
882  set_param_references(root, plan);
883  }
884  break;
885 
886  case T_Hash:
887  set_hash_references(root, plan, rtoffset);
888  break;
889 
890  case T_Memoize:
891  {
892  Memoize *mplan = (Memoize *) plan;
893 
894  /*
895  * Memoize does not evaluate its targetlist. It just uses the
896  * same targetlist from its outer subnode.
897  */
898  set_dummy_tlist_references(plan, rtoffset);
899 
900  mplan->param_exprs = fix_scan_list(root, mplan->param_exprs,
901  rtoffset,
902  NUM_EXEC_TLIST(plan));
903  break;
904  }
905 
906  case T_Material:
907  case T_Sort:
908  case T_IncrementalSort:
909  case T_Unique:
910  case T_SetOp:
911 
912  /*
913  * These plan types don't actually bother to evaluate their
914  * targetlists, because they just return their unmodified input
915  * tuples. Even though the targetlist won't be used by the
916  * executor, we fix it up for possible use by EXPLAIN (not to
917  * mention ease of debugging --- wrong varnos are very confusing).
918  */
919  set_dummy_tlist_references(plan, rtoffset);
920 
921  /*
922  * Since these plan types don't check quals either, we should not
923  * find any qual expression attached to them.
924  */
925  Assert(plan->qual == NIL);
926  break;
927  case T_LockRows:
928  {
929  LockRows *splan = (LockRows *) plan;
930 
931  /*
932  * Like the plan types above, LockRows doesn't evaluate its
933  * tlist or quals. But we have to fix up the RT indexes in
934  * its rowmarks.
935  */
936  set_dummy_tlist_references(plan, rtoffset);
937  Assert(splan->plan.qual == NIL);
938 
939  foreach(l, splan->rowMarks)
940  {
941  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
942 
943  rc->rti += rtoffset;
944  rc->prti += rtoffset;
945  }
946  }
947  break;
948  case T_Limit:
949  {
950  Limit *splan = (Limit *) plan;
951 
952  /*
953  * Like the plan types above, Limit doesn't evaluate its tlist
954  * or quals. It does have live expressions for limit/offset,
955  * however; and those cannot contain subplan variable refs, so
956  * fix_scan_expr works for them.
957  */
958  set_dummy_tlist_references(plan, rtoffset);
959  Assert(splan->plan.qual == NIL);
960 
961  splan->limitOffset =
962  fix_scan_expr(root, splan->limitOffset, rtoffset, 1);
963  splan->limitCount =
964  fix_scan_expr(root, splan->limitCount, rtoffset, 1);
965  }
966  break;
967  case T_Agg:
968  {
969  Agg *agg = (Agg *) plan;
970 
971  /*
972  * If this node is combining partial-aggregation results, we
973  * must convert its Aggrefs to contain references to the
974  * partial-aggregate subexpressions that will be available
975  * from the child plan node.
976  */
977  if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
978  {
979  plan->targetlist = (List *)
980  convert_combining_aggrefs((Node *) plan->targetlist,
981  NULL);
982  plan->qual = (List *)
983  convert_combining_aggrefs((Node *) plan->qual,
984  NULL);
985  }
986 
987  set_upper_references(root, plan, rtoffset);
988  }
989  break;
990  case T_Group:
991  set_upper_references(root, plan, rtoffset);
992  break;
993  case T_WindowAgg:
994  {
995  WindowAgg *wplan = (WindowAgg *) plan;
996 
997  /*
998  * Adjust the WindowAgg's run conditions by swapping the
999  * WindowFuncs references out to instead reference the Var in
1000  * the scan slot so that when the executor evaluates the
1001  * runCondition, it receives the WindowFunc's value from the
1002  * slot that the result has just been stored into rather than
1003  * evaluating the WindowFunc all over again.
1004  */
1006  wplan->runCondition,
1007  (Plan *) wplan);
1008 
1009  set_upper_references(root, plan, rtoffset);
1010 
1011  /*
1012  * Like Limit node limit/offset expressions, WindowAgg has
1013  * frame offset expressions, which cannot contain subplan
1014  * variable refs, so fix_scan_expr works for them.
1015  */
1016  wplan->startOffset =
1017  fix_scan_expr(root, wplan->startOffset, rtoffset, 1);
1018  wplan->endOffset =
1019  fix_scan_expr(root, wplan->endOffset, rtoffset, 1);
1020  wplan->runCondition = fix_scan_list(root,
1021  wplan->runCondition,
1022  rtoffset,
1023  NUM_EXEC_TLIST(plan));
1024  wplan->runConditionOrig = fix_scan_list(root,
1025  wplan->runConditionOrig,
1026  rtoffset,
1027  NUM_EXEC_TLIST(plan));
1028  }
1029  break;
1030  case T_Result:
1031  {
1032  Result *splan = (Result *) plan;
1033 
1034  /*
1035  * Result may or may not have a subplan; if not, it's more
1036  * like a scan node than an upper node.
1037  */
1038  if (splan->plan.lefttree != NULL)
1039  set_upper_references(root, plan, rtoffset);
1040  else
1041  {
1042  /*
1043  * The tlist of a childless Result could contain
1044  * unresolved ROWID_VAR Vars, in case it's representing a
1045  * target relation which is completely empty because of
1046  * constraint exclusion. Replace any such Vars by null
1047  * constants, as though they'd been resolved for a leaf
1048  * scan node that doesn't support them. We could have
1049  * fix_scan_expr do this, but since the case is only
1050  * expected to occur here, it seems safer to special-case
1051  * it here and keep the assertions that ROWID_VARs
1052  * shouldn't be seen by fix_scan_expr.
1053  */
1054  foreach(l, splan->plan.targetlist)
1055  {
1056  TargetEntry *tle = (TargetEntry *) lfirst(l);
1057  Var *var = (Var *) tle->expr;
1058 
1059  if (var && IsA(var, Var) && var->varno == ROWID_VAR)
1060  tle->expr = (Expr *) makeNullConst(var->vartype,
1061  var->vartypmod,
1062  var->varcollid);
1063  }
1064 
1065  splan->plan.targetlist =
1066  fix_scan_list(root, splan->plan.targetlist,
1067  rtoffset, NUM_EXEC_TLIST(plan));
1068  splan->plan.qual =
1069  fix_scan_list(root, splan->plan.qual,
1070  rtoffset, NUM_EXEC_QUAL(plan));
1071  }
1072  /* resconstantqual can't contain any subplan variable refs */
1073  splan->resconstantqual =
1074  fix_scan_expr(root, splan->resconstantqual, rtoffset, 1);
1075  }
1076  break;
1077  case T_ProjectSet:
1078  set_upper_references(root, plan, rtoffset);
1079  break;
1080  case T_ModifyTable:
1081  {
1082  ModifyTable *splan = (ModifyTable *) plan;
1083  Plan *subplan = outerPlan(splan);
1084 
1085  Assert(splan->plan.targetlist == NIL);
1086  Assert(splan->plan.qual == NIL);
1087 
1088  splan->withCheckOptionLists =
1089  fix_scan_list(root, splan->withCheckOptionLists,
1090  rtoffset, 1);
1091 
1092  if (splan->returningLists)
1093  {
1094  List *newRL = NIL;
1095  ListCell *lcrl,
1096  *lcrr;
1097 
1098  /*
1099  * Pass each per-resultrel returningList through
1100  * set_returning_clause_references().
1101  */
1102  Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
1103  forboth(lcrl, splan->returningLists,
1104  lcrr, splan->resultRelations)
1105  {
1106  List *rlist = (List *) lfirst(lcrl);
1107  Index resultrel = lfirst_int(lcrr);
1108 
1109  rlist = set_returning_clause_references(root,
1110  rlist,
1111  subplan,
1112  resultrel,
1113  rtoffset);
1114  newRL = lappend(newRL, rlist);
1115  }
1116  splan->returningLists = newRL;
1117 
1118  /*
1119  * Set up the visible plan targetlist as being the same as
1120  * the first RETURNING list. This is for the use of
1121  * EXPLAIN; the executor won't pay any attention to the
1122  * targetlist. We postpone this step until here so that
1123  * we don't have to do set_returning_clause_references()
1124  * twice on identical targetlists.
1125  */
1126  splan->plan.targetlist = copyObject(linitial(newRL));
1127  }
1128 
1129  /*
1130  * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
1131  * join', where the inner side is the EXCLUDED tuple.
1132  * Therefore use fix_join_expr to setup the relevant variables
1133  * to INNER_VAR. We explicitly don't create any OUTER_VARs as
1134  * those are already used by RETURNING and it seems better to
1135  * be non-conflicting.
1136  */
1137  if (splan->onConflictSet)
1138  {
1139  indexed_tlist *itlist;
1140 
1141  itlist = build_tlist_index(splan->exclRelTlist);
1142 
1143  splan->onConflictSet =
1144  fix_join_expr(root, splan->onConflictSet,
1145  NULL, itlist,
1146  linitial_int(splan->resultRelations),
1147  rtoffset, NRM_EQUAL, NUM_EXEC_QUAL(plan));
1148 
1149  splan->onConflictWhere = (Node *)
1150  fix_join_expr(root, (List *) splan->onConflictWhere,
1151  NULL, itlist,
1152  linitial_int(splan->resultRelations),
1153  rtoffset, NRM_EQUAL, NUM_EXEC_QUAL(plan));
1154 
1155  pfree(itlist);
1156 
1157  splan->exclRelTlist =
1158  fix_scan_list(root, splan->exclRelTlist, rtoffset, 1);
1159  }
1160 
1161  /*
1162  * The MERGE statement produces the target rows by performing
1163  * a right join between the target relation and the source
1164  * relation (which could be a plain relation or a subquery).
1165  * The INSERT and UPDATE actions of the MERGE statement
1166  * require access to the columns from the source relation. We
1167  * arrange things so that the source relation attributes are
1168  * available as INNER_VAR and the target relation attributes
1169  * are available from the scan tuple.
1170  */
1171  if (splan->mergeActionLists != NIL)
1172  {
1173  ListCell *lca,
1174  *lcr;
1175 
1176  /*
1177  * Fix the targetList of individual action nodes so that
1178  * the so-called "source relation" Vars are referenced as
1179  * INNER_VAR. Note that for this to work correctly during
1180  * execution, the ecxt_innertuple must be set to the tuple
1181  * obtained by executing the subplan, which is what
1182  * constitutes the "source relation".
1183  *
1184  * We leave the Vars from the result relation (i.e. the
1185  * target relation) unchanged i.e. those Vars would be
1186  * picked from the scan slot. So during execution, we must
1187  * ensure that ecxt_scantuple is setup correctly to refer
1188  * to the tuple from the target relation.
1189  */
1190  indexed_tlist *itlist;
1191 
1192  itlist = build_tlist_index(subplan->targetlist);
1193 
1194  forboth(lca, splan->mergeActionLists,
1195  lcr, splan->resultRelations)
1196  {
1197  List *mergeActionList = lfirst(lca);
1198  Index resultrel = lfirst_int(lcr);
1199 
1200  foreach(l, mergeActionList)
1201  {
1203 
1204  /* Fix targetList of each action. */
1205  action->targetList = fix_join_expr(root,
1206  action->targetList,
1207  NULL, itlist,
1208  resultrel,
1209  rtoffset,
1210  NRM_EQUAL,
1211  NUM_EXEC_TLIST(plan));
1212 
1213  /* Fix quals too. */
1214  action->qual = (Node *) fix_join_expr(root,
1215  (List *) action->qual,
1216  NULL, itlist,
1217  resultrel,
1218  rtoffset,
1219  NRM_EQUAL,
1220  NUM_EXEC_QUAL(plan));
1221  }
1222  }
1223  }
1224 
1225  splan->nominalRelation += rtoffset;
1226  if (splan->rootRelation)
1227  splan->rootRelation += rtoffset;
1228  splan->exclRelRTI += rtoffset;
1229 
1230  foreach(l, splan->resultRelations)
1231  {
1232  lfirst_int(l) += rtoffset;
1233  }
1234  foreach(l, splan->rowMarks)
1235  {
1236  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
1237 
1238  rc->rti += rtoffset;
1239  rc->prti += rtoffset;
1240  }
1241 
1242  /*
1243  * Append this ModifyTable node's final result relation RT
1244  * index(es) to the global list for the plan.
1245  */
1246  root->glob->resultRelations =
1248  splan->resultRelations);
1249  if (splan->rootRelation)
1250  {
1251  root->glob->resultRelations =
1253  splan->rootRelation);
1254  }
1255  }
1256  break;
1257  case T_Append:
1258  /* Needs special treatment, see comments below */
1259  return set_append_references(root,
1260  (Append *) plan,
1261  rtoffset);
1262  case T_MergeAppend:
1263  /* Needs special treatment, see comments below */
1264  return set_mergeappend_references(root,
1265  (MergeAppend *) plan,
1266  rtoffset);
1267  case T_RecursiveUnion:
1268  /* This doesn't evaluate targetlist or check quals either */
1269  set_dummy_tlist_references(plan, rtoffset);
1270  Assert(plan->qual == NIL);
1271  break;
1272  case T_BitmapAnd:
1273  {
1274  BitmapAnd *splan = (BitmapAnd *) plan;
1275 
1276  /* BitmapAnd works like Append, but has no tlist */
1277  Assert(splan->plan.targetlist == NIL);
1278  Assert(splan->plan.qual == NIL);
1279  foreach(l, splan->bitmapplans)
1280  {
1281  lfirst(l) = set_plan_refs(root,
1282  (Plan *) lfirst(l),
1283  rtoffset);
1284  }
1285  }
1286  break;
1287  case T_BitmapOr:
1288  {
1289  BitmapOr *splan = (BitmapOr *) plan;
1290 
1291  /* BitmapOr works like Append, but has no tlist */
1292  Assert(splan->plan.targetlist == NIL);
1293  Assert(splan->plan.qual == NIL);
1294  foreach(l, splan->bitmapplans)
1295  {
1296  lfirst(l) = set_plan_refs(root,
1297  (Plan *) lfirst(l),
1298  rtoffset);
1299  }
1300  }
1301  break;
1302  default:
1303  elog(ERROR, "unrecognized node type: %d",
1304  (int) nodeTag(plan));
1305  break;
1306  }
1307 
1308  /*
1309  * Now recurse into child plans, if any
1310  *
1311  * NOTE: it is essential that we recurse into child plans AFTER we set
1312  * subplan references in this plan's tlist and quals. If we did the
1313  * reference-adjustments bottom-up, then we would fail to match this
1314  * plan's var nodes against the already-modified nodes of the children.
1315  */
1316  plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
1317  plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
1318 
1319  return plan;
1320 }
1321 
1322 /*
1323  * set_indexonlyscan_references
1324  * Do set_plan_references processing on an IndexOnlyScan
1325  *
1326  * This is unlike the handling of a plain IndexScan because we have to
1327  * convert Vars referencing the heap into Vars referencing the index.
1328  * We can use the fix_upper_expr machinery for that, by working from a
1329  * targetlist describing the index columns.
1330  */
1331 static Plan *
1333  IndexOnlyScan *plan,
1334  int rtoffset)
1335 {
1336  indexed_tlist *index_itlist;
1337  List *stripped_indextlist;
1338  ListCell *lc;
1339 
1340  /*
1341  * Vars in the plan node's targetlist, qual, and recheckqual must only
1342  * reference columns that the index AM can actually return. To ensure
1343  * this, remove non-returnable columns (which are marked as resjunk) from
1344  * the indexed tlist. We can just drop them because the indexed_tlist
1345  * machinery pays attention to TLE resnos, not physical list position.
1346  */
1347  stripped_indextlist = NIL;
1348  foreach(lc, plan->indextlist)
1349  {
1350  TargetEntry *indextle = (TargetEntry *) lfirst(lc);
1351 
1352  if (!indextle->resjunk)
1353  stripped_indextlist = lappend(stripped_indextlist, indextle);
1354  }
1355 
1356  index_itlist = build_tlist_index(stripped_indextlist);
1357 
1358  plan->scan.scanrelid += rtoffset;
1359  plan->scan.plan.targetlist = (List *)
1360  fix_upper_expr(root,
1361  (Node *) plan->scan.plan.targetlist,
1362  index_itlist,
1363  INDEX_VAR,
1364  rtoffset,
1365  NRM_EQUAL,
1366  NUM_EXEC_TLIST((Plan *) plan));
1367  plan->scan.plan.qual = (List *)
1368  fix_upper_expr(root,
1369  (Node *) plan->scan.plan.qual,
1370  index_itlist,
1371  INDEX_VAR,
1372  rtoffset,
1373  NRM_EQUAL,
1374  NUM_EXEC_QUAL((Plan *) plan));
1375  plan->recheckqual = (List *)
1376  fix_upper_expr(root,
1377  (Node *) plan->recheckqual,
1378  index_itlist,
1379  INDEX_VAR,
1380  rtoffset,
1381  NRM_EQUAL,
1382  NUM_EXEC_QUAL((Plan *) plan));
1383  /* indexqual is already transformed to reference index columns */
1384  plan->indexqual = fix_scan_list(root, plan->indexqual,
1385  rtoffset, 1);
1386  /* indexorderby is already transformed to reference index columns */
1387  plan->indexorderby = fix_scan_list(root, plan->indexorderby,
1388  rtoffset, 1);
1389  /* indextlist must NOT be transformed to reference index columns */
1390  plan->indextlist = fix_scan_list(root, plan->indextlist,
1391  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
1392 
1393  pfree(index_itlist);
1394 
1395  return (Plan *) plan;
1396 }
1397 
1398 /*
1399  * set_subqueryscan_references
1400  * Do set_plan_references processing on a SubqueryScan
1401  *
1402  * We try to strip out the SubqueryScan entirely; if we can't, we have
1403  * to do the normal processing on it.
1404  */
1405 static Plan *
1407  SubqueryScan *plan,
1408  int rtoffset)
1409 {
1410  RelOptInfo *rel;
1411  Plan *result;
1412 
1413  /* Need to look up the subquery's RelOptInfo, since we need its subroot */
1414  rel = find_base_rel(root, plan->scan.scanrelid);
1415 
1416  /* Recursively process the subplan */
1417  plan->subplan = set_plan_references(rel->subroot, plan->subplan);
1418 
1419  if (trivial_subqueryscan(plan))
1420  {
1421  /*
1422  * We can omit the SubqueryScan node and just pull up the subplan.
1423  */
1424  result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
1425  }
1426  else
1427  {
1428  /*
1429  * Keep the SubqueryScan node. We have to do the processing that
1430  * set_plan_references would otherwise have done on it. Notice we do
1431  * not do set_upper_references() here, because a SubqueryScan will
1432  * always have been created with correct references to its subplan's
1433  * outputs to begin with.
1434  */
1435  plan->scan.scanrelid += rtoffset;
1436  plan->scan.plan.targetlist =
1437  fix_scan_list(root, plan->scan.plan.targetlist,
1438  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
1439  plan->scan.plan.qual =
1440  fix_scan_list(root, plan->scan.plan.qual,
1441  rtoffset, NUM_EXEC_QUAL((Plan *) plan));
1442 
1443  result = (Plan *) plan;
1444  }
1445 
1446  return result;
1447 }
1448 
1449 /*
1450  * trivial_subqueryscan
1451  * Detect whether a SubqueryScan can be deleted from the plan tree.
1452  *
1453  * We can delete it if it has no qual to check and the targetlist just
1454  * regurgitates the output of the child plan.
1455  *
1456  * This can be called from mark_async_capable_plan(), a helper function for
1457  * create_append_plan(), before set_subqueryscan_references(), to determine
1458  * triviality of a SubqueryScan that is a child of an Append node. So we
1459  * cache the result in the SubqueryScan node to avoid repeated computation.
1460  *
1461  * Note: when called from mark_async_capable_plan(), we determine the result
1462  * before running finalize_plan() on the SubqueryScan node (if needed) and
1463  * set_plan_references() on the subplan tree, but this would be safe, because
1464  * 1) finalize_plan() doesn't modify the tlist or quals for the SubqueryScan
1465  * node (or that for any plan node in the subplan tree), and
1466  * 2) set_plan_references() modifies the tlist for every plan node in the
1467  * subplan tree, but keeps const/resjunk columns as const/resjunk ones and
1468  * preserves the length and order of the tlist, and
1469  * 3) set_plan_references() might delete the topmost plan node like an Append
1470  * or MergeAppend from the subplan tree and pull up the child plan node,
1471  * but in that case, the tlist for the child plan node exactly matches the
1472  * parent.
1473  */
1474 bool
1476 {
1477  int attrno;
1478  ListCell *lp,
1479  *lc;
1480 
1481  /* We might have detected this already; in which case reuse the result */
1482  if (plan->scanstatus == SUBQUERY_SCAN_TRIVIAL)
1483  return true;
1484  if (plan->scanstatus == SUBQUERY_SCAN_NONTRIVIAL)
1485  return false;
1487  /* Initially, mark the SubqueryScan as non-deletable from the plan tree */
1489 
1490  if (plan->scan.plan.qual != NIL)
1491  return false;
1492 
1493  if (list_length(plan->scan.plan.targetlist) !=
1494  list_length(plan->subplan->targetlist))
1495  return false; /* tlists not same length */
1496 
1497  attrno = 1;
1498  forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1499  {
1500  TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1501  TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1502 
1503  if (ptle->resjunk != ctle->resjunk)
1504  return false; /* tlist doesn't match junk status */
1505 
1506  /*
1507  * We accept either a Var referencing the corresponding element of the
1508  * subplan tlist, or a Const equaling the subplan element. See
1509  * generate_setop_tlist() for motivation.
1510  */
1511  if (ptle->expr && IsA(ptle->expr, Var))
1512  {
1513  Var *var = (Var *) ptle->expr;
1514 
1515  Assert(var->varno == plan->scan.scanrelid);
1516  Assert(var->varlevelsup == 0);
1517  if (var->varattno != attrno)
1518  return false; /* out of order */
1519  }
1520  else if (ptle->expr && IsA(ptle->expr, Const))
1521  {
1522  if (!equal(ptle->expr, ctle->expr))
1523  return false;
1524  }
1525  else
1526  return false;
1527 
1528  attrno++;
1529  }
1530 
1531  /* Re-mark the SubqueryScan as deletable from the plan tree */
1533 
1534  return true;
1535 }
1536 
1537 /*
1538  * clean_up_removed_plan_level
1539  * Do necessary cleanup when we strip out a SubqueryScan, Append, etc
1540  *
1541  * We are dropping the "parent" plan in favor of returning just its "child".
1542  * A few small tweaks are needed.
1543  */
1544 static Plan *
1546 {
1547  /* We have to be sure we don't lose any initplans */
1548  child->initPlan = list_concat(parent->initPlan,
1549  child->initPlan);
1550 
1551  /*
1552  * We also have to transfer the parent's column labeling info into the
1553  * child, else columns sent to client will be improperly labeled if this
1554  * is the topmost plan level. resjunk and so on may be important too.
1555  */
1556  apply_tlist_labeling(child->targetlist, parent->targetlist);
1557 
1558  return child;
1559 }
1560 
1561 /*
1562  * set_foreignscan_references
1563  * Do set_plan_references processing on a ForeignScan
1564  */
1565 static void
1567  ForeignScan *fscan,
1568  int rtoffset)
1569 {
1570  /* Adjust scanrelid if it's valid */
1571  if (fscan->scan.scanrelid > 0)
1572  fscan->scan.scanrelid += rtoffset;
1573 
1574  if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
1575  {
1576  /*
1577  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1578  * foreign scan tuple
1579  */
1581 
1582  fscan->scan.plan.targetlist = (List *)
1583  fix_upper_expr(root,
1584  (Node *) fscan->scan.plan.targetlist,
1585  itlist,
1586  INDEX_VAR,
1587  rtoffset,
1588  NRM_EQUAL,
1589  NUM_EXEC_TLIST((Plan *) fscan));
1590  fscan->scan.plan.qual = (List *)
1591  fix_upper_expr(root,
1592  (Node *) fscan->scan.plan.qual,
1593  itlist,
1594  INDEX_VAR,
1595  rtoffset,
1596  NRM_EQUAL,
1597  NUM_EXEC_QUAL((Plan *) fscan));
1598  fscan->fdw_exprs = (List *)
1599  fix_upper_expr(root,
1600  (Node *) fscan->fdw_exprs,
1601  itlist,
1602  INDEX_VAR,
1603  rtoffset,
1604  NRM_EQUAL,
1605  NUM_EXEC_QUAL((Plan *) fscan));
1606  fscan->fdw_recheck_quals = (List *)
1607  fix_upper_expr(root,
1608  (Node *) fscan->fdw_recheck_quals,
1609  itlist,
1610  INDEX_VAR,
1611  rtoffset,
1612  NRM_EQUAL,
1613  NUM_EXEC_QUAL((Plan *) fscan));
1614  pfree(itlist);
1615  /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1616  fscan->fdw_scan_tlist =
1617  fix_scan_list(root, fscan->fdw_scan_tlist,
1618  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
1619  }
1620  else
1621  {
1622  /*
1623  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
1624  * way
1625  */
1626  fscan->scan.plan.targetlist =
1627  fix_scan_list(root, fscan->scan.plan.targetlist,
1628  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
1629  fscan->scan.plan.qual =
1630  fix_scan_list(root, fscan->scan.plan.qual,
1631  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1632  fscan->fdw_exprs =
1633  fix_scan_list(root, fscan->fdw_exprs,
1634  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1635  fscan->fdw_recheck_quals =
1636  fix_scan_list(root, fscan->fdw_recheck_quals,
1637  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1638  }
1639 
1640  fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset);
1641  fscan->fs_base_relids = offset_relid_set(fscan->fs_base_relids, rtoffset);
1642 
1643  /* Adjust resultRelation if it's valid */
1644  if (fscan->resultRelation > 0)
1645  fscan->resultRelation += rtoffset;
1646 }
1647 
1648 /*
1649  * set_customscan_references
1650  * Do set_plan_references processing on a CustomScan
1651  */
1652 static void
1654  CustomScan *cscan,
1655  int rtoffset)
1656 {
1657  ListCell *lc;
1658 
1659  /* Adjust scanrelid if it's valid */
1660  if (cscan->scan.scanrelid > 0)
1661  cscan->scan.scanrelid += rtoffset;
1662 
1663  if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
1664  {
1665  /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1667 
1668  cscan->scan.plan.targetlist = (List *)
1669  fix_upper_expr(root,
1670  (Node *) cscan->scan.plan.targetlist,
1671  itlist,
1672  INDEX_VAR,
1673  rtoffset,
1674  NRM_EQUAL,
1675  NUM_EXEC_TLIST((Plan *) cscan));
1676  cscan->scan.plan.qual = (List *)
1677  fix_upper_expr(root,
1678  (Node *) cscan->scan.plan.qual,
1679  itlist,
1680  INDEX_VAR,
1681  rtoffset,
1682  NRM_EQUAL,
1683  NUM_EXEC_QUAL((Plan *) cscan));
1684  cscan->custom_exprs = (List *)
1685  fix_upper_expr(root,
1686  (Node *) cscan->custom_exprs,
1687  itlist,
1688  INDEX_VAR,
1689  rtoffset,
1690  NRM_EQUAL,
1691  NUM_EXEC_QUAL((Plan *) cscan));
1692  pfree(itlist);
1693  /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1694  cscan->custom_scan_tlist =
1695  fix_scan_list(root, cscan->custom_scan_tlist,
1696  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
1697  }
1698  else
1699  {
1700  /* Adjust tlist, qual, custom_exprs in the standard way */
1701  cscan->scan.plan.targetlist =
1702  fix_scan_list(root, cscan->scan.plan.targetlist,
1703  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
1704  cscan->scan.plan.qual =
1705  fix_scan_list(root, cscan->scan.plan.qual,
1706  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
1707  cscan->custom_exprs =
1708  fix_scan_list(root, cscan->custom_exprs,
1709  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
1710  }
1711 
1712  /* Adjust child plan-nodes recursively, if needed */
1713  foreach(lc, cscan->custom_plans)
1714  {
1715  lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
1716  }
1717 
1718  cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
1719 }
1720 
1721 /*
1722  * set_append_references
1723  * Do set_plan_references processing on an Append
1724  *
1725  * We try to strip out the Append entirely; if we can't, we have
1726  * to do the normal processing on it.
1727  */
1728 static Plan *
1730  Append *aplan,
1731  int rtoffset)
1732 {
1733  ListCell *l;
1734 
1735  /*
1736  * Append, like Sort et al, doesn't actually evaluate its targetlist or
1737  * check quals. If it's got exactly one child plan, then it's not doing
1738  * anything useful at all, and we can strip it out.
1739  */
1740  Assert(aplan->plan.qual == NIL);
1741 
1742  /* First, we gotta recurse on the children */
1743  foreach(l, aplan->appendplans)
1744  {
1745  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1746  }
1747 
1748  /*
1749  * See if it's safe to get rid of the Append entirely. For this to be
1750  * safe, there must be only one child plan and that child plan's parallel
1751  * awareness must match the Append's. The reason for the latter is that
1752  * if the Append is parallel aware and the child is not, then the calling
1753  * plan may execute the non-parallel aware child multiple times. (If you
1754  * change these rules, update create_append_path to match.)
1755  */
1756  if (list_length(aplan->appendplans) == 1)
1757  {
1758  Plan *p = (Plan *) linitial(aplan->appendplans);
1759 
1760  if (p->parallel_aware == aplan->plan.parallel_aware)
1761  return clean_up_removed_plan_level((Plan *) aplan, p);
1762  }
1763 
1764  /*
1765  * Otherwise, clean up the Append as needed. It's okay to do this after
1766  * recursing to the children, because set_dummy_tlist_references doesn't
1767  * look at those.
1768  */
1769  set_dummy_tlist_references((Plan *) aplan, rtoffset);
1770 
1771  aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
1772 
1773  /*
1774  * PartitionPruneInfos will be added to a list in PlannerGlobal, so update
1775  * the index.
1776  */
1777  if (aplan->part_prune_index >= 0)
1778  aplan->part_prune_index += list_length(root->glob->partPruneInfos);
1779 
1780  /* We don't need to recurse to lefttree or righttree ... */
1781  Assert(aplan->plan.lefttree == NULL);
1782  Assert(aplan->plan.righttree == NULL);
1783 
1784  return (Plan *) aplan;
1785 }
1786 
1787 /*
1788  * set_mergeappend_references
1789  * Do set_plan_references processing on a MergeAppend
1790  *
1791  * We try to strip out the MergeAppend entirely; if we can't, we have
1792  * to do the normal processing on it.
1793  */
1794 static Plan *
1796  MergeAppend *mplan,
1797  int rtoffset)
1798 {
1799  ListCell *l;
1800 
1801  /*
1802  * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
1803  * or check quals. If it's got exactly one child plan, then it's not
1804  * doing anything useful at all, and we can strip it out.
1805  */
1806  Assert(mplan->plan.qual == NIL);
1807 
1808  /* First, we gotta recurse on the children */
1809  foreach(l, mplan->mergeplans)
1810  {
1811  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1812  }
1813 
1814  /*
1815  * See if it's safe to get rid of the MergeAppend entirely. For this to
1816  * be safe, there must be only one child plan and that child plan's
1817  * parallel awareness must match the MergeAppend's. The reason for the
1818  * latter is that if the MergeAppend is parallel aware and the child is
1819  * not, then the calling plan may execute the non-parallel aware child
1820  * multiple times. (If you change these rules, update
1821  * create_merge_append_path to match.)
1822  */
1823  if (list_length(mplan->mergeplans) == 1)
1824  {
1825  Plan *p = (Plan *) linitial(mplan->mergeplans);
1826 
1827  if (p->parallel_aware == mplan->plan.parallel_aware)
1828  return clean_up_removed_plan_level((Plan *) mplan, p);
1829  }
1830 
1831  /*
1832  * Otherwise, clean up the MergeAppend as needed. It's okay to do this
1833  * after recursing to the children, because set_dummy_tlist_references
1834  * doesn't look at those.
1835  */
1836  set_dummy_tlist_references((Plan *) mplan, rtoffset);
1837 
1838  mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
1839 
1840  /*
1841  * PartitionPruneInfos will be added to a list in PlannerGlobal, so update
1842  * the index.
1843  */
1844  if (mplan->part_prune_index >= 0)
1845  mplan->part_prune_index += list_length(root->glob->partPruneInfos);
1846 
1847  /* We don't need to recurse to lefttree or righttree ... */
1848  Assert(mplan->plan.lefttree == NULL);
1849  Assert(mplan->plan.righttree == NULL);
1850 
1851  return (Plan *) mplan;
1852 }
1853 
1854 /*
1855  * set_hash_references
1856  * Do set_plan_references processing on a Hash node
1857  */
1858 static void
1859 set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
1860 {
1861  Hash *hplan = (Hash *) plan;
1862  Plan *outer_plan = plan->lefttree;
1863  indexed_tlist *outer_itlist;
1864 
1865  /*
1866  * Hash's hashkeys are used when feeding tuples into the hashtable,
1867  * therefore have them reference Hash's outer plan (which itself is the
1868  * inner plan of the HashJoin).
1869  */
1870  outer_itlist = build_tlist_index(outer_plan->targetlist);
1871  hplan->hashkeys = (List *)
1872  fix_upper_expr(root,
1873  (Node *) hplan->hashkeys,
1874  outer_itlist,
1875  OUTER_VAR,
1876  rtoffset,
1877  NRM_EQUAL,
1878  NUM_EXEC_QUAL(plan));
1879 
1880  /* Hash doesn't project */
1881  set_dummy_tlist_references(plan, rtoffset);
1882 
1883  /* Hash nodes don't have their own quals */
1884  Assert(plan->qual == NIL);
1885 }
1886 
1887 /*
1888  * offset_relid_set
1889  * Apply rtoffset to the members of a Relids set.
1890  */
1891 static Relids
1892 offset_relid_set(Relids relids, int rtoffset)
1893 {
1894  Relids result = NULL;
1895  int rtindex;
1896 
1897  /* If there's no offset to apply, we needn't recompute the value */
1898  if (rtoffset == 0)
1899  return relids;
1900  rtindex = -1;
1901  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
1902  result = bms_add_member(result, rtindex + rtoffset);
1903  return result;
1904 }
1905 
1906 /*
1907  * copyVar
1908  * Copy a Var node.
1909  *
1910  * fix_scan_expr and friends do this enough times that it's worth having
1911  * a bespoke routine instead of using the generic copyObject() function.
1912  */
1913 static inline Var *
1915 {
1916  Var *newvar = (Var *) palloc(sizeof(Var));
1917 
1918  *newvar = *var;
1919  return newvar;
1920 }
1921 
1922 /*
1923  * fix_expr_common
1924  * Do generic set_plan_references processing on an expression node
1925  *
1926  * This is code that is common to all variants of expression-fixing.
1927  * We must look up operator opcode info for OpExpr and related nodes,
1928  * add OIDs from regclass Const nodes into root->glob->relationOids, and
1929  * add PlanInvalItems for user-defined functions into root->glob->invalItems.
1930  * We also fill in column index lists for GROUPING() expressions.
1931  *
1932  * We assume it's okay to update opcode info in-place. So this could possibly
1933  * scribble on the planner's input data structures, but it's OK.
1934  */
1935 static void
1937 {
1938  /* We assume callers won't call us on a NULL pointer */
1939  if (IsA(node, Aggref))
1940  {
1942  ((Aggref *) node)->aggfnoid);
1943  }
1944  else if (IsA(node, WindowFunc))
1945  {
1947  ((WindowFunc *) node)->winfnoid);
1948  }
1949  else if (IsA(node, FuncExpr))
1950  {
1952  ((FuncExpr *) node)->funcid);
1953  }
1954  else if (IsA(node, OpExpr))
1955  {
1956  set_opfuncid((OpExpr *) node);
1958  ((OpExpr *) node)->opfuncid);
1959  }
1960  else if (IsA(node, DistinctExpr))
1961  {
1962  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1964  ((DistinctExpr *) node)->opfuncid);
1965  }
1966  else if (IsA(node, NullIfExpr))
1967  {
1968  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1970  ((NullIfExpr *) node)->opfuncid);
1971  }
1972  else if (IsA(node, ScalarArrayOpExpr))
1973  {
1974  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
1975 
1976  set_sa_opfuncid(saop);
1977  record_plan_function_dependency(root, saop->opfuncid);
1978 
1979  if (!OidIsValid(saop->hashfuncid))
1980  record_plan_function_dependency(root, saop->hashfuncid);
1981 
1982  if (!OidIsValid(saop->negfuncid))
1983  record_plan_function_dependency(root, saop->negfuncid);
1984  }
1985  else if (IsA(node, Const))
1986  {
1987  Const *con = (Const *) node;
1988 
1989  /* Check for regclass reference */
1990  if (ISREGCLASSCONST(con))
1991  root->glob->relationOids =
1992  lappend_oid(root->glob->relationOids,
1993  DatumGetObjectId(con->constvalue));
1994  }
1995  else if (IsA(node, GroupingFunc))
1996  {
1997  GroupingFunc *g = (GroupingFunc *) node;
1998  AttrNumber *grouping_map = root->grouping_map;
1999 
2000  /* If there are no grouping sets, we don't need this. */
2001 
2002  Assert(grouping_map || g->cols == NIL);
2003 
2004  if (grouping_map)
2005  {
2006  ListCell *lc;
2007  List *cols = NIL;
2008 
2009  foreach(lc, g->refs)
2010  {
2011  cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
2012  }
2013 
2014  Assert(!g->cols || equal(cols, g->cols));
2015 
2016  if (!g->cols)
2017  g->cols = cols;
2018  }
2019  }
2020 }
2021 
2022 /*
2023  * fix_param_node
2024  * Do set_plan_references processing on a Param
2025  *
2026  * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from
2027  * root->multiexpr_params; otherwise no change is needed.
2028  * Just for paranoia's sake, we make a copy of the node in either case.
2029  */
2030 static Node *
2032 {
2033  if (p->paramkind == PARAM_MULTIEXPR)
2034  {
2035  int subqueryid = p->paramid >> 16;
2036  int colno = p->paramid & 0xFFFF;
2037  List *params;
2038 
2039  if (subqueryid <= 0 ||
2040  subqueryid > list_length(root->multiexpr_params))
2041  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
2042  params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
2043  if (colno <= 0 || colno > list_length(params))
2044  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
2045  return copyObject(list_nth(params, colno - 1));
2046  }
2047  return (Node *) copyObject(p);
2048 }
2049 
2050 /*
2051  * fix_alternative_subplan
2052  * Do set_plan_references processing on an AlternativeSubPlan
2053  *
2054  * Choose one of the alternative implementations and return just that one,
2055  * discarding the rest of the AlternativeSubPlan structure.
2056  * Note: caller must still recurse into the result!
2057  *
2058  * We don't make any attempt to fix up cost estimates in the parent plan
2059  * node or higher-level nodes.
2060  */
2061 static Node *
2063  double num_exec)
2064 {
2065  SubPlan *bestplan = NULL;
2066  Cost bestcost = 0;
2067  ListCell *lc;
2068 
2069  /*
2070  * Compute the estimated cost of each subplan assuming num_exec
2071  * executions, and keep the cheapest one. In event of exact equality of
2072  * estimates, we prefer the later plan; this is a bit arbitrary, but in
2073  * current usage it biases us to break ties against fast-start subplans.
2074  */
2075  Assert(asplan->subplans != NIL);
2076 
2077  foreach(lc, asplan->subplans)
2078  {
2079  SubPlan *curplan = (SubPlan *) lfirst(lc);
2080  Cost curcost;
2081 
2082  curcost = curplan->startup_cost + num_exec * curplan->per_call_cost;
2083  if (bestplan == NULL || curcost <= bestcost)
2084  {
2085  bestplan = curplan;
2086  bestcost = curcost;
2087  }
2088 
2089  /* Also mark all subplans that are in AlternativeSubPlans */
2090  root->isAltSubplan[curplan->plan_id - 1] = true;
2091  }
2092 
2093  /* Mark the subplan we selected */
2094  root->isUsedSubplan[bestplan->plan_id - 1] = true;
2095 
2096  return (Node *) bestplan;
2097 }
2098 
2099 /*
2100  * fix_scan_expr
2101  * Do set_plan_references processing on a scan-level expression
2102  *
2103  * This consists of incrementing all Vars' varnos by rtoffset,
2104  * replacing PARAM_MULTIEXPR Params, expanding PlaceHolderVars,
2105  * replacing Aggref nodes that should be replaced by initplan output Params,
2106  * choosing the best implementation for AlternativeSubPlans,
2107  * looking up operator opcode info for OpExpr and related nodes,
2108  * and adding OIDs from regclass Const nodes into root->glob->relationOids.
2109  *
2110  * 'node': the expression to be modified
2111  * 'rtoffset': how much to increment varnos by
2112  * 'num_exec': estimated number of executions of expression
2113  *
2114  * The expression tree is either copied-and-modified, or modified in-place
2115  * if that seems safe.
2116  */
2117 static Node *
2118 fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
2119 {
2120  fix_scan_expr_context context;
2121 
2122  context.root = root;
2123  context.rtoffset = rtoffset;
2124  context.num_exec = num_exec;
2125 
2126  if (rtoffset != 0 ||
2127  root->multiexpr_params != NIL ||
2128  root->glob->lastPHId != 0 ||
2129  root->minmax_aggs != NIL ||
2130  root->hasAlternativeSubPlans)
2131  {
2132  return fix_scan_expr_mutator(node, &context);
2133  }
2134  else
2135  {
2136  /*
2137  * If rtoffset == 0, we don't need to change any Vars, and if there
2138  * are no MULTIEXPR subqueries then we don't need to replace
2139  * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
2140  * we won't need to remove them, and if there are no minmax Aggrefs we
2141  * won't need to replace them, and if there are no AlternativeSubPlans
2142  * we won't need to remove them. Then it's OK to just scribble on the
2143  * input node tree instead of copying (since the only change, filling
2144  * in any unset opfuncid fields, is harmless). This saves just enough
2145  * cycles to be noticeable on trivial queries.
2146  */
2147  (void) fix_scan_expr_walker(node, &context);
2148  return node;
2149  }
2150 }
2151 
2152 static Node *
2154 {
2155  if (node == NULL)
2156  return NULL;
2157  if (IsA(node, Var))
2158  {
2159  Var *var = copyVar((Var *) node);
2160 
2161  Assert(var->varlevelsup == 0);
2162 
2163  /*
2164  * We should not see Vars marked INNER_VAR, OUTER_VAR, or ROWID_VAR.
2165  * But an indexqual expression could contain INDEX_VAR Vars.
2166  */
2167  Assert(var->varno != INNER_VAR);
2168  Assert(var->varno != OUTER_VAR);
2169  Assert(var->varno != ROWID_VAR);
2170  if (!IS_SPECIAL_VARNO(var->varno))
2171  var->varno += context->rtoffset;
2172  if (var->varnosyn > 0)
2173  var->varnosyn += context->rtoffset;
2174  return (Node *) var;
2175  }
2176  if (IsA(node, Param))
2177  return fix_param_node(context->root, (Param *) node);
2178  if (IsA(node, Aggref))
2179  {
2180  Aggref *aggref = (Aggref *) node;
2181 
2182  /* See if the Aggref should be replaced by a Param */
2183  if (context->root->minmax_aggs != NIL &&
2184  list_length(aggref->args) == 1)
2185  {
2186  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
2187  ListCell *lc;
2188 
2189  foreach(lc, context->root->minmax_aggs)
2190  {
2191  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
2192 
2193  if (mminfo->aggfnoid == aggref->aggfnoid &&
2194  equal(mminfo->target, curTarget->expr))
2195  return (Node *) copyObject(mminfo->param);
2196  }
2197  }
2198  /* If no match, just fall through to process it normally */
2199  }
2200  if (IsA(node, CurrentOfExpr))
2201  {
2202  CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
2203 
2204  Assert(!IS_SPECIAL_VARNO(cexpr->cvarno));
2205  cexpr->cvarno += context->rtoffset;
2206  return (Node *) cexpr;
2207  }
2208  if (IsA(node, PlaceHolderVar))
2209  {
2210  /* At scan level, we should always just evaluate the contained expr */
2211  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2212 
2213  /* XXX can we assert something about phnullingrels? */
2214  return fix_scan_expr_mutator((Node *) phv->phexpr, context);
2215  }
2216  if (IsA(node, AlternativeSubPlan))
2218  (AlternativeSubPlan *) node,
2219  context->num_exec),
2220  context);
2221  fix_expr_common(context->root, node);
2223  (void *) context);
2224 }
2225 
2226 static bool
2228 {
2229  if (node == NULL)
2230  return false;
2231  Assert(!(IsA(node, Var) && ((Var *) node)->varno == ROWID_VAR));
2232  Assert(!IsA(node, PlaceHolderVar));
2233  Assert(!IsA(node, AlternativeSubPlan));
2234  fix_expr_common(context->root, node);
2236  (void *) context);
2237 }
2238 
2239 /*
2240  * set_join_references
2241  * Modify the target list and quals of a join node to reference its
2242  * subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting
2243  * attno values to the result domain number of either the corresponding
2244  * outer or inner join tuple item. Also perform opcode lookup for these
2245  * expressions, and add regclass OIDs to root->glob->relationOids.
2246  */
2247 static void
2248 set_join_references(PlannerInfo *root, Join *join, int rtoffset)
2249 {
2250  Plan *outer_plan = join->plan.lefttree;
2251  Plan *inner_plan = join->plan.righttree;
2252  indexed_tlist *outer_itlist;
2253  indexed_tlist *inner_itlist;
2254 
2255  outer_itlist = build_tlist_index(outer_plan->targetlist);
2256  inner_itlist = build_tlist_index(inner_plan->targetlist);
2257 
2258  /*
2259  * First process the joinquals (including merge or hash clauses). These
2260  * are logically below the join so they can always use all values
2261  * available from the input tlists. It's okay to also handle
2262  * NestLoopParams now, because those couldn't refer to nullable
2263  * subexpressions.
2264  */
2265  join->joinqual = fix_join_expr(root,
2266  join->joinqual,
2267  outer_itlist,
2268  inner_itlist,
2269  (Index) 0,
2270  rtoffset,
2271  NRM_EQUAL,
2272  NUM_EXEC_QUAL((Plan *) join));
2273 
2274  /* Now do join-type-specific stuff */
2275  if (IsA(join, NestLoop))
2276  {
2277  NestLoop *nl = (NestLoop *) join;
2278  ListCell *lc;
2279 
2280  foreach(lc, nl->nestParams)
2281  {
2282  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
2283 
2284  /*
2285  * Because we don't reparameterize parameterized paths to match
2286  * the outer-join level at which they are used, Vars seen in the
2287  * NestLoopParam expression may have nullingrels that are just a
2288  * subset of those in the Vars actually available from the outer
2289  * side. Not checking this exactly is a bit grotty, but the work
2290  * needed to make things match up perfectly seems well out of
2291  * proportion to the value.
2292  */
2293  nlp->paramval = (Var *) fix_upper_expr(root,
2294  (Node *) nlp->paramval,
2295  outer_itlist,
2296  OUTER_VAR,
2297  rtoffset,
2298  NRM_SUBSET,
2299  NUM_EXEC_TLIST(outer_plan));
2300  /* Check we replaced any PlaceHolderVar with simple Var */
2301  if (!(IsA(nlp->paramval, Var) &&
2302  nlp->paramval->varno == OUTER_VAR))
2303  elog(ERROR, "NestLoopParam was not reduced to a simple Var");
2304  }
2305  }
2306  else if (IsA(join, MergeJoin))
2307  {
2308  MergeJoin *mj = (MergeJoin *) join;
2309 
2310  mj->mergeclauses = fix_join_expr(root,
2311  mj->mergeclauses,
2312  outer_itlist,
2313  inner_itlist,
2314  (Index) 0,
2315  rtoffset,
2316  NRM_EQUAL,
2317  NUM_EXEC_QUAL((Plan *) join));
2318  }
2319  else if (IsA(join, HashJoin))
2320  {
2321  HashJoin *hj = (HashJoin *) join;
2322 
2323  hj->hashclauses = fix_join_expr(root,
2324  hj->hashclauses,
2325  outer_itlist,
2326  inner_itlist,
2327  (Index) 0,
2328  rtoffset,
2329  NRM_EQUAL,
2330  NUM_EXEC_QUAL((Plan *) join));
2331 
2332  /*
2333  * HashJoin's hashkeys are used to look for matching tuples from its
2334  * outer plan (not the Hash node!) in the hashtable.
2335  */
2336  hj->hashkeys = (List *) fix_upper_expr(root,
2337  (Node *) hj->hashkeys,
2338  outer_itlist,
2339  OUTER_VAR,
2340  rtoffset,
2341  NRM_EQUAL,
2342  NUM_EXEC_QUAL((Plan *) join));
2343  }
2344 
2345  /*
2346  * Now we need to fix up the targetlist and qpqual, which are logically
2347  * above the join. This means that, if it's not an inner join, any Vars
2348  * and PHVs appearing here should have nullingrels that include the
2349  * effects of the outer join, ie they will have nullingrels equal to the
2350  * input Vars' nullingrels plus the bit added by the outer join. We don't
2351  * currently have enough info available here to identify what that should
2352  * be, so we just tell fix_join_expr to accept superset nullingrels
2353  * matches instead of exact ones.
2354  */
2355  join->plan.targetlist = fix_join_expr(root,
2356  join->plan.targetlist,
2357  outer_itlist,
2358  inner_itlist,
2359  (Index) 0,
2360  rtoffset,
2361  (join->jointype == JOIN_INNER ? NRM_EQUAL : NRM_SUPERSET),
2362  NUM_EXEC_TLIST((Plan *) join));
2363  join->plan.qual = fix_join_expr(root,
2364  join->plan.qual,
2365  outer_itlist,
2366  inner_itlist,
2367  (Index) 0,
2368  rtoffset,
2369  (join->jointype == JOIN_INNER ? NRM_EQUAL : NRM_SUPERSET),
2370  NUM_EXEC_QUAL((Plan *) join));
2371 
2372  pfree(outer_itlist);
2373  pfree(inner_itlist);
2374 }
2375 
2376 /*
2377  * set_upper_references
2378  * Update the targetlist and quals of an upper-level plan node
2379  * to refer to the tuples returned by its lefttree subplan.
2380  * Also perform opcode lookup for these expressions, and
2381  * add regclass OIDs to root->glob->relationOids.
2382  *
2383  * This is used for single-input plan types like Agg, Group, Result.
2384  *
2385  * In most cases, we have to match up individual Vars in the tlist and
2386  * qual expressions with elements of the subplan's tlist (which was
2387  * generated by flattening these selfsame expressions, so it should have all
2388  * the required variables). There is an important exception, however:
2389  * depending on where we are in the plan tree, sort/group columns may have
2390  * been pushed into the subplan tlist unflattened. If these values are also
2391  * needed in the output then we want to reference the subplan tlist element
2392  * rather than recomputing the expression.
2393  */
2394 static void
2395 set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
2396 {
2397  Plan *subplan = plan->lefttree;
2398  indexed_tlist *subplan_itlist;
2399  List *output_targetlist;
2400  ListCell *l;
2401 
2402  subplan_itlist = build_tlist_index(subplan->targetlist);
2403 
2404  output_targetlist = NIL;
2405  foreach(l, plan->targetlist)
2406  {
2407  TargetEntry *tle = (TargetEntry *) lfirst(l);
2408  Node *newexpr;
2409 
2410  /* If it's a sort/group item, first try to match by sortref */
2411  if (tle->ressortgroupref != 0)
2412  {
2413  newexpr = (Node *)
2415  tle->ressortgroupref,
2416  subplan_itlist,
2417  OUTER_VAR);
2418  if (!newexpr)
2419  newexpr = fix_upper_expr(root,
2420  (Node *) tle->expr,
2421  subplan_itlist,
2422  OUTER_VAR,
2423  rtoffset,
2424  NRM_EQUAL,
2425  NUM_EXEC_TLIST(plan));
2426  }
2427  else
2428  newexpr = fix_upper_expr(root,
2429  (Node *) tle->expr,
2430  subplan_itlist,
2431  OUTER_VAR,
2432  rtoffset,
2433  NRM_EQUAL,
2434  NUM_EXEC_TLIST(plan));
2435  tle = flatCopyTargetEntry(tle);
2436  tle->expr = (Expr *) newexpr;
2437  output_targetlist = lappend(output_targetlist, tle);
2438  }
2439  plan->targetlist = output_targetlist;
2440 
2441  plan->qual = (List *)
2442  fix_upper_expr(root,
2443  (Node *) plan->qual,
2444  subplan_itlist,
2445  OUTER_VAR,
2446  rtoffset,
2447  NRM_EQUAL,
2448  NUM_EXEC_QUAL(plan));
2449 
2450  pfree(subplan_itlist);
2451 }
2452 
2453 /*
2454  * set_param_references
2455  * Initialize the initParam list in Gather or Gather merge node such that
2456  * it contains reference of all the params that needs to be evaluated
2457  * before execution of the node. It contains the initplan params that are
2458  * being passed to the plan nodes below it.
2459  */
2460 static void
2462 {
2463  Assert(IsA(plan, Gather) || IsA(plan, GatherMerge));
2464 
2465  if (plan->lefttree->extParam)
2466  {
2467  PlannerInfo *proot;
2468  Bitmapset *initSetParam = NULL;
2469  ListCell *l;
2470 
2471  for (proot = root; proot != NULL; proot = proot->parent_root)
2472  {
2473  foreach(l, proot->init_plans)
2474  {
2475  SubPlan *initsubplan = (SubPlan *) lfirst(l);
2476  ListCell *l2;
2477 
2478  foreach(l2, initsubplan->setParam)
2479  {
2480  initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
2481  }
2482  }
2483  }
2484 
2485  /*
2486  * Remember the list of all external initplan params that are used by
2487  * the children of Gather or Gather merge node.
2488  */
2489  if (IsA(plan, Gather))
2490  ((Gather *) plan)->initParam =
2491  bms_intersect(plan->lefttree->extParam, initSetParam);
2492  else
2493  ((GatherMerge *) plan)->initParam =
2494  bms_intersect(plan->lefttree->extParam, initSetParam);
2495  }
2496 }
2497 
2498 /*
2499  * Recursively scan an expression tree and convert Aggrefs to the proper
2500  * intermediate form for combining aggregates. This means (1) replacing each
2501  * one's argument list with a single argument that is the original Aggref
2502  * modified to show partial aggregation and (2) changing the upper Aggref to
2503  * show combining aggregation.
2504  *
2505  * After this step, set_upper_references will replace the partial Aggrefs
2506  * with Vars referencing the lower Agg plan node's outputs, so that the final
2507  * form seen by the executor is a combining Aggref with a Var as input.
2508  *
2509  * It's rather messy to postpone this step until setrefs.c; ideally it'd be
2510  * done in createplan.c. The difficulty is that once we modify the Aggref
2511  * expressions, they will no longer be equal() to their original form and
2512  * so cross-plan-node-level matches will fail. So this has to happen after
2513  * the plan node above the Agg has resolved its subplan references.
2514  */
2515 static Node *
2516 convert_combining_aggrefs(Node *node, void *context)
2517 {
2518  if (node == NULL)
2519  return NULL;
2520  if (IsA(node, Aggref))
2521  {
2522  Aggref *orig_agg = (Aggref *) node;
2523  Aggref *child_agg;
2524  Aggref *parent_agg;
2525 
2526  /* Assert we've not chosen to partial-ize any unsupported cases */
2527  Assert(orig_agg->aggorder == NIL);
2528  Assert(orig_agg->aggdistinct == NIL);
2529 
2530  /*
2531  * Since aggregate calls can't be nested, we needn't recurse into the
2532  * arguments. But for safety, flat-copy the Aggref node itself rather
2533  * than modifying it in-place.
2534  */
2535  child_agg = makeNode(Aggref);
2536  memcpy(child_agg, orig_agg, sizeof(Aggref));
2537 
2538  /*
2539  * For the parent Aggref, we want to copy all the fields of the
2540  * original aggregate *except* the args list, which we'll replace
2541  * below, and the aggfilter expression, which should be applied only
2542  * by the child not the parent. Rather than explicitly knowing about
2543  * all the other fields here, we can momentarily modify child_agg to
2544  * provide a suitable source for copyObject.
2545  */
2546  child_agg->args = NIL;
2547  child_agg->aggfilter = NULL;
2548  parent_agg = copyObject(child_agg);
2549  child_agg->args = orig_agg->args;
2550  child_agg->aggfilter = orig_agg->aggfilter;
2551 
2552  /*
2553  * Now, set up child_agg to represent the first phase of partial
2554  * aggregation. For now, assume serialization is required.
2555  */
2557 
2558  /*
2559  * And set up parent_agg to represent the second phase.
2560  */
2561  parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
2562  1, NULL, false));
2564 
2565  return (Node *) parent_agg;
2566  }
2568  (void *) context);
2569 }
2570 
2571 /*
2572  * set_dummy_tlist_references
2573  * Replace the targetlist of an upper-level plan node with a simple
2574  * list of OUTER_VAR references to its child.
2575  *
2576  * This is used for plan types like Sort and Append that don't evaluate
2577  * their targetlists. Although the executor doesn't care at all what's in
2578  * the tlist, EXPLAIN needs it to be realistic.
2579  *
2580  * Note: we could almost use set_upper_references() here, but it fails for
2581  * Append for lack of a lefttree subplan. Single-purpose code is faster
2582  * anyway.
2583  */
2584 static void
2585 set_dummy_tlist_references(Plan *plan, int rtoffset)
2586 {
2587  List *output_targetlist;
2588  ListCell *l;
2589 
2590  output_targetlist = NIL;
2591  foreach(l, plan->targetlist)
2592  {
2593  TargetEntry *tle = (TargetEntry *) lfirst(l);
2594  Var *oldvar = (Var *) tle->expr;
2595  Var *newvar;
2596 
2597  /*
2598  * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
2599  * as Consts, not Vars referencing Consts. Here, there's no speed
2600  * advantage to be had, but it makes EXPLAIN output look cleaner, and
2601  * again it avoids confusing the executor.
2602  */
2603  if (IsA(oldvar, Const))
2604  {
2605  /* just reuse the existing TLE node */
2606  output_targetlist = lappend(output_targetlist, tle);
2607  continue;
2608  }
2609 
2610  newvar = makeVar(OUTER_VAR,
2611  tle->resno,
2612  exprType((Node *) oldvar),
2613  exprTypmod((Node *) oldvar),
2614  exprCollation((Node *) oldvar),
2615  0);
2616  if (IsA(oldvar, Var) &&
2617  oldvar->varnosyn > 0)
2618  {
2619  newvar->varnosyn = oldvar->varnosyn + rtoffset;
2620  newvar->varattnosyn = oldvar->varattnosyn;
2621  }
2622  else
2623  {
2624  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2625  newvar->varattnosyn = 0;
2626  }
2627 
2628  tle = flatCopyTargetEntry(tle);
2629  tle->expr = (Expr *) newvar;
2630  output_targetlist = lappend(output_targetlist, tle);
2631  }
2632  plan->targetlist = output_targetlist;
2633 
2634  /* We don't touch plan->qual here */
2635 }
2636 
2637 
2638 /*
2639  * build_tlist_index --- build an index data structure for a child tlist
2640  *
2641  * In most cases, subplan tlists will be "flat" tlists with only Vars,
2642  * so we try to optimize that case by extracting information about Vars
2643  * in advance. Matching a parent tlist to a child is still an O(N^2)
2644  * operation, but at least with a much smaller constant factor than plain
2645  * tlist_member() searches.
2646  *
2647  * The result of this function is an indexed_tlist struct to pass to
2648  * search_indexed_tlist_for_var() and siblings.
2649  * When done, the indexed_tlist may be freed with a single pfree().
2650  */
2651 static indexed_tlist *
2653 {
2654  indexed_tlist *itlist;
2655  tlist_vinfo *vinfo;
2656  ListCell *l;
2657 
2658  /* Create data structure with enough slots for all tlist entries */
2659  itlist = (indexed_tlist *)
2660  palloc(offsetof(indexed_tlist, vars) +
2661  list_length(tlist) * sizeof(tlist_vinfo));
2662 
2663  itlist->tlist = tlist;
2664  itlist->has_ph_vars = false;
2665  itlist->has_non_vars = false;
2666 
2667  /* Find the Vars and fill in the index array */
2668  vinfo = itlist->vars;
2669  foreach(l, tlist)
2670  {
2671  TargetEntry *tle = (TargetEntry *) lfirst(l);
2672 
2673  if (tle->expr && IsA(tle->expr, Var))
2674  {
2675  Var *var = (Var *) tle->expr;
2676 
2677  vinfo->varno = var->varno;
2678  vinfo->varattno = var->varattno;
2679  vinfo->resno = tle->resno;
2680 #ifdef USE_ASSERT_CHECKING
2681  vinfo->varnullingrels = var->varnullingrels;
2682 #endif
2683  vinfo++;
2684  }
2685  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2686  itlist->has_ph_vars = true;
2687  else
2688  itlist->has_non_vars = true;
2689  }
2690 
2691  itlist->num_vars = (vinfo - itlist->vars);
2692 
2693  return itlist;
2694 }
2695 
2696 /*
2697  * build_tlist_index_other_vars --- build a restricted tlist index
2698  *
2699  * This is like build_tlist_index, but we only index tlist entries that
2700  * are Vars belonging to some rel other than the one specified. We will set
2701  * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
2702  * (so nothing other than Vars and PlaceHolderVars can be matched).
2703  */
2704 static indexed_tlist *
2705 build_tlist_index_other_vars(List *tlist, int ignore_rel)
2706 {
2707  indexed_tlist *itlist;
2708  tlist_vinfo *vinfo;
2709  ListCell *l;
2710 
2711  /* Create data structure with enough slots for all tlist entries */
2712  itlist = (indexed_tlist *)
2713  palloc(offsetof(indexed_tlist, vars) +
2714  list_length(tlist) * sizeof(tlist_vinfo));
2715 
2716  itlist->tlist = tlist;
2717  itlist->has_ph_vars = false;
2718  itlist->has_non_vars = false;
2719 
2720  /* Find the desired Vars and fill in the index array */
2721  vinfo = itlist->vars;
2722  foreach(l, tlist)
2723  {
2724  TargetEntry *tle = (TargetEntry *) lfirst(l);
2725 
2726  if (tle->expr && IsA(tle->expr, Var))
2727  {
2728  Var *var = (Var *) tle->expr;
2729 
2730  if (var->varno != ignore_rel)
2731  {
2732  vinfo->varno = var->varno;
2733  vinfo->varattno = var->varattno;
2734  vinfo->resno = tle->resno;
2735 #ifdef USE_ASSERT_CHECKING
2736  vinfo->varnullingrels = var->varnullingrels;
2737 #endif
2738  vinfo++;
2739  }
2740  }
2741  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2742  itlist->has_ph_vars = true;
2743  }
2744 
2745  itlist->num_vars = (vinfo - itlist->vars);
2746 
2747  return itlist;
2748 }
2749 
2750 /*
2751  * search_indexed_tlist_for_var --- find a Var in an indexed tlist
2752  *
2753  * If a match is found, return a copy of the given Var with suitably
2754  * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
2755  * Also ensure that varnosyn is incremented by rtoffset.
2756  * If no match, return NULL.
2757  *
2758  * In debugging builds, we cross-check the varnullingrels of the subplan
2759  * output Var based on nrm_match. Most call sites should pass NRM_EQUAL
2760  * indicating we expect an exact match. However, there are places where
2761  * we haven't cleaned things up completely, and we have to settle for
2762  * allowing subset or superset matches.
2763  */
2764 static Var *
2766  int newvarno, int rtoffset,
2767  NullingRelsMatch nrm_match)
2768 {
2769  int varno = var->varno;
2770  AttrNumber varattno = var->varattno;
2771  tlist_vinfo *vinfo;
2772  int i;
2773 
2774  vinfo = itlist->vars;
2775  i = itlist->num_vars;
2776  while (i-- > 0)
2777  {
2778  if (vinfo->varno == varno && vinfo->varattno == varattno)
2779  {
2780  /* Found a match */
2781  Var *newvar = copyVar(var);
2782 
2783  /*
2784  * Assert that we kept all the nullingrels machinations straight.
2785  *
2786  * XXX we skip the check for system columns and whole-row Vars.
2787  * That's because such Vars might be row identity Vars, which are
2788  * generated without any varnullingrels. It'd be hard to do
2789  * otherwise, since they're normally made very early in planning,
2790  * when we haven't looked at the jointree yet and don't know which
2791  * joins might null such Vars. Doesn't seem worth the expense to
2792  * make them fully valid. (While it's slightly annoying that we
2793  * thereby lose checking for user-written references to such
2794  * columns, it seems unlikely that a bug in nullingrels logic
2795  * would affect only system columns.)
2796  */
2797  Assert(varattno <= 0 ||
2798  (nrm_match == NRM_SUBSET ?
2799  bms_is_subset(var->varnullingrels, vinfo->varnullingrels) :
2800  nrm_match == NRM_SUPERSET ?
2801  bms_is_subset(vinfo->varnullingrels, var->varnullingrels) :
2802  bms_equal(vinfo->varnullingrels, var->varnullingrels)));
2803 
2804  newvar->varno = newvarno;
2805  newvar->varattno = vinfo->resno;
2806  if (newvar->varnosyn > 0)
2807  newvar->varnosyn += rtoffset;
2808  return newvar;
2809  }
2810  vinfo++;
2811  }
2812  return NULL; /* no match */
2813 }
2814 
2815 /*
2816  * search_indexed_tlist_for_phv --- find a PlaceHolderVar in an indexed tlist
2817  *
2818  * If a match is found, return a Var constructed to reference the tlist item.
2819  * If no match, return NULL.
2820  *
2821  * Cross-check phnullingrels as in search_indexed_tlist_for_var.
2822  *
2823  * NOTE: it is a waste of time to call this unless itlist->has_ph_vars.
2824  */
2825 static Var *
2827  indexed_tlist *itlist, int newvarno,
2828  NullingRelsMatch nrm_match)
2829 {
2830  ListCell *lc;
2831 
2832  foreach(lc, itlist->tlist)
2833  {
2834  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2835 
2836  if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2837  {
2838  PlaceHolderVar *subphv = (PlaceHolderVar *) tle->expr;
2839  Var *newvar;
2840 
2841  /*
2842  * Analogously to search_indexed_tlist_for_var, we match on phid
2843  * only. We don't use equal(), partially for speed but mostly
2844  * because phnullingrels might not be exactly equal.
2845  */
2846  if (phv->phid != subphv->phid)
2847  continue;
2848 
2849  /* Assert that we kept all the nullingrels machinations straight */
2850  Assert(nrm_match == NRM_SUBSET ?
2851  bms_is_subset(phv->phnullingrels, subphv->phnullingrels) :
2852  nrm_match == NRM_SUPERSET ?
2853  bms_is_subset(subphv->phnullingrels, phv->phnullingrels) :
2854  bms_equal(subphv->phnullingrels, phv->phnullingrels));
2855 
2856  /* Found a matching subplan output expression */
2857  newvar = makeVarFromTargetEntry(newvarno, tle);
2858  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2859  newvar->varattnosyn = 0;
2860  return newvar;
2861  }
2862  }
2863  return NULL; /* no match */
2864 }
2865 
2866 /*
2867  * search_indexed_tlist_for_non_var --- find a non-Var/PHV in an indexed tlist
2868  *
2869  * If a match is found, return a Var constructed to reference the tlist item.
2870  * If no match, return NULL.
2871  *
2872  * NOTE: it is a waste of time to call this unless itlist->has_non_vars.
2873  */
2874 static Var *
2876  indexed_tlist *itlist, int newvarno)
2877 {
2878  TargetEntry *tle;
2879 
2880  /*
2881  * If it's a simple Const, replacing it with a Var is silly, even if there
2882  * happens to be an identical Const below; a Var is more expensive to
2883  * execute than a Const. What's more, replacing it could confuse some
2884  * places in the executor that expect to see simple Consts for, eg,
2885  * dropped columns.
2886  */
2887  if (IsA(node, Const))
2888  return NULL;
2889 
2890  tle = tlist_member(node, itlist->tlist);
2891  if (tle)
2892  {
2893  /* Found a matching subplan output expression */
2894  Var *newvar;
2895 
2896  newvar = makeVarFromTargetEntry(newvarno, tle);
2897  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2898  newvar->varattnosyn = 0;
2899  return newvar;
2900  }
2901  return NULL; /* no match */
2902 }
2903 
2904 /*
2905  * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
2906  *
2907  * If a match is found, return a Var constructed to reference the tlist item.
2908  * If no match, return NULL.
2909  *
2910  * This is needed to ensure that we select the right subplan TLE in cases
2911  * where there are multiple textually-equal()-but-volatile sort expressions.
2912  * And it's also faster than search_indexed_tlist_for_non_var.
2913  */
2914 static Var *
2916  Index sortgroupref,
2917  indexed_tlist *itlist,
2918  int newvarno)
2919 {
2920  ListCell *lc;
2921 
2922  foreach(lc, itlist->tlist)
2923  {
2924  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2925 
2926  /* The equal() check should be redundant, but let's be paranoid */
2927  if (tle->ressortgroupref == sortgroupref &&
2928  equal(node, tle->expr))
2929  {
2930  /* Found a matching subplan output expression */
2931  Var *newvar;
2932 
2933  newvar = makeVarFromTargetEntry(newvarno, tle);
2934  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2935  newvar->varattnosyn = 0;
2936  return newvar;
2937  }
2938  }
2939  return NULL; /* no match */
2940 }
2941 
2942 /*
2943  * fix_join_expr
2944  * Create a new set of targetlist entries or join qual clauses by
2945  * changing the varno/varattno values of variables in the clauses
2946  * to reference target list values from the outer and inner join
2947  * relation target lists. Also perform opcode lookup and add
2948  * regclass OIDs to root->glob->relationOids.
2949  *
2950  * This is used in four different scenarios:
2951  * 1) a normal join clause, where all the Vars in the clause *must* be
2952  * replaced by OUTER_VAR or INNER_VAR references. In this case
2953  * acceptable_rel should be zero so that any failure to match a Var will be
2954  * reported as an error.
2955  * 2) RETURNING clauses, which may contain both Vars of the target relation
2956  * and Vars of other relations. In this case we want to replace the
2957  * other-relation Vars by OUTER_VAR references, while leaving target Vars
2958  * alone. Thus inner_itlist = NULL and acceptable_rel = the ID of the
2959  * target relation should be passed.
2960  * 3) ON CONFLICT UPDATE SET/WHERE clauses. Here references to EXCLUDED are
2961  * to be replaced with INNER_VAR references, while leaving target Vars (the
2962  * to-be-updated relation) alone. Correspondingly inner_itlist is to be
2963  * EXCLUDED elements, outer_itlist = NULL and acceptable_rel the target
2964  * relation.
2965  * 4) MERGE. In this case, references to the source relation are to be
2966  * replaced with INNER_VAR references, leaving Vars of the target
2967  * relation (the to-be-modified relation) alone. So inner_itlist is to be
2968  * the source relation elements, outer_itlist = NULL and acceptable_rel
2969  * the target relation.
2970  *
2971  * 'clauses' is the targetlist or list of join clauses
2972  * 'outer_itlist' is the indexed target list of the outer join relation,
2973  * or NULL
2974  * 'inner_itlist' is the indexed target list of the inner join relation,
2975  * or NULL
2976  * 'acceptable_rel' is either zero or the rangetable index of a relation
2977  * whose Vars may appear in the clause without provoking an error
2978  * 'rtoffset': how much to increment varnos by
2979  * 'nrm_match': as for search_indexed_tlist_for_var()
2980  * 'num_exec': estimated number of executions of expression
2981  *
2982  * Returns the new expression tree. The original clause structure is
2983  * not modified.
2984  */
2985 static List *
2987  List *clauses,
2988  indexed_tlist *outer_itlist,
2989  indexed_tlist *inner_itlist,
2990  Index acceptable_rel,
2991  int rtoffset,
2992  NullingRelsMatch nrm_match,
2993  double num_exec)
2994 {
2995  fix_join_expr_context context;
2996 
2997  context.root = root;
2998  context.outer_itlist = outer_itlist;
2999  context.inner_itlist = inner_itlist;
3000  context.acceptable_rel = acceptable_rel;
3001  context.rtoffset = rtoffset;
3002  context.nrm_match = nrm_match;
3003  context.num_exec = num_exec;
3004  return (List *) fix_join_expr_mutator((Node *) clauses, &context);
3005 }
3006 
3007 static Node *
3009 {
3010  Var *newvar;
3011 
3012  if (node == NULL)
3013  return NULL;
3014  if (IsA(node, Var))
3015  {
3016  Var *var = (Var *) node;
3017 
3018  /* Look for the var in the input tlists, first in the outer */
3019  if (context->outer_itlist)
3020  {
3021  newvar = search_indexed_tlist_for_var(var,
3022  context->outer_itlist,
3023  OUTER_VAR,
3024  context->rtoffset,
3025  context->nrm_match);
3026  if (newvar)
3027  return (Node *) newvar;
3028  }
3029 
3030  /* then in the inner. */
3031  if (context->inner_itlist)
3032  {
3033  newvar = search_indexed_tlist_for_var(var,
3034  context->inner_itlist,
3035  INNER_VAR,
3036  context->rtoffset,
3037  context->nrm_match);
3038  if (newvar)
3039  return (Node *) newvar;
3040  }
3041 
3042  /* If it's for acceptable_rel, adjust and return it */
3043  if (var->varno == context->acceptable_rel)
3044  {
3045  var = copyVar(var);
3046  var->varno += context->rtoffset;
3047  if (var->varnosyn > 0)
3048  var->varnosyn += context->rtoffset;
3049  return (Node *) var;
3050  }
3051 
3052  /* No referent found for Var */
3053  elog(ERROR, "variable not found in subplan target lists");
3054  }
3055  if (IsA(node, PlaceHolderVar))
3056  {
3057  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3058 
3059  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
3060  if (context->outer_itlist && context->outer_itlist->has_ph_vars)
3061  {
3062  newvar = search_indexed_tlist_for_phv(phv,
3063  context->outer_itlist,
3064  OUTER_VAR,
3065  context->nrm_match);
3066  if (newvar)
3067  return (Node *) newvar;
3068  }
3069  if (context->inner_itlist && context->inner_itlist->has_ph_vars)
3070  {
3071  newvar = search_indexed_tlist_for_phv(phv,
3072  context->inner_itlist,
3073  INNER_VAR,
3074  context->nrm_match);
3075  if (newvar)
3076  return (Node *) newvar;
3077  }
3078 
3079  /* If not supplied by input plans, evaluate the contained expr */
3080  /* XXX can we assert something about phnullingrels? */
3081  return fix_join_expr_mutator((Node *) phv->phexpr, context);
3082  }
3083  /* Try matching more complex expressions too, if tlists have any */
3084  if (context->outer_itlist && context->outer_itlist->has_non_vars)
3085  {
3086  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3087  context->outer_itlist,
3088  OUTER_VAR);
3089  if (newvar)
3090  return (Node *) newvar;
3091  }
3092  if (context->inner_itlist && context->inner_itlist->has_non_vars)
3093  {
3094  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3095  context->inner_itlist,
3096  INNER_VAR);
3097  if (newvar)
3098  return (Node *) newvar;
3099  }
3100  /* Special cases (apply only AFTER failing to match to lower tlist) */
3101  if (IsA(node, Param))
3102  return fix_param_node(context->root, (Param *) node);
3103  if (IsA(node, AlternativeSubPlan))
3105  (AlternativeSubPlan *) node,
3106  context->num_exec),
3107  context);
3108  fix_expr_common(context->root, node);
3109  return expression_tree_mutator(node,
3111  (void *) context);
3112 }
3113 
3114 /*
3115  * fix_upper_expr
3116  * Modifies an expression tree so that all Var nodes reference outputs
3117  * of a subplan. Also looks for Aggref nodes that should be replaced
3118  * by initplan output Params. Also performs opcode lookup, and adds
3119  * regclass OIDs to root->glob->relationOids.
3120  *
3121  * This is used to fix up target and qual expressions of non-join upper-level
3122  * plan nodes, as well as index-only scan nodes.
3123  *
3124  * An error is raised if no matching var can be found in the subplan tlist
3125  * --- so this routine should only be applied to nodes whose subplans'
3126  * targetlists were generated by flattening the expressions used in the
3127  * parent node.
3128  *
3129  * If itlist->has_non_vars is true, then we try to match whole subexpressions
3130  * against elements of the subplan tlist, so that we can avoid recomputing
3131  * expressions that were already computed by the subplan. (This is relatively
3132  * expensive, so we don't want to try it in the common case where the
3133  * subplan tlist is just a flattened list of Vars.)
3134  *
3135  * 'node': the tree to be fixed (a target item or qual)
3136  * 'subplan_itlist': indexed target list for subplan (or index)
3137  * 'newvarno': varno to use for Vars referencing tlist elements
3138  * 'rtoffset': how much to increment varnos by
3139  * 'nrm_match': as for search_indexed_tlist_for_var()
3140  * 'num_exec': estimated number of executions of expression
3141  *
3142  * The resulting tree is a copy of the original in which all Var nodes have
3143  * varno = newvarno, varattno = resno of corresponding targetlist element.
3144  * The original tree is not modified.
3145  */
3146 static Node *
3148  Node *node,
3149  indexed_tlist *subplan_itlist,
3150  int newvarno,
3151  int rtoffset,
3152  NullingRelsMatch nrm_match,
3153  double num_exec)
3154 {
3155  fix_upper_expr_context context;
3156 
3157  context.root = root;
3158  context.subplan_itlist = subplan_itlist;
3159  context.newvarno = newvarno;
3160  context.rtoffset = rtoffset;
3161  context.nrm_match = nrm_match;
3162  context.num_exec = num_exec;
3163  return fix_upper_expr_mutator(node, &context);
3164 }
3165 
3166 static Node *
3168 {
3169  Var *newvar;
3170 
3171  if (node == NULL)
3172  return NULL;
3173  if (IsA(node, Var))
3174  {
3175  Var *var = (Var *) node;
3176 
3177  newvar = search_indexed_tlist_for_var(var,
3178  context->subplan_itlist,
3179  context->newvarno,
3180  context->rtoffset,
3181  context->nrm_match);
3182  if (!newvar)
3183  elog(ERROR, "variable not found in subplan target list");
3184  return (Node *) newvar;
3185  }
3186  if (IsA(node, PlaceHolderVar))
3187  {
3188  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3189 
3190  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
3191  if (context->subplan_itlist->has_ph_vars)
3192  {
3193  newvar = search_indexed_tlist_for_phv(phv,
3194  context->subplan_itlist,
3195  context->newvarno,
3196  context->nrm_match);
3197  if (newvar)
3198  return (Node *) newvar;
3199  }
3200  /* If not supplied by input plan, evaluate the contained expr */
3201  /* XXX can we assert something about phnullingrels? */
3202  return fix_upper_expr_mutator((Node *) phv->phexpr, context);
3203  }
3204  /* Try matching more complex expressions too, if tlist has any */
3205  if (context->subplan_itlist->has_non_vars)
3206  {
3207  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3208  context->subplan_itlist,
3209  context->newvarno);
3210  if (newvar)
3211  return (Node *) newvar;
3212  }
3213  /* Special cases (apply only AFTER failing to match to lower tlist) */
3214  if (IsA(node, Param))
3215  return fix_param_node(context->root, (Param *) node);
3216  if (IsA(node, Aggref))
3217  {
3218  Aggref *aggref = (Aggref *) node;
3219 
3220  /* See if the Aggref should be replaced by a Param */
3221  if (context->root->minmax_aggs != NIL &&
3222  list_length(aggref->args) == 1)
3223  {
3224  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
3225  ListCell *lc;
3226 
3227  foreach(lc, context->root->minmax_aggs)
3228  {
3229  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3230 
3231  if (mminfo->aggfnoid == aggref->aggfnoid &&
3232  equal(mminfo->target, curTarget->expr))
3233  return (Node *) copyObject(mminfo->param);
3234  }
3235  }
3236  /* If no match, just fall through to process it normally */
3237  }
3238  if (IsA(node, AlternativeSubPlan))
3240  (AlternativeSubPlan *) node,
3241  context->num_exec),
3242  context);
3243  fix_expr_common(context->root, node);
3244  return expression_tree_mutator(node,
3246  (void *) context);
3247 }
3248 
3249 /*
3250  * set_returning_clause_references
3251  * Perform setrefs.c's work on a RETURNING targetlist
3252  *
3253  * If the query involves more than just the result table, we have to
3254  * adjust any Vars that refer to other tables to reference junk tlist
3255  * entries in the top subplan's targetlist. Vars referencing the result
3256  * table should be left alone, however (the executor will evaluate them
3257  * using the actual heap tuple, after firing triggers if any). In the
3258  * adjusted RETURNING list, result-table Vars will have their original
3259  * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
3260  *
3261  * We also must perform opcode lookup and add regclass OIDs to
3262  * root->glob->relationOids.
3263  *
3264  * 'rlist': the RETURNING targetlist to be fixed
3265  * 'topplan': the top subplan node that will be just below the ModifyTable
3266  * node (note it's not yet passed through set_plan_refs)
3267  * 'resultRelation': RT index of the associated result relation
3268  * 'rtoffset': how much to increment varnos by
3269  *
3270  * Note: the given 'root' is for the parent query level, not the 'topplan'.
3271  * This does not matter currently since we only access the dependency-item
3272  * lists in root->glob, but it would need some hacking if we wanted a root
3273  * that actually matches the subplan.
3274  *
3275  * Note: resultRelation is not yet adjusted by rtoffset.
3276  */
3277 static List *
3279  List *rlist,
3280  Plan *topplan,
3281  Index resultRelation,
3282  int rtoffset)
3283 {
3284  indexed_tlist *itlist;
3285 
3286  /*
3287  * We can perform the desired Var fixup by abusing the fix_join_expr
3288  * machinery that formerly handled inner indexscan fixup. We search the
3289  * top plan's targetlist for Vars of non-result relations, and use
3290  * fix_join_expr to convert RETURNING Vars into references to those tlist
3291  * entries, while leaving result-rel Vars as-is.
3292  *
3293  * PlaceHolderVars will also be sought in the targetlist, but no
3294  * more-complex expressions will be. Note that it is not possible for a
3295  * PlaceHolderVar to refer to the result relation, since the result is
3296  * never below an outer join. If that case could happen, we'd have to be
3297  * prepared to pick apart the PlaceHolderVar and evaluate its contained
3298  * expression instead.
3299  */
3300  itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
3301 
3302  rlist = fix_join_expr(root,
3303  rlist,
3304  itlist,
3305  NULL,
3306  resultRelation,
3307  rtoffset,
3308  NRM_EQUAL,
3309  NUM_EXEC_TLIST(topplan));
3310 
3311  pfree(itlist);
3312 
3313  return rlist;
3314 }
3315 
3316 /*
3317  * fix_windowagg_condition_expr_mutator
3318  * Mutator function for replacing WindowFuncs with the corresponding Var
3319  * in the targetlist which references that WindowFunc.
3320  */
3321 static Node *
3323  fix_windowagg_cond_context *context)
3324 {
3325  if (node == NULL)
3326  return NULL;
3327 
3328  if (IsA(node, WindowFunc))
3329  {
3330  Var *newvar;
3331 
3332  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3333  context->subplan_itlist,
3334  context->newvarno);
3335  if (newvar)
3336  return (Node *) newvar;
3337  elog(ERROR, "WindowFunc not found in subplan target lists");
3338  }
3339 
3340  return expression_tree_mutator(node,
3342  (void *) context);
3343 }
3344 
3345 /*
3346  * fix_windowagg_condition_expr
3347  * Converts references in 'runcondition' so that any WindowFunc
3348  * references are swapped out for a Var which references the matching
3349  * WindowFunc in 'subplan_itlist'.
3350  */
3351 static List *
3353  List *runcondition,
3354  indexed_tlist *subplan_itlist)
3355 {
3357 
3358  context.root = root;
3359  context.subplan_itlist = subplan_itlist;
3360  context.newvarno = 0;
3361 
3362  return (List *) fix_windowagg_condition_expr_mutator((Node *) runcondition,
3363  &context);
3364 }
3365 
3366 /*
3367  * set_windowagg_runcondition_references
3368  * Converts references in 'runcondition' so that any WindowFunc
3369  * references are swapped out for a Var which references the matching
3370  * WindowFunc in 'plan' targetlist.
3371  */
3372 static List *
3374  List *runcondition,
3375  Plan *plan)
3376 {
3377  List *newlist;
3378  indexed_tlist *itlist;
3379 
3380  itlist = build_tlist_index(plan->targetlist);
3381 
3382  newlist = fix_windowagg_condition_expr(root, runcondition, itlist);
3383 
3384  pfree(itlist);
3385 
3386  return newlist;
3387 }
3388 
3389 /*****************************************************************************
3390  * QUERY DEPENDENCY MANAGEMENT
3391  *****************************************************************************/
3392 
3393 /*
3394  * record_plan_function_dependency
3395  * Mark the current plan as depending on a particular function.
3396  *
3397  * This is exported so that the function-inlining code can record a
3398  * dependency on a function that it's removed from the plan tree.
3399  */
3400 void
3402 {
3403  /*
3404  * For performance reasons, we don't bother to track built-in functions;
3405  * we just assume they'll never change (or at least not in ways that'd
3406  * invalidate plans using them). For this purpose we can consider a
3407  * built-in function to be one with OID less than FirstUnpinnedObjectId.
3408  * Note that the OID generator guarantees never to generate such an OID
3409  * after startup, even at OID wraparound.
3410  */
3411  if (funcid >= (Oid) FirstUnpinnedObjectId)
3412  {
3413  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3414 
3415  /*
3416  * It would work to use any syscache on pg_proc, but the easiest is
3417  * PROCOID since we already have the function's OID at hand. Note
3418  * that plancache.c knows we use PROCOID.
3419  */
3420  inval_item->cacheId = PROCOID;
3421  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3422  ObjectIdGetDatum(funcid));
3423 
3424  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3425  }
3426 }
3427 
3428 /*
3429  * record_plan_type_dependency
3430  * Mark the current plan as depending on a particular type.
3431  *
3432  * This is exported so that eval_const_expressions can record a
3433  * dependency on a domain that it's removed a CoerceToDomain node for.
3434  *
3435  * We don't currently need to record dependencies on domains that the
3436  * plan contains CoerceToDomain nodes for, though that might change in
3437  * future. Hence, this isn't actually called in this module, though
3438  * someday fix_expr_common might call it.
3439  */
3440 void
3442 {
3443  /*
3444  * As in record_plan_function_dependency, ignore the possibility that
3445  * someone would change a built-in domain.
3446  */
3447  if (typid >= (Oid) FirstUnpinnedObjectId)
3448  {
3449  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3450 
3451  /*
3452  * It would work to use any syscache on pg_type, but the easiest is
3453  * TYPEOID since we already have the type's OID at hand. Note that
3454  * plancache.c knows we use TYPEOID.
3455  */
3456  inval_item->cacheId = TYPEOID;
3457  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3458  ObjectIdGetDatum(typid));
3459 
3460  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3461  }
3462 }
3463 
3464 /*
3465  * extract_query_dependencies
3466  * Given a rewritten, but not yet planned, query or queries
3467  * (i.e. a Query node or list of Query nodes), extract dependencies
3468  * just as set_plan_references would do. Also detect whether any
3469  * rewrite steps were affected by RLS.
3470  *
3471  * This is needed by plancache.c to handle invalidation of cached unplanned
3472  * queries.
3473  *
3474  * Note: this does not go through eval_const_expressions, and hence doesn't
3475  * reflect its additions of inlined functions and elided CoerceToDomain nodes
3476  * to the invalItems list. This is obviously OK for functions, since we'll
3477  * see them in the original query tree anyway. For domains, it's OK because
3478  * we don't care about domains unless they get elided. That is, a plan might
3479  * have domain dependencies that the query tree doesn't.
3480  */
3481 void
3483  List **relationOids,
3484  List **invalItems,
3485  bool *hasRowSecurity)
3486 {
3487  PlannerGlobal glob;
3488  PlannerInfo root;
3489 
3490  /* Make up dummy planner state so we can use this module's machinery */
3491  MemSet(&glob, 0, sizeof(glob));
3492  glob.type = T_PlannerGlobal;
3493  glob.relationOids = NIL;
3494  glob.invalItems = NIL;
3495  /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
3496  glob.dependsOnRole = false;
3497 
3498  MemSet(&root, 0, sizeof(root));
3499  root.type = T_PlannerInfo;
3500  root.glob = &glob;
3501 
3502  (void) extract_query_dependencies_walker(query, &root);
3503 
3504  *relationOids = glob.relationOids;
3505  *invalItems = glob.invalItems;
3506  *hasRowSecurity = glob.dependsOnRole;
3507 }
3508 
3509 /*
3510  * Tree walker for extract_query_dependencies.
3511  *
3512  * This is exported so that expression_planner_with_deps can call it on
3513  * simple expressions (post-planning, not before planning, in that case).
3514  * In that usage, glob.dependsOnRole isn't meaningful, but the relationOids
3515  * and invalItems lists are added to as needed.
3516  */
3517 bool
3519 {
3520  if (node == NULL)
3521  return false;
3522  Assert(!IsA(node, PlaceHolderVar));
3523  if (IsA(node, Query))
3524  {
3525  Query *query = (Query *) node;
3526  ListCell *lc;
3527 
3528  if (query->commandType == CMD_UTILITY)
3529  {
3530  /*
3531  * Ignore utility statements, except those (such as EXPLAIN) that
3532  * contain a parsed-but-not-planned query.
3533  */
3534  query = UtilityContainsQuery(query->utilityStmt);
3535  if (query == NULL)
3536  return false;
3537  }
3538 
3539  /* Remember if any Query has RLS quals applied by rewriter */
3540  if (query->hasRowSecurity)
3541  context->glob->dependsOnRole = true;
3542 
3543  /* Collect relation OIDs in this Query's rtable */
3544  foreach(lc, query->rtable)
3545  {
3546  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3547 
3548  if (rte->rtekind == RTE_RELATION ||
3549  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
3550  (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
3551  context->glob->relationOids =
3552  lappend_oid(context->glob->relationOids, rte->relid);
3553  }
3554 
3555  /* And recurse into the query's subexpressions */
3557  (void *) context, 0);
3558  }
3559  /* Extract function dependencies and check for regclass Consts */
3560  fix_expr_common(context, node);
3562  (void *) context);
3563 }
int16 AttrNumber
Definition: attnum.h:21
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:94
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1039
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:332
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:755
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:260
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:382
unsigned char bool
Definition: c.h:440
unsigned int Index
Definition: c.h:598
#define MemSet(start, val, len)
Definition: c.h:1004
#define OidIsValid(objectId)
Definition: c.h:759
#define ERROR
Definition: elog.h:39
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
List * lappend_int(List *list, int datum)
Definition: list.c:356
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
Datum lca(PG_FUNCTION_ARGS)
Definition: ltree_op.c:501
Var * makeVarFromTargetEntry(int varno, TargetEntry *tle)
Definition: makefuncs.c:105
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:339
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:273
void pfree(void *pointer)
Definition: mcxt.c:1436
void * palloc0(Size size)
Definition: mcxt.c:1241
void * palloc(Size size)
Definition: mcxt.c:1210
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:266
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:764
void set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
Definition: nodeFuncs.c:1683
void set_opfuncid(OpExpr *opexpr)
Definition: nodeFuncs.c:1672
#define expression_tree_mutator(n, m, c)
Definition: nodeFuncs.h:153
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:156
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
#define QTW_EXAMINE_RTES_BEFORE
Definition: nodeFuncs.h:27
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define copyObject(obj)
Definition: nodes.h:244
double Cost
Definition: nodes.h:262
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:393
@ CMD_UTILITY
Definition: nodes.h:281
@ AGGSPLIT_FINAL_DESERIAL
Definition: nodes.h:389
@ AGGSPLIT_INITIAL_SERIAL
Definition: nodes.h:387
#define makeNode(_type_)
Definition: nodes.h:176
@ JOIN_INNER
Definition: nodes.h:304
RTEPermissionInfo * addRTEPermissionInfo(List **rteperminfos, RangeTblEntry *rte)
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1021
@ RTE_SUBQUERY
Definition: parsenodes.h:1015
@ RTE_RELATION
Definition: parsenodes.h:1014
#define IS_DUMMY_REL(r)
Definition: pathnodes.h:1907
@ UPPERREL_FINAL
Definition: pathnodes.h:79
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
#define lfirst_int(lc)
Definition: pg_list.h:173
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial_int(l)
Definition: pg_list.h:179
#define linitial(l)
Definition: pg_list.h:178
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define foreach_current_index(cell)
Definition: pg_list.h:403
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition: planner.c:5524
@ SUBQUERY_SCAN_NONTRIVIAL
Definition: plannodes.h:596
@ SUBQUERY_SCAN_UNKNOWN
Definition: plannodes.h:594
@ SUBQUERY_SCAN_TRIVIAL
Definition: plannodes.h:595
#define outerPlan(node)
Definition: plannodes.h:186
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
#define ROWID_VAR
Definition: primnodes.h:217
@ PARAM_MULTIEXPR
Definition: primnodes.h:348
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:219
#define OUTER_VAR
Definition: primnodes.h:215
#define INNER_VAR
Definition: primnodes.h:214
#define INDEX_VAR
Definition: primnodes.h:216
static SPIPlanPtr splan
Definition: regress.c:270
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:404
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1411
NullingRelsMatch
Definition: setrefs.c:34
@ NRM_EQUAL
Definition: setrefs.c:35
@ NRM_SUPERSET
Definition: setrefs.c:37
@ NRM_SUBSET
Definition: setrefs.c:36
void record_plan_type_dependency(PlannerInfo *root, Oid typid)
Definition: setrefs.c:3441
#define NUM_EXEC_QUAL(parentplan)
Definition: setrefs.c:118
static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:1859
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1936
static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
Definition: setrefs.c:418
static Node * fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
Definition: setrefs.c:3008
static void add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos, RangeTblEntry *rte)
Definition: setrefs.c:565
static Plan * set_append_references(PlannerInfo *root, Append *aplan, int rtoffset)
Definition: setrefs.c:1729
static Node * fix_param_node(PlannerInfo *root, Param *p)
Definition: setrefs.c:2031
static Plan * set_mergeappend_references(PlannerInfo *root, MergeAppend *mplan, int rtoffset)
Definition: setrefs.c:1795
static indexed_tlist * build_tlist_index_other_vars(List *tlist, int ignore_rel)
Definition: setrefs.c:2705
static List * set_returning_clause_references(PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
Definition: setrefs.c:3278
void record_plan_function_dependency(PlannerInfo *root, Oid funcid)
Definition: setrefs.c:3401
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1892
static bool flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt)
Definition: setrefs.c:519
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2652
static List * set_windowagg_runcondition_references(PlannerInfo *root, List *runcondition, Plan *plan)
Definition: setrefs.c:3373
bool trivial_subqueryscan(SubqueryScan *plan)
Definition: setrefs.c:1475
static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:2395
static Node * fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec)
Definition: setrefs.c:2062
static Var * search_indexed_tlist_for_sortgroupref(Expr *node, Index sortgroupref, indexed_tlist *itlist, int newvarno)
Definition: setrefs.c:2915
static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
Definition: setrefs.c:507
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int newvarno, int rtoffset, NullingRelsMatch nrm_match, double num_exec)
Definition: setrefs.c:3147
static void set_param_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:2461
static Var * search_indexed_tlist_for_non_var(Expr *node, indexed_tlist *itlist, int newvarno)
Definition: setrefs.c:2875
static Node * fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
Definition: setrefs.c:3167
static Node * fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:2153
static void set_foreignscan_references(PlannerInfo *root, ForeignScan *fscan, int rtoffset)
Definition: setrefs.c:1566
static Plan * set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset)
Definition: setrefs.c:1406
static Var * search_indexed_tlist_for_phv(PlaceHolderVar *phv, indexed_tlist *itlist, int newvarno, NullingRelsMatch nrm_match)
Definition: setrefs.c:2826
static Plan * set_indexonlyscan_references(PlannerInfo *root, IndexOnlyScan *plan, int rtoffset)
Definition: setrefs.c:1332
static List * fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset, NullingRelsMatch nrm_match, double num_exec)
Definition: setrefs.c:2986
static Node * convert_combining_aggrefs(Node *node, void *context)
Definition: setrefs.c:2516
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2585
static void set_customscan_references(PlannerInfo *root, CustomScan *cscan, int rtoffset)
Definition: setrefs.c:1653
static Node * fix_windowagg_condition_expr_mutator(Node *node, fix_windowagg_cond_context *context)
Definition: setrefs.c:3322
#define ISREGCLASSCONST(con)
Definition: setrefs.c:127
Plan * set_plan_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:289
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition: setrefs.c:3482
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3518
static Var * copyVar(Var *var)
Definition: setrefs.c:1914
#define NUM_EXEC_TLIST(parentplan)
Definition: setrefs.c:117
static void set_join_references(PlannerInfo *root, Join *join, int rtoffset)
Definition: setrefs.c:2248
static List * fix_windowagg_condition_expr(PlannerInfo *root, List *runcondition, indexed_tlist *subplan_itlist)
Definition: setrefs.c:3352
static Plan * clean_up_removed_plan_level(Plan *parent, Plan *child)
Definition: setrefs.c:1545
static Node * fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
Definition: setrefs.c:2118
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:635
static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:2227
static Var * search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, int newvarno, int rtoffset, NullingRelsMatch nrm_match)
Definition: setrefs.c:2765
#define fix_scan_list(root, lst, rtoffset, num_exec)
Definition: setrefs.c:131
Definition: plannodes.h:998
AggSplit aggsplit
Definition: plannodes.h:1005
Oid aggfnoid
Definition: primnodes.h:422
List * aggdistinct
Definition: primnodes.h:452
List * args
Definition: primnodes.h:446
Expr * aggfilter
Definition: primnodes.h:455
List * aggorder
Definition: primnodes.h:449
Index child_relid
Definition: pathnodes.h:2904
List * translated_vars
Definition: pathnodes.h:2931
Index parent_relid
Definition: pathnodes.h:2903
int part_prune_index
Definition: plannodes.h:280
Bitmapset * apprelids
Definition: plannodes.h:269
Plan plan
Definition: plannodes.h:268
List * appendplans
Definition: plannodes.h:270
List * custom_scan_tlist
Definition: plannodes.h:748
Scan scan
Definition: plannodes.h:742
Bitmapset * custom_relids
Definition: plannodes.h:749
List * custom_plans
Definition: plannodes.h:745
Bitmapset * fs_relids
Definition: plannodes.h:720
Bitmapset * fs_base_relids
Definition: plannodes.h:721
Index resultRelation
Definition: plannodes.h:712
List * fdw_scan_tlist
Definition: plannodes.h:718
List * hashclauses
Definition: plannodes.h:866
List * hashkeys
Definition: plannodes.h:874
List * hashkeys
Definition: plannodes.h:1206
List * indexqual
Definition: plannodes.h:497
List * recheckqual
Definition: plannodes.h:498
List * indextlist
Definition: plannodes.h:500
List * indexorderby
Definition: plannodes.h:499
List * joinqual
Definition: plannodes.h:794
JoinType jointype
Definition: plannodes.h:792
Definition: pg_list.h:54
List * param_exprs
Definition: plannodes.h:904
int part_prune_index
Definition: plannodes.h:315
Bitmapset * apprelids
Definition: plannodes.h:293
List * mergeplans
Definition: plannodes.h:295
List * mergeclauses
Definition: plannodes.h:842
Param * param
Definition: pathnodes.h:3067
Expr * target
Definition: pathnodes.h:3052
Var * paramval
Definition: plannodes.h:820
List * nestParams
Definition: plannodes.h:811
Definition: nodes.h:129
int paramid
Definition: primnodes.h:355
ParamKind paramkind
Definition: primnodes.h:354
Bitmapset * root_parent_relids
Definition: plannodes.h:1431
Relids phnullingrels
Definition: pathnodes.h:2734
uint32 hashValue
Definition: plannodes.h:1577
Index prti
Definition: plannodes.h:1384
Bitmapset * extParam
Definition: plannodes.h:174
struct Plan * lefttree
Definition: plannodes.h:158
struct Plan * righttree
Definition: plannodes.h:159
bool parallel_aware
Definition: plannodes.h:144
List * qual
Definition: plannodes.h:157
int plan_node_id
Definition: plannodes.h:155
List * targetlist
Definition: plannodes.h:156
List * initPlan
Definition: plannodes.h:160
int lastPlanNodeId
Definition: pathnodes.h:147
List * subplans
Definition: pathnodes.h:105
bool dependsOnRole
Definition: pathnodes.h:153
List * appendRelations
Definition: pathnodes.h:126
List * finalrowmarks
Definition: pathnodes.h:120
List * invalItems
Definition: pathnodes.h:135
List * relationOids
Definition: pathnodes.h:132
List * finalrteperminfos
Definition: pathnodes.h:117
Index lastPHId
Definition: pathnodes.h:141
List * resultRelations
Definition: pathnodes.h:123
List * partPruneInfos
Definition: pathnodes.h:129
List * finalrtable
Definition: pathnodes.h:114
List * minmax_aggs
Definition: pathnodes.h:472
List * init_plans
Definition: pathnodes.h:299
List * multiexpr_params
Definition: pathnodes.h:308
List * append_rel_list
Definition: pathnodes.h:365
PlannerGlobal * glob
Definition: pathnodes.h:205
bool hasAlternativeSubPlans
Definition: pathnodes.h:500
List * partPruneInfos
Definition: pathnodes.h:552
Query * parse
Definition: pathnodes.h:202
List * rowMarks
Definition: pathnodes.h:371
List * rtable
Definition: parsenodes.h:175
CmdType commandType
Definition: parsenodes.h:128
Node * utilityStmt
Definition: parsenodes.h:143
List * colcollations
Definition: parsenodes.h:1188
TableFunc * tablefunc
Definition: parsenodes.h:1154
Alias * join_using_alias
Definition: parsenodes.h:1138
struct TableSampleClause * tablesample
Definition: parsenodes.h:1075
List * securityQuals
Definition: parsenodes.h:1204
Query * subquery
Definition: parsenodes.h:1081
List * coltypes
Definition: parsenodes.h:1186
List * joinrightcols
Definition: parsenodes.h:1131
List * values_lists
Definition: parsenodes.h:1159
List * joinaliasvars
Definition: parsenodes.h:1129
List * coltypmods
Definition: parsenodes.h:1187
List * functions
Definition: parsenodes.h:1148
Index perminfoindex
Definition: parsenodes.h:1076
List * joinleftcols
Definition: parsenodes.h:1130
RTEKind rtekind
Definition: parsenodes.h:1033
Index relid
Definition: pathnodes.h:909
PlannerInfo * subroot
Definition: pathnodes.h:938
Index scanrelid
Definition: plannodes.h:390
int plan_id
Definition: primnodes.h:997
List * setParam
Definition: primnodes.h:1015
Cost startup_cost
Definition: primnodes.h:1020
Cost per_call_cost
Definition: primnodes.h:1021
SubqueryScanStatus scanstatus
Definition: plannodes.h:603
Plan * subplan
Definition: plannodes.h:602
Expr * expr
Definition: primnodes.h:1731
AttrNumber resno
Definition: primnodes.h:1733
Index ressortgroupref
Definition: primnodes.h:1737
Definition: primnodes.h:226
AttrNumber varattno
Definition: primnodes.h:238
int varno
Definition: primnodes.h:233
Index varlevelsup
Definition: primnodes.h:258
Node * endOffset
Definition: plannodes.h:1077
List * runConditionOrig
Definition: plannodes.h:1083
Node * startOffset
Definition: plannodes.h:1074
List * runCondition
Definition: plannodes.h:1080
NullingRelsMatch nrm_match
Definition: setrefs.c:73
indexed_tlist * outer_itlist
Definition: setrefs.c:69
PlannerInfo * root
Definition: setrefs.c:68
indexed_tlist * inner_itlist
Definition: setrefs.c:70
PlannerInfo * root
Definition: setrefs.c:61
indexed_tlist * subplan_itlist
Definition: setrefs.c:80
PlannerInfo * root
Definition: setrefs.c:79
NullingRelsMatch nrm_match
Definition: setrefs.c:83
indexed_tlist * subplan_itlist
Definition: setrefs.c:90
PlannerInfo * root
Definition: setrefs.c:89
PlannerGlobal * glob
Definition: setrefs.c:97
tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]
Definition: setrefs.c:56
bool has_ph_vars
Definition: setrefs.c:54
bool has_non_vars
Definition: setrefs.c:55
int num_vars
Definition: setrefs.c:53
List * tlist
Definition: setrefs.c:52
AttrNumber resno
Definition: setrefs.c:44
int varno
Definition: setrefs.c:42
AttrNumber varattno
Definition: setrefs.c:43
Definition: regcomp.c:282
@ TYPEOID
Definition: syscache.h:114
@ PROCOID
Definition: syscache.h:79
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:206
void apply_tlist_labeling(List *dest_tlist, List *src_tlist)
Definition: tlist.c:318
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:79
#define FirstUnpinnedObjectId
Definition: transam.h:196
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2173