PostgreSQL Source Code git master
Loading...
Searching...
No Matches
setrefs.c File Reference
#include "postgres.h"
#include "access/transam.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "optimizer/subselect.h"
#include "optimizer/tlist.h"
#include "parser/parse_relation.h"
#include "rewrite/rewriteManip.h"
#include "tcop/utility.h"
#include "utils/syscache.h"
Include dependency graph for setrefs.c:

Go to the source code of this file.

Data Structures

struct  tlist_vinfo
 
struct  indexed_tlist
 
struct  fix_scan_expr_context
 
struct  fix_join_expr_context
 
struct  fix_upper_expr_context
 
struct  fix_windowagg_cond_context
 
struct  flatten_rtes_walker_context
 

Macros

#define NUM_EXEC_TLIST(parentplan)   ((parentplan)->plan_rows)
 
#define NUM_EXEC_QUAL(parentplan)   ((parentplan)->plan_rows * 2.0)
 
#define ISREGCLASSCONST(con)
 
#define fix_scan_list(root, lst, rtoffset, num_exec)    ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))
 

Enumerations

enum  NullingRelsMatch { NRM_EQUAL , NRM_SUPERSET }
 

Functions

static void add_rtes_to_flat_rtable (PlannerInfo *root, bool recursing)
 
static void flatten_unplanned_rtes (PlannerGlobal *glob, RangeTblEntry *rte)
 
static bool flatten_rtes_walker (Node *node, flatten_rtes_walker_context *cxt)
 
static void add_rte_to_flat_rtable (PlannerGlobal *glob, List *rteperminfos, RangeTblEntry *rte)
 
static Planset_plan_refs (PlannerInfo *root, Plan *plan, int rtoffset)
 
static Planset_indexonlyscan_references (PlannerInfo *root, IndexOnlyScan *plan, int rtoffset)
 
static Planset_subqueryscan_references (PlannerInfo *root, SubqueryScan *plan, int rtoffset)
 
static Planclean_up_removed_plan_level (Plan *parent, Plan *child)
 
static void set_foreignscan_references (PlannerInfo *root, ForeignScan *fscan, int rtoffset)
 
static void set_customscan_references (PlannerInfo *root, CustomScan *cscan, int rtoffset)
 
static Planset_append_references (PlannerInfo *root, Append *aplan, int rtoffset)
 
static Planset_mergeappend_references (PlannerInfo *root, MergeAppend *mplan, int rtoffset)
 
static void set_hash_references (PlannerInfo *root, Plan *plan, int rtoffset)
 
static Relids offset_relid_set (Relids relids, int rtoffset)
 
static Nodefix_scan_expr (PlannerInfo *root, Node *node, int rtoffset, double num_exec)
 
static Nodefix_scan_expr_mutator (Node *node, fix_scan_expr_context *context)
 
static bool fix_scan_expr_walker (Node *node, fix_scan_expr_context *context)
 
static void set_join_references (PlannerInfo *root, Join *join, int rtoffset)
 
static void set_upper_references (PlannerInfo *root, Plan *plan, int rtoffset)
 
static void set_param_references (PlannerInfo *root, Plan *plan)
 
static Nodeconvert_combining_aggrefs (Node *node, void *context)
 
static void set_dummy_tlist_references (Plan *plan, int rtoffset)
 
static indexed_tlistbuild_tlist_index (List *tlist)
 
static Varsearch_indexed_tlist_for_var (Var *var, indexed_tlist *itlist, int newvarno, int rtoffset, NullingRelsMatch nrm_match)
 
static Varsearch_indexed_tlist_for_phv (PlaceHolderVar *phv, indexed_tlist *itlist, int newvarno, NullingRelsMatch nrm_match)
 
static Varsearch_indexed_tlist_for_non_var (Expr *node, indexed_tlist *itlist, int newvarno)
 
static Varsearch_indexed_tlist_for_sortgroupref (Expr *node, Index sortgroupref, indexed_tlist *itlist, int newvarno)
 
static Listfix_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)
 
static Nodefix_join_expr_mutator (Node *node, fix_join_expr_context *context)
 
static Nodefix_upper_expr (PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int newvarno, int rtoffset, double num_exec)
 
static Nodefix_upper_expr_mutator (Node *node, fix_upper_expr_context *context)
 
static Listset_returning_clause_references (PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
 
static Listset_windowagg_runcondition_references (PlannerInfo *root, List *runcondition, Plan *plan)
 
static void record_elided_node (PlannerGlobal *glob, int plan_node_id, NodeTag elided_type, Bitmapset *relids)
 
Planset_plan_references (PlannerInfo *root, Plan *plan)
 
bool trivial_subqueryscan (SubqueryScan *plan)
 
static int register_partpruneinfo (PlannerInfo *root, int part_prune_index, int rtoffset)
 
static VarcopyVar (Var *var)
 
static void fix_expr_common (PlannerInfo *root, Node *node)
 
static Nodefix_param_node (PlannerInfo *root, Param *p)
 
static Nodefix_alternative_subplan (PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec)
 
static indexed_tlistbuild_tlist_index_other_vars (List *tlist, int ignore_rel)
 
static Nodefix_windowagg_condition_expr_mutator (Node *node, fix_windowagg_cond_context *context)
 
static Listfix_windowagg_condition_expr (PlannerInfo *root, List *runcondition, indexed_tlist *subplan_itlist)
 
Paramfind_minmax_agg_replacement_param (PlannerInfo *root, Aggref *aggref)
 
void record_plan_function_dependency (PlannerInfo *root, Oid funcid)
 
void record_plan_type_dependency (PlannerInfo *root, Oid typid)
 
void extract_query_dependencies (Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
 
bool extract_query_dependencies_walker (Node *node, PlannerInfo *context)
 

Macro Definition Documentation

◆ fix_scan_list

#define fix_scan_list (   root,
  lst,
  rtoffset,
  num_exec 
)     ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))

Definition at line 128 of file setrefs.c.

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

◆ ISREGCLASSCONST

#define ISREGCLASSCONST (   con)
Value:
(((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
!(con)->constisnull)

Definition at line 124 of file setrefs.c.

◆ NUM_EXEC_QUAL

#define NUM_EXEC_QUAL (   parentplan)    ((parentplan)->plan_rows * 2.0)

Definition at line 115 of file setrefs.c.

◆ NUM_EXEC_TLIST

#define NUM_EXEC_TLIST (   parentplan)    ((parentplan)->plan_rows)

Definition at line 114 of file setrefs.c.

Enumeration Type Documentation

◆ NullingRelsMatch

Enumerator
NRM_EQUAL 
NRM_SUPERSET 

Definition at line 34 of file setrefs.c.

35{
36 NRM_EQUAL, /* expect exact match of nullingrels */
37 NRM_SUPERSET, /* actual Var may have a superset of input */

Function Documentation

◆ add_rte_to_flat_rtable()

static void add_rte_to_flat_rtable ( PlannerGlobal glob,
List rteperminfos,
RangeTblEntry rte 
)
static

Definition at line 562 of file setrefs.c.

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}

References addRTEPermissionInfo(), PlannerGlobal::allRelids, bms_add_member(), fb(), PlannerGlobal::finalrtable, PlannerGlobal::finalrteperminfos, getRTEPermissionInfo(), lappend(), lappend_oid(), list_length(), memcpy(), NIL, OidIsValid, palloc_object, PlannerGlobal::relationOids, RTE_RELATION, and RTE_SUBQUERY.

Referenced by add_rtes_to_flat_rtable(), and flatten_rtes_walker().

◆ add_rtes_to_flat_rtable()

static void add_rtes_to_flat_rtable ( PlannerInfo root,
bool  recursing 
)
static

Definition at line 396 of file setrefs.c.

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}

References add_rte_to_flat_rtable(), add_rtes_to_flat_rtable(), Assert, fb(), fetch_upper_rel(), flatten_unplanned_rtes(), IS_DUMMY_REL, lappend(), lfirst, list_length(), makeNode, NIL, OidIsValid, RelOptInfo::relid, root, RTE_RELATION, RTE_SUBQUERY, RelOptInfo::subroot, and UPPERREL_FINAL.

Referenced by add_rtes_to_flat_rtable(), and set_plan_references().

◆ build_tlist_index()

static indexed_tlist * build_tlist_index ( List tlist)
static

Definition at line 2809 of file setrefs.c.

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}

References fb(), IsA, lfirst, list_length(), palloc(), Var::varattno, and Var::varno.

Referenced by set_customscan_references(), set_foreignscan_references(), set_hash_references(), set_indexonlyscan_references(), set_join_references(), set_plan_refs(), set_upper_references(), and set_windowagg_runcondition_references().

◆ build_tlist_index_other_vars()

static indexed_tlist * build_tlist_index_other_vars ( List tlist,
int  ignore_rel 
)
static

Definition at line 2860 of file setrefs.c.

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}

References fb(), IsA, lfirst, list_length(), palloc(), Var::varattno, and Var::varno.

Referenced by set_returning_clause_references().

◆ clean_up_removed_plan_level()

static Plan * clean_up_removed_plan_level ( Plan parent,
Plan child 
)
static

Definition at line 1592 of file setrefs.c.

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}

References apply_tlist_labeling(), fb(), Plan::initPlan, list_concat(), Plan::parallel_safe, SS_compute_initplan_cost(), Plan::startup_cost, Plan::targetlist, and Plan::total_cost.

Referenced by set_append_references(), set_mergeappend_references(), and set_subqueryscan_references().

◆ convert_combining_aggrefs()

static Node * convert_combining_aggrefs ( Node node,
void context 
)
static

Definition at line 2674 of file setrefs.c.

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}

References AGGSPLIT_FINAL_DESERIAL, AGGSPLIT_INITIAL_SERIAL, Assert, convert_combining_aggrefs(), copyObject, expression_tree_mutator, fb(), IsA, list_make1, makeNode, makeTargetEntry(), mark_partial_aggref(), memcpy(), and NIL.

Referenced by convert_combining_aggrefs(), and set_plan_refs().

◆ copyVar()

static Var * copyVar ( Var var)
inlinestatic

Definition at line 2060 of file setrefs.c.

2061{
2063
2064 *newvar = *var;
2065 return newvar;
2066}

References fb(), and palloc_object.

Referenced by fix_join_expr_mutator(), fix_scan_expr_mutator(), and search_indexed_tlist_for_var().

◆ extract_query_dependencies()

void extract_query_dependencies ( Node query,
List **  relationOids,
List **  invalItems,
bool hasRowSecurity 
)

Definition at line 3680 of file setrefs.c.

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}

References PlannerGlobal::dependsOnRole, extract_query_dependencies_walker(), fb(), PlannerGlobal::invalItems, MemSet, NIL, PlannerGlobal::relationOids, and root.

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 3716 of file setrefs.c.

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}

References Assert, CMD_UTILITY, Query::commandType, PlannerGlobal::dependsOnRole, expression_tree_walker, extract_query_dependencies_walker(), fb(), fix_expr_common(), PlannerInfo::glob, IsA, lappend_oid(), lfirst, OidIsValid, query_tree_walker, PlannerGlobal::relationOids, Query::rtable, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_SUBQUERY, UtilityContainsQuery(), and Query::utilityStmt.

Referenced by expression_planner_with_deps(), extract_query_dependencies(), and extract_query_dependencies_walker().

◆ find_minmax_agg_replacement_param()

Param * find_minmax_agg_replacement_param ( PlannerInfo root,
Aggref aggref 
)

Definition at line 3566 of file setrefs.c.

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}

References Aggref::aggfnoid, Aggref::args, equal(), fb(), lfirst, linitial, list_length(), NIL, MinMaxAggInfo::param, and root.

Referenced by finalize_primnode(), fix_scan_expr_mutator(), and fix_upper_expr_mutator().

◆ fix_alternative_subplan()

static Node * fix_alternative_subplan ( PlannerInfo root,
AlternativeSubPlan asplan,
double  num_exec 
)
static

Definition at line 2208 of file setrefs.c.

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}

References Assert, fb(), lfirst, NIL, root, and SubPlan::startup_cost.

Referenced by fix_join_expr_mutator(), fix_scan_expr_mutator(), and fix_upper_expr_mutator().

◆ fix_expr_common()

static void fix_expr_common ( PlannerInfo root,
Node node 
)
static

Definition at line 2082 of file setrefs.c.

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}

References Assert, DatumGetObjectId(), equal(), fb(), IsA, ISREGCLASSCONST, lappend_int(), lappend_oid(), lfirst_int, NIL, OidIsValid, record_plan_function_dependency(), root, set_opfuncid(), and set_sa_opfuncid().

Referenced by extract_query_dependencies_walker(), fix_join_expr_mutator(), fix_scan_expr_mutator(), fix_scan_expr_walker(), and fix_upper_expr_mutator().

◆ fix_join_expr()

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 
)
static

Definition at line 3149 of file setrefs.c.

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}

References fix_join_expr_context::acceptable_rel, fix_join_expr_mutator(), fix_join_expr_context::inner_itlist, fix_join_expr_context::nrm_match, fix_join_expr_context::num_exec, fix_join_expr_context::outer_itlist, fix_join_expr_context::root, root, and fix_join_expr_context::rtoffset.

Referenced by set_join_references(), set_plan_refs(), and set_returning_clause_references().

◆ fix_join_expr_mutator()

static Node * fix_join_expr_mutator ( Node node,
fix_join_expr_context context 
)
static

Definition at line 3171 of file setrefs.c.

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}

References fix_join_expr_context::acceptable_rel, copyVar(), elog, ERROR, expression_tree_mutator, fb(), fix_alternative_subplan(), fix_expr_common(), fix_join_expr_mutator(), fix_param_node(), indexed_tlist::has_non_vars, indexed_tlist::has_ph_vars, fix_join_expr_context::inner_itlist, INNER_VAR, IsA, fix_join_expr_context::nrm_match, fix_join_expr_context::num_exec, fix_join_expr_context::outer_itlist, OUTER_VAR, fix_join_expr_context::root, fix_join_expr_context::rtoffset, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_phv(), search_indexed_tlist_for_var(), VAR_RETURNING_DEFAULT, Var::varno, and Var::varreturningtype.

Referenced by fix_join_expr(), and fix_join_expr_mutator().

◆ fix_param_node()

static Node * fix_param_node ( PlannerInfo root,
Param p 
)
static

Definition at line 2177 of file setrefs.c.

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}

References copyObject, elog, ERROR, fb(), list_length(), list_nth(), PARAM_MULTIEXPR, Param::paramid, Param::paramkind, and root.

Referenced by fix_join_expr_mutator(), fix_scan_expr_mutator(), and fix_upper_expr_mutator().

◆ fix_scan_expr()

static Node * fix_scan_expr ( PlannerInfo root,
Node node,
int  rtoffset,
double  num_exec 
)
static

Definition at line 2270 of file setrefs.c.

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}

References fb(), fix_scan_expr_mutator(), fix_scan_expr_walker(), NIL, fix_scan_expr_context::num_exec, fix_scan_expr_context::root, root, and fix_scan_expr_context::rtoffset.

Referenced by set_plan_refs().

◆ fix_scan_expr_mutator()

static Node * fix_scan_expr_mutator ( Node node,
fix_scan_expr_context context 
)
static

Definition at line 2305 of file setrefs.c.

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}

References Assert, copyObject, copyVar(), CurrentOfExpr::cvarno, expression_tree_mutator, fb(), find_minmax_agg_replacement_param(), fix_alternative_subplan(), fix_expr_common(), fix_param_node(), fix_scan_expr_mutator(), INNER_VAR, IS_SPECIAL_VARNO, IsA, fix_scan_expr_context::num_exec, OUTER_VAR, fix_scan_expr_context::root, ROWID_VAR, fix_scan_expr_context::rtoffset, Var::varlevelsup, and Var::varno.

Referenced by fix_scan_expr(), and fix_scan_expr_mutator().

◆ fix_scan_expr_walker()

static bool fix_scan_expr_walker ( Node node,
fix_scan_expr_context context 
)
static

Definition at line 2370 of file setrefs.c.

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}

References Assert, expression_tree_walker, fb(), fix_expr_common(), fix_scan_expr_walker(), IsA, fix_scan_expr_context::root, and ROWID_VAR.

Referenced by fix_scan_expr(), and fix_scan_expr_walker().

◆ fix_upper_expr()

static Node * fix_upper_expr ( PlannerInfo root,
Node node,
indexed_tlist subplan_itlist,
int  newvarno,
int  rtoffset,
double  num_exec 
)
static

◆ fix_upper_expr_mutator()

static Node * fix_upper_expr_mutator ( Node node,
fix_upper_expr_context context 
)
static

Definition at line 3343 of file setrefs.c.

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}

References copyObject, elog, ERROR, expression_tree_mutator, fb(), find_minmax_agg_replacement_param(), fix_alternative_subplan(), fix_expr_common(), fix_param_node(), fix_upper_expr_mutator(), indexed_tlist::has_non_vars, indexed_tlist::has_ph_vars, IsA, fix_upper_expr_context::newvarno, NRM_EQUAL, fix_upper_expr_context::num_exec, fix_upper_expr_context::root, fix_upper_expr_context::rtoffset, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_phv(), search_indexed_tlist_for_var(), and fix_upper_expr_context::subplan_itlist.

Referenced by fix_upper_expr(), and fix_upper_expr_mutator().

◆ fix_windowagg_condition_expr()

static List * fix_windowagg_condition_expr ( PlannerInfo root,
List runcondition,
indexed_tlist subplan_itlist 
)
static

Definition at line 3518 of file setrefs.c.

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}

References fix_windowagg_condition_expr_mutator(), fix_windowagg_cond_context::newvarno, fix_windowagg_cond_context::root, root, and fix_windowagg_cond_context::subplan_itlist.

Referenced by set_windowagg_runcondition_references().

◆ fix_windowagg_condition_expr_mutator()

static Node * fix_windowagg_condition_expr_mutator ( Node node,
fix_windowagg_cond_context context 
)
static

Definition at line 3488 of file setrefs.c.

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}

References elog, ERROR, expression_tree_mutator, fb(), fix_windowagg_condition_expr_mutator(), IsA, fix_windowagg_cond_context::newvarno, search_indexed_tlist_for_non_var(), and fix_windowagg_cond_context::subplan_itlist.

Referenced by fix_windowagg_condition_expr(), and fix_windowagg_condition_expr_mutator().

◆ flatten_rtes_walker()

static bool flatten_rtes_walker ( Node node,
flatten_rtes_walker_context cxt 
)
static

Definition at line 517 of file setrefs.c.

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}

References add_rte_to_flat_rtable(), expression_tree_walker, fb(), flatten_rtes_walker(), flatten_rtes_walker_context::glob, IsA, OidIsValid, QTW_EXAMINE_RTES_BEFORE, flatten_rtes_walker_context::query, query_tree_walker, result, RTE_RELATION, and RTE_SUBQUERY.

Referenced by flatten_rtes_walker(), and flatten_unplanned_rtes().

◆ flatten_unplanned_rtes()

static void flatten_unplanned_rtes ( PlannerGlobal glob,
RangeTblEntry rte 
)
static

Definition at line 505 of file setrefs.c.

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}

References fb(), flatten_rtes_walker(), QTW_EXAMINE_RTES_BEFORE, and query_tree_walker.

Referenced by add_rtes_to_flat_rtable().

◆ offset_relid_set()

static Relids offset_relid_set ( Relids  relids,
int  rtoffset 
)
static

Definition at line 2044 of file setrefs.c.

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}

References bms_offset_members().

Referenced by register_partpruneinfo(), set_append_references(), set_customscan_references(), set_foreignscan_references(), set_mergeappend_references(), and set_plan_refs().

◆ record_elided_node()

static void record_elided_node ( PlannerGlobal glob,
int  plan_node_id,
NodeTag  elided_type,
Bitmapset relids 
)
static

Definition at line 3788 of file setrefs.c.

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}

References ElidedNode::elided_type, PlannerGlobal::elidedNodes, lappend(), makeNode, ElidedNode::plan_node_id, and ElidedNode::relids.

Referenced by set_append_references(), set_mergeappend_references(), and set_subqueryscan_references().

◆ record_plan_function_dependency()

void record_plan_function_dependency ( PlannerInfo root,
Oid  funcid 
)

Definition at line 3599 of file setrefs.c.

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}

References fb(), FirstUnpinnedObjectId, GetSysCacheHashValue1, lappend(), makeNode, ObjectIdGetDatum(), and root.

Referenced by fix_expr_common(), inline_function(), and inline_function_in_from().

◆ record_plan_type_dependency()

void record_plan_type_dependency ( PlannerInfo root,
Oid  typid 
)

Definition at line 3639 of file setrefs.c.

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}

References fb(), FirstUnpinnedObjectId, GetSysCacheHashValue1, lappend(), makeNode, ObjectIdGetDatum(), and root.

Referenced by eval_const_expressions_mutator().

◆ register_partpruneinfo()

static int register_partpruneinfo ( PlannerInfo root,
int  part_prune_index,
int  rtoffset 
)
static

Definition at line 1799 of file setrefs.c.

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}

References Assert, bms_add_member(), fb(), fix_scan_list, i, lappend(), lfirst, list_length(), list_nth_node, offset_relid_set(), PlannerGlobal::partPruneInfos, PlannerGlobal::prunableRelids, PartitionPruneInfo::prune_infos, PartitionPruneInfo::relids, and root.

Referenced by set_append_references(), and set_mergeappend_references().

◆ search_indexed_tlist_for_non_var()

static Var * search_indexed_tlist_for_non_var ( Expr node,
indexed_tlist itlist,
int  newvarno 
)
static

Definition at line 3031 of file setrefs.c.

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}

References fb(), IsA, makeVarFromTargetEntry(), and tlist_member().

Referenced by fix_join_expr_mutator(), fix_upper_expr_mutator(), and fix_windowagg_condition_expr_mutator().

◆ search_indexed_tlist_for_phv()

static Var * search_indexed_tlist_for_phv ( PlaceHolderVar phv,
indexed_tlist itlist,
int  newvarno,
NullingRelsMatch  nrm_match 
)
static

Definition at line 2980 of file setrefs.c.

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}

References bms_equal(), bms_is_subset(), bmsToString(), elog, ERROR, fb(), IsA, lfirst, makeVarFromTargetEntry(), and NRM_SUPERSET.

Referenced by fix_join_expr_mutator(), and fix_upper_expr_mutator().

◆ search_indexed_tlist_for_sortgroupref()

static Var * search_indexed_tlist_for_sortgroupref ( Expr node,
Index  sortgroupref,
indexed_tlist itlist,
int  newvarno 
)
static

Definition at line 3071 of file setrefs.c.

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}

References equal(), fb(), lfirst, and makeVarFromTargetEntry().

Referenced by set_upper_references().

◆ search_indexed_tlist_for_var()

static Var * search_indexed_tlist_for_var ( Var var,
indexed_tlist itlist,
int  newvarno,
int  rtoffset,
NullingRelsMatch  nrm_match 
)
static

Definition at line 2917 of file setrefs.c.

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}

References bms_equal(), bms_is_subset(), bmsToString(), copyVar(), elog, ERROR, fb(), i, NRM_SUPERSET, Var::varattno, and Var::varno.

Referenced by fix_join_expr_mutator(), and fix_upper_expr_mutator().

◆ set_append_references()

static Plan * set_append_references ( PlannerInfo root,
Append aplan,
int  rtoffset 
)
static

Definition at line 1860 of file setrefs.c.

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}

References Assert, clean_up_removed_plan_level(), fb(), lfirst, linitial, list_length(), NIL, offset_relid_set(), Plan::parallel_aware, Plan::plan_node_id, record_elided_node(), register_partpruneinfo(), result, root, set_dummy_tlist_references(), and set_plan_refs().

Referenced by set_plan_refs().

◆ set_customscan_references()

static void set_customscan_references ( PlannerInfo root,
CustomScan cscan,
int  rtoffset 
)
static

Definition at line 1719 of file setrefs.c.

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}

References build_tlist_index(), fb(), fix_scan_list, fix_upper_expr(), INDEX_VAR, lfirst, NIL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, offset_relid_set(), pfree(), root, and set_plan_refs().

Referenced by set_plan_refs().

◆ set_dummy_tlist_references()

static void set_dummy_tlist_references ( Plan plan,
int  rtoffset 
)
static

Definition at line 2742 of file setrefs.c.

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}

References exprCollation(), exprType(), exprTypmod(), fb(), flatCopyTargetEntry(), IsA, lappend(), lfirst, makeVar(), NIL, OUTER_VAR, and plan.

Referenced by set_append_references(), set_hash_references(), set_mergeappend_references(), and set_plan_refs().

◆ set_foreignscan_references()

static void set_foreignscan_references ( PlannerInfo root,
ForeignScan fscan,
int  rtoffset 
)
static

Definition at line 1636 of file setrefs.c.

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}

References build_tlist_index(), fb(), fix_scan_list, fix_upper_expr(), INDEX_VAR, NIL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, offset_relid_set(), pfree(), and root.

Referenced by set_plan_refs().

◆ set_hash_references()

static void set_hash_references ( PlannerInfo root,
Plan plan,
int  rtoffset 
)
static

Definition at line 2012 of file setrefs.c.

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}

References Assert, build_tlist_index(), fb(), fix_upper_expr(), Plan::lefttree, NIL, NUM_EXEC_QUAL, OUTER_VAR, plan, root, set_dummy_tlist_references(), and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_indexonlyscan_references()

static Plan * set_indexonlyscan_references ( PlannerInfo root,
IndexOnlyScan plan,
int  rtoffset 
)
static

Definition at line 1375 of file setrefs.c.

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}

References build_tlist_index(), fb(), fix_scan_list, fix_upper_expr(), INDEX_VAR, lappend(), lfirst, NIL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, pfree(), plan, and root.

Referenced by set_plan_refs().

◆ set_join_references()

static void set_join_references ( PlannerInfo root,
Join join,
int  rtoffset 
)
static

Definition at line 2390 of file setrefs.c.

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
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
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}

References bms_is_empty, build_tlist_index(), elog, ERROR, fb(), fix_join_expr(), fix_upper_expr(), IsA, Join::joinqual, lfirst, NRM_EQUAL, NRM_SUPERSET, NUM_EXEC_QUAL, NUM_EXEC_TLIST, Join::ojrelids, OUTER_VAR, NestLoopParam::paramval, pfree(), root, and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_mergeappend_references()

static Plan * set_mergeappend_references ( PlannerInfo root,
MergeAppend mplan,
int  rtoffset 
)
static

Definition at line 1937 of file setrefs.c.

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}

References Assert, clean_up_removed_plan_level(), fb(), lfirst, linitial, list_length(), NIL, offset_relid_set(), Plan::parallel_aware, Plan::plan_node_id, record_elided_node(), register_partpruneinfo(), result, root, set_dummy_tlist_references(), and set_plan_refs().

Referenced by set_plan_refs().

◆ set_param_references()

static void set_param_references ( PlannerInfo root,
Plan plan 
)
static

Definition at line 2619 of file setrefs.c.

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}

References Assert, bms_add_member(), bms_intersect(), fb(), IsA, lfirst, lfirst_int, plan, and root.

Referenced by set_plan_refs().

◆ set_plan_references()

Plan * set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 288 of file setrefs.c.

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}

References add_rtes_to_flat_rtable(), PlannerGlobal::appendRelations, Assert, fb(), PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, foreach_current_index, lappend(), lfirst, lfirst_node, list_length(), memcpy(), NIL, palloc0(), palloc_object, plan, result, root, PlanRowMark::rti, set_plan_refs(), and PlannerGlobal::subplans.

Referenced by set_subqueryscan_references(), and standard_planner().

◆ set_plan_refs()

static Plan * set_plan_refs ( PlannerInfo root,
Plan plan,
int  rtoffset 
)
static

Definition at line 639 of file setrefs.c.

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 {
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}

References Assert, build_tlist_index(), convert_combining_aggrefs(), copyObject, DO_AGGSPLIT_COMBINE, elog, ERROR, fb(), fix_join_expr(), fix_scan_expr(), fix_scan_list, forboth, forthree, IsA, lappend(), lappend_int(), lca(), lfirst, lfirst_int, linitial, linitial_int, list_concat(), list_length(), makeNullConst(), makeVar(), NIL, nodeTag, NRM_EQUAL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, offset_relid_set(), ONCONFLICT_SELECT, ONCONFLICT_UPDATE, outerPlan, pfree(), plan, PlanRowMark::prti, root, ROWID_VAR, PlanRowMark::rti, WindowAgg::runCondition, SeqScan::scan, SampleScan::scan, IndexScan::scan, BitmapIndexScan::scan, BitmapHeapScan::scan, TidScan::scan, TidRangeScan::scan, FunctionScan::scan, ValuesScan::scan, TableFuncScan::scan, CteScan::scan, NamedTuplestoreScan::scan, WorkTableScan::scan, Scan::scanrelid, set_append_references(), set_customscan_references(), set_dummy_tlist_references(), set_foreignscan_references(), set_hash_references(), set_indexonlyscan_references(), set_join_references(), set_mergeappend_references(), set_param_references(), set_plan_refs(), set_returning_clause_references(), set_subqueryscan_references(), set_upper_references(), set_windowagg_runcondition_references(), Plan::targetlist, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by set_append_references(), set_customscan_references(), set_mergeappend_references(), set_plan_references(), and set_plan_refs().

◆ set_returning_clause_references()

static List * set_returning_clause_references ( PlannerInfo root,
List rlist,
Plan topplan,
Index  resultRelation,
int  rtoffset 
)
static

Definition at line 3444 of file setrefs.c.

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}

References build_tlist_index_other_vars(), fb(), fix_join_expr(), NRM_EQUAL, NUM_EXEC_TLIST, pfree(), and root.

Referenced by set_plan_refs().

◆ set_subqueryscan_references()

static Plan * set_subqueryscan_references ( PlannerInfo root,
SubqueryScan plan,
int  rtoffset 
)
static

Definition at line 1446 of file setrefs.c.

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}

References bms_make_singleton(), clean_up_removed_plan_level(), fb(), find_base_rel(), fix_scan_list, NUM_EXEC_QUAL, NUM_EXEC_TLIST, plan, record_elided_node(), result, root, set_plan_references(), RelOptInfo::subroot, and trivial_subqueryscan().

Referenced by set_plan_refs().

◆ set_upper_references()

static void set_upper_references ( PlannerInfo root,
Plan plan,
int  rtoffset 
)
static

Definition at line 2534 of file setrefs.c.

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}

References bms_make_singleton(), build_tlist_index(), fb(), fix_upper_expr(), flatCopyTargetEntry(), IsA, lappend(), Plan::lefttree, lfirst, NIL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, OUTER_VAR, pfree(), plan, remove_nulling_relids(), root, search_indexed_tlist_for_sortgroupref(), and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_windowagg_runcondition_references()

static List * set_windowagg_runcondition_references ( PlannerInfo root,
List runcondition,
Plan plan 
)
static

Definition at line 3539 of file setrefs.c.

3542{
3543 List *newlist;
3545
3546 itlist = build_tlist_index(plan->targetlist);
3547
3549
3550 pfree(itlist);
3551
3552 return newlist;
3553}

References build_tlist_index(), fb(), fix_windowagg_condition_expr(), pfree(), plan, and root.

Referenced by set_plan_refs().

◆ trivial_subqueryscan()

bool trivial_subqueryscan ( SubqueryScan plan)

Definition at line 1522 of file setrefs.c.

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}

References Assert, equal(), fb(), forboth, IsA, lfirst, list_length(), NIL, plan, SUBQUERY_SCAN_NONTRIVIAL, SUBQUERY_SCAN_TRIVIAL, SUBQUERY_SCAN_UNKNOWN, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by mark_async_capable_plan(), and set_subqueryscan_references().