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