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