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