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