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