Line data Source code
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 *
209 25224 : set_plan_references(PlannerInfo *root, Plan *plan)
210 : {
211 25224 : PlannerGlobal *glob = root->glob;
212 25224 : 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 25224 : add_rtes_to_flat_rtable(root, false);
221 :
222 : /*
223 : * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
224 : */
225 25760 : foreach(lc, root->rowMarks)
226 : {
227 536 : PlanRowMark *rc = lfirst_node(PlanRowMark, lc);
228 : PlanRowMark *newrc;
229 :
230 : /* flat copy is enough since all fields are scalars */
231 536 : newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
232 536 : memcpy(newrc, rc, sizeof(PlanRowMark));
233 :
234 : /* adjust indexes ... but *not* the rowmarkId */
235 536 : newrc->rti += rtoffset;
236 536 : newrc->prti += rtoffset;
237 :
238 536 : glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
239 : }
240 :
241 : /* Now fix the Plan tree */
242 25224 : 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
251 25227 : add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
252 : {
253 25227 : 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 55387 : foreach(lc, root->parse->rtable)
265 : {
266 30160 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
267 :
268 30160 : if (!recursing || rte->rtekind == RTE_RELATION)
269 30160 : 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 25227 : rti = 1;
283 55387 : foreach(lc, root->parse->rtable)
284 : {
285 30160 : 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 32986 : if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
294 2826 : rti < root->simple_rel_array_size)
295 : {
296 2764 : RelOptInfo *rel = root->simple_rel_array[rti];
297 :
298 2764 : if (rel != NULL)
299 : {
300 1068 : 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 1068 : if (rel->subroot == NULL)
322 6 : flatten_unplanned_rtes(glob, rte);
323 2124 : else if (recursing ||
324 2124 : IS_DUMMY_REL(fetch_upper_rel(rel->subroot,
325 : UPPERREL_FINAL, NULL)))
326 3 : add_rtes_to_flat_rtable(rel->subroot, true);
327 : }
328 : }
329 30160 : rti++;
330 : }
331 25227 : }
332 :
333 : /*
334 : * Extract RangeTblEntries from a subquery that was never planned at all
335 : */
336 : static void
337 6 : flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
338 : {
339 : /* Use query_tree_walker to find all RTEs in the parse tree */
340 6 : (void) query_tree_walker(rte->subquery,
341 : flatten_rtes_walker,
342 : (void *) glob,
343 : QTW_EXAMINE_RTES);
344 6 : }
345 :
346 : static bool
347 154 : flatten_rtes_walker(Node *node, PlannerGlobal *glob)
348 : {
349 154 : if (node == NULL)
350 86 : return false;
351 68 : if (IsA(node, RangeTblEntry))
352 : {
353 9 : RangeTblEntry *rte = (RangeTblEntry *) node;
354 :
355 : /* As above, we need only save relation RTEs */
356 9 : if (rte->rtekind == RTE_RELATION)
357 7 : add_rte_to_flat_rtable(glob, rte);
358 9 : return false;
359 : }
360 59 : if (IsA(node, Query))
361 : {
362 : /* Recurse into subselects */
363 2 : return query_tree_walker((Query *) node,
364 : flatten_rtes_walker,
365 : (void *) glob,
366 : QTW_EXAMINE_RTES);
367 : }
368 57 : 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
383 30167 : add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
384 : {
385 : RangeTblEntry *newrte;
386 :
387 : /* flat copy to duplicate all the scalar fields */
388 30167 : newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
389 30167 : memcpy(newrte, rte, sizeof(RangeTblEntry));
390 :
391 : /* zap unneeded sub-structure */
392 30167 : newrte->tablesample = NULL;
393 30167 : newrte->subquery = NULL;
394 30167 : newrte->joinaliasvars = NIL;
395 30167 : newrte->functions = NIL;
396 30167 : newrte->tablefunc = NULL;
397 30167 : newrte->values_lists = NIL;
398 30167 : newrte->coltypes = NIL;
399 30167 : newrte->coltypmods = NIL;
400 30167 : newrte->colcollations = NIL;
401 30167 : newrte->securityQuals = NIL;
402 :
403 30167 : 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 30167 : if (IS_SPECIAL_VARNO(list_length(glob->finalrtable)))
411 0 : 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 30167 : if (newrte->rtekind == RTE_RELATION)
427 22567 : glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
428 30167 : }
429 :
430 : /*
431 : * set_plan_refs: recurse through the Plan nodes of a single subquery level
432 : */
433 : static Plan *
434 125524 : set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
435 : {
436 : ListCell *l;
437 :
438 125524 : if (plan == NULL)
439 76691 : return NULL;
440 :
441 : /* Assign this node a unique ID. */
442 48833 : plan->plan_node_id = root->glob->lastPlanNodeId++;
443 :
444 : /*
445 : * Plan-type-specific fixes
446 : */
447 48833 : switch (nodeTag(plan))
448 : {
449 : case T_SeqScan:
450 : {
451 9154 : SeqScan *splan = (SeqScan *) plan;
452 :
453 9154 : splan->scanrelid += rtoffset;
454 9154 : splan->plan.targetlist =
455 9154 : fix_scan_list(root, splan->plan.targetlist, rtoffset);
456 9154 : splan->plan.qual =
457 9154 : fix_scan_list(root, splan->plan.qual, rtoffset);
458 : }
459 9154 : break;
460 : case T_SampleScan:
461 : {
462 36 : SampleScan *splan = (SampleScan *) plan;
463 :
464 36 : splan->scan.scanrelid += rtoffset;
465 36 : splan->scan.plan.targetlist =
466 36 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
467 36 : splan->scan.plan.qual =
468 36 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
469 36 : splan->tablesample = (TableSampleClause *)
470 36 : fix_scan_expr(root, (Node *) splan->tablesample, rtoffset);
471 : }
472 36 : break;
473 : case T_IndexScan:
474 : {
475 3852 : IndexScan *splan = (IndexScan *) plan;
476 :
477 3852 : splan->scan.scanrelid += rtoffset;
478 3852 : splan->scan.plan.targetlist =
479 3852 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
480 3852 : splan->scan.plan.qual =
481 3852 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
482 3852 : splan->indexqual =
483 3852 : fix_scan_list(root, splan->indexqual, rtoffset);
484 3852 : splan->indexqualorig =
485 3852 : fix_scan_list(root, splan->indexqualorig, rtoffset);
486 3852 : splan->indexorderby =
487 3852 : fix_scan_list(root, splan->indexorderby, rtoffset);
488 3852 : splan->indexorderbyorig =
489 3852 : fix_scan_list(root, splan->indexorderbyorig, rtoffset);
490 : }
491 3852 : break;
492 : case T_IndexOnlyScan:
493 : {
494 659 : IndexOnlyScan *splan = (IndexOnlyScan *) plan;
495 :
496 659 : return set_indexonlyscan_references(root, splan, rtoffset);
497 : }
498 : break;
499 : case T_BitmapIndexScan:
500 : {
501 1612 : BitmapIndexScan *splan = (BitmapIndexScan *) plan;
502 :
503 1612 : splan->scan.scanrelid += rtoffset;
504 : /* no need to fix targetlist and qual */
505 1612 : Assert(splan->scan.plan.targetlist == NIL);
506 1612 : Assert(splan->scan.plan.qual == NIL);
507 1612 : splan->indexqual =
508 1612 : fix_scan_list(root, splan->indexqual, rtoffset);
509 1612 : splan->indexqualorig =
510 1612 : fix_scan_list(root, splan->indexqualorig, rtoffset);
511 : }
512 1612 : break;
513 : case T_BitmapHeapScan:
514 : {
515 1587 : BitmapHeapScan *splan = (BitmapHeapScan *) plan;
516 :
517 1587 : splan->scan.scanrelid += rtoffset;
518 1587 : splan->scan.plan.targetlist =
519 1587 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
520 1587 : splan->scan.plan.qual =
521 1587 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
522 1587 : splan->bitmapqualorig =
523 1587 : fix_scan_list(root, splan->bitmapqualorig, rtoffset);
524 : }
525 1587 : break;
526 : case T_TidScan:
527 : {
528 66 : TidScan *splan = (TidScan *) plan;
529 :
530 66 : splan->scan.scanrelid += rtoffset;
531 66 : splan->scan.plan.targetlist =
532 66 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
533 66 : splan->scan.plan.qual =
534 66 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
535 66 : splan->tidquals =
536 66 : fix_scan_list(root, splan->tidquals, rtoffset);
537 : }
538 66 : break;
539 : case T_SubqueryScan:
540 : /* Needs special treatment, see comments below */
541 1059 : return set_subqueryscan_references(root,
542 : (SubqueryScan *) plan,
543 : rtoffset);
544 : case T_FunctionScan:
545 : {
546 1327 : FunctionScan *splan = (FunctionScan *) plan;
547 :
548 1327 : splan->scan.scanrelid += rtoffset;
549 1327 : splan->scan.plan.targetlist =
550 1327 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
551 1327 : splan->scan.plan.qual =
552 1327 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
553 1327 : splan->functions =
554 1327 : fix_scan_list(root, splan->functions, rtoffset);
555 : }
556 1327 : break;
557 : case T_TableFuncScan:
558 : {
559 22 : TableFuncScan *splan = (TableFuncScan *) plan;
560 :
561 22 : splan->scan.scanrelid += rtoffset;
562 22 : splan->scan.plan.targetlist =
563 22 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
564 22 : splan->scan.plan.qual =
565 22 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
566 22 : splan->tablefunc = (TableFunc *)
567 22 : fix_scan_expr(root, (Node *) splan->tablefunc, rtoffset);
568 : }
569 22 : break;
570 : case T_ValuesScan:
571 : {
572 463 : ValuesScan *splan = (ValuesScan *) plan;
573 :
574 463 : splan->scan.scanrelid += rtoffset;
575 463 : splan->scan.plan.targetlist =
576 463 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
577 463 : splan->scan.plan.qual =
578 463 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
579 463 : splan->values_lists =
580 463 : fix_scan_list(root, splan->values_lists, rtoffset);
581 : }
582 463 : break;
583 : case T_CteScan:
584 : {
585 162 : CteScan *splan = (CteScan *) plan;
586 :
587 162 : splan->scan.scanrelid += rtoffset;
588 162 : splan->scan.plan.targetlist =
589 162 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
590 162 : splan->scan.plan.qual =
591 162 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
592 : }
593 162 : break;
594 : case T_NamedTuplestoreScan:
595 : {
596 43 : NamedTuplestoreScan *splan = (NamedTuplestoreScan *) plan;
597 :
598 43 : splan->scan.scanrelid += rtoffset;
599 43 : splan->scan.plan.targetlist =
600 43 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
601 43 : splan->scan.plan.qual =
602 43 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
603 : }
604 43 : break;
605 : case T_WorkTableScan:
606 : {
607 40 : WorkTableScan *splan = (WorkTableScan *) plan;
608 :
609 40 : splan->scan.scanrelid += rtoffset;
610 40 : splan->scan.plan.targetlist =
611 40 : fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
612 40 : splan->scan.plan.qual =
613 40 : fix_scan_list(root, splan->scan.plan.qual, rtoffset);
614 : }
615 40 : break;
616 : case T_ForeignScan:
617 0 : set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
618 0 : break;
619 : case T_CustomScan:
620 0 : set_customscan_references(root, (CustomScan *) plan, rtoffset);
621 0 : break;
622 :
623 : case T_NestLoop:
624 : case T_MergeJoin:
625 : case T_HashJoin:
626 3715 : set_join_references(root, (Join *) plan, rtoffset);
627 3715 : break;
628 :
629 : case T_Gather:
630 : case T_GatherMerge:
631 34 : set_upper_references(root, plan, rtoffset);
632 34 : 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 4470 : 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 4470 : Assert(plan->qual == NIL);
654 4470 : break;
655 : case T_LockRows:
656 : {
657 328 : 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 328 : set_dummy_tlist_references(plan, rtoffset);
665 328 : Assert(splan->plan.qual == NIL);
666 :
667 680 : foreach(l, splan->rowMarks)
668 : {
669 352 : PlanRowMark *rc = (PlanRowMark *) lfirst(l);
670 :
671 352 : rc->rti += rtoffset;
672 352 : rc->prti += rtoffset;
673 : }
674 : }
675 328 : break;
676 : case T_Limit:
677 : {
678 260 : 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 260 : set_dummy_tlist_references(plan, rtoffset);
687 260 : Assert(splan->plan.qual == NIL);
688 :
689 260 : splan->limitOffset =
690 260 : fix_scan_expr(root, splan->limitOffset, rtoffset);
691 260 : splan->limitCount =
692 260 : fix_scan_expr(root, splan->limitCount, rtoffset);
693 : }
694 260 : break;
695 : case T_Agg:
696 : {
697 2421 : 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 2421 : if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
706 : {
707 22 : plan->targetlist = (List *)
708 22 : convert_combining_aggrefs((Node *) plan->targetlist,
709 : NULL);
710 22 : plan->qual = (List *)
711 22 : convert_combining_aggrefs((Node *) plan->qual,
712 : NULL);
713 : }
714 :
715 2421 : set_upper_references(root, plan, rtoffset);
716 : }
717 2421 : break;
718 : case T_Group:
719 11 : set_upper_references(root, plan, rtoffset);
720 11 : break;
721 : case T_WindowAgg:
722 : {
723 140 : WindowAgg *wplan = (WindowAgg *) plan;
724 :
725 140 : 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 140 : wplan->startOffset =
733 140 : fix_scan_expr(root, wplan->startOffset, rtoffset);
734 140 : wplan->endOffset =
735 140 : fix_scan_expr(root, wplan->endOffset, rtoffset);
736 : }
737 140 : break;
738 : case T_Result:
739 : {
740 12137 : 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 12137 : if (splan->plan.lefttree != NULL)
747 552 : set_upper_references(root, plan, rtoffset);
748 : else
749 : {
750 11585 : splan->plan.targetlist =
751 11585 : fix_scan_list(root, splan->plan.targetlist, rtoffset);
752 11585 : splan->plan.qual =
753 11585 : fix_scan_list(root, splan->plan.qual, rtoffset);
754 : }
755 : /* resconstantqual can't contain any subplan variable refs */
756 12137 : splan->resconstantqual =
757 12137 : fix_scan_expr(root, splan->resconstantqual, rtoffset);
758 : }
759 12137 : break;
760 : case T_ProjectSet:
761 226 : set_upper_references(root, plan, rtoffset);
762 226 : break;
763 : case T_ModifyTable:
764 : {
765 4314 : ModifyTable *splan = (ModifyTable *) plan;
766 :
767 4314 : Assert(splan->plan.targetlist == NIL);
768 4314 : Assert(splan->plan.qual == NIL);
769 :
770 4314 : splan->withCheckOptionLists =
771 4314 : fix_scan_list(root, splan->withCheckOptionLists, rtoffset);
772 :
773 4314 : if (splan->returningLists)
774 : {
775 208 : 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 208 : Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
785 208 : Assert(list_length(splan->returningLists) == list_length(splan->plans));
786 429 : forthree(lcrl, splan->returningLists,
787 : lcrr, splan->resultRelations,
788 : lcp, splan->plans)
789 : {
790 221 : List *rlist = (List *) lfirst(lcrl);
791 221 : Index resultrel = lfirst_int(lcrr);
792 221 : Plan *subplan = (Plan *) lfirst(lcp);
793 :
794 221 : rlist = set_returning_clause_references(root,
795 : rlist,
796 : subplan,
797 : resultrel,
798 : rtoffset);
799 221 : newRL = lappend(newRL, rlist);
800 : }
801 208 : 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 208 : 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 4314 : if (splan->onConflictSet)
823 : {
824 : indexed_tlist *itlist;
825 :
826 140 : itlist = build_tlist_index(splan->exclRelTlist);
827 :
828 140 : splan->onConflictSet =
829 140 : fix_join_expr(root, splan->onConflictSet,
830 : NULL, itlist,
831 140 : linitial_int(splan->resultRelations),
832 : rtoffset);
833 :
834 140 : splan->onConflictWhere = (Node *)
835 140 : fix_join_expr(root, (List *) splan->onConflictWhere,
836 : NULL, itlist,
837 140 : linitial_int(splan->resultRelations),
838 : rtoffset);
839 :
840 140 : pfree(itlist);
841 :
842 140 : splan->exclRelTlist =
843 140 : fix_scan_list(root, splan->exclRelTlist, rtoffset);
844 : }
845 :
846 4314 : splan->nominalRelation += rtoffset;
847 4314 : splan->exclRelRTI += rtoffset;
848 :
849 4325 : foreach(l, splan->partitioned_rels)
850 : {
851 11 : lfirst_int(l) += rtoffset;
852 : }
853 8744 : foreach(l, splan->resultRelations)
854 : {
855 4430 : lfirst_int(l) += rtoffset;
856 : }
857 4498 : foreach(l, splan->rowMarks)
858 : {
859 184 : PlanRowMark *rc = (PlanRowMark *) lfirst(l);
860 :
861 184 : rc->rti += rtoffset;
862 184 : rc->prti += rtoffset;
863 : }
864 8744 : foreach(l, splan->plans)
865 : {
866 4430 : lfirst(l) = set_plan_refs(root,
867 4430 : (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 4314 : splan->resultRelIndex = list_length(root->glob->resultRelations);
878 8628 : root->glob->resultRelations =
879 4314 : list_concat(root->glob->resultRelations,
880 4314 : 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 identitied as such during the executor
888 : * initialization.
889 : */
890 4314 : if (splan->partitioned_rels != NIL)
891 : {
892 22 : root->glob->nonleafResultRelations =
893 11 : list_concat(root->glob->nonleafResultRelations,
894 11 : list_copy(splan->partitioned_rels));
895 : /* Remember where this root will be in the global list. */
896 11 : splan->rootResultRelIndex =
897 11 : list_length(root->glob->rootResultRelations);
898 22 : root->glob->rootResultRelations =
899 11 : lappend_int(root->glob->rootResultRelations,
900 11 : linitial_int(splan->partitioned_rels));
901 : }
902 : }
903 4314 : break;
904 : case T_Append:
905 : {
906 601 : Append *splan = (Append *) plan;
907 :
908 : /*
909 : * Append, like Sort et al, doesn't actually evaluate its
910 : * targetlist or check quals.
911 : */
912 601 : set_dummy_tlist_references(plan, rtoffset);
913 601 : Assert(splan->plan.qual == NIL);
914 686 : foreach(l, splan->partitioned_rels)
915 : {
916 85 : lfirst_int(l) += rtoffset;
917 : }
918 2096 : foreach(l, splan->appendplans)
919 : {
920 1495 : lfirst(l) = set_plan_refs(root,
921 1495 : (Plan *) lfirst(l),
922 : rtoffset);
923 : }
924 : }
925 601 : break;
926 : case T_MergeAppend:
927 : {
928 34 : MergeAppend *splan = (MergeAppend *) plan;
929 :
930 : /*
931 : * MergeAppend, like Sort et al, doesn't actually evaluate its
932 : * targetlist or check quals.
933 : */
934 34 : set_dummy_tlist_references(plan, rtoffset);
935 34 : Assert(splan->plan.qual == NIL);
936 38 : foreach(l, splan->partitioned_rels)
937 : {
938 4 : lfirst_int(l) += rtoffset;
939 : }
940 134 : foreach(l, splan->mergeplans)
941 : {
942 100 : lfirst(l) = set_plan_refs(root,
943 100 : (Plan *) lfirst(l),
944 : rtoffset);
945 : }
946 : }
947 34 : break;
948 : case T_RecursiveUnion:
949 : /* This doesn't evaluate targetlist or check quals either */
950 40 : set_dummy_tlist_references(plan, rtoffset);
951 40 : Assert(plan->qual == NIL);
952 40 : break;
953 : case T_BitmapAnd:
954 : {
955 3 : BitmapAnd *splan = (BitmapAnd *) plan;
956 :
957 : /* BitmapAnd works like Append, but has no tlist */
958 3 : Assert(splan->plan.targetlist == NIL);
959 3 : Assert(splan->plan.qual == NIL);
960 9 : foreach(l, splan->bitmapplans)
961 : {
962 6 : lfirst(l) = set_plan_refs(root,
963 6 : (Plan *) lfirst(l),
964 : rtoffset);
965 : }
966 : }
967 3 : break;
968 : case T_BitmapOr:
969 : {
970 17 : BitmapOr *splan = (BitmapOr *) plan;
971 :
972 : /* BitmapOr works like Append, but has no tlist */
973 17 : Assert(splan->plan.targetlist == NIL);
974 17 : Assert(splan->plan.qual == NIL);
975 56 : foreach(l, splan->bitmapplans)
976 : {
977 39 : lfirst(l) = set_plan_refs(root,
978 39 : (Plan *) lfirst(l),
979 : rtoffset);
980 : }
981 : }
982 17 : break;
983 : default:
984 0 : 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 47115 : plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
998 47115 : plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
999 :
1000 47115 : 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 *
1013 659 : set_indexonlyscan_references(PlannerInfo *root,
1014 : IndexOnlyScan *plan,
1015 : int rtoffset)
1016 : {
1017 : indexed_tlist *index_itlist;
1018 :
1019 659 : index_itlist = build_tlist_index(plan->indextlist);
1020 :
1021 659 : plan->scan.scanrelid += rtoffset;
1022 659 : plan->scan.plan.targetlist = (List *)
1023 659 : fix_upper_expr(root,
1024 659 : (Node *) plan->scan.plan.targetlist,
1025 : index_itlist,
1026 : INDEX_VAR,
1027 : rtoffset);
1028 659 : plan->scan.plan.qual = (List *)
1029 659 : fix_upper_expr(root,
1030 659 : (Node *) plan->scan.plan.qual,
1031 : index_itlist,
1032 : INDEX_VAR,
1033 : rtoffset);
1034 : /* indexqual is already transformed to reference index columns */
1035 659 : plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset);
1036 : /* indexorderby is already transformed to reference index columns */
1037 659 : plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset);
1038 : /* indextlist must NOT be transformed to reference index columns */
1039 659 : plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset);
1040 :
1041 659 : pfree(index_itlist);
1042 :
1043 659 : 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 *
1054 1059 : 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 1059 : rel = find_base_rel(root, plan->scan.scanrelid);
1063 :
1064 : /* Recursively process the subplan */
1065 1059 : plan->subplan = set_plan_references(rel->subroot, plan->subplan);
1066 :
1067 1059 : 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 776 : result = plan->subplan;
1076 :
1077 : /* We have to be sure we don't lose any initplans */
1078 776 : 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 2090 : forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist)
1088 : {
1089 1314 : TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1090 1314 : TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1091 :
1092 1314 : ctle->resname = ptle->resname;
1093 1314 : ctle->resorigtbl = ptle->resorigtbl;
1094 1314 : 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 283 : plan->scan.scanrelid += rtoffset;
1107 283 : plan->scan.plan.targetlist =
1108 283 : fix_scan_list(root, plan->scan.plan.targetlist, rtoffset);
1109 283 : plan->scan.plan.qual =
1110 283 : fix_scan_list(root, plan->scan.plan.qual, rtoffset);
1111 :
1112 283 : result = (Plan *) plan;
1113 : }
1114 :
1115 1059 : 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
1126 1059 : trivial_subqueryscan(SubqueryScan *plan)
1127 : {
1128 : int attrno;
1129 : ListCell *lp,
1130 : *lc;
1131 :
1132 1059 : if (plan->scan.plan.qual != NIL)
1133 101 : return false;
1134 :
1135 1916 : if (list_length(plan->scan.plan.targetlist) !=
1136 958 : list_length(plan->subplan->targetlist))
1137 134 : return false; /* tlists not same length */
1138 :
1139 824 : attrno = 1;
1140 2154 : forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1141 : {
1142 1378 : TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1143 1378 : TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1144 :
1145 1378 : if (ptle->resjunk != ctle->resjunk)
1146 3 : 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 1375 : if (ptle->expr && IsA(ptle->expr, Var))
1154 1201 : {
1155 1218 : Var *var = (Var *) ptle->expr;
1156 :
1157 1218 : Assert(var->varno == plan->scan.scanrelid);
1158 1218 : Assert(var->varlevelsup == 0);
1159 1218 : if (var->varattno != attrno)
1160 17 : return false; /* out of order */
1161 : }
1162 157 : else if (ptle->expr && IsA(ptle->expr, Const))
1163 : {
1164 259 : if (!equal(ptle->expr, ctle->expr))
1165 1 : return false;
1166 : }
1167 : else
1168 27 : return false;
1169 :
1170 1330 : attrno++;
1171 : }
1172 :
1173 776 : return true;
1174 : }
1175 :
1176 : /*
1177 : * set_foreignscan_references
1178 : * Do set_plan_references processing on a ForeignScan
1179 : */
1180 : static void
1181 0 : set_foreignscan_references(PlannerInfo *root,
1182 : ForeignScan *fscan,
1183 : int rtoffset)
1184 : {
1185 : /* Adjust scanrelid if it's valid */
1186 0 : if (fscan->scan.scanrelid > 0)
1187 0 : fscan->scan.scanrelid += rtoffset;
1188 :
1189 0 : if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
1190 0 : {
1191 : /*
1192 : * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1193 : * foreign scan tuple
1194 : */
1195 0 : indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist);
1196 :
1197 0 : fscan->scan.plan.targetlist = (List *)
1198 0 : fix_upper_expr(root,
1199 0 : (Node *) fscan->scan.plan.targetlist,
1200 : itlist,
1201 : INDEX_VAR,
1202 : rtoffset);
1203 0 : fscan->scan.plan.qual = (List *)
1204 0 : fix_upper_expr(root,
1205 0 : (Node *) fscan->scan.plan.qual,
1206 : itlist,
1207 : INDEX_VAR,
1208 : rtoffset);
1209 0 : fscan->fdw_exprs = (List *)
1210 0 : fix_upper_expr(root,
1211 0 : (Node *) fscan->fdw_exprs,
1212 : itlist,
1213 : INDEX_VAR,
1214 : rtoffset);
1215 0 : fscan->fdw_recheck_quals = (List *)
1216 0 : fix_upper_expr(root,
1217 0 : (Node *) fscan->fdw_recheck_quals,
1218 : itlist,
1219 : INDEX_VAR,
1220 : rtoffset);
1221 0 : pfree(itlist);
1222 : /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1223 0 : fscan->fdw_scan_tlist =
1224 0 : 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 0 : fscan->scan.plan.targetlist =
1233 0 : fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset);
1234 0 : fscan->scan.plan.qual =
1235 0 : fix_scan_list(root, fscan->scan.plan.qual, rtoffset);
1236 0 : fscan->fdw_exprs =
1237 0 : fix_scan_list(root, fscan->fdw_exprs, rtoffset);
1238 0 : fscan->fdw_recheck_quals =
1239 0 : fix_scan_list(root, fscan->fdw_recheck_quals, rtoffset);
1240 : }
1241 :
1242 : /* Adjust fs_relids if needed */
1243 0 : if (rtoffset > 0)
1244 : {
1245 0 : Bitmapset *tempset = NULL;
1246 0 : int x = -1;
1247 :
1248 0 : while ((x = bms_next_member(fscan->fs_relids, x)) >= 0)
1249 0 : tempset = bms_add_member(tempset, x + rtoffset);
1250 0 : fscan->fs_relids = tempset;
1251 : }
1252 0 : }
1253 :
1254 : /*
1255 : * set_customscan_references
1256 : * Do set_plan_references processing on a CustomScan
1257 : */
1258 : static void
1259 0 : set_customscan_references(PlannerInfo *root,
1260 : CustomScan *cscan,
1261 : int rtoffset)
1262 : {
1263 : ListCell *lc;
1264 :
1265 : /* Adjust scanrelid if it's valid */
1266 0 : if (cscan->scan.scanrelid > 0)
1267 0 : cscan->scan.scanrelid += rtoffset;
1268 :
1269 0 : if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
1270 0 : {
1271 : /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1272 0 : indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist);
1273 :
1274 0 : cscan->scan.plan.targetlist = (List *)
1275 0 : fix_upper_expr(root,
1276 0 : (Node *) cscan->scan.plan.targetlist,
1277 : itlist,
1278 : INDEX_VAR,
1279 : rtoffset);
1280 0 : cscan->scan.plan.qual = (List *)
1281 0 : fix_upper_expr(root,
1282 0 : (Node *) cscan->scan.plan.qual,
1283 : itlist,
1284 : INDEX_VAR,
1285 : rtoffset);
1286 0 : cscan->custom_exprs = (List *)
1287 0 : fix_upper_expr(root,
1288 0 : (Node *) cscan->custom_exprs,
1289 : itlist,
1290 : INDEX_VAR,
1291 : rtoffset);
1292 0 : pfree(itlist);
1293 : /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1294 0 : cscan->custom_scan_tlist =
1295 0 : fix_scan_list(root, cscan->custom_scan_tlist, rtoffset);
1296 : }
1297 : else
1298 : {
1299 : /* Adjust tlist, qual, custom_exprs in the standard way */
1300 0 : cscan->scan.plan.targetlist =
1301 0 : fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
1302 0 : cscan->scan.plan.qual =
1303 0 : fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
1304 0 : cscan->custom_exprs =
1305 0 : fix_scan_list(root, cscan->custom_exprs, rtoffset);
1306 : }
1307 :
1308 : /* Adjust child plan-nodes recursively, if needed */
1309 0 : foreach(lc, cscan->custom_plans)
1310 : {
1311 0 : lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
1312 : }
1313 :
1314 : /* Adjust custom_relids if needed */
1315 0 : if (rtoffset > 0)
1316 : {
1317 0 : Bitmapset *tempset = NULL;
1318 0 : int x = -1;
1319 :
1320 0 : while ((x = bms_next_member(cscan->custom_relids, x)) >= 0)
1321 0 : tempset = bms_add_member(tempset, x + rtoffset);
1322 0 : cscan->custom_relids = tempset;
1323 : }
1324 0 : }
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 *
1334 51837 : copyVar(Var *var)
1335 : {
1336 51837 : Var *newvar = (Var *) palloc(sizeof(Var));
1337 :
1338 51837 : *newvar = *var;
1339 51837 : 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
1356 386303 : fix_expr_common(PlannerInfo *root, Node *node)
1357 : {
1358 : /* We assume callers won't call us on a NULL pointer */
1359 386303 : if (IsA(node, Aggref))
1360 : {
1361 3053 : record_plan_function_dependency(root,
1362 : ((Aggref *) node)->aggfnoid);
1363 : }
1364 383250 : else if (IsA(node, WindowFunc))
1365 : {
1366 166 : record_plan_function_dependency(root,
1367 : ((WindowFunc *) node)->winfnoid);
1368 : }
1369 383084 : else if (IsA(node, FuncExpr))
1370 : {
1371 13484 : record_plan_function_dependency(root,
1372 : ((FuncExpr *) node)->funcid);
1373 : }
1374 369600 : else if (IsA(node, OpExpr))
1375 : {
1376 30168 : set_opfuncid((OpExpr *) node);
1377 30168 : record_plan_function_dependency(root,
1378 : ((OpExpr *) node)->opfuncid);
1379 : }
1380 339432 : else if (IsA(node, DistinctExpr))
1381 : {
1382 33 : set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1383 33 : record_plan_function_dependency(root,
1384 : ((DistinctExpr *) node)->opfuncid);
1385 : }
1386 339399 : else if (IsA(node, NullIfExpr))
1387 : {
1388 11 : set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1389 11 : record_plan_function_dependency(root,
1390 : ((NullIfExpr *) node)->opfuncid);
1391 : }
1392 339388 : else if (IsA(node, ScalarArrayOpExpr))
1393 : {
1394 781 : set_sa_opfuncid((ScalarArrayOpExpr *) node);
1395 781 : record_plan_function_dependency(root,
1396 : ((ScalarArrayOpExpr *) node)->opfuncid);
1397 : }
1398 338607 : else if (IsA(node, ArrayCoerceExpr))
1399 : {
1400 12 : if (OidIsValid(((ArrayCoerceExpr *) node)->elemfuncid))
1401 2 : record_plan_function_dependency(root,
1402 : ((ArrayCoerceExpr *) node)->elemfuncid);
1403 : }
1404 338595 : else if (IsA(node, Const))
1405 : {
1406 50545 : Const *con = (Const *) node;
1407 :
1408 : /* Check for regclass reference */
1409 50545 : if (ISREGCLASSCONST(con))
1410 13432 : root->glob->relationOids =
1411 6716 : lappend_oid(root->glob->relationOids,
1412 : DatumGetObjectId(con->constvalue));
1413 : }
1414 288050 : else if (IsA(node, GroupingFunc))
1415 : {
1416 39 : GroupingFunc *g = (GroupingFunc *) node;
1417 39 : AttrNumber *grouping_map = root->grouping_map;
1418 :
1419 : /* If there are no grouping sets, we don't need this. */
1420 :
1421 39 : Assert(grouping_map || g->cols == NIL);
1422 :
1423 39 : if (grouping_map)
1424 : {
1425 : ListCell *lc;
1426 31 : List *cols = NIL;
1427 :
1428 89 : foreach(lc, g->refs)
1429 : {
1430 58 : cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
1431 : }
1432 :
1433 31 : Assert(!g->cols || equal(cols, g->cols));
1434 :
1435 31 : if (!g->cols)
1436 31 : g->cols = cols;
1437 : }
1438 : }
1439 386303 : }
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 *
1450 3765 : fix_param_node(PlannerInfo *root, Param *p)
1451 : {
1452 3765 : if (p->paramkind == PARAM_MULTIEXPR)
1453 : {
1454 18 : int subqueryid = p->paramid >> 16;
1455 18 : int colno = p->paramid & 0xFFFF;
1456 : List *params;
1457 :
1458 36 : if (subqueryid <= 0 ||
1459 18 : subqueryid > list_length(root->multiexpr_params))
1460 0 : elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1461 18 : params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
1462 18 : if (colno <= 0 || colno > list_length(params))
1463 0 : elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1464 18 : return copyObject(list_nth(params, colno - 1));
1465 : }
1466 3747 : 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 *
1480 98741 : fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
1481 : {
1482 : fix_scan_expr_context context;
1483 :
1484 98741 : context.root = root;
1485 98741 : context.rtoffset = rtoffset;
1486 :
1487 184684 : if (rtoffset != 0 ||
1488 171854 : root->multiexpr_params != NIL ||
1489 171301 : root->glob->lastPHId != 0 ||
1490 85390 : root->minmax_aggs != NIL)
1491 : {
1492 13555 : 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 85186 : (void) fix_scan_expr_walker(node, &context);
1507 85186 : return node;
1508 : }
1509 : }
1510 :
1511 : static Node *
1512 81045 : fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
1513 : {
1514 81045 : if (node == NULL)
1515 4698 : return NULL;
1516 76347 : if (IsA(node, Var))
1517 : {
1518 25255 : Var *var = copyVar((Var *) node);
1519 :
1520 25255 : 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 25255 : Assert(var->varno != INNER_VAR);
1527 25255 : Assert(var->varno != OUTER_VAR);
1528 25255 : if (!IS_SPECIAL_VARNO(var->varno))
1529 23968 : var->varno += context->rtoffset;
1530 25255 : if (var->varnoold > 0)
1531 25255 : var->varnoold += context->rtoffset;
1532 25255 : return (Node *) var;
1533 : }
1534 51092 : if (IsA(node, Param))
1535 3591 : return fix_param_node(context->root, (Param *) node);
1536 47501 : if (IsA(node, Aggref))
1537 : {
1538 81 : Aggref *aggref = (Aggref *) node;
1539 :
1540 : /* See if the Aggref should be replaced by a Param */
1541 162 : if (context->root->minmax_aggs != NIL &&
1542 81 : list_length(aggref->args) == 1)
1543 : {
1544 81 : TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
1545 : ListCell *lc;
1546 :
1547 87 : foreach(lc, context->root->minmax_aggs)
1548 : {
1549 87 : MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
1550 :
1551 168 : if (mminfo->aggfnoid == aggref->aggfnoid &&
1552 81 : equal(mminfo->target, curTarget->expr))
1553 81 : return (Node *) copyObject(mminfo->param);
1554 : }
1555 : }
1556 : /* If no match, just fall through to process it normally */
1557 : }
1558 47420 : if (IsA(node, CurrentOfExpr))
1559 : {
1560 0 : CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
1561 :
1562 0 : Assert(cexpr->cvarno != INNER_VAR);
1563 0 : Assert(cexpr->cvarno != OUTER_VAR);
1564 0 : if (!IS_SPECIAL_VARNO(cexpr->cvarno))
1565 0 : cexpr->cvarno += context->rtoffset;
1566 0 : return (Node *) cexpr;
1567 : }
1568 47420 : if (IsA(node, PlaceHolderVar))
1569 : {
1570 : /* At scan level, we should always just evaluate the contained expr */
1571 35 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
1572 :
1573 35 : return fix_scan_expr_mutator((Node *) phv->phexpr, context);
1574 : }
1575 47385 : fix_expr_common(context->root, node);
1576 47385 : return expression_tree_mutator(node, fix_scan_expr_mutator,
1577 : (void *) context);
1578 : }
1579 :
1580 : static bool
1581 300139 : fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
1582 : {
1583 300139 : if (node == NULL)
1584 44780 : return false;
1585 255359 : Assert(!IsA(node, PlaceHolderVar));
1586 255359 : fix_expr_common(context->root, node);
1587 255359 : 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
1600 3715 : set_join_references(PlannerInfo *root, Join *join, int rtoffset)
1601 : {
1602 3715 : Plan *outer_plan = join->plan.lefttree;
1603 3715 : Plan *inner_plan = join->plan.righttree;
1604 : indexed_tlist *outer_itlist;
1605 : indexed_tlist *inner_itlist;
1606 :
1607 3715 : outer_itlist = build_tlist_index(outer_plan->targetlist);
1608 3715 : 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 3715 : 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 3715 : if (IsA(join, NestLoop))
1626 : {
1627 2186 : NestLoop *nl = (NestLoop *) join;
1628 : ListCell *lc;
1629 :
1630 3298 : foreach(lc, nl->nestParams)
1631 : {
1632 1112 : NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
1633 :
1634 1112 : nlp->paramval = (Var *) fix_upper_expr(root,
1635 1112 : (Node *) nlp->paramval,
1636 : outer_itlist,
1637 : OUTER_VAR,
1638 : rtoffset);
1639 : /* Check we replaced any PlaceHolderVar with simple Var */
1640 2224 : if (!(IsA(nlp->paramval, Var) &&
1641 1112 : nlp->paramval->varno == OUTER_VAR))
1642 0 : elog(ERROR, "NestLoopParam was not reduced to a simple Var");
1643 : }
1644 : }
1645 1529 : else if (IsA(join, MergeJoin))
1646 : {
1647 165 : MergeJoin *mj = (MergeJoin *) join;
1648 :
1649 165 : mj->mergeclauses = fix_join_expr(root,
1650 : mj->mergeclauses,
1651 : outer_itlist,
1652 : inner_itlist,
1653 : (Index) 0,
1654 : rtoffset);
1655 : }
1656 1364 : else if (IsA(join, HashJoin))
1657 : {
1658 1364 : HashJoin *hj = (HashJoin *) join;
1659 :
1660 1364 : 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 3715 : switch (join->jointype)
1681 : {
1682 : case JOIN_LEFT:
1683 : case JOIN_SEMI:
1684 : case JOIN_ANTI:
1685 849 : inner_itlist->has_non_vars = false;
1686 849 : break;
1687 : case JOIN_RIGHT:
1688 186 : outer_itlist->has_non_vars = false;
1689 186 : break;
1690 : case JOIN_FULL:
1691 28 : outer_itlist->has_non_vars = false;
1692 28 : inner_itlist->has_non_vars = false;
1693 28 : break;
1694 : default:
1695 2652 : break;
1696 : }
1697 :
1698 3715 : join->plan.targetlist = fix_join_expr(root,
1699 : join->plan.targetlist,
1700 : outer_itlist,
1701 : inner_itlist,
1702 : (Index) 0,
1703 : rtoffset);
1704 3715 : join->plan.qual = fix_join_expr(root,
1705 : join->plan.qual,
1706 : outer_itlist,
1707 : inner_itlist,
1708 : (Index) 0,
1709 : rtoffset);
1710 :
1711 3715 : pfree(outer_itlist);
1712 3715 : pfree(inner_itlist);
1713 3715 : }
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
1734 3384 : set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
1735 : {
1736 3384 : Plan *subplan = plan->lefttree;
1737 : indexed_tlist *subplan_itlist;
1738 : List *output_targetlist;
1739 : ListCell *l;
1740 :
1741 3384 : subplan_itlist = build_tlist_index(subplan->targetlist);
1742 :
1743 3384 : output_targetlist = NIL;
1744 8554 : foreach(l, plan->targetlist)
1745 : {
1746 5170 : TargetEntry *tle = (TargetEntry *) lfirst(l);
1747 : Node *newexpr;
1748 :
1749 : /* If it's a non-Var sort/group item, first try to match by sortref */
1750 5170 : if (tle->ressortgroupref != 0 && !IsA(tle->expr, Var))
1751 : {
1752 191 : newexpr = (Node *)
1753 191 : search_indexed_tlist_for_sortgroupref(tle->expr,
1754 : tle->ressortgroupref,
1755 : subplan_itlist,
1756 : OUTER_VAR);
1757 382 : if (!newexpr)
1758 100 : newexpr = fix_upper_expr(root,
1759 100 : (Node *) tle->expr,
1760 : subplan_itlist,
1761 : OUTER_VAR,
1762 : rtoffset);
1763 : }
1764 : else
1765 4979 : newexpr = fix_upper_expr(root,
1766 4979 : (Node *) tle->expr,
1767 : subplan_itlist,
1768 : OUTER_VAR,
1769 : rtoffset);
1770 5170 : tle = flatCopyTargetEntry(tle);
1771 5170 : tle->expr = (Expr *) newexpr;
1772 5170 : output_targetlist = lappend(output_targetlist, tle);
1773 : }
1774 3384 : plan->targetlist = output_targetlist;
1775 :
1776 3384 : plan->qual = (List *)
1777 3384 : fix_upper_expr(root,
1778 3384 : (Node *) plan->qual,
1779 : subplan_itlist,
1780 : OUTER_VAR,
1781 : rtoffset);
1782 :
1783 3384 : pfree(subplan_itlist);
1784 3384 : }
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 *
1804 106 : convert_combining_aggrefs(Node *node, void *context)
1805 : {
1806 106 : if (node == NULL)
1807 22 : return NULL;
1808 84 : if (IsA(node, Aggref))
1809 : {
1810 20 : 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 20 : Assert(orig_agg->aggorder == NIL);
1816 20 : 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 20 : child_agg = makeNode(Aggref);
1824 20 : 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 20 : child_agg->args = NIL;
1835 20 : child_agg->aggfilter = NULL;
1836 20 : parent_agg = copyObject(child_agg);
1837 20 : child_agg->args = orig_agg->args;
1838 20 : 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 20 : mark_partial_aggref(child_agg, AGGSPLIT_INITIAL_SERIAL);
1845 :
1846 : /*
1847 : * And set up parent_agg to represent the second phase.
1848 : */
1849 20 : parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
1850 : 1, NULL, false));
1851 20 : mark_partial_aggref(parent_agg, AGGSPLIT_FINAL_DESERIAL);
1852 :
1853 20 : return (Node *) parent_agg;
1854 : }
1855 64 : 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
1873 5733 : set_dummy_tlist_references(Plan *plan, int rtoffset)
1874 : {
1875 : List *output_targetlist;
1876 : ListCell *l;
1877 :
1878 5733 : output_targetlist = NIL;
1879 20205 : foreach(l, plan->targetlist)
1880 : {
1881 14472 : TargetEntry *tle = (TargetEntry *) lfirst(l);
1882 14472 : 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 14472 : if (IsA(oldvar, Const))
1892 : {
1893 : /* just reuse the existing TLE node */
1894 458 : output_targetlist = lappend(output_targetlist, tle);
1895 458 : continue;
1896 : }
1897 :
1898 28028 : newvar = makeVar(OUTER_VAR,
1899 14014 : tle->resno,
1900 : exprType((Node *) oldvar),
1901 : exprTypmod((Node *) oldvar),
1902 : exprCollation((Node *) oldvar),
1903 : 0);
1904 14014 : if (IsA(oldvar, Var))
1905 : {
1906 10870 : newvar->varnoold = oldvar->varno + rtoffset;
1907 10870 : newvar->varoattno = oldvar->varattno;
1908 : }
1909 : else
1910 : {
1911 3144 : newvar->varnoold = 0; /* wasn't ever a plain Var */
1912 3144 : newvar->varoattno = 0;
1913 : }
1914 :
1915 14014 : tle = flatCopyTargetEntry(tle);
1916 14014 : tle->expr = (Expr *) newvar;
1917 14014 : output_targetlist = lappend(output_targetlist, tle);
1918 : }
1919 5733 : plan->targetlist = output_targetlist;
1920 :
1921 : /* We don't touch plan->qual here */
1922 5733 : }
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 *
1939 11613 : 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 11613 : itlist = (indexed_tlist *)
1947 11613 : palloc(offsetof(indexed_tlist, vars) +
1948 11613 : list_length(tlist) * sizeof(tlist_vinfo));
1949 :
1950 11613 : itlist->tlist = tlist;
1951 11613 : itlist->has_ph_vars = false;
1952 11613 : itlist->has_non_vars = false;
1953 :
1954 : /* Find the Vars and fill in the index array */
1955 11613 : vinfo = itlist->vars;
1956 59374 : foreach(l, tlist)
1957 : {
1958 47761 : TargetEntry *tle = (TargetEntry *) lfirst(l);
1959 :
1960 47761 : if (tle->expr && IsA(tle->expr, Var))
1961 47223 : {
1962 47223 : Var *var = (Var *) tle->expr;
1963 :
1964 47223 : vinfo->varno = var->varno;
1965 47223 : vinfo->varattno = var->varattno;
1966 47223 : vinfo->resno = tle->resno;
1967 47223 : vinfo++;
1968 : }
1969 538 : else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
1970 92 : itlist->has_ph_vars = true;
1971 : else
1972 446 : itlist->has_non_vars = true;
1973 : }
1974 :
1975 11613 : itlist->num_vars = (vinfo - itlist->vars);
1976 :
1977 11613 : 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 *
1989 221 : 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 221 : itlist = (indexed_tlist *)
1997 221 : palloc(offsetof(indexed_tlist, vars) +
1998 221 : list_length(tlist) * sizeof(tlist_vinfo));
1999 :
2000 221 : itlist->tlist = tlist;
2001 221 : itlist->has_ph_vars = false;
2002 221 : itlist->has_non_vars = false;
2003 :
2004 : /* Find the desired Vars and fill in the index array */
2005 221 : vinfo = itlist->vars;
2006 934 : foreach(l, tlist)
2007 : {
2008 713 : TargetEntry *tle = (TargetEntry *) lfirst(l);
2009 :
2010 713 : if (tle->expr && IsA(tle->expr, Var))
2011 375 : {
2012 375 : Var *var = (Var *) tle->expr;
2013 :
2014 375 : if (var->varno != ignore_rel)
2015 : {
2016 192 : vinfo->varno = var->varno;
2017 192 : vinfo->varattno = var->varattno;
2018 192 : vinfo->resno = tle->resno;
2019 192 : vinfo++;
2020 : }
2021 : }
2022 338 : else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2023 0 : itlist->has_ph_vars = true;
2024 : }
2025 :
2026 221 : itlist->num_vars = (vinfo - itlist->vars);
2027 :
2028 221 : 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 *
2040 34536 : search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
2041 : Index newvarno, int rtoffset)
2042 : {
2043 34536 : Index varno = var->varno;
2044 34536 : AttrNumber varattno = var->varattno;
2045 : tlist_vinfo *vinfo;
2046 : int i;
2047 :
2048 34536 : vinfo = itlist->vars;
2049 34536 : i = itlist->num_vars;
2050 180165 : while (i-- > 0)
2051 : {
2052 136895 : if (vinfo->varno == varno && vinfo->varattno == varattno)
2053 : {
2054 : /* Found a match */
2055 25802 : Var *newvar = copyVar(var);
2056 :
2057 25802 : newvar->varno = newvarno;
2058 25802 : newvar->varattno = vinfo->resno;
2059 25802 : if (newvar->varnoold > 0)
2060 25758 : newvar->varnoold += rtoffset;
2061 25802 : return newvar;
2062 : }
2063 111093 : vinfo++;
2064 : }
2065 8734 : 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 *
2080 1221 : 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 1221 : if (IsA(node, Const))
2093 94 : return NULL;
2094 :
2095 1127 : tle = tlist_member(node, itlist->tlist);
2096 1127 : if (tle)
2097 : {
2098 : /* Found a matching subplan output expression */
2099 : Var *newvar;
2100 :
2101 524 : newvar = makeVarFromTargetEntry(newvarno, tle);
2102 524 : newvar->varnoold = 0; /* wasn't ever a plain Var */
2103 524 : newvar->varoattno = 0;
2104 524 : return newvar;
2105 : }
2106 603 : return NULL; /* no match */
2107 : }
2108 :
2109 : /*
2110 : * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
2111 : * (which is assumed not to be just a Var)
2112 : *
2113 : * If a match is found, return a Var constructed to reference the tlist item.
2114 : * If no match, return NULL.
2115 : *
2116 : * This is needed to ensure that we select the right subplan TLE in cases
2117 : * where there are multiple textually-equal()-but-volatile sort expressions.
2118 : * And it's also faster than search_indexed_tlist_for_non_var.
2119 : */
2120 : static Var *
2121 191 : search_indexed_tlist_for_sortgroupref(Expr *node,
2122 : Index sortgroupref,
2123 : indexed_tlist *itlist,
2124 : Index newvarno)
2125 : {
2126 : ListCell *lc;
2127 :
2128 592 : foreach(lc, itlist->tlist)
2129 : {
2130 492 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
2131 :
2132 : /* The equal() check should be redundant, but let's be paranoid */
2133 585 : if (tle->ressortgroupref == sortgroupref &&
2134 93 : equal(node, tle->expr))
2135 : {
2136 : /* Found a matching subplan output expression */
2137 : Var *newvar;
2138 :
2139 91 : newvar = makeVarFromTargetEntry(newvarno, tle);
2140 91 : newvar->varnoold = 0; /* wasn't ever a plain Var */
2141 91 : newvar->varoattno = 0;
2142 91 : return newvar;
2143 : }
2144 : }
2145 100 : return NULL; /* no match */
2146 : }
2147 :
2148 : /*
2149 : * fix_join_expr
2150 : * Create a new set of targetlist entries or join qual clauses by
2151 : * changing the varno/varattno values of variables in the clauses
2152 : * to reference target list values from the outer and inner join
2153 : * relation target lists. Also perform opcode lookup and add
2154 : * regclass OIDs to root->glob->relationOids.
2155 : *
2156 : * This is used in three different scenarios:
2157 : * 1) a normal join clause, where all the Vars in the clause *must* be
2158 : * replaced by OUTER_VAR or INNER_VAR references. In this case
2159 : * acceptable_rel should be zero so that any failure to match a Var will be
2160 : * reported as an error.
2161 : * 2) RETURNING clauses, which may contain both Vars of the target relation
2162 : * and Vars of other relations. In this case we want to replace the
2163 : * other-relation Vars by OUTER_VAR references, while leaving target Vars
2164 : * alone. Thus inner_itlist = NULL and acceptable_rel = the ID of the
2165 : * target relation should be passed.
2166 : * 3) ON CONFLICT UPDATE SET/WHERE clauses. Here references to EXCLUDED are
2167 : * to be replaced with INNER_VAR references, while leaving target Vars (the
2168 : * to-be-updated relation) alone. Correspondingly inner_itlist is to be
2169 : * EXCLUDED elements, outer_itlist = NULL and acceptable_rel the target
2170 : * relation.
2171 : *
2172 : * 'clauses' is the targetlist or list of join clauses
2173 : * 'outer_itlist' is the indexed target list of the outer join relation,
2174 : * or NULL
2175 : * 'inner_itlist' is the indexed target list of the inner join relation,
2176 : * or NULL
2177 : * 'acceptable_rel' is either zero or the rangetable index of a relation
2178 : * whose Vars may appear in the clause without provoking an error
2179 : * 'rtoffset': how much to increment varnoold by
2180 : *
2181 : * Returns the new expression tree. The original clause structure is
2182 : * not modified.
2183 : */
2184 : static List *
2185 13175 : fix_join_expr(PlannerInfo *root,
2186 : List *clauses,
2187 : indexed_tlist *outer_itlist,
2188 : indexed_tlist *inner_itlist,
2189 : Index acceptable_rel,
2190 : int rtoffset)
2191 : {
2192 : fix_join_expr_context context;
2193 :
2194 13175 : context.root = root;
2195 13175 : context.outer_itlist = outer_itlist;
2196 13175 : context.inner_itlist = inner_itlist;
2197 13175 : context.acceptable_rel = acceptable_rel;
2198 13175 : context.rtoffset = rtoffset;
2199 13175 : return (List *) fix_join_expr_mutator((Node *) clauses, &context);
2200 : }
2201 :
2202 : static Node *
2203 67817 : fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
2204 : {
2205 : Var *newvar;
2206 :
2207 67817 : if (node == NULL)
2208 7899 : return NULL;
2209 59918 : if (IsA(node, Var))
2210 : {
2211 20645 : Var *var = (Var *) node;
2212 :
2213 : /* Look for the var in the input tlists, first in the outer */
2214 20645 : if (context->outer_itlist)
2215 : {
2216 20268 : newvar = search_indexed_tlist_for_var(var,
2217 : context->outer_itlist,
2218 : OUTER_VAR,
2219 : context->rtoffset);
2220 20268 : if (newvar)
2221 11800 : return (Node *) newvar;
2222 : }
2223 :
2224 : /* then in the inner. */
2225 8845 : if (context->inner_itlist)
2226 : {
2227 8331 : newvar = search_indexed_tlist_for_var(var,
2228 : context->inner_itlist,
2229 : INNER_VAR,
2230 : context->rtoffset);
2231 8331 : if (newvar)
2232 8065 : return (Node *) newvar;
2233 : }
2234 :
2235 : /* If it's for acceptable_rel, adjust and return it */
2236 780 : if (var->varno == context->acceptable_rel)
2237 : {
2238 780 : var = copyVar(var);
2239 780 : var->varno += context->rtoffset;
2240 780 : if (var->varnoold > 0)
2241 780 : var->varnoold += context->rtoffset;
2242 780 : return (Node *) var;
2243 : }
2244 :
2245 : /* No referent found for Var */
2246 0 : elog(ERROR, "variable not found in subplan target lists");
2247 : }
2248 39273 : if (IsA(node, PlaceHolderVar))
2249 : {
2250 109 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
2251 :
2252 : /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2253 109 : if (context->outer_itlist && context->outer_itlist->has_ph_vars)
2254 : {
2255 43 : newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2256 : context->outer_itlist,
2257 : OUTER_VAR);
2258 43 : if (newvar)
2259 34 : return (Node *) newvar;
2260 : }
2261 75 : if (context->inner_itlist && context->inner_itlist->has_ph_vars)
2262 : {
2263 54 : newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2264 : context->inner_itlist,
2265 : INNER_VAR);
2266 54 : if (newvar)
2267 52 : return (Node *) newvar;
2268 : }
2269 :
2270 : /* If not supplied by input plans, evaluate the contained expr */
2271 23 : return fix_join_expr_mutator((Node *) phv->phexpr, context);
2272 : }
2273 39164 : if (IsA(node, Param))
2274 134 : return fix_param_node(context->root, (Param *) node);
2275 : /* Try matching more complex expressions too, if tlists have any */
2276 39030 : if (context->outer_itlist && context->outer_itlist->has_non_vars)
2277 : {
2278 21 : newvar = search_indexed_tlist_for_non_var((Expr *) node,
2279 : context->outer_itlist,
2280 : OUTER_VAR);
2281 21 : if (newvar)
2282 1 : return (Node *) newvar;
2283 : }
2284 39029 : if (context->inner_itlist && context->inner_itlist->has_non_vars)
2285 : {
2286 63 : newvar = search_indexed_tlist_for_non_var((Expr *) node,
2287 : context->inner_itlist,
2288 : INNER_VAR);
2289 63 : if (newvar)
2290 8 : return (Node *) newvar;
2291 : }
2292 39021 : fix_expr_common(context->root, node);
2293 39021 : 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 *
2329 10893 : 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 10893 : context.root = root;
2338 10893 : context.subplan_itlist = subplan_itlist;
2339 10893 : context.newvarno = newvarno;
2340 10893 : context.rtoffset = rtoffset;
2341 10893 : return fix_upper_expr_mutator(node, &context);
2342 : }
2343 :
2344 : static Node *
2345 34874 : fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
2346 : {
2347 : Var *newvar;
2348 :
2349 34874 : if (node == NULL)
2350 14795 : return NULL;
2351 20079 : if (IsA(node, Var))
2352 : {
2353 5937 : Var *var = (Var *) node;
2354 :
2355 5937 : newvar = search_indexed_tlist_for_var(var,
2356 : context->subplan_itlist,
2357 : context->newvarno,
2358 : context->rtoffset);
2359 5937 : if (!newvar)
2360 0 : elog(ERROR, "variable not found in subplan target list");
2361 5937 : return (Node *) newvar;
2362 : }
2363 14142 : if (IsA(node, PlaceHolderVar))
2364 : {
2365 24 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
2366 :
2367 : /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2368 24 : if (context->subplan_itlist->has_ph_vars)
2369 : {
2370 17 : newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2371 : context->subplan_itlist,
2372 : context->newvarno);
2373 17 : if (newvar)
2374 17 : return (Node *) newvar;
2375 : }
2376 : /* If not supplied by input plan, evaluate the contained expr */
2377 7 : return fix_upper_expr_mutator((Node *) phv->phexpr, context);
2378 : }
2379 14118 : if (IsA(node, Param))
2380 40 : return fix_param_node(context->root, (Param *) node);
2381 14078 : if (IsA(node, Aggref))
2382 : {
2383 2579 : Aggref *aggref = (Aggref *) node;
2384 :
2385 : /* See if the Aggref should be replaced by a Param */
2386 2581 : if (context->root->minmax_aggs != NIL &&
2387 2 : list_length(aggref->args) == 1)
2388 : {
2389 2 : TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
2390 : ListCell *lc;
2391 :
2392 2 : foreach(lc, context->root->minmax_aggs)
2393 : {
2394 2 : MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
2395 :
2396 4 : if (mminfo->aggfnoid == aggref->aggfnoid &&
2397 2 : equal(mminfo->target, curTarget->expr))
2398 2 : return (Node *) copyObject(mminfo->param);
2399 : }
2400 : }
2401 : /* If no match, just fall through to process it normally */
2402 : }
2403 : /* Try matching more complex expressions too, if tlist has any */
2404 14076 : if (context->subplan_itlist->has_non_vars)
2405 : {
2406 1023 : newvar = search_indexed_tlist_for_non_var((Expr *) node,
2407 : context->subplan_itlist,
2408 : context->newvarno);
2409 1023 : if (newvar)
2410 412 : return (Node *) newvar;
2411 : }
2412 13664 : fix_expr_common(context->root, node);
2413 13664 : return expression_tree_mutator(node,
2414 : fix_upper_expr_mutator,
2415 : (void *) context);
2416 : }
2417 :
2418 : /*
2419 : * set_returning_clause_references
2420 : * Perform setrefs.c's work on a RETURNING targetlist
2421 : *
2422 : * If the query involves more than just the result table, we have to
2423 : * adjust any Vars that refer to other tables to reference junk tlist
2424 : * entries in the top subplan's targetlist. Vars referencing the result
2425 : * table should be left alone, however (the executor will evaluate them
2426 : * using the actual heap tuple, after firing triggers if any). In the
2427 : * adjusted RETURNING list, result-table Vars will have their original
2428 : * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
2429 : *
2430 : * We also must perform opcode lookup and add regclass OIDs to
2431 : * root->glob->relationOids.
2432 : *
2433 : * 'rlist': the RETURNING targetlist to be fixed
2434 : * 'topplan': the top subplan node that will be just below the ModifyTable
2435 : * node (note it's not yet passed through set_plan_refs)
2436 : * 'resultRelation': RT index of the associated result relation
2437 : * 'rtoffset': how much to increment varnos by
2438 : *
2439 : * Note: the given 'root' is for the parent query level, not the 'topplan'.
2440 : * This does not matter currently since we only access the dependency-item
2441 : * lists in root->glob, but it would need some hacking if we wanted a root
2442 : * that actually matches the subplan.
2443 : *
2444 : * Note: resultRelation is not yet adjusted by rtoffset.
2445 : */
2446 : static List *
2447 221 : set_returning_clause_references(PlannerInfo *root,
2448 : List *rlist,
2449 : Plan *topplan,
2450 : Index resultRelation,
2451 : int rtoffset)
2452 : {
2453 : indexed_tlist *itlist;
2454 :
2455 : /*
2456 : * We can perform the desired Var fixup by abusing the fix_join_expr
2457 : * machinery that formerly handled inner indexscan fixup. We search the
2458 : * top plan's targetlist for Vars of non-result relations, and use
2459 : * fix_join_expr to convert RETURNING Vars into references to those tlist
2460 : * entries, while leaving result-rel Vars as-is.
2461 : *
2462 : * PlaceHolderVars will also be sought in the targetlist, but no
2463 : * more-complex expressions will be. Note that it is not possible for a
2464 : * PlaceHolderVar to refer to the result relation, since the result is
2465 : * never below an outer join. If that case could happen, we'd have to be
2466 : * prepared to pick apart the PlaceHolderVar and evaluate its contained
2467 : * expression instead.
2468 : */
2469 221 : itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
2470 :
2471 221 : rlist = fix_join_expr(root,
2472 : rlist,
2473 : itlist,
2474 : NULL,
2475 : resultRelation,
2476 : rtoffset);
2477 :
2478 221 : pfree(itlist);
2479 :
2480 221 : return rlist;
2481 : }
2482 :
2483 :
2484 : /*****************************************************************************
2485 : * QUERY DEPENDENCY MANAGEMENT
2486 : *****************************************************************************/
2487 :
2488 : /*
2489 : * record_plan_function_dependency
2490 : * Mark the current plan as depending on a particular function.
2491 : *
2492 : * This is exported so that the function-inlining code can record a
2493 : * dependency on a function that it's removed from the plan tree.
2494 : */
2495 : void
2496 50162 : record_plan_function_dependency(PlannerInfo *root, Oid funcid)
2497 : {
2498 : /*
2499 : * For performance reasons, we don't bother to track built-in functions;
2500 : * we just assume they'll never change (or at least not in ways that'd
2501 : * invalidate plans using them). For this purpose we can consider a
2502 : * built-in function to be one with OID less than FirstBootstrapObjectId.
2503 : * Note that the OID generator guarantees never to generate such an OID
2504 : * after startup, even at OID wraparound.
2505 : */
2506 50162 : if (funcid >= (Oid) FirstBootstrapObjectId)
2507 : {
2508 5864 : PlanInvalItem *inval_item = makeNode(PlanInvalItem);
2509 :
2510 : /*
2511 : * It would work to use any syscache on pg_proc, but the easiest is
2512 : * PROCOID since we already have the function's OID at hand. Note
2513 : * that plancache.c knows we use PROCOID.
2514 : */
2515 5864 : inval_item->cacheId = PROCOID;
2516 5864 : inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
2517 : ObjectIdGetDatum(funcid));
2518 :
2519 5864 : root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
2520 : }
2521 50162 : }
2522 :
2523 : /*
2524 : * extract_query_dependencies
2525 : * Given a rewritten, but not yet planned, query or queries
2526 : * (i.e. a Query node or list of Query nodes), extract dependencies
2527 : * just as set_plan_references would do. Also detect whether any
2528 : * rewrite steps were affected by RLS.
2529 : *
2530 : * This is needed by plancache.c to handle invalidation of cached unplanned
2531 : * queries.
2532 : */
2533 : void
2534 2947 : extract_query_dependencies(Node *query,
2535 : List **relationOids,
2536 : List **invalItems,
2537 : bool *hasRowSecurity)
2538 : {
2539 : PlannerGlobal glob;
2540 : PlannerInfo root;
2541 :
2542 : /* Make up dummy planner state so we can use this module's machinery */
2543 2947 : MemSet(&glob, 0, sizeof(glob));
2544 2947 : glob.type = T_PlannerGlobal;
2545 2947 : glob.relationOids = NIL;
2546 2947 : glob.invalItems = NIL;
2547 : /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
2548 2947 : glob.dependsOnRole = false;
2549 :
2550 2947 : MemSet(&root, 0, sizeof(root));
2551 2947 : root.type = T_PlannerInfo;
2552 2947 : root.glob = &glob;
2553 :
2554 2947 : (void) extract_query_dependencies_walker(query, &root);
2555 :
2556 2947 : *relationOids = glob.relationOids;
2557 2947 : *invalItems = glob.invalItems;
2558 2947 : *hasRowSecurity = glob.dependsOnRole;
2559 2947 : }
2560 :
2561 : static bool
2562 62166 : extract_query_dependencies_walker(Node *node, PlannerInfo *context)
2563 : {
2564 62166 : if (node == NULL)
2565 31292 : return false;
2566 30874 : Assert(!IsA(node, PlaceHolderVar));
2567 : /* Extract function dependencies and check for regclass Consts */
2568 30874 : fix_expr_common(context, node);
2569 30874 : if (IsA(node, Query))
2570 : {
2571 3039 : Query *query = (Query *) node;
2572 : ListCell *lc;
2573 :
2574 3039 : if (query->commandType == CMD_UTILITY)
2575 : {
2576 : /*
2577 : * Ignore utility statements, except those (such as EXPLAIN) that
2578 : * contain a parsed-but-not-planned query.
2579 : */
2580 522 : query = UtilityContainsQuery(query->utilityStmt);
2581 522 : if (query == NULL)
2582 19 : return false;
2583 : }
2584 :
2585 : /* Remember if any Query has RLS quals applied by rewriter */
2586 3020 : if (query->hasRowSecurity)
2587 27 : context->glob->dependsOnRole = true;
2588 :
2589 : /* Collect relation OIDs in this Query's rtable */
2590 4282 : foreach(lc, query->rtable)
2591 : {
2592 1262 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2593 :
2594 1262 : if (rte->rtekind == RTE_RELATION)
2595 2148 : context->glob->relationOids =
2596 1074 : lappend_oid(context->glob->relationOids, rte->relid);
2597 231 : else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
2598 43 : OidIsValid(rte->relid))
2599 86 : context->glob->relationOids =
2600 43 : lappend_oid(context->glob->relationOids,
2601 : rte->relid);
2602 : }
2603 :
2604 : /* And recurse into the query's subexpressions */
2605 3020 : return query_tree_walker(query, extract_query_dependencies_walker,
2606 : (void *) context, 0);
2607 : }
2608 27835 : return expression_tree_walker(node, extract_query_dependencies_walker,
2609 : (void *) context);
2610 : }
|