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