LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - relnode.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 772 803 96.1 %
Date: 2025-08-19 18:18:19 Functions: 30 30 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * relnode.c
       4             :  *    Relation-node lookup/construction routines
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/optimizer/util/relnode.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include <limits.h>
      18             : 
      19             : #include "miscadmin.h"
      20             : #include "nodes/nodeFuncs.h"
      21             : #include "optimizer/appendinfo.h"
      22             : #include "optimizer/clauses.h"
      23             : #include "optimizer/cost.h"
      24             : #include "optimizer/inherit.h"
      25             : #include "optimizer/optimizer.h"
      26             : #include "optimizer/pathnode.h"
      27             : #include "optimizer/paths.h"
      28             : #include "optimizer/placeholder.h"
      29             : #include "optimizer/plancat.h"
      30             : #include "optimizer/restrictinfo.h"
      31             : #include "optimizer/tlist.h"
      32             : #include "parser/parse_relation.h"
      33             : #include "rewrite/rewriteManip.h"
      34             : #include "utils/hsearch.h"
      35             : #include "utils/lsyscache.h"
      36             : 
      37             : 
      38             : typedef struct JoinHashEntry
      39             : {
      40             :     Relids      join_relids;    /* hash key --- MUST BE FIRST */
      41             :     RelOptInfo *join_rel;
      42             : } JoinHashEntry;
      43             : 
      44             : static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
      45             :                                 RelOptInfo *input_rel,
      46             :                                 SpecialJoinInfo *sjinfo,
      47             :                                 List *pushed_down_joins,
      48             :                                 bool can_null);
      49             : static List *build_joinrel_restrictlist(PlannerInfo *root,
      50             :                                         RelOptInfo *joinrel,
      51             :                                         RelOptInfo *outer_rel,
      52             :                                         RelOptInfo *inner_rel,
      53             :                                         SpecialJoinInfo *sjinfo);
      54             : static void build_joinrel_joinlist(RelOptInfo *joinrel,
      55             :                                    RelOptInfo *outer_rel,
      56             :                                    RelOptInfo *inner_rel);
      57             : static List *subbuild_joinrel_restrictlist(PlannerInfo *root,
      58             :                                            RelOptInfo *joinrel,
      59             :                                            RelOptInfo *input_rel,
      60             :                                            Relids both_input_relids,
      61             :                                            List *new_restrictlist);
      62             : static List *subbuild_joinrel_joinlist(RelOptInfo *joinrel,
      63             :                                        List *joininfo_list,
      64             :                                        List *new_joininfo);
      65             : static void set_foreign_rel_properties(RelOptInfo *joinrel,
      66             :                                        RelOptInfo *outer_rel, RelOptInfo *inner_rel);
      67             : static void add_join_rel(PlannerInfo *root, RelOptInfo *joinrel);
      68             : static void build_joinrel_partition_info(PlannerInfo *root,
      69             :                                          RelOptInfo *joinrel,
      70             :                                          RelOptInfo *outer_rel, RelOptInfo *inner_rel,
      71             :                                          SpecialJoinInfo *sjinfo,
      72             :                                          List *restrictlist);
      73             : static bool have_partkey_equi_join(PlannerInfo *root, RelOptInfo *joinrel,
      74             :                                    RelOptInfo *rel1, RelOptInfo *rel2,
      75             :                                    JoinType jointype, List *restrictlist);
      76             : static int  match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel,
      77             :                                          bool strict_op);
      78             : static void set_joinrel_partition_key_exprs(RelOptInfo *joinrel,
      79             :                                             RelOptInfo *outer_rel, RelOptInfo *inner_rel,
      80             :                                             JoinType jointype);
      81             : static void build_child_join_reltarget(PlannerInfo *root,
      82             :                                        RelOptInfo *parentrel,
      83             :                                        RelOptInfo *childrel,
      84             :                                        int nappinfos,
      85             :                                        AppendRelInfo **appinfos);
      86             : 
      87             : 
      88             : /*
      89             :  * setup_simple_rel_arrays
      90             :  *    Prepare the arrays we use for quickly accessing base relations
      91             :  *    and AppendRelInfos.
      92             :  */
      93             : void
      94      549062 : setup_simple_rel_arrays(PlannerInfo *root)
      95             : {
      96             :     int         size;
      97             :     Index       rti;
      98             :     ListCell   *lc;
      99             : 
     100             :     /* Arrays are accessed using RT indexes (1..N) */
     101      549062 :     size = list_length(root->parse->rtable) + 1;
     102      549062 :     root->simple_rel_array_size = size;
     103             : 
     104             :     /*
     105             :      * simple_rel_array is initialized to all NULLs, since no RelOptInfos
     106             :      * exist yet.  It'll be filled by later calls to build_simple_rel().
     107             :      */
     108      549062 :     root->simple_rel_array = (RelOptInfo **)
     109      549062 :         palloc0(size * sizeof(RelOptInfo *));
     110             : 
     111             :     /* simple_rte_array is an array equivalent of the rtable list */
     112      549062 :     root->simple_rte_array = (RangeTblEntry **)
     113      549062 :         palloc0(size * sizeof(RangeTblEntry *));
     114      549062 :     rti = 1;
     115     1463244 :     foreach(lc, root->parse->rtable)
     116             :     {
     117      914182 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
     118             : 
     119      914182 :         root->simple_rte_array[rti++] = rte;
     120             :     }
     121             : 
     122             :     /* append_rel_array is not needed if there are no AppendRelInfos */
     123      549062 :     if (root->append_rel_list == NIL)
     124             :     {
     125      544422 :         root->append_rel_array = NULL;
     126      544422 :         return;
     127             :     }
     128             : 
     129        4640 :     root->append_rel_array = (AppendRelInfo **)
     130        4640 :         palloc0(size * sizeof(AppendRelInfo *));
     131             : 
     132             :     /*
     133             :      * append_rel_array is filled with any already-existing AppendRelInfos,
     134             :      * which currently could only come from UNION ALL flattening.  We might
     135             :      * add more later during inheritance expansion, but it's the
     136             :      * responsibility of the expansion code to update the array properly.
     137             :      */
     138       15008 :     foreach(lc, root->append_rel_list)
     139             :     {
     140       10368 :         AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
     141       10368 :         int         child_relid = appinfo->child_relid;
     142             : 
     143             :         /* Sanity check */
     144             :         Assert(child_relid < size);
     145             : 
     146       10368 :         if (root->append_rel_array[child_relid])
     147           0 :             elog(ERROR, "child relation already exists");
     148             : 
     149       10368 :         root->append_rel_array[child_relid] = appinfo;
     150             :     }
     151             : }
     152             : 
     153             : /*
     154             :  * expand_planner_arrays
     155             :  *      Expand the PlannerInfo's per-RTE arrays by add_size members
     156             :  *      and initialize the newly added entries to NULLs
     157             :  *
     158             :  * Note: this causes the append_rel_array to become allocated even if
     159             :  * it was not before.  This is okay for current uses, because we only call
     160             :  * this when adding child relations, which always have AppendRelInfos.
     161             :  */
     162             : void
     163       19412 : expand_planner_arrays(PlannerInfo *root, int add_size)
     164             : {
     165             :     int         new_size;
     166             : 
     167             :     Assert(add_size > 0);
     168             : 
     169       19412 :     new_size = root->simple_rel_array_size + add_size;
     170             : 
     171       19412 :     root->simple_rel_array =
     172       19412 :         repalloc0_array(root->simple_rel_array, RelOptInfo *, root->simple_rel_array_size, new_size);
     173             : 
     174       19412 :     root->simple_rte_array =
     175       19412 :         repalloc0_array(root->simple_rte_array, RangeTblEntry *, root->simple_rel_array_size, new_size);
     176             : 
     177       19412 :     if (root->append_rel_array)
     178        5452 :         root->append_rel_array =
     179        5452 :             repalloc0_array(root->append_rel_array, AppendRelInfo *, root->simple_rel_array_size, new_size);
     180             :     else
     181       13960 :         root->append_rel_array =
     182       13960 :             palloc0_array(AppendRelInfo *, new_size);
     183             : 
     184       19412 :     root->simple_rel_array_size = new_size;
     185       19412 : }
     186             : 
     187             : /*
     188             :  * build_simple_rel
     189             :  *    Construct a new RelOptInfo for a base relation or 'other' relation.
     190             :  */
     191             : RelOptInfo *
     192      751372 : build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
     193             : {
     194             :     RelOptInfo *rel;
     195             :     RangeTblEntry *rte;
     196             : 
     197             :     /* Rel should not exist already */
     198             :     Assert(relid > 0 && relid < root->simple_rel_array_size);
     199      751372 :     if (root->simple_rel_array[relid] != NULL)
     200           0 :         elog(ERROR, "rel %d already exists", relid);
     201             : 
     202             :     /* Fetch RTE for relation */
     203      751372 :     rte = root->simple_rte_array[relid];
     204             :     Assert(rte != NULL);
     205             : 
     206      751372 :     rel = makeNode(RelOptInfo);
     207      751372 :     rel->reloptkind = parent ? RELOPT_OTHER_MEMBER_REL : RELOPT_BASEREL;
     208      751372 :     rel->relids = bms_make_singleton(relid);
     209      751372 :     rel->rows = 0;
     210             :     /* cheap startup cost is interesting iff not all tuples to be retrieved */
     211      751372 :     rel->consider_startup = (root->tuple_fraction > 0);
     212      751372 :     rel->consider_param_startup = false; /* might get changed later */
     213      751372 :     rel->consider_parallel = false; /* might get changed later */
     214      751372 :     rel->reltarget = create_empty_pathtarget();
     215      751372 :     rel->pathlist = NIL;
     216      751372 :     rel->ppilist = NIL;
     217      751372 :     rel->partial_pathlist = NIL;
     218      751372 :     rel->cheapest_startup_path = NULL;
     219      751372 :     rel->cheapest_total_path = NULL;
     220      751372 :     rel->cheapest_parameterized_paths = NIL;
     221      751372 :     rel->relid = relid;
     222      751372 :     rel->rtekind = rte->rtekind;
     223             :     /* min_attr, max_attr, attr_needed, attr_widths are set below */
     224      751372 :     rel->notnullattnums = NULL;
     225      751372 :     rel->lateral_vars = NIL;
     226      751372 :     rel->indexlist = NIL;
     227      751372 :     rel->statlist = NIL;
     228      751372 :     rel->pages = 0;
     229      751372 :     rel->tuples = 0;
     230      751372 :     rel->allvisfrac = 0;
     231      751372 :     rel->eclass_indexes = NULL;
     232      751372 :     rel->subroot = NULL;
     233      751372 :     rel->subplan_params = NIL;
     234      751372 :     rel->rel_parallel_workers = -1; /* set up in get_relation_info */
     235      751372 :     rel->amflags = 0;
     236      751372 :     rel->serverid = InvalidOid;
     237      751372 :     if (rte->rtekind == RTE_RELATION)
     238             :     {
     239             :         Assert(parent == NULL ||
     240             :                parent->rtekind == RTE_RELATION ||
     241             :                parent->rtekind == RTE_SUBQUERY);
     242             : 
     243             :         /*
     244             :          * For any RELATION rte, we need a userid with which to check
     245             :          * permission access. Baserels simply use their own
     246             :          * RTEPermissionInfo's checkAsUser.
     247             :          *
     248             :          * For otherrels normally there's no RTEPermissionInfo, so we use the
     249             :          * parent's, which normally has one. The exceptional case is that the
     250             :          * parent is a subquery, in which case the otherrel will have its own.
     251             :          */
     252      458412 :         if (rel->reloptkind == RELOPT_BASEREL ||
     253       41770 :             (rel->reloptkind == RELOPT_OTHER_MEMBER_REL &&
     254       41770 :              parent->rtekind == RTE_SUBQUERY))
     255      417752 :         {
     256             :             RTEPermissionInfo *perminfo;
     257             : 
     258      417752 :             perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
     259      417752 :             rel->userid = perminfo->checkAsUser;
     260             :         }
     261             :         else
     262       40660 :             rel->userid = parent->userid;
     263             :     }
     264             :     else
     265      292960 :         rel->userid = InvalidOid;
     266      751372 :     rel->useridiscurrent = false;
     267      751372 :     rel->fdwroutine = NULL;
     268      751372 :     rel->fdw_private = NULL;
     269      751372 :     rel->unique_for_rels = NIL;
     270      751372 :     rel->non_unique_for_rels = NIL;
     271      751372 :     rel->unique_rel = NULL;
     272      751372 :     rel->unique_pathkeys = NIL;
     273      751372 :     rel->unique_groupclause = NIL;
     274      751372 :     rel->baserestrictinfo = NIL;
     275      751372 :     rel->baserestrictcost.startup = 0;
     276      751372 :     rel->baserestrictcost.per_tuple = 0;
     277      751372 :     rel->baserestrict_min_security = UINT_MAX;
     278      751372 :     rel->joininfo = NIL;
     279      751372 :     rel->has_eclass_joins = false;
     280      751372 :     rel->consider_partitionwise_join = false;    /* might get changed later */
     281      751372 :     rel->part_scheme = NULL;
     282      751372 :     rel->nparts = -1;
     283      751372 :     rel->boundinfo = NULL;
     284      751372 :     rel->partbounds_merged = false;
     285      751372 :     rel->partition_qual = NIL;
     286      751372 :     rel->part_rels = NULL;
     287      751372 :     rel->live_parts = NULL;
     288      751372 :     rel->all_partrels = NULL;
     289      751372 :     rel->partexprs = NULL;
     290      751372 :     rel->nullable_partexprs = NULL;
     291             : 
     292             :     /*
     293             :      * Pass assorted information down the inheritance hierarchy.
     294             :      */
     295      751372 :     if (parent)
     296             :     {
     297             :         /* We keep back-links to immediate parent and topmost parent. */
     298       51028 :         rel->parent = parent;
     299       51028 :         rel->top_parent = parent->top_parent ? parent->top_parent : parent;
     300       51028 :         rel->top_parent_relids = rel->top_parent->relids;
     301             : 
     302             :         /*
     303             :          * A child rel is below the same outer joins as its parent.  (We
     304             :          * presume this info was already calculated for the parent.)
     305             :          */
     306       51028 :         rel->nulling_relids = parent->nulling_relids;
     307             : 
     308             :         /*
     309             :          * Also propagate lateral-reference information from appendrel parent
     310             :          * rels to their child rels.  We intentionally give each child rel the
     311             :          * same minimum parameterization, even though it's quite possible that
     312             :          * some don't reference all the lateral rels.  This is because any
     313             :          * append path for the parent will have to have the same
     314             :          * parameterization for every child anyway, and there's no value in
     315             :          * forcing extra reparameterize_path() calls.  Similarly, a lateral
     316             :          * reference to the parent prevents use of otherwise-movable join rels
     317             :          * for each child.
     318             :          *
     319             :          * It's possible for child rels to have their own children, in which
     320             :          * case the topmost parent's lateral info propagates all the way down.
     321             :          */
     322       51028 :         rel->direct_lateral_relids = parent->direct_lateral_relids;
     323       51028 :         rel->lateral_relids = parent->lateral_relids;
     324       51028 :         rel->lateral_referencers = parent->lateral_referencers;
     325             :     }
     326             :     else
     327             :     {
     328      700344 :         rel->parent = NULL;
     329      700344 :         rel->top_parent = NULL;
     330      700344 :         rel->top_parent_relids = NULL;
     331      700344 :         rel->nulling_relids = NULL;
     332      700344 :         rel->direct_lateral_relids = NULL;
     333      700344 :         rel->lateral_relids = NULL;
     334      700344 :         rel->lateral_referencers = NULL;
     335             :     }
     336             : 
     337             :     /* Check type of rtable entry */
     338      751372 :     switch (rte->rtekind)
     339             :     {
     340      458412 :         case RTE_RELATION:
     341             :             /* Table --- retrieve statistics from the system catalogs */
     342      458412 :             get_relation_info(root, rte->relid, rte->inh, rel);
     343      458394 :             break;
     344       97700 :         case RTE_SUBQUERY:
     345             :         case RTE_FUNCTION:
     346             :         case RTE_TABLEFUNC:
     347             :         case RTE_VALUES:
     348             :         case RTE_CTE:
     349             :         case RTE_NAMEDTUPLESTORE:
     350             : 
     351             :             /*
     352             :              * Subquery, function, tablefunc, values list, CTE, or ENR --- set
     353             :              * up attr range and arrays
     354             :              *
     355             :              * Note: 0 is included in range to support whole-row Vars
     356             :              */
     357       97700 :             rel->min_attr = 0;
     358       97700 :             rel->max_attr = list_length(rte->eref->colnames);
     359       97700 :             rel->attr_needed = (Relids *)
     360       97700 :                 palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
     361       97700 :             rel->attr_widths = (int32 *)
     362       97700 :                 palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
     363       97700 :             break;
     364      195260 :         case RTE_RESULT:
     365             :             /* RTE_RESULT has no columns, nor could it have whole-row Var */
     366      195260 :             rel->min_attr = 0;
     367      195260 :             rel->max_attr = -1;
     368      195260 :             rel->attr_needed = NULL;
     369      195260 :             rel->attr_widths = NULL;
     370      195260 :             break;
     371           0 :         default:
     372           0 :             elog(ERROR, "unrecognized RTE kind: %d",
     373             :                  (int) rte->rtekind);
     374             :             break;
     375             :     }
     376             : 
     377             :     /*
     378             :      * We must apply the partially filled in RelOptInfo before calling
     379             :      * apply_child_basequals due to some transformations within that function
     380             :      * which require the RelOptInfo to be available in the simple_rel_array.
     381             :      */
     382      751354 :     root->simple_rel_array[relid] = rel;
     383             : 
     384             :     /*
     385             :      * Apply the parent's quals to the child, with appropriate substitution of
     386             :      * variables.  If the resulting clause is constant-FALSE or NULL after
     387             :      * applying transformations, apply_child_basequals returns false to
     388             :      * indicate that scanning this relation won't yield any rows.  In this
     389             :      * case, we mark the child as dummy right away.  (We must do this
     390             :      * immediately so that pruning works correctly when recursing in
     391             :      * expand_partitioned_rtentry.)
     392             :      */
     393      751354 :     if (parent)
     394             :     {
     395       51028 :         AppendRelInfo *appinfo = root->append_rel_array[relid];
     396             : 
     397             :         Assert(appinfo != NULL);
     398       51028 :         if (!apply_child_basequals(root, parent, rel, rte, appinfo))
     399             :         {
     400             :             /*
     401             :              * Restriction clause reduced to constant FALSE or NULL.  Mark as
     402             :              * dummy so we won't scan this relation.
     403             :              */
     404          90 :             mark_dummy_rel(rel);
     405             :         }
     406             :     }
     407             : 
     408      751354 :     return rel;
     409             : }
     410             : 
     411             : /*
     412             :  * find_base_rel
     413             :  *    Find a base or otherrel relation entry, which must already exist.
     414             :  */
     415             : RelOptInfo *
     416     6586552 : find_base_rel(PlannerInfo *root, int relid)
     417             : {
     418             :     RelOptInfo *rel;
     419             : 
     420             :     /* use an unsigned comparison to prevent negative array element access */
     421     6586552 :     if ((uint32) relid < (uint32) root->simple_rel_array_size)
     422             :     {
     423     6586552 :         rel = root->simple_rel_array[relid];
     424     6586552 :         if (rel)
     425     6586552 :             return rel;
     426             :     }
     427             : 
     428           0 :     elog(ERROR, "no relation entry for relid %d", relid);
     429             : 
     430             :     return NULL;                /* keep compiler quiet */
     431             : }
     432             : 
     433             : /*
     434             :  * find_base_rel_noerr
     435             :  *    Find a base or otherrel relation entry, returning NULL if there's none
     436             :  */
     437             : RelOptInfo *
     438     1475324 : find_base_rel_noerr(PlannerInfo *root, int relid)
     439             : {
     440             :     /* use an unsigned comparison to prevent negative array element access */
     441     1475324 :     if ((uint32) relid < (uint32) root->simple_rel_array_size)
     442     1475324 :         return root->simple_rel_array[relid];
     443           0 :     return NULL;
     444             : }
     445             : 
     446             : /*
     447             :  * find_base_rel_ignore_join
     448             :  *    Find a base or otherrel relation entry, which must already exist.
     449             :  *
     450             :  * Unlike find_base_rel, if relid references an outer join then this
     451             :  * will return NULL rather than raising an error.  This is convenient
     452             :  * for callers that must deal with relid sets including both base and
     453             :  * outer joins.
     454             :  */
     455             : RelOptInfo *
     456      180752 : find_base_rel_ignore_join(PlannerInfo *root, int relid)
     457             : {
     458             :     /* use an unsigned comparison to prevent negative array element access */
     459      180752 :     if ((uint32) relid < (uint32) root->simple_rel_array_size)
     460             :     {
     461             :         RelOptInfo *rel;
     462             :         RangeTblEntry *rte;
     463             : 
     464      180752 :         rel = root->simple_rel_array[relid];
     465      180752 :         if (rel)
     466      167588 :             return rel;
     467             : 
     468             :         /*
     469             :          * We could just return NULL here, but for debugging purposes it seems
     470             :          * best to actually verify that the relid is an outer join and not
     471             :          * something weird.
     472             :          */
     473       13164 :         rte = root->simple_rte_array[relid];
     474       13164 :         if (rte && rte->rtekind == RTE_JOIN && rte->jointype != JOIN_INNER)
     475       13164 :             return NULL;
     476             :     }
     477             : 
     478           0 :     elog(ERROR, "no relation entry for relid %d", relid);
     479             : 
     480             :     return NULL;                /* keep compiler quiet */
     481             : }
     482             : 
     483             : /*
     484             :  * build_join_rel_hash
     485             :  *    Construct the auxiliary hash table for join relations.
     486             :  */
     487             : static void
     488          56 : build_join_rel_hash(PlannerInfo *root)
     489             : {
     490             :     HTAB       *hashtab;
     491             :     HASHCTL     hash_ctl;
     492             :     ListCell   *l;
     493             : 
     494             :     /* Create the hash table */
     495          56 :     hash_ctl.keysize = sizeof(Relids);
     496          56 :     hash_ctl.entrysize = sizeof(JoinHashEntry);
     497          56 :     hash_ctl.hash = bitmap_hash;
     498          56 :     hash_ctl.match = bitmap_match;
     499          56 :     hash_ctl.hcxt = CurrentMemoryContext;
     500          56 :     hashtab = hash_create("JoinRelHashTable",
     501             :                           256L,
     502             :                           &hash_ctl,
     503             :                           HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);
     504             : 
     505             :     /* Insert all the already-existing joinrels */
     506        1904 :     foreach(l, root->join_rel_list)
     507             :     {
     508        1848 :         RelOptInfo *rel = (RelOptInfo *) lfirst(l);
     509             :         JoinHashEntry *hentry;
     510             :         bool        found;
     511             : 
     512        1848 :         hentry = (JoinHashEntry *) hash_search(hashtab,
     513        1848 :                                                &(rel->relids),
     514             :                                                HASH_ENTER,
     515             :                                                &found);
     516             :         Assert(!found);
     517        1848 :         hentry->join_rel = rel;
     518             :     }
     519             : 
     520          56 :     root->join_rel_hash = hashtab;
     521          56 : }
     522             : 
     523             : /*
     524             :  * find_join_rel
     525             :  *    Returns relation entry corresponding to 'relids' (a set of RT indexes),
     526             :  *    or NULL if none exists.  This is for join relations.
     527             :  */
     528             : RelOptInfo *
     529      315064 : find_join_rel(PlannerInfo *root, Relids relids)
     530             : {
     531             :     /*
     532             :      * Switch to using hash lookup when list grows "too long".  The threshold
     533             :      * is arbitrary and is known only here.
     534             :      */
     535      315064 :     if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)
     536          56 :         build_join_rel_hash(root);
     537             : 
     538             :     /*
     539             :      * Use either hashtable lookup or linear search, as appropriate.
     540             :      *
     541             :      * Note: the seemingly redundant hashkey variable is used to avoid taking
     542             :      * the address of relids; unless the compiler is exceedingly smart, doing
     543             :      * so would force relids out of a register and thus probably slow down the
     544             :      * list-search case.
     545             :      */
     546      315064 :     if (root->join_rel_hash)
     547             :     {
     548        4704 :         Relids      hashkey = relids;
     549             :         JoinHashEntry *hentry;
     550             : 
     551        4704 :         hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
     552             :                                                &hashkey,
     553             :                                                HASH_FIND,
     554             :                                                NULL);
     555        4704 :         if (hentry)
     556        4158 :             return hentry->join_rel;
     557             :     }
     558             :     else
     559             :     {
     560             :         ListCell   *l;
     561             : 
     562     1924064 :         foreach(l, root->join_rel_list)
     563             :         {
     564     1721354 :             RelOptInfo *rel = (RelOptInfo *) lfirst(l);
     565             : 
     566     1721354 :             if (bms_equal(rel->relids, relids))
     567      107650 :                 return rel;
     568             :         }
     569             :     }
     570             : 
     571      203256 :     return NULL;
     572             : }
     573             : 
     574             : /*
     575             :  * set_foreign_rel_properties
     576             :  *      Set up foreign-join fields if outer and inner relation are foreign
     577             :  *      tables (or joins) belonging to the same server and assigned to the same
     578             :  *      user to check access permissions as.
     579             :  *
     580             :  * In addition to an exact match of userid, we allow the case where one side
     581             :  * has zero userid (implying current user) and the other side has explicit
     582             :  * userid that happens to equal the current user; but in that case, pushdown of
     583             :  * the join is only valid for the current user.  The useridiscurrent field
     584             :  * records whether we had to make such an assumption for this join or any
     585             :  * sub-join.
     586             :  *
     587             :  * Otherwise these fields are left invalid, so GetForeignJoinPaths will not be
     588             :  * called for the join relation.
     589             :  */
     590             : static void
     591      206340 : set_foreign_rel_properties(RelOptInfo *joinrel, RelOptInfo *outer_rel,
     592             :                            RelOptInfo *inner_rel)
     593             : {
     594      206340 :     if (OidIsValid(outer_rel->serverid) &&
     595         890 :         inner_rel->serverid == outer_rel->serverid)
     596             :     {
     597         798 :         if (inner_rel->userid == outer_rel->userid)
     598             :         {
     599         786 :             joinrel->serverid = outer_rel->serverid;
     600         786 :             joinrel->userid = outer_rel->userid;
     601         786 :             joinrel->useridiscurrent = outer_rel->useridiscurrent || inner_rel->useridiscurrent;
     602         786 :             joinrel->fdwroutine = outer_rel->fdwroutine;
     603             :         }
     604          20 :         else if (!OidIsValid(inner_rel->userid) &&
     605           8 :                  outer_rel->userid == GetUserId())
     606             :         {
     607           4 :             joinrel->serverid = outer_rel->serverid;
     608           4 :             joinrel->userid = outer_rel->userid;
     609           4 :             joinrel->useridiscurrent = true;
     610           4 :             joinrel->fdwroutine = outer_rel->fdwroutine;
     611             :         }
     612           8 :         else if (!OidIsValid(outer_rel->userid) &&
     613           0 :                  inner_rel->userid == GetUserId())
     614             :         {
     615           0 :             joinrel->serverid = outer_rel->serverid;
     616           0 :             joinrel->userid = inner_rel->userid;
     617           0 :             joinrel->useridiscurrent = true;
     618           0 :             joinrel->fdwroutine = outer_rel->fdwroutine;
     619             :         }
     620             :     }
     621      206340 : }
     622             : 
     623             : /*
     624             :  * add_join_rel
     625             :  *      Add given join relation to the list of join relations in the given
     626             :  *      PlannerInfo. Also add it to the auxiliary hashtable if there is one.
     627             :  */
     628             : static void
     629      206340 : add_join_rel(PlannerInfo *root, RelOptInfo *joinrel)
     630             : {
     631             :     /* GEQO requires us to append the new joinrel to the end of the list! */
     632      206340 :     root->join_rel_list = lappend(root->join_rel_list, joinrel);
     633             : 
     634             :     /* store it into the auxiliary hashtable if there is one. */
     635      206340 :     if (root->join_rel_hash)
     636             :     {
     637             :         JoinHashEntry *hentry;
     638             :         bool        found;
     639             : 
     640         546 :         hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
     641         546 :                                                &(joinrel->relids),
     642             :                                                HASH_ENTER,
     643             :                                                &found);
     644             :         Assert(!found);
     645         546 :         hentry->join_rel = joinrel;
     646             :     }
     647      206340 : }
     648             : 
     649             : /*
     650             :  * build_join_rel
     651             :  *    Returns relation entry corresponding to the union of two given rels,
     652             :  *    creating a new relation entry if none already exists.
     653             :  *
     654             :  * 'joinrelids' is the Relids set that uniquely identifies the join
     655             :  * 'outer_rel' and 'inner_rel' are relation nodes for the relations to be
     656             :  *      joined
     657             :  * 'sjinfo': join context info
     658             :  * 'pushed_down_joins': any pushed-down outer joins that are now completed
     659             :  * 'restrictlist_ptr': result variable.  If not NULL, *restrictlist_ptr
     660             :  *      receives the list of RestrictInfo nodes that apply to this
     661             :  *      particular pair of joinable relations.
     662             :  *
     663             :  * restrictlist_ptr makes the routine's API a little grotty, but it saves
     664             :  * duplicated calculation of the restrictlist...
     665             :  */
     666             : RelOptInfo *
     667      310804 : build_join_rel(PlannerInfo *root,
     668             :                Relids joinrelids,
     669             :                RelOptInfo *outer_rel,
     670             :                RelOptInfo *inner_rel,
     671             :                SpecialJoinInfo *sjinfo,
     672             :                List *pushed_down_joins,
     673             :                List **restrictlist_ptr)
     674             : {
     675             :     RelOptInfo *joinrel;
     676             :     List       *restrictlist;
     677             : 
     678             :     /* This function should be used only for join between parents. */
     679             :     Assert(!IS_OTHER_REL(outer_rel) && !IS_OTHER_REL(inner_rel));
     680             : 
     681             :     /*
     682             :      * See if we already have a joinrel for this set of base rels.
     683             :      */
     684      310804 :     joinrel = find_join_rel(root, joinrelids);
     685             : 
     686      310804 :     if (joinrel)
     687             :     {
     688             :         /*
     689             :          * Yes, so we only need to figure the restrictlist for this particular
     690             :          * pair of component relations.
     691             :          */
     692      109466 :         if (restrictlist_ptr)
     693      109466 :             *restrictlist_ptr = build_joinrel_restrictlist(root,
     694             :                                                            joinrel,
     695             :                                                            outer_rel,
     696             :                                                            inner_rel,
     697             :                                                            sjinfo);
     698      109466 :         return joinrel;
     699             :     }
     700             : 
     701             :     /*
     702             :      * Nope, so make one.
     703             :      */
     704      201338 :     joinrel = makeNode(RelOptInfo);
     705      201338 :     joinrel->reloptkind = RELOPT_JOINREL;
     706      201338 :     joinrel->relids = bms_copy(joinrelids);
     707      201338 :     joinrel->rows = 0;
     708             :     /* cheap startup cost is interesting iff not all tuples to be retrieved */
     709      201338 :     joinrel->consider_startup = (root->tuple_fraction > 0);
     710      201338 :     joinrel->consider_param_startup = false;
     711      201338 :     joinrel->consider_parallel = false;
     712      201338 :     joinrel->reltarget = create_empty_pathtarget();
     713      201338 :     joinrel->pathlist = NIL;
     714      201338 :     joinrel->ppilist = NIL;
     715      201338 :     joinrel->partial_pathlist = NIL;
     716      201338 :     joinrel->cheapest_startup_path = NULL;
     717      201338 :     joinrel->cheapest_total_path = NULL;
     718      201338 :     joinrel->cheapest_parameterized_paths = NIL;
     719             :     /* init direct_lateral_relids from children; we'll finish it up below */
     720      201338 :     joinrel->direct_lateral_relids =
     721      201338 :         bms_union(outer_rel->direct_lateral_relids,
     722      201338 :                   inner_rel->direct_lateral_relids);
     723      201338 :     joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids,
     724             :                                                         outer_rel, inner_rel);
     725      201338 :     joinrel->relid = 0;          /* indicates not a baserel */
     726      201338 :     joinrel->rtekind = RTE_JOIN;
     727      201338 :     joinrel->min_attr = 0;
     728      201338 :     joinrel->max_attr = 0;
     729      201338 :     joinrel->attr_needed = NULL;
     730      201338 :     joinrel->attr_widths = NULL;
     731      201338 :     joinrel->notnullattnums = NULL;
     732      201338 :     joinrel->nulling_relids = NULL;
     733      201338 :     joinrel->lateral_vars = NIL;
     734      201338 :     joinrel->lateral_referencers = NULL;
     735      201338 :     joinrel->indexlist = NIL;
     736      201338 :     joinrel->statlist = NIL;
     737      201338 :     joinrel->pages = 0;
     738      201338 :     joinrel->tuples = 0;
     739      201338 :     joinrel->allvisfrac = 0;
     740      201338 :     joinrel->eclass_indexes = NULL;
     741      201338 :     joinrel->subroot = NULL;
     742      201338 :     joinrel->subplan_params = NIL;
     743      201338 :     joinrel->rel_parallel_workers = -1;
     744      201338 :     joinrel->amflags = 0;
     745      201338 :     joinrel->serverid = InvalidOid;
     746      201338 :     joinrel->userid = InvalidOid;
     747      201338 :     joinrel->useridiscurrent = false;
     748      201338 :     joinrel->fdwroutine = NULL;
     749      201338 :     joinrel->fdw_private = NULL;
     750      201338 :     joinrel->unique_for_rels = NIL;
     751      201338 :     joinrel->non_unique_for_rels = NIL;
     752      201338 :     joinrel->unique_rel = NULL;
     753      201338 :     joinrel->unique_pathkeys = NIL;
     754      201338 :     joinrel->unique_groupclause = NIL;
     755      201338 :     joinrel->baserestrictinfo = NIL;
     756      201338 :     joinrel->baserestrictcost.startup = 0;
     757      201338 :     joinrel->baserestrictcost.per_tuple = 0;
     758      201338 :     joinrel->baserestrict_min_security = UINT_MAX;
     759      201338 :     joinrel->joininfo = NIL;
     760      201338 :     joinrel->has_eclass_joins = false;
     761      201338 :     joinrel->consider_partitionwise_join = false;    /* might get changed later */
     762      201338 :     joinrel->parent = NULL;
     763      201338 :     joinrel->top_parent = NULL;
     764      201338 :     joinrel->top_parent_relids = NULL;
     765      201338 :     joinrel->part_scheme = NULL;
     766      201338 :     joinrel->nparts = -1;
     767      201338 :     joinrel->boundinfo = NULL;
     768      201338 :     joinrel->partbounds_merged = false;
     769      201338 :     joinrel->partition_qual = NIL;
     770      201338 :     joinrel->part_rels = NULL;
     771      201338 :     joinrel->live_parts = NULL;
     772      201338 :     joinrel->all_partrels = NULL;
     773      201338 :     joinrel->partexprs = NULL;
     774      201338 :     joinrel->nullable_partexprs = NULL;
     775             : 
     776             :     /* Compute information relevant to the foreign relations. */
     777      201338 :     set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
     778             : 
     779             :     /*
     780             :      * Fill the joinrel's tlist with just the Vars and PHVs that need to be
     781             :      * output from this join (ie, are needed for higher joinclauses or final
     782             :      * output).
     783             :      *
     784             :      * NOTE: the tlist order for a join rel will depend on which pair of outer
     785             :      * and inner rels we first try to build it from.  But the contents should
     786             :      * be the same regardless.
     787             :      */
     788      201338 :     build_joinrel_tlist(root, joinrel, outer_rel, sjinfo, pushed_down_joins,
     789      201338 :                         (sjinfo->jointype == JOIN_FULL));
     790      201338 :     build_joinrel_tlist(root, joinrel, inner_rel, sjinfo, pushed_down_joins,
     791      201338 :                         (sjinfo->jointype != JOIN_INNER));
     792      201338 :     add_placeholders_to_joinrel(root, joinrel, outer_rel, inner_rel, sjinfo);
     793             : 
     794             :     /*
     795             :      * add_placeholders_to_joinrel also took care of adding the ph_lateral
     796             :      * sets of any PlaceHolderVars computed here to direct_lateral_relids, so
     797             :      * now we can finish computing that.  This is much like the computation of
     798             :      * the transitively-closed lateral_relids in min_join_parameterization,
     799             :      * except that here we *do* have to consider the added PHVs.
     800             :      */
     801      201338 :     joinrel->direct_lateral_relids =
     802      201338 :         bms_del_members(joinrel->direct_lateral_relids, joinrel->relids);
     803             : 
     804             :     /*
     805             :      * Construct restrict and join clause lists for the new joinrel. (The
     806             :      * caller might or might not need the restrictlist, but I need it anyway
     807             :      * for set_joinrel_size_estimates().)
     808             :      */
     809      201338 :     restrictlist = build_joinrel_restrictlist(root, joinrel,
     810             :                                               outer_rel, inner_rel,
     811             :                                               sjinfo);
     812      201338 :     if (restrictlist_ptr)
     813      201338 :         *restrictlist_ptr = restrictlist;
     814      201338 :     build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
     815             : 
     816             :     /*
     817             :      * This is also the right place to check whether the joinrel has any
     818             :      * pending EquivalenceClass joins.
     819             :      */
     820      201338 :     joinrel->has_eclass_joins = has_relevant_eclass_joinclause(root, joinrel);
     821             : 
     822             :     /* Store the partition information. */
     823      201338 :     build_joinrel_partition_info(root, joinrel, outer_rel, inner_rel, sjinfo,
     824             :                                  restrictlist);
     825             : 
     826             :     /*
     827             :      * Set estimates of the joinrel's size.
     828             :      */
     829      201338 :     set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
     830             :                                sjinfo, restrictlist);
     831             : 
     832             :     /*
     833             :      * Set the consider_parallel flag if this joinrel could potentially be
     834             :      * scanned within a parallel worker.  If this flag is false for either
     835             :      * inner_rel or outer_rel, then it must be false for the joinrel also.
     836             :      * Even if both are true, there might be parallel-restricted expressions
     837             :      * in the targetlist or quals.
     838             :      *
     839             :      * Note that if there are more than two rels in this relation, they could
     840             :      * be divided between inner_rel and outer_rel in any arbitrary way.  We
     841             :      * assume this doesn't matter, because we should hit all the same baserels
     842             :      * and joinclauses while building up to this joinrel no matter which we
     843             :      * take; therefore, we should make the same decision here however we get
     844             :      * here.
     845             :      */
     846      367560 :     if (inner_rel->consider_parallel && outer_rel->consider_parallel &&
     847      331842 :         is_parallel_safe(root, (Node *) restrictlist) &&
     848      165620 :         is_parallel_safe(root, (Node *) joinrel->reltarget->exprs))
     849      165608 :         joinrel->consider_parallel = true;
     850             : 
     851             :     /* Add the joinrel to the PlannerInfo. */
     852      201338 :     add_join_rel(root, joinrel);
     853             : 
     854             :     /*
     855             :      * Also, if dynamic-programming join search is active, add the new joinrel
     856             :      * to the appropriate sublist.  Note: you might think the Assert on number
     857             :      * of members should be for equality, but some of the level 1 rels might
     858             :      * have been joinrels already, so we can only assert <=.
     859             :      */
     860      201338 :     if (root->join_rel_level)
     861             :     {
     862             :         Assert(root->join_cur_level > 0);
     863             :         Assert(root->join_cur_level <= bms_num_members(joinrel->relids));
     864      198242 :         root->join_rel_level[root->join_cur_level] =
     865      198242 :             lappend(root->join_rel_level[root->join_cur_level], joinrel);
     866             :     }
     867             : 
     868      201338 :     return joinrel;
     869             : }
     870             : 
     871             : /*
     872             :  * build_child_join_rel
     873             :  *    Builds RelOptInfo representing join between given two child relations.
     874             :  *
     875             :  * 'outer_rel' and 'inner_rel' are the RelOptInfos of child relations being
     876             :  *      joined
     877             :  * 'parent_joinrel' is the RelOptInfo representing the join between parent
     878             :  *      relations. Some of the members of new RelOptInfo are produced by
     879             :  *      translating corresponding members of this RelOptInfo
     880             :  * 'restrictlist': list of RestrictInfo nodes that apply to this particular
     881             :  *      pair of joinable relations
     882             :  * 'sjinfo': child join's join-type details
     883             :  * 'nappinfos' and 'appinfos': AppendRelInfo array for child relids
     884             :  */
     885             : RelOptInfo *
     886        5002 : build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
     887             :                      RelOptInfo *inner_rel, RelOptInfo *parent_joinrel,
     888             :                      List *restrictlist, SpecialJoinInfo *sjinfo,
     889             :                      int nappinfos, AppendRelInfo **appinfos)
     890             : {
     891        5002 :     RelOptInfo *joinrel = makeNode(RelOptInfo);
     892             : 
     893             :     /* Only joins between "other" relations land here. */
     894             :     Assert(IS_OTHER_REL(outer_rel) && IS_OTHER_REL(inner_rel));
     895             : 
     896             :     /* The parent joinrel should have consider_partitionwise_join set. */
     897             :     Assert(parent_joinrel->consider_partitionwise_join);
     898             : 
     899        5002 :     joinrel->reloptkind = RELOPT_OTHER_JOINREL;
     900        5002 :     joinrel->relids = adjust_child_relids(parent_joinrel->relids,
     901             :                                           nappinfos, appinfos);
     902        5002 :     joinrel->rows = 0;
     903             :     /* cheap startup cost is interesting iff not all tuples to be retrieved */
     904        5002 :     joinrel->consider_startup = (root->tuple_fraction > 0);
     905        5002 :     joinrel->consider_param_startup = false;
     906        5002 :     joinrel->consider_parallel = false;
     907        5002 :     joinrel->reltarget = create_empty_pathtarget();
     908        5002 :     joinrel->pathlist = NIL;
     909        5002 :     joinrel->ppilist = NIL;
     910        5002 :     joinrel->partial_pathlist = NIL;
     911        5002 :     joinrel->cheapest_startup_path = NULL;
     912        5002 :     joinrel->cheapest_total_path = NULL;
     913        5002 :     joinrel->cheapest_parameterized_paths = NIL;
     914        5002 :     joinrel->direct_lateral_relids = NULL;
     915        5002 :     joinrel->lateral_relids = NULL;
     916        5002 :     joinrel->relid = 0;          /* indicates not a baserel */
     917        5002 :     joinrel->rtekind = RTE_JOIN;
     918        5002 :     joinrel->min_attr = 0;
     919        5002 :     joinrel->max_attr = 0;
     920        5002 :     joinrel->attr_needed = NULL;
     921        5002 :     joinrel->attr_widths = NULL;
     922        5002 :     joinrel->notnullattnums = NULL;
     923        5002 :     joinrel->nulling_relids = NULL;
     924        5002 :     joinrel->lateral_vars = NIL;
     925        5002 :     joinrel->lateral_referencers = NULL;
     926        5002 :     joinrel->indexlist = NIL;
     927        5002 :     joinrel->pages = 0;
     928        5002 :     joinrel->tuples = 0;
     929        5002 :     joinrel->allvisfrac = 0;
     930        5002 :     joinrel->eclass_indexes = NULL;
     931        5002 :     joinrel->subroot = NULL;
     932        5002 :     joinrel->subplan_params = NIL;
     933        5002 :     joinrel->amflags = 0;
     934        5002 :     joinrel->serverid = InvalidOid;
     935        5002 :     joinrel->userid = InvalidOid;
     936        5002 :     joinrel->useridiscurrent = false;
     937        5002 :     joinrel->fdwroutine = NULL;
     938        5002 :     joinrel->fdw_private = NULL;
     939        5002 :     joinrel->unique_rel = NULL;
     940        5002 :     joinrel->unique_pathkeys = NIL;
     941        5002 :     joinrel->unique_groupclause = NIL;
     942        5002 :     joinrel->baserestrictinfo = NIL;
     943        5002 :     joinrel->baserestrictcost.startup = 0;
     944        5002 :     joinrel->baserestrictcost.per_tuple = 0;
     945        5002 :     joinrel->joininfo = NIL;
     946        5002 :     joinrel->has_eclass_joins = false;
     947        5002 :     joinrel->consider_partitionwise_join = false;    /* might get changed later */
     948        5002 :     joinrel->parent = parent_joinrel;
     949        5002 :     joinrel->top_parent = parent_joinrel->top_parent ? parent_joinrel->top_parent : parent_joinrel;
     950        5002 :     joinrel->top_parent_relids = joinrel->top_parent->relids;
     951        5002 :     joinrel->part_scheme = NULL;
     952        5002 :     joinrel->nparts = -1;
     953        5002 :     joinrel->boundinfo = NULL;
     954        5002 :     joinrel->partbounds_merged = false;
     955        5002 :     joinrel->partition_qual = NIL;
     956        5002 :     joinrel->part_rels = NULL;
     957        5002 :     joinrel->live_parts = NULL;
     958        5002 :     joinrel->all_partrels = NULL;
     959        5002 :     joinrel->partexprs = NULL;
     960        5002 :     joinrel->nullable_partexprs = NULL;
     961             : 
     962             :     /* Compute information relevant to foreign relations. */
     963        5002 :     set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
     964             : 
     965             :     /* Set up reltarget struct */
     966        5002 :     build_child_join_reltarget(root, parent_joinrel, joinrel,
     967             :                                nappinfos, appinfos);
     968             : 
     969             :     /* Construct joininfo list. */
     970       10004 :     joinrel->joininfo = (List *) adjust_appendrel_attrs(root,
     971        5002 :                                                         (Node *) parent_joinrel->joininfo,
     972             :                                                         nappinfos,
     973             :                                                         appinfos);
     974             : 
     975             :     /*
     976             :      * Lateral relids referred in child join will be same as that referred in
     977             :      * the parent relation.
     978             :      */
     979        5002 :     joinrel->direct_lateral_relids = (Relids) bms_copy(parent_joinrel->direct_lateral_relids);
     980        5002 :     joinrel->lateral_relids = (Relids) bms_copy(parent_joinrel->lateral_relids);
     981             : 
     982             :     /*
     983             :      * If the parent joinrel has pending equivalence classes, so does the
     984             :      * child.
     985             :      */
     986        5002 :     joinrel->has_eclass_joins = parent_joinrel->has_eclass_joins;
     987             : 
     988             :     /* Is the join between partitions itself partitioned? */
     989        5002 :     build_joinrel_partition_info(root, joinrel, outer_rel, inner_rel, sjinfo,
     990             :                                  restrictlist);
     991             : 
     992             :     /* Child joinrel is parallel safe if parent is parallel safe. */
     993        5002 :     joinrel->consider_parallel = parent_joinrel->consider_parallel;
     994             : 
     995             :     /* Set estimates of the child-joinrel's size. */
     996        5002 :     set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
     997             :                                sjinfo, restrictlist);
     998             : 
     999             :     /* We build the join only once. */
    1000             :     Assert(!find_join_rel(root, joinrel->relids));
    1001             : 
    1002             :     /* Add the relation to the PlannerInfo. */
    1003        5002 :     add_join_rel(root, joinrel);
    1004             : 
    1005             :     /*
    1006             :      * We might need EquivalenceClass members corresponding to the child join,
    1007             :      * so that we can represent sort pathkeys for it.  As with children of
    1008             :      * baserels, we shouldn't need this unless there are relevant eclass joins
    1009             :      * (implying that a merge join might be possible) or pathkeys to sort by.
    1010             :      */
    1011        5002 :     if (joinrel->has_eclass_joins || has_useful_pathkeys(root, parent_joinrel))
    1012        4462 :         add_child_join_rel_equivalences(root,
    1013             :                                         nappinfos, appinfos,
    1014             :                                         parent_joinrel, joinrel);
    1015             : 
    1016        5002 :     return joinrel;
    1017             : }
    1018             : 
    1019             : /*
    1020             :  * min_join_parameterization
    1021             :  *
    1022             :  * Determine the minimum possible parameterization of a joinrel, that is, the
    1023             :  * set of other rels it contains LATERAL references to.  We save this value in
    1024             :  * the join's RelOptInfo.  This function is split out of build_join_rel()
    1025             :  * because join_is_legal() needs the value to check a prospective join.
    1026             :  */
    1027             : Relids
    1028      219038 : min_join_parameterization(PlannerInfo *root,
    1029             :                           Relids joinrelids,
    1030             :                           RelOptInfo *outer_rel,
    1031             :                           RelOptInfo *inner_rel)
    1032             : {
    1033             :     Relids      result;
    1034             : 
    1035             :     /*
    1036             :      * Basically we just need the union of the inputs' lateral_relids, less
    1037             :      * whatever is already in the join.
    1038             :      *
    1039             :      * It's not immediately obvious that this is a valid way to compute the
    1040             :      * result, because it might seem that we're ignoring possible lateral refs
    1041             :      * of PlaceHolderVars that are due to be computed at the join but not in
    1042             :      * either input.  However, because create_lateral_join_info() already
    1043             :      * charged all such PHV refs to each member baserel of the join, they'll
    1044             :      * be accounted for already in the inputs' lateral_relids.  Likewise, we
    1045             :      * do not need to worry about doing transitive closure here, because that
    1046             :      * was already accounted for in the original baserel lateral_relids.
    1047             :      */
    1048      219038 :     result = bms_union(outer_rel->lateral_relids, inner_rel->lateral_relids);
    1049      219038 :     result = bms_del_members(result, joinrelids);
    1050      219038 :     return result;
    1051             : }
    1052             : 
    1053             : /*
    1054             :  * build_joinrel_tlist
    1055             :  *    Builds a join relation's target list from an input relation.
    1056             :  *    (This is invoked twice to handle the two input relations.)
    1057             :  *
    1058             :  * The join's targetlist includes all Vars of its member relations that
    1059             :  * will still be needed above the join.  This subroutine adds all such
    1060             :  * Vars from the specified input rel's tlist to the join rel's tlist.
    1061             :  * Likewise for any PlaceHolderVars emitted by the input rel.
    1062             :  *
    1063             :  * We also compute the expected width of the join's output, making use
    1064             :  * of data that was cached at the baserel level by set_rel_width().
    1065             :  *
    1066             :  * Pass can_null as true if the join is an outer join that can null Vars
    1067             :  * from this input relation.  If so, we will (normally) add the join's relid
    1068             :  * to the nulling bitmaps of Vars and PHVs bubbled up from the input.
    1069             :  *
    1070             :  * When forming an outer join's target list, special handling is needed in
    1071             :  * case the outer join was commuted with another one per outer join identity 3
    1072             :  * (see optimizer/README).  We must take steps to ensure that the output Vars
    1073             :  * have the same nulling bitmaps that they would if the two joins had been
    1074             :  * done in syntactic order; else they won't match Vars appearing higher in
    1075             :  * the query tree.  An exception to the match-the-syntactic-order rule is
    1076             :  * that when an outer join is pushed down into another one's RHS per identity
    1077             :  * 3, we can't mark its Vars as nulled until the now-upper outer join is also
    1078             :  * completed.  So we need to do three things:
    1079             :  *
    1080             :  * First, we add the outer join's relid to the nulling bitmap only if the
    1081             :  * outer join has been completely performed and the Var or PHV actually
    1082             :  * comes from within the syntactically nullable side(s) of the outer join.
    1083             :  * This takes care of the possibility that we have transformed
    1084             :  *      (A leftjoin B on (Pab)) leftjoin C on (Pbc)
    1085             :  * to
    1086             :  *      A leftjoin (B leftjoin C on (Pbc)) on (Pab)
    1087             :  * Here the pushed-down B/C join cannot mark C columns as nulled yet,
    1088             :  * while the now-upper A/B join must not mark C columns as nulled by itself.
    1089             :  *
    1090             :  * Second, perform the same operation for each SpecialJoinInfo listed in
    1091             :  * pushed_down_joins (which, in this example, would be the B/C join when
    1092             :  * we are at the now-upper A/B join).  This allows the now-upper join to
    1093             :  * complete the marking of "C" Vars that now have fully valid values.
    1094             :  *
    1095             :  * Third, any relid in sjinfo->commute_above_r that is already part of
    1096             :  * the joinrel is added to the nulling bitmaps of nullable Vars and PHVs.
    1097             :  * This takes care of the reverse case where we implement
    1098             :  *      A leftjoin (B leftjoin C on (Pbc)) on (Pab)
    1099             :  * as
    1100             :  *      (A leftjoin B on (Pab)) leftjoin C on (Pbc)
    1101             :  * The C columns emitted by the B/C join need to be shown as nulled by both
    1102             :  * the B/C and A/B joins, even though they've not physically traversed the
    1103             :  * A/B join.
    1104             :  */
    1105             : static void
    1106      402676 : build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
    1107             :                     RelOptInfo *input_rel,
    1108             :                     SpecialJoinInfo *sjinfo,
    1109             :                     List *pushed_down_joins,
    1110             :                     bool can_null)
    1111             : {
    1112      402676 :     Relids      relids = joinrel->relids;
    1113      402676 :     int64       tuple_width = joinrel->reltarget->width;
    1114             :     ListCell   *vars;
    1115             :     ListCell   *lc;
    1116             : 
    1117     2041082 :     foreach(vars, input_rel->reltarget->exprs)
    1118             :     {
    1119     1638406 :         Var        *var = (Var *) lfirst(vars);
    1120             : 
    1121             :         /*
    1122             :          * For a PlaceHolderVar, we have to look up the PlaceHolderInfo.
    1123             :          */
    1124     1638406 :         if (IsA(var, PlaceHolderVar))
    1125        2056 :         {
    1126        2056 :             PlaceHolderVar *phv = (PlaceHolderVar *) var;
    1127        2056 :             PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
    1128             : 
    1129             :             /* Is it still needed above this joinrel? */
    1130        2056 :             if (bms_nonempty_difference(phinfo->ph_needed, relids))
    1131             :             {
    1132             :                 /*
    1133             :                  * Yup, add it to the output.  If this join potentially nulls
    1134             :                  * this input, we have to update the PHV's phnullingrels,
    1135             :                  * which means making a copy.
    1136             :                  */
    1137        1540 :                 if (can_null)
    1138             :                 {
    1139         994 :                     phv = copyObject(phv);
    1140             :                     /* See comments above to understand this logic */
    1141        1988 :                     if (sjinfo->ojrelid != 0 &&
    1142        1964 :                         bms_is_member(sjinfo->ojrelid, relids) &&
    1143         970 :                         (bms_is_subset(phv->phrels, sjinfo->syn_righthand) ||
    1144         240 :                          (sjinfo->jointype == JOIN_FULL &&
    1145         114 :                           bms_is_subset(phv->phrels, sjinfo->syn_lefthand))))
    1146         958 :                         phv->phnullingrels = bms_add_member(phv->phnullingrels,
    1147         958 :                                                             sjinfo->ojrelid);
    1148        1012 :                     foreach(lc, pushed_down_joins)
    1149             :                     {
    1150          18 :                         SpecialJoinInfo *othersj = (SpecialJoinInfo *) lfirst(lc);
    1151             : 
    1152             :                         Assert(bms_is_member(othersj->ojrelid, relids));
    1153          18 :                         if (bms_is_subset(phv->phrels, othersj->syn_righthand))
    1154          12 :                             phv->phnullingrels = bms_add_member(phv->phnullingrels,
    1155          12 :                                                                 othersj->ojrelid);
    1156             :                     }
    1157         994 :                     phv->phnullingrels =
    1158         994 :                         bms_join(phv->phnullingrels,
    1159         994 :                                  bms_intersect(sjinfo->commute_above_r,
    1160             :                                                relids));
    1161             :                 }
    1162             : 
    1163        1540 :                 joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
    1164             :                                                     phv);
    1165             :                 /* Bubbling up the precomputed result has cost zero */
    1166        1540 :                 tuple_width += phinfo->ph_width;
    1167             :             }
    1168        2056 :             continue;
    1169             :         }
    1170             : 
    1171             :         /*
    1172             :          * Otherwise, anything in a baserel or joinrel targetlist ought to be
    1173             :          * a Var.  (More general cases can only appear in appendrel child
    1174             :          * rels, which will never be seen here.)
    1175             :          */
    1176     1636350 :         if (!IsA(var, Var))
    1177           0 :             elog(ERROR, "unexpected node type in rel targetlist: %d",
    1178             :                  (int) nodeTag(var));
    1179             : 
    1180     1636350 :         if (var->varno == ROWID_VAR)
    1181             :         {
    1182             :             /* UPDATE/DELETE/MERGE row identity vars are always needed */
    1183             :             RowIdentityVarInfo *ridinfo = (RowIdentityVarInfo *)
    1184        1248 :                 list_nth(root->row_identity_vars, var->varattno - 1);
    1185             : 
    1186             :             /* Update reltarget width estimate from RowIdentityVarInfo */
    1187        1248 :             tuple_width += ridinfo->rowidwidth;
    1188             :         }
    1189             :         else
    1190             :         {
    1191             :             RelOptInfo *baserel;
    1192             :             int         ndx;
    1193             : 
    1194             :             /* Get the Var's original base rel */
    1195     1635102 :             baserel = find_base_rel(root, var->varno);
    1196             : 
    1197             :             /* Is it still needed above this joinrel? */
    1198     1635102 :             ndx = var->varattno - baserel->min_attr;
    1199     1635102 :             if (!bms_nonempty_difference(baserel->attr_needed[ndx], relids))
    1200      296486 :                 continue;       /* nope, skip it */
    1201             : 
    1202             :             /* Update reltarget width estimate from baserel's attr_widths */
    1203     1338616 :             tuple_width += baserel->attr_widths[ndx];
    1204             :         }
    1205             : 
    1206             :         /*
    1207             :          * Add the Var to the output.  If this join potentially nulls this
    1208             :          * input, we have to update the Var's varnullingrels, which means
    1209             :          * making a copy.  But note that we don't ever add nullingrel bits to
    1210             :          * row identity Vars (cf. comments in setrefs.c).
    1211             :          */
    1212     1339864 :         if (can_null && var->varno != ROWID_VAR)
    1213             :         {
    1214      134536 :             var = copyObject(var);
    1215             :             /* See comments above to understand this logic */
    1216      268366 :             if (sjinfo->ojrelid != 0 &&
    1217      262316 :                 bms_is_member(sjinfo->ojrelid, relids) &&
    1218      128486 :                 (bms_is_member(var->varno, sjinfo->syn_righthand) ||
    1219        3888 :                  (sjinfo->jointype == JOIN_FULL &&
    1220        1812 :                   bms_is_member(var->varno, sjinfo->syn_lefthand))))
    1221      128222 :                 var->varnullingrels = bms_add_member(var->varnullingrels,
    1222      128222 :                                                      sjinfo->ojrelid);
    1223      135214 :             foreach(lc, pushed_down_joins)
    1224             :             {
    1225         678 :                 SpecialJoinInfo *othersj = (SpecialJoinInfo *) lfirst(lc);
    1226             : 
    1227             :                 Assert(bms_is_member(othersj->ojrelid, relids));
    1228         678 :                 if (bms_is_member(var->varno, othersj->syn_righthand))
    1229         264 :                     var->varnullingrels = bms_add_member(var->varnullingrels,
    1230         264 :                                                          othersj->ojrelid);
    1231             :             }
    1232      134536 :             var->varnullingrels =
    1233      134536 :                 bms_join(var->varnullingrels,
    1234      134536 :                          bms_intersect(sjinfo->commute_above_r,
    1235             :                                        relids));
    1236             :         }
    1237             : 
    1238     1339864 :         joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
    1239             :                                             var);
    1240             : 
    1241             :         /* Vars have cost zero, so no need to adjust reltarget->cost */
    1242             :     }
    1243             : 
    1244      402676 :     joinrel->reltarget->width = clamp_width_est(tuple_width);
    1245      402676 : }
    1246             : 
    1247             : /*
    1248             :  * build_joinrel_restrictlist
    1249             :  * build_joinrel_joinlist
    1250             :  *    These routines build lists of restriction and join clauses for a
    1251             :  *    join relation from the joininfo lists of the relations it joins.
    1252             :  *
    1253             :  *    These routines are separate because the restriction list must be
    1254             :  *    built afresh for each pair of input sub-relations we consider, whereas
    1255             :  *    the join list need only be computed once for any join RelOptInfo.
    1256             :  *    The join list is fully determined by the set of rels making up the
    1257             :  *    joinrel, so we should get the same results (up to ordering) from any
    1258             :  *    candidate pair of sub-relations.  But the restriction list is whatever
    1259             :  *    is not handled in the sub-relations, so it depends on which
    1260             :  *    sub-relations are considered.
    1261             :  *
    1262             :  *    If a join clause from an input relation refers to base+OJ rels still not
    1263             :  *    present in the joinrel, then it is still a join clause for the joinrel;
    1264             :  *    we put it into the joininfo list for the joinrel.  Otherwise,
    1265             :  *    the clause is now a restrict clause for the joined relation, and we
    1266             :  *    return it to the caller of build_joinrel_restrictlist() to be stored in
    1267             :  *    join paths made from this pair of sub-relations.  (It will not need to
    1268             :  *    be considered further up the join tree.)
    1269             :  *
    1270             :  *    In many cases we will find the same RestrictInfos in both input
    1271             :  *    relations' joinlists, so be careful to eliminate duplicates.
    1272             :  *    Pointer equality should be a sufficient test for dups, since all
    1273             :  *    the various joinlist entries ultimately refer to RestrictInfos
    1274             :  *    pushed into them by distribute_restrictinfo_to_rels().
    1275             :  *
    1276             :  * 'joinrel' is a join relation node
    1277             :  * 'outer_rel' and 'inner_rel' are a pair of relations that can be joined
    1278             :  *      to form joinrel.
    1279             :  * 'sjinfo': join context info
    1280             :  *
    1281             :  * build_joinrel_restrictlist() returns a list of relevant restrictinfos,
    1282             :  * whereas build_joinrel_joinlist() stores its results in the joinrel's
    1283             :  * joininfo list.  One or the other must accept each given clause!
    1284             :  *
    1285             :  * NB: Formerly, we made deep(!) copies of each input RestrictInfo to pass
    1286             :  * up to the join relation.  I believe this is no longer necessary, because
    1287             :  * RestrictInfo nodes are no longer context-dependent.  Instead, just include
    1288             :  * the original nodes in the lists made for the join relation.
    1289             :  */
    1290             : static List *
    1291      310804 : build_joinrel_restrictlist(PlannerInfo *root,
    1292             :                            RelOptInfo *joinrel,
    1293             :                            RelOptInfo *outer_rel,
    1294             :                            RelOptInfo *inner_rel,
    1295             :                            SpecialJoinInfo *sjinfo)
    1296             : {
    1297             :     List       *result;
    1298             :     Relids      both_input_relids;
    1299             : 
    1300      310804 :     both_input_relids = bms_union(outer_rel->relids, inner_rel->relids);
    1301             : 
    1302             :     /*
    1303             :      * Collect all the clauses that syntactically belong at this level,
    1304             :      * eliminating any duplicates (important since we will see many of the
    1305             :      * same clauses arriving from both input relations).
    1306             :      */
    1307      310804 :     result = subbuild_joinrel_restrictlist(root, joinrel, outer_rel,
    1308             :                                            both_input_relids, NIL);
    1309      310804 :     result = subbuild_joinrel_restrictlist(root, joinrel, inner_rel,
    1310             :                                            both_input_relids, result);
    1311             : 
    1312             :     /*
    1313             :      * Add on any clauses derived from EquivalenceClasses.  These cannot be
    1314             :      * redundant with the clauses in the joininfo lists, so don't bother
    1315             :      * checking.
    1316             :      */
    1317      310804 :     result = list_concat(result,
    1318      310804 :                          generate_join_implied_equalities(root,
    1319             :                                                           joinrel->relids,
    1320             :                                                           outer_rel->relids,
    1321             :                                                           inner_rel,
    1322             :                                                           sjinfo));
    1323             : 
    1324      310804 :     return result;
    1325             : }
    1326             : 
    1327             : static void
    1328      201338 : build_joinrel_joinlist(RelOptInfo *joinrel,
    1329             :                        RelOptInfo *outer_rel,
    1330             :                        RelOptInfo *inner_rel)
    1331             : {
    1332             :     List       *result;
    1333             : 
    1334             :     /*
    1335             :      * Collect all the clauses that syntactically belong above this level,
    1336             :      * eliminating any duplicates (important since we will see many of the
    1337             :      * same clauses arriving from both input relations).
    1338             :      */
    1339      201338 :     result = subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo, NIL);
    1340      201338 :     result = subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo, result);
    1341             : 
    1342      201338 :     joinrel->joininfo = result;
    1343      201338 : }
    1344             : 
    1345             : static List *
    1346      621608 : subbuild_joinrel_restrictlist(PlannerInfo *root,
    1347             :                               RelOptInfo *joinrel,
    1348             :                               RelOptInfo *input_rel,
    1349             :                               Relids both_input_relids,
    1350             :                               List *new_restrictlist)
    1351             : {
    1352             :     ListCell   *l;
    1353             : 
    1354     1213154 :     foreach(l, input_rel->joininfo)
    1355             :     {
    1356      591546 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
    1357             : 
    1358      591546 :         if (bms_is_subset(rinfo->required_relids, joinrel->relids))
    1359             :         {
    1360             :             /*
    1361             :              * This clause should become a restriction clause for the joinrel,
    1362             :              * since it refers to no outside rels.  However, if it's a clone
    1363             :              * clause then it might be too late to evaluate it, so we have to
    1364             :              * check.  (If it is too late, just ignore the clause, taking it
    1365             :              * on faith that another clone was or will be selected.)  Clone
    1366             :              * clauses should always be outer-join clauses, so we compare
    1367             :              * against both_input_relids.
    1368             :              */
    1369      350868 :             if (rinfo->has_clone || rinfo->is_clone)
    1370             :             {
    1371             :                 Assert(!RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids));
    1372       63370 :                 if (!bms_is_subset(rinfo->required_relids, both_input_relids))
    1373       10602 :                     continue;
    1374       52768 :                 if (bms_overlap(rinfo->incompatible_relids, both_input_relids))
    1375       20920 :                     continue;
    1376             :             }
    1377             :             else
    1378             :             {
    1379             :                 /*
    1380             :                  * For non-clone clauses, we just Assert it's OK.  These might
    1381             :                  * be either join or filter clauses; if it's a join clause
    1382             :                  * then it should not refer to the current join's output.
    1383             :                  * (There is little point in checking incompatible_relids,
    1384             :                  * because it'll be NULL.)
    1385             :                  */
    1386             :                 Assert(RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids) ||
    1387             :                        bms_is_subset(rinfo->required_relids,
    1388             :                                      both_input_relids));
    1389             :             }
    1390             : 
    1391             :             /*
    1392             :              * OK, so add it to the list, being careful to eliminate
    1393             :              * duplicates.  (Since RestrictInfo nodes in different joinlists
    1394             :              * will have been multiply-linked rather than copied, pointer
    1395             :              * equality should be a sufficient test.)
    1396             :              */
    1397      319346 :             new_restrictlist = list_append_unique_ptr(new_restrictlist, rinfo);
    1398             :         }
    1399             :         else
    1400             :         {
    1401             :             /*
    1402             :              * This clause is still a join clause at this level, so we ignore
    1403             :              * it in this routine.
    1404             :              */
    1405             :         }
    1406             :     }
    1407             : 
    1408      621608 :     return new_restrictlist;
    1409             : }
    1410             : 
    1411             : static List *
    1412      402676 : subbuild_joinrel_joinlist(RelOptInfo *joinrel,
    1413             :                           List *joininfo_list,
    1414             :                           List *new_joininfo)
    1415             : {
    1416             :     ListCell   *l;
    1417             : 
    1418             :     /* Expected to be called only for join between parent relations. */
    1419             :     Assert(joinrel->reloptkind == RELOPT_JOINREL);
    1420             : 
    1421      773562 :     foreach(l, joininfo_list)
    1422             :     {
    1423      370886 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
    1424             : 
    1425      370886 :         if (bms_is_subset(rinfo->required_relids, joinrel->relids))
    1426             :         {
    1427             :             /*
    1428             :              * This clause becomes a restriction clause for the joinrel, since
    1429             :              * it refers to no outside rels.  So we can ignore it in this
    1430             :              * routine.
    1431             :              */
    1432             :         }
    1433             :         else
    1434             :         {
    1435             :             /*
    1436             :              * This clause is still a join clause at this level, so add it to
    1437             :              * the new joininfo list, being careful to eliminate duplicates.
    1438             :              * (Since RestrictInfo nodes in different joinlists will have been
    1439             :              * multiply-linked rather than copied, pointer equality should be
    1440             :              * a sufficient test.)
    1441             :              */
    1442      146872 :             new_joininfo = list_append_unique_ptr(new_joininfo, rinfo);
    1443             :         }
    1444             :     }
    1445             : 
    1446      402676 :     return new_joininfo;
    1447             : }
    1448             : 
    1449             : 
    1450             : /*
    1451             :  * fetch_upper_rel
    1452             :  *      Build a RelOptInfo describing some post-scan/join query processing,
    1453             :  *      or return a pre-existing one if somebody already built it.
    1454             :  *
    1455             :  * An "upper" relation is identified by an UpperRelationKind and a Relids set.
    1456             :  * The meaning of the Relids set is not specified here, and very likely will
    1457             :  * vary for different relation kinds.
    1458             :  *
    1459             :  * Most of the fields in an upper-level RelOptInfo are not used and are not
    1460             :  * set here (though makeNode should ensure they're zeroes).  We basically only
    1461             :  * care about fields that are of interest to add_path() and set_cheapest().
    1462             :  */
    1463             : RelOptInfo *
    1464     1722584 : fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
    1465             : {
    1466             :     RelOptInfo *upperrel;
    1467             :     ListCell   *lc;
    1468             : 
    1469             :     /*
    1470             :      * For the moment, our indexing data structure is just a List for each
    1471             :      * relation kind.  If we ever get so many of one kind that this stops
    1472             :      * working well, we can improve it.  No code outside this function should
    1473             :      * assume anything about how to find a particular upperrel.
    1474             :      */
    1475             : 
    1476             :     /* If we already made this upperrel for the query, return it */
    1477     1729526 :     foreach(lc, root->upper_rels[kind])
    1478             :     {
    1479     1088922 :         upperrel = (RelOptInfo *) lfirst(lc);
    1480             : 
    1481     1088922 :         if (bms_equal(upperrel->relids, relids))
    1482     1081980 :             return upperrel;
    1483             :     }
    1484             : 
    1485      640604 :     upperrel = makeNode(RelOptInfo);
    1486      640604 :     upperrel->reloptkind = RELOPT_UPPER_REL;
    1487      640604 :     upperrel->relids = bms_copy(relids);
    1488             : 
    1489             :     /* cheap startup cost is interesting iff not all tuples to be retrieved */
    1490      640604 :     upperrel->consider_startup = (root->tuple_fraction > 0);
    1491      640604 :     upperrel->consider_param_startup = false;
    1492      640604 :     upperrel->consider_parallel = false; /* might get changed later */
    1493      640604 :     upperrel->reltarget = create_empty_pathtarget();
    1494      640604 :     upperrel->pathlist = NIL;
    1495      640604 :     upperrel->cheapest_startup_path = NULL;
    1496      640604 :     upperrel->cheapest_total_path = NULL;
    1497      640604 :     upperrel->cheapest_parameterized_paths = NIL;
    1498             : 
    1499      640604 :     root->upper_rels[kind] = lappend(root->upper_rels[kind], upperrel);
    1500             : 
    1501      640604 :     return upperrel;
    1502             : }
    1503             : 
    1504             : 
    1505             : /*
    1506             :  * find_childrel_parents
    1507             :  *      Compute the set of parent relids of an appendrel child rel.
    1508             :  *
    1509             :  * Since appendrels can be nested, a child could have multiple levels of
    1510             :  * appendrel ancestors.  This function computes a Relids set of all the
    1511             :  * parent relation IDs.
    1512             :  */
    1513             : Relids
    1514       12166 : find_childrel_parents(PlannerInfo *root, RelOptInfo *rel)
    1515             : {
    1516       12166 :     Relids      result = NULL;
    1517             : 
    1518             :     Assert(rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
    1519             :     Assert(rel->relid > 0 && rel->relid < root->simple_rel_array_size);
    1520             : 
    1521             :     do
    1522             :     {
    1523       14346 :         AppendRelInfo *appinfo = root->append_rel_array[rel->relid];
    1524       14346 :         Index       prelid = appinfo->parent_relid;
    1525             : 
    1526       14346 :         result = bms_add_member(result, prelid);
    1527             : 
    1528             :         /* traverse up to the parent rel, loop if it's also a child rel */
    1529       14346 :         rel = find_base_rel(root, prelid);
    1530       14346 :     } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
    1531             : 
    1532             :     Assert(rel->reloptkind == RELOPT_BASEREL);
    1533             : 
    1534       12166 :     return result;
    1535             : }
    1536             : 
    1537             : 
    1538             : /*
    1539             :  * get_baserel_parampathinfo
    1540             :  *      Get the ParamPathInfo for a parameterized path for a base relation,
    1541             :  *      constructing one if we don't have one already.
    1542             :  *
    1543             :  * This centralizes estimating the rowcounts for parameterized paths.
    1544             :  * We need to cache those to be sure we use the same rowcount for all paths
    1545             :  * of the same parameterization for a given rel.  This is also a convenient
    1546             :  * place to determine which movable join clauses the parameterized path will
    1547             :  * be responsible for evaluating.
    1548             :  */
    1549             : ParamPathInfo *
    1550     1752642 : get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
    1551             :                           Relids required_outer)
    1552             : {
    1553             :     ParamPathInfo *ppi;
    1554             :     Relids      joinrelids;
    1555             :     List       *pclauses;
    1556             :     List       *eqclauses;
    1557             :     Bitmapset  *pserials;
    1558             :     double      rows;
    1559             :     ListCell   *lc;
    1560             : 
    1561             :     /* If rel has LATERAL refs, every path for it should account for them */
    1562             :     Assert(bms_is_subset(baserel->lateral_relids, required_outer));
    1563             : 
    1564             :     /* Unparameterized paths have no ParamPathInfo */
    1565     1752642 :     if (bms_is_empty(required_outer))
    1566     1446690 :         return NULL;
    1567             : 
    1568             :     Assert(!bms_overlap(baserel->relids, required_outer));
    1569             : 
    1570             :     /* If we already have a PPI for this parameterization, just return it */
    1571      305952 :     if ((ppi = find_param_path_info(baserel, required_outer)))
    1572      162584 :         return ppi;
    1573             : 
    1574             :     /*
    1575             :      * Identify all joinclauses that are movable to this base rel given this
    1576             :      * parameterization.
    1577             :      */
    1578      143368 :     joinrelids = bms_union(baserel->relids, required_outer);
    1579      143368 :     pclauses = NIL;
    1580      239866 :     foreach(lc, baserel->joininfo)
    1581             :     {
    1582       96498 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1583             : 
    1584       96498 :         if (join_clause_is_movable_into(rinfo,
    1585             :                                         baserel->relids,
    1586             :                                         joinrelids))
    1587       40930 :             pclauses = lappend(pclauses, rinfo);
    1588             :     }
    1589             : 
    1590             :     /*
    1591             :      * Add in joinclauses generated by EquivalenceClasses, too.  (These
    1592             :      * necessarily satisfy join_clause_is_movable_into; but in assert-enabled
    1593             :      * builds, let's verify that.)
    1594             :      */
    1595      143368 :     eqclauses = generate_join_implied_equalities(root,
    1596             :                                                  joinrelids,
    1597             :                                                  required_outer,
    1598             :                                                  baserel,
    1599             :                                                  NULL);
    1600             : #ifdef USE_ASSERT_CHECKING
    1601             :     foreach(lc, eqclauses)
    1602             :     {
    1603             :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1604             : 
    1605             :         Assert(join_clause_is_movable_into(rinfo,
    1606             :                                            baserel->relids,
    1607             :                                            joinrelids));
    1608             :     }
    1609             : #endif
    1610      143368 :     pclauses = list_concat(pclauses, eqclauses);
    1611             : 
    1612             :     /* Compute set of serial numbers of the enforced clauses */
    1613      143368 :     pserials = NULL;
    1614      289948 :     foreach(lc, pclauses)
    1615             :     {
    1616      146580 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1617             : 
    1618      146580 :         pserials = bms_add_member(pserials, rinfo->rinfo_serial);
    1619             :     }
    1620             : 
    1621             :     /* Estimate the number of rows returned by the parameterized scan */
    1622      143368 :     rows = get_parameterized_baserel_size(root, baserel, pclauses);
    1623             : 
    1624             :     /* And now we can build the ParamPathInfo */
    1625      143368 :     ppi = makeNode(ParamPathInfo);
    1626      143368 :     ppi->ppi_req_outer = required_outer;
    1627      143368 :     ppi->ppi_rows = rows;
    1628      143368 :     ppi->ppi_clauses = pclauses;
    1629      143368 :     ppi->ppi_serials = pserials;
    1630      143368 :     baserel->ppilist = lappend(baserel->ppilist, ppi);
    1631             : 
    1632      143368 :     return ppi;
    1633             : }
    1634             : 
    1635             : /*
    1636             :  * get_joinrel_parampathinfo
    1637             :  *      Get the ParamPathInfo for a parameterized path for a join relation,
    1638             :  *      constructing one if we don't have one already.
    1639             :  *
    1640             :  * This centralizes estimating the rowcounts for parameterized paths.
    1641             :  * We need to cache those to be sure we use the same rowcount for all paths
    1642             :  * of the same parameterization for a given rel.  This is also a convenient
    1643             :  * place to determine which movable join clauses the parameterized path will
    1644             :  * be responsible for evaluating.
    1645             :  *
    1646             :  * outer_path and inner_path are a pair of input paths that can be used to
    1647             :  * construct the join, and restrict_clauses is the list of regular join
    1648             :  * clauses (including clauses derived from EquivalenceClasses) that must be
    1649             :  * applied at the join node when using these inputs.
    1650             :  *
    1651             :  * Unlike the situation for base rels, the set of movable join clauses to be
    1652             :  * enforced at a join varies with the selected pair of input paths, so we
    1653             :  * must calculate that and pass it back, even if we already have a matching
    1654             :  * ParamPathInfo.  We handle this by adding any clauses moved down to this
    1655             :  * join to *restrict_clauses, which is an in/out parameter.  (The addition
    1656             :  * is done in such a way as to not modify the passed-in List structure.)
    1657             :  *
    1658             :  * Note: when considering a nestloop join, the caller must have removed from
    1659             :  * restrict_clauses any movable clauses that are themselves scheduled to be
    1660             :  * pushed into the right-hand path.  We do not do that here since it's
    1661             :  * unnecessary for other join types.
    1662             :  */
    1663             : ParamPathInfo *
    1664     1918430 : get_joinrel_parampathinfo(PlannerInfo *root, RelOptInfo *joinrel,
    1665             :                           Path *outer_path,
    1666             :                           Path *inner_path,
    1667             :                           SpecialJoinInfo *sjinfo,
    1668             :                           Relids required_outer,
    1669             :                           List **restrict_clauses)
    1670             : {
    1671             :     ParamPathInfo *ppi;
    1672             :     Relids      join_and_req;
    1673             :     Relids      outer_and_req;
    1674             :     Relids      inner_and_req;
    1675             :     List       *pclauses;
    1676             :     List       *eclauses;
    1677             :     List       *dropped_ecs;
    1678             :     double      rows;
    1679             :     ListCell   *lc;
    1680             : 
    1681             :     /* If rel has LATERAL refs, every path for it should account for them */
    1682             :     Assert(bms_is_subset(joinrel->lateral_relids, required_outer));
    1683             : 
    1684             :     /* Unparameterized paths have no ParamPathInfo or extra join clauses */
    1685     1918430 :     if (bms_is_empty(required_outer))
    1686     1885476 :         return NULL;
    1687             : 
    1688             :     Assert(!bms_overlap(joinrel->relids, required_outer));
    1689             : 
    1690             :     /*
    1691             :      * Identify all joinclauses that are movable to this join rel given this
    1692             :      * parameterization.  These are the clauses that are movable into this
    1693             :      * join, but not movable into either input path.  Treat an unparameterized
    1694             :      * input path as not accepting parameterized clauses (because it won't,
    1695             :      * per the shortcut exit above), even though the joinclause movement rules
    1696             :      * might allow the same clauses to be moved into a parameterized path for
    1697             :      * that rel.
    1698             :      */
    1699       32954 :     join_and_req = bms_union(joinrel->relids, required_outer);
    1700       32954 :     if (outer_path->param_info)
    1701       28346 :         outer_and_req = bms_union(outer_path->parent->relids,
    1702       28346 :                                   PATH_REQ_OUTER(outer_path));
    1703             :     else
    1704        4608 :         outer_and_req = NULL;   /* outer path does not accept parameters */
    1705       32954 :     if (inner_path->param_info)
    1706       17870 :         inner_and_req = bms_union(inner_path->parent->relids,
    1707       17870 :                                   PATH_REQ_OUTER(inner_path));
    1708             :     else
    1709       15084 :         inner_and_req = NULL;   /* inner path does not accept parameters */
    1710             : 
    1711       32954 :     pclauses = NIL;
    1712       83372 :     foreach(lc, joinrel->joininfo)
    1713             :     {
    1714       50418 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1715             : 
    1716       50418 :         if (join_clause_is_movable_into(rinfo,
    1717             :                                         joinrel->relids,
    1718       24620 :                                         join_and_req) &&
    1719       24620 :             !join_clause_is_movable_into(rinfo,
    1720       24620 :                                          outer_path->parent->relids,
    1721         766 :                                          outer_and_req) &&
    1722         766 :             !join_clause_is_movable_into(rinfo,
    1723         766 :                                          inner_path->parent->relids,
    1724             :                                          inner_and_req))
    1725          96 :             pclauses = lappend(pclauses, rinfo);
    1726             :     }
    1727             : 
    1728             :     /* Consider joinclauses generated by EquivalenceClasses, too */
    1729       32954 :     eclauses = generate_join_implied_equalities(root,
    1730             :                                                 join_and_req,
    1731             :                                                 required_outer,
    1732             :                                                 joinrel,
    1733             :                                                 NULL);
    1734             :     /* We only want ones that aren't movable to lower levels */
    1735       32954 :     dropped_ecs = NIL;
    1736       39770 :     foreach(lc, eclauses)
    1737             :     {
    1738        6816 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1739             : 
    1740             :         Assert(join_clause_is_movable_into(rinfo,
    1741             :                                            joinrel->relids,
    1742             :                                            join_and_req));
    1743        6816 :         if (join_clause_is_movable_into(rinfo,
    1744        6816 :                                         outer_path->parent->relids,
    1745             :                                         outer_and_req))
    1746        3050 :             continue;           /* drop if movable into LHS */
    1747        3766 :         if (join_clause_is_movable_into(rinfo,
    1748        3766 :                                         inner_path->parent->relids,
    1749             :                                         inner_and_req))
    1750             :         {
    1751             :             /* drop if movable into RHS, but remember EC for use below */
    1752             :             Assert(rinfo->left_ec == rinfo->right_ec);
    1753        2504 :             dropped_ecs = lappend(dropped_ecs, rinfo->left_ec);
    1754        2504 :             continue;
    1755             :         }
    1756        1262 :         pclauses = lappend(pclauses, rinfo);
    1757             :     }
    1758             : 
    1759             :     /*
    1760             :      * EquivalenceClasses are harder to deal with than we could wish, because
    1761             :      * of the fact that a given EC can generate different clauses depending on
    1762             :      * context.  Suppose we have an EC {X.X, Y.Y, Z.Z} where X and Y are the
    1763             :      * LHS and RHS of the current join and Z is in required_outer, and further
    1764             :      * suppose that the inner_path is parameterized by both X and Z.  The code
    1765             :      * above will have produced either Z.Z = X.X or Z.Z = Y.Y from that EC,
    1766             :      * and in the latter case will have discarded it as being movable into the
    1767             :      * RHS.  However, the EC machinery might have produced either Y.Y = X.X or
    1768             :      * Y.Y = Z.Z as the EC enforcement clause within the inner_path; it will
    1769             :      * not have produced both, and we can't readily tell from here which one
    1770             :      * it did pick.  If we add no clause to this join, we'll end up with
    1771             :      * insufficient enforcement of the EC; either Z.Z or X.X will fail to be
    1772             :      * constrained to be equal to the other members of the EC.  (When we come
    1773             :      * to join Z to this X/Y path, we will certainly drop whichever EC clause
    1774             :      * is generated at that join, so this omission won't get fixed later.)
    1775             :      *
    1776             :      * To handle this, for each EC we discarded such a clause from, try to
    1777             :      * generate a clause connecting the required_outer rels to the join's LHS
    1778             :      * ("Z.Z = X.X" in the terms of the above example).  If successful, and if
    1779             :      * the clause can't be moved to the LHS, add it to the current join's
    1780             :      * restriction clauses.  (If an EC cannot generate such a clause then it
    1781             :      * has nothing that needs to be enforced here, while if the clause can be
    1782             :      * moved into the LHS then it should have been enforced within that path.)
    1783             :      *
    1784             :      * Note that we don't need similar processing for ECs whose clause was
    1785             :      * considered to be movable into the LHS, because the LHS can't refer to
    1786             :      * the RHS so there is no comparable ambiguity about what it might
    1787             :      * actually be enforcing internally.
    1788             :      */
    1789       32954 :     if (dropped_ecs)
    1790             :     {
    1791             :         Relids      real_outer_and_req;
    1792             : 
    1793        2438 :         real_outer_and_req = bms_union(outer_path->parent->relids,
    1794             :                                        required_outer);
    1795             :         eclauses =
    1796        2438 :             generate_join_implied_equalities_for_ecs(root,
    1797             :                                                      dropped_ecs,
    1798             :                                                      real_outer_and_req,
    1799             :                                                      required_outer,
    1800             :                                                      outer_path->parent);
    1801        2738 :         foreach(lc, eclauses)
    1802             :         {
    1803         300 :             RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1804             : 
    1805             :             Assert(join_clause_is_movable_into(rinfo,
    1806             :                                                outer_path->parent->relids,
    1807             :                                                real_outer_and_req));
    1808         300 :             if (!join_clause_is_movable_into(rinfo,
    1809         300 :                                              outer_path->parent->relids,
    1810             :                                              outer_and_req))
    1811         270 :                 pclauses = lappend(pclauses, rinfo);
    1812             :         }
    1813             :     }
    1814             : 
    1815             :     /*
    1816             :      * Now, attach the identified moved-down clauses to the caller's
    1817             :      * restrict_clauses list.  By using list_concat in this order, we leave
    1818             :      * the original list structure of restrict_clauses undamaged.
    1819             :      */
    1820       32954 :     *restrict_clauses = list_concat(pclauses, *restrict_clauses);
    1821             : 
    1822             :     /* If we already have a PPI for this parameterization, just return it */
    1823       32954 :     if ((ppi = find_param_path_info(joinrel, required_outer)))
    1824       24440 :         return ppi;
    1825             : 
    1826             :     /* Estimate the number of rows returned by the parameterized join */
    1827        8514 :     rows = get_parameterized_joinrel_size(root, joinrel,
    1828             :                                           outer_path,
    1829             :                                           inner_path,
    1830             :                                           sjinfo,
    1831             :                                           *restrict_clauses);
    1832             : 
    1833             :     /*
    1834             :      * And now we can build the ParamPathInfo.  No point in saving the
    1835             :      * input-pair-dependent clause list, though.
    1836             :      *
    1837             :      * Note: in GEQO mode, we'll be called in a temporary memory context, but
    1838             :      * the joinrel structure is there too, so no problem.
    1839             :      */
    1840        8514 :     ppi = makeNode(ParamPathInfo);
    1841        8514 :     ppi->ppi_req_outer = required_outer;
    1842        8514 :     ppi->ppi_rows = rows;
    1843        8514 :     ppi->ppi_clauses = NIL;
    1844        8514 :     ppi->ppi_serials = NULL;
    1845        8514 :     joinrel->ppilist = lappend(joinrel->ppilist, ppi);
    1846             : 
    1847        8514 :     return ppi;
    1848             : }
    1849             : 
    1850             : /*
    1851             :  * get_appendrel_parampathinfo
    1852             :  *      Get the ParamPathInfo for a parameterized path for an append relation.
    1853             :  *
    1854             :  * For an append relation, the rowcount estimate will just be the sum of
    1855             :  * the estimates for its children.  However, we still need a ParamPathInfo
    1856             :  * to flag the fact that the path requires parameters.  So this just creates
    1857             :  * a suitable struct with zero ppi_rows (and no ppi_clauses either, since
    1858             :  * the Append node isn't responsible for checking quals).
    1859             :  */
    1860             : ParamPathInfo *
    1861       38348 : get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
    1862             : {
    1863             :     ParamPathInfo *ppi;
    1864             : 
    1865             :     /* If rel has LATERAL refs, every path for it should account for them */
    1866             :     Assert(bms_is_subset(appendrel->lateral_relids, required_outer));
    1867             : 
    1868             :     /* Unparameterized paths have no ParamPathInfo */
    1869       38348 :     if (bms_is_empty(required_outer))
    1870       37780 :         return NULL;
    1871             : 
    1872             :     Assert(!bms_overlap(appendrel->relids, required_outer));
    1873             : 
    1874             :     /* If we already have a PPI for this parameterization, just return it */
    1875         568 :     if ((ppi = find_param_path_info(appendrel, required_outer)))
    1876         132 :         return ppi;
    1877             : 
    1878             :     /* Else build the ParamPathInfo */
    1879         436 :     ppi = makeNode(ParamPathInfo);
    1880         436 :     ppi->ppi_req_outer = required_outer;
    1881         436 :     ppi->ppi_rows = 0;
    1882         436 :     ppi->ppi_clauses = NIL;
    1883         436 :     ppi->ppi_serials = NULL;
    1884         436 :     appendrel->ppilist = lappend(appendrel->ppilist, ppi);
    1885             : 
    1886         436 :     return ppi;
    1887             : }
    1888             : 
    1889             : /*
    1890             :  * Returns a ParamPathInfo for the parameterization given by required_outer, if
    1891             :  * already available in the given rel. Returns NULL otherwise.
    1892             :  */
    1893             : ParamPathInfo *
    1894      340500 : find_param_path_info(RelOptInfo *rel, Relids required_outer)
    1895             : {
    1896             :     ListCell   *lc;
    1897             : 
    1898      394922 :     foreach(lc, rel->ppilist)
    1899             :     {
    1900      241740 :         ParamPathInfo *ppi = (ParamPathInfo *) lfirst(lc);
    1901             : 
    1902      241740 :         if (bms_equal(ppi->ppi_req_outer, required_outer))
    1903      187318 :             return ppi;
    1904             :     }
    1905             : 
    1906      153182 :     return NULL;
    1907             : }
    1908             : 
    1909             : /*
    1910             :  * get_param_path_clause_serials
    1911             :  *      Given a parameterized Path, return the set of pushed-down clauses
    1912             :  *      (identified by rinfo_serial numbers) enforced within the Path.
    1913             :  */
    1914             : Bitmapset *
    1915      397374 : get_param_path_clause_serials(Path *path)
    1916             : {
    1917      397374 :     if (path->param_info == NULL)
    1918        1896 :         return NULL;            /* not parameterized */
    1919             : 
    1920             :     /*
    1921             :      * We don't currently support parameterized MergeAppend paths, as
    1922             :      * explained in the comments for generate_orderedappend_paths.
    1923             :      */
    1924             :     Assert(!IsA(path, MergeAppendPath));
    1925             : 
    1926      395478 :     if (IsA(path, NestPath) ||
    1927      386728 :         IsA(path, MergePath) ||
    1928      386722 :         IsA(path, HashPath))
    1929             :     {
    1930             :         /*
    1931             :          * For a join path, combine clauses enforced within either input path
    1932             :          * with those enforced as joinrestrictinfo in this path.  Note that
    1933             :          * joinrestrictinfo may include some non-pushed-down clauses, but for
    1934             :          * current purposes it's okay if we include those in the result. (To
    1935             :          * be more careful, we could check for clause_relids overlapping the
    1936             :          * path parameterization, but it's not worth the cycles for now.)
    1937             :          */
    1938        9572 :         JoinPath   *jpath = (JoinPath *) path;
    1939             :         Bitmapset  *pserials;
    1940             :         ListCell   *lc;
    1941             : 
    1942        9572 :         pserials = NULL;
    1943        9572 :         pserials = bms_add_members(pserials,
    1944        9572 :                                    get_param_path_clause_serials(jpath->outerjoinpath));
    1945        9572 :         pserials = bms_add_members(pserials,
    1946        9572 :                                    get_param_path_clause_serials(jpath->innerjoinpath));
    1947       11440 :         foreach(lc, jpath->joinrestrictinfo)
    1948             :         {
    1949        1868 :             RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    1950             : 
    1951        1868 :             pserials = bms_add_member(pserials, rinfo->rinfo_serial);
    1952             :         }
    1953        9572 :         return pserials;
    1954             :     }
    1955      385906 :     else if (IsA(path, AppendPath))
    1956             :     {
    1957             :         /*
    1958             :          * For an appendrel, take the intersection of the sets of clauses
    1959             :          * enforced in each input path.
    1960             :          */
    1961        2348 :         AppendPath *apath = (AppendPath *) path;
    1962             :         Bitmapset  *pserials;
    1963             :         ListCell   *lc;
    1964             : 
    1965        2348 :         pserials = NULL;
    1966        9716 :         foreach(lc, apath->subpaths)
    1967             :         {
    1968        7368 :             Path       *subpath = (Path *) lfirst(lc);
    1969             :             Bitmapset  *subserials;
    1970             : 
    1971        7368 :             subserials = get_param_path_clause_serials(subpath);
    1972        7368 :             if (lc == list_head(apath->subpaths))
    1973        2324 :                 pserials = bms_copy(subserials);
    1974             :             else
    1975        5044 :                 pserials = bms_int_members(pserials, subserials);
    1976             :         }
    1977        2348 :         return pserials;
    1978             :     }
    1979             :     else
    1980             :     {
    1981             :         /*
    1982             :          * Otherwise, it's a baserel path and we can use the
    1983             :          * previously-computed set of serial numbers.
    1984             :          */
    1985      383558 :         return path->param_info->ppi_serials;
    1986             :     }
    1987             : }
    1988             : 
    1989             : /*
    1990             :  * build_joinrel_partition_info
    1991             :  *      Checks if the two relations being joined can use partitionwise join
    1992             :  *      and if yes, initialize partitioning information of the resulting
    1993             :  *      partitioned join relation.
    1994             :  */
    1995             : static void
    1996      206340 : build_joinrel_partition_info(PlannerInfo *root,
    1997             :                              RelOptInfo *joinrel, RelOptInfo *outer_rel,
    1998             :                              RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo,
    1999             :                              List *restrictlist)
    2000             : {
    2001             :     PartitionScheme part_scheme;
    2002             : 
    2003             :     /* Nothing to do if partitionwise join technique is disabled. */
    2004      206340 :     if (!enable_partitionwise_join)
    2005             :     {
    2006             :         Assert(!IS_PARTITIONED_REL(joinrel));
    2007      199266 :         return;
    2008             :     }
    2009             : 
    2010             :     /*
    2011             :      * We can only consider this join as an input to further partitionwise
    2012             :      * joins if (a) the input relations are partitioned and have
    2013             :      * consider_partitionwise_join=true, (b) the partition schemes match, and
    2014             :      * (c) we can identify an equi-join between the partition keys.  Note that
    2015             :      * if it were possible for have_partkey_equi_join to return different
    2016             :      * answers for the same joinrel depending on which join ordering we try
    2017             :      * first, this logic would break.  That shouldn't happen, though, because
    2018             :      * of the way the query planner deduces implied equalities and reorders
    2019             :      * the joins.  Please see optimizer/README for details.
    2020             :      */
    2021        7074 :     if (outer_rel->part_scheme == NULL || inner_rel->part_scheme == NULL ||
    2022        2306 :         !outer_rel->consider_partitionwise_join ||
    2023        2262 :         !inner_rel->consider_partitionwise_join ||
    2024        2226 :         outer_rel->part_scheme != inner_rel->part_scheme ||
    2025        2202 :         !have_partkey_equi_join(root, joinrel, outer_rel, inner_rel,
    2026             :                                 sjinfo->jointype, restrictlist))
    2027             :     {
    2028             :         Assert(!IS_PARTITIONED_REL(joinrel));
    2029        5040 :         return;
    2030             :     }
    2031             : 
    2032        2034 :     part_scheme = outer_rel->part_scheme;
    2033             : 
    2034             :     /*
    2035             :      * This function will be called only once for each joinrel, hence it
    2036             :      * should not have partitioning fields filled yet.
    2037             :      */
    2038             :     Assert(!joinrel->part_scheme && !joinrel->partexprs &&
    2039             :            !joinrel->nullable_partexprs && !joinrel->part_rels &&
    2040             :            !joinrel->boundinfo);
    2041             : 
    2042             :     /*
    2043             :      * If the join relation is partitioned, it uses the same partitioning
    2044             :      * scheme as the joining relations.
    2045             :      *
    2046             :      * Note: we calculate the partition bounds, number of partitions, and
    2047             :      * child-join relations of the join relation in try_partitionwise_join().
    2048             :      */
    2049        2034 :     joinrel->part_scheme = part_scheme;
    2050        2034 :     set_joinrel_partition_key_exprs(joinrel, outer_rel, inner_rel,
    2051             :                                     sjinfo->jointype);
    2052             : 
    2053             :     /*
    2054             :      * Set the consider_partitionwise_join flag.
    2055             :      */
    2056             :     Assert(outer_rel->consider_partitionwise_join);
    2057             :     Assert(inner_rel->consider_partitionwise_join);
    2058        2034 :     joinrel->consider_partitionwise_join = true;
    2059             : }
    2060             : 
    2061             : /*
    2062             :  * have_partkey_equi_join
    2063             :  *
    2064             :  * Returns true if there exist equi-join conditions involving pairs
    2065             :  * of matching partition keys of the relations being joined for all
    2066             :  * partition keys.
    2067             :  */
    2068             : static bool
    2069        2202 : have_partkey_equi_join(PlannerInfo *root, RelOptInfo *joinrel,
    2070             :                        RelOptInfo *rel1, RelOptInfo *rel2,
    2071             :                        JoinType jointype, List *restrictlist)
    2072             : {
    2073        2202 :     PartitionScheme part_scheme = rel1->part_scheme;
    2074             :     bool        pk_known_equal[PARTITION_MAX_KEYS];
    2075             :     int         num_equal_pks;
    2076             :     ListCell   *lc;
    2077             : 
    2078             :     /*
    2079             :      * This function must only be called when the joined relations have same
    2080             :      * partitioning scheme.
    2081             :      */
    2082             :     Assert(rel1->part_scheme == rel2->part_scheme);
    2083             :     Assert(part_scheme);
    2084             : 
    2085             :     /* We use a bool array to track which partkey columns are known equal */
    2086        2202 :     memset(pk_known_equal, 0, sizeof(pk_known_equal));
    2087             :     /* ... as well as a count of how many are known equal */
    2088        2202 :     num_equal_pks = 0;
    2089             : 
    2090             :     /* First, look through the join's restriction clauses */
    2091        3420 :     foreach(lc, restrictlist)
    2092             :     {
    2093        3222 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
    2094             :         OpExpr     *opexpr;
    2095             :         Expr       *expr1;
    2096             :         Expr       *expr2;
    2097             :         bool        strict_op;
    2098             :         int         ipk1;
    2099             :         int         ipk2;
    2100             : 
    2101             :         /* If processing an outer join, only use its own join clauses. */
    2102        3222 :         if (IS_OUTER_JOIN(jointype) &&
    2103        1658 :             RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids))
    2104         246 :             continue;
    2105             : 
    2106             :         /* Skip clauses which can not be used for a join. */
    2107        2976 :         if (!rinfo->can_join)
    2108          18 :             continue;
    2109             : 
    2110             :         /* Skip clauses which are not equality conditions. */
    2111        2958 :         if (!rinfo->mergeopfamilies && !OidIsValid(rinfo->hashjoinoperator))
    2112           6 :             continue;
    2113             : 
    2114             :         /* Should be OK to assume it's an OpExpr. */
    2115        2952 :         opexpr = castNode(OpExpr, rinfo->clause);
    2116             : 
    2117             :         /* Match the operands to the relation. */
    2118        5754 :         if (bms_is_subset(rinfo->left_relids, rel1->relids) &&
    2119        2802 :             bms_is_subset(rinfo->right_relids, rel2->relids))
    2120             :         {
    2121        2802 :             expr1 = linitial(opexpr->args);
    2122        2802 :             expr2 = lsecond(opexpr->args);
    2123             :         }
    2124         300 :         else if (bms_is_subset(rinfo->left_relids, rel2->relids) &&
    2125         150 :                  bms_is_subset(rinfo->right_relids, rel1->relids))
    2126             :         {
    2127         150 :             expr1 = lsecond(opexpr->args);
    2128         150 :             expr2 = linitial(opexpr->args);
    2129             :         }
    2130             :         else
    2131           0 :             continue;
    2132             : 
    2133             :         /*
    2134             :          * Now we need to know whether the join operator is strict; see
    2135             :          * comments in pathnodes.h.
    2136             :          */
    2137        2952 :         strict_op = op_strict(opexpr->opno);
    2138             : 
    2139             :         /*
    2140             :          * Vars appearing in the relation's partition keys will not have any
    2141             :          * varnullingrels, but those in expr1 and expr2 will if we're above
    2142             :          * outer joins that could null the respective rels.  It's okay to
    2143             :          * match anyway, if the join operator is strict.
    2144             :          */
    2145        2952 :         if (strict_op)
    2146             :         {
    2147        2952 :             if (bms_overlap(rel1->relids, root->outer_join_rels))
    2148         180 :                 expr1 = (Expr *) remove_nulling_relids((Node *) expr1,
    2149         180 :                                                        root->outer_join_rels,
    2150             :                                                        NULL);
    2151        2952 :             if (bms_overlap(rel2->relids, root->outer_join_rels))
    2152           0 :                 expr2 = (Expr *) remove_nulling_relids((Node *) expr2,
    2153           0 :                                                        root->outer_join_rels,
    2154             :                                                        NULL);
    2155             :         }
    2156             : 
    2157             :         /*
    2158             :          * Only clauses referencing the partition keys are useful for
    2159             :          * partitionwise join.
    2160             :          */
    2161        2952 :         ipk1 = match_expr_to_partition_keys(expr1, rel1, strict_op);
    2162        2952 :         if (ipk1 < 0)
    2163         876 :             continue;
    2164        2076 :         ipk2 = match_expr_to_partition_keys(expr2, rel2, strict_op);
    2165        2076 :         if (ipk2 < 0)
    2166          48 :             continue;
    2167             : 
    2168             :         /*
    2169             :          * If the clause refers to keys at different ordinal positions, it can
    2170             :          * not be used for partitionwise join.
    2171             :          */
    2172        2028 :         if (ipk1 != ipk2)
    2173           6 :             continue;
    2174             : 
    2175             :         /* Ignore clause if we already proved these keys equal. */
    2176        2022 :         if (pk_known_equal[ipk1])
    2177           0 :             continue;
    2178             : 
    2179             :         /* Reject if the partition key collation differs from the clause's. */
    2180        2022 :         if (rel1->part_scheme->partcollation[ipk1] != opexpr->inputcollid)
    2181        2004 :             return false;
    2182             : 
    2183             :         /*
    2184             :          * The clause allows partitionwise join only if it uses the same
    2185             :          * operator family as that specified by the partition key.
    2186             :          */
    2187        2010 :         if (part_scheme->strategy == PARTITION_STRATEGY_HASH)
    2188             :         {
    2189          72 :             if (!OidIsValid(rinfo->hashjoinoperator) ||
    2190          72 :                 !op_in_opfamily(rinfo->hashjoinoperator,
    2191          72 :                                 part_scheme->partopfamily[ipk1]))
    2192           0 :                 continue;
    2193             :         }
    2194        1938 :         else if (!list_member_oid(rinfo->mergeopfamilies,
    2195        1938 :                                   part_scheme->partopfamily[ipk1]))
    2196           0 :             continue;
    2197             : 
    2198             :         /* Mark the partition key as having an equi-join clause. */
    2199        2010 :         pk_known_equal[ipk1] = true;
    2200             : 
    2201             :         /* We can stop examining clauses once we prove all keys equal. */
    2202        2010 :         if (++num_equal_pks == part_scheme->partnatts)
    2203        1992 :             return true;
    2204             :     }
    2205             : 
    2206             :     /*
    2207             :      * Also check to see if any keys are known equal by equivclass.c.  In most
    2208             :      * cases there would have been a join restriction clause generated from
    2209             :      * any EC that had such knowledge, but there might be no such clause, or
    2210             :      * it might happen to constrain other members of the ECs than the ones we
    2211             :      * are looking for.
    2212             :      */
    2213         204 :     for (int ipk = 0; ipk < part_scheme->partnatts; ipk++)
    2214             :     {
    2215             :         Oid         btree_opfamily;
    2216             : 
    2217             :         /* Ignore if we already proved these keys equal. */
    2218         204 :         if (pk_known_equal[ipk])
    2219           6 :             continue;
    2220             : 
    2221             :         /*
    2222             :          * We need a btree opfamily to ask equivclass.c about.  If the
    2223             :          * partopfamily is a hash opfamily, look up its equality operator, and
    2224             :          * select some btree opfamily that that operator is part of.  (Any
    2225             :          * such opfamily should be good enough, since equivclass.c will track
    2226             :          * multiple opfamilies as appropriate.)
    2227             :          */
    2228         198 :         if (part_scheme->strategy == PARTITION_STRATEGY_HASH)
    2229             :         {
    2230             :             Oid         eq_op;
    2231             :             List       *eq_opfamilies;
    2232             : 
    2233           0 :             eq_op = get_opfamily_member(part_scheme->partopfamily[ipk],
    2234           0 :                                         part_scheme->partopcintype[ipk],
    2235           0 :                                         part_scheme->partopcintype[ipk],
    2236             :                                         HTEqualStrategyNumber);
    2237           0 :             if (!OidIsValid(eq_op))
    2238           0 :                 break;          /* we're not going to succeed */
    2239           0 :             eq_opfamilies = get_mergejoin_opfamilies(eq_op);
    2240           0 :             if (eq_opfamilies == NIL)
    2241           0 :                 break;          /* we're not going to succeed */
    2242           0 :             btree_opfamily = linitial_oid(eq_opfamilies);
    2243             :         }
    2244             :         else
    2245         198 :             btree_opfamily = part_scheme->partopfamily[ipk];
    2246             : 
    2247             :         /*
    2248             :          * We consider only non-nullable partition keys here; nullable ones
    2249             :          * would not be treated as part of the same equivalence classes as
    2250             :          * non-nullable ones.
    2251             :          */
    2252         354 :         foreach(lc, rel1->partexprs[ipk])
    2253             :         {
    2254         198 :             Node       *expr1 = (Node *) lfirst(lc);
    2255             :             ListCell   *lc2;
    2256         198 :             Oid         partcoll1 = rel1->part_scheme->partcollation[ipk];
    2257         198 :             Oid         exprcoll1 = exprCollation(expr1);
    2258             : 
    2259         366 :             foreach(lc2, rel2->partexprs[ipk])
    2260             :             {
    2261         210 :                 Node       *expr2 = (Node *) lfirst(lc2);
    2262             : 
    2263         210 :                 if (exprs_known_equal(root, expr1, expr2, btree_opfamily))
    2264             :                 {
    2265             :                     /*
    2266             :                      * Ensure that the collation of the expression matches
    2267             :                      * that of the partition key. Checking just one collation
    2268             :                      * (partcoll1 and exprcoll1) suffices because partcoll1
    2269             :                      * and partcoll2, as well as exprcoll1 and exprcoll2,
    2270             :                      * should be identical. This holds because both rel1 and
    2271             :                      * rel2 use the same PartitionScheme and expr1 and expr2
    2272             :                      * are equal.
    2273             :                      */
    2274          54 :                     if (partcoll1 == exprcoll1)
    2275             :                     {
    2276          42 :                         Oid         partcoll2 PG_USED_FOR_ASSERTS_ONLY =
    2277          42 :                             rel2->part_scheme->partcollation[ipk];
    2278             :                         Oid         exprcoll2 PG_USED_FOR_ASSERTS_ONLY =
    2279          42 :                             exprCollation(expr2);
    2280             : 
    2281             :                         Assert(partcoll2 == exprcoll2);
    2282          42 :                         pk_known_equal[ipk] = true;
    2283          42 :                         break;
    2284             :                     }
    2285             :                 }
    2286             :             }
    2287         198 :             if (pk_known_equal[ipk])
    2288          42 :                 break;
    2289             :         }
    2290             : 
    2291         198 :         if (pk_known_equal[ipk])
    2292             :         {
    2293             :             /* We can stop examining keys once we prove all keys equal. */
    2294          42 :             if (++num_equal_pks == part_scheme->partnatts)
    2295          42 :                 return true;
    2296             :         }
    2297             :         else
    2298         156 :             break;              /* no chance to succeed, give up */
    2299             :     }
    2300             : 
    2301         156 :     return false;
    2302             : }
    2303             : 
    2304             : /*
    2305             :  * match_expr_to_partition_keys
    2306             :  *
    2307             :  * Tries to match an expression to one of the nullable or non-nullable
    2308             :  * partition keys of "rel".  Returns the matched key's ordinal position,
    2309             :  * or -1 if the expression could not be matched to any of the keys.
    2310             :  *
    2311             :  * strict_op must be true if the expression will be compared with the
    2312             :  * partition key using a strict operator.  This allows us to consider
    2313             :  * nullable as well as nonnullable partition keys.
    2314             :  */
    2315             : static int
    2316        5028 : match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel, bool strict_op)
    2317             : {
    2318             :     int         cnt;
    2319             : 
    2320             :     /* This function should be called only for partitioned relations. */
    2321             :     Assert(rel->part_scheme);
    2322             :     Assert(rel->partexprs);
    2323             :     Assert(rel->nullable_partexprs);
    2324             : 
    2325             :     /* Remove any relabel decorations. */
    2326        5316 :     while (IsA(expr, RelabelType))
    2327         288 :         expr = (Expr *) (castNode(RelabelType, expr))->arg;
    2328             : 
    2329        5988 :     for (cnt = 0; cnt < rel->part_scheme->partnatts; cnt++)
    2330             :     {
    2331             :         ListCell   *lc;
    2332             : 
    2333             :         /* We can always match to the non-nullable partition keys. */
    2334        6060 :         foreach(lc, rel->partexprs[cnt])
    2335             :         {
    2336        5016 :             if (equal(lfirst(lc), expr))
    2337        4020 :                 return cnt;
    2338             :         }
    2339             : 
    2340        1044 :         if (!strict_op)
    2341           0 :             continue;
    2342             : 
    2343             :         /*
    2344             :          * If it's a strict join operator then a NULL partition key on one
    2345             :          * side will not join to any partition key on the other side, and in
    2346             :          * particular such a row can't join to a row from a different
    2347             :          * partition on the other side.  So, it's okay to search the nullable
    2348             :          * partition keys as well.
    2349             :          */
    2350        1188 :         foreach(lc, rel->nullable_partexprs[cnt])
    2351             :         {
    2352         228 :             if (equal(lfirst(lc), expr))
    2353          84 :                 return cnt;
    2354             :         }
    2355             :     }
    2356             : 
    2357         924 :     return -1;
    2358             : }
    2359             : 
    2360             : /*
    2361             :  * set_joinrel_partition_key_exprs
    2362             :  *      Initialize partition key expressions for a partitioned joinrel.
    2363             :  */
    2364             : static void
    2365        2034 : set_joinrel_partition_key_exprs(RelOptInfo *joinrel,
    2366             :                                 RelOptInfo *outer_rel, RelOptInfo *inner_rel,
    2367             :                                 JoinType jointype)
    2368             : {
    2369        2034 :     PartitionScheme part_scheme = joinrel->part_scheme;
    2370        2034 :     int         partnatts = part_scheme->partnatts;
    2371             : 
    2372        2034 :     joinrel->partexprs = (List **) palloc0(sizeof(List *) * partnatts);
    2373        2034 :     joinrel->nullable_partexprs =
    2374        2034 :         (List **) palloc0(sizeof(List *) * partnatts);
    2375             : 
    2376             :     /*
    2377             :      * The joinrel's partition expressions are the same as those of the input
    2378             :      * rels, but we must properly classify them as nullable or not in the
    2379             :      * joinrel's output.  (Also, we add some more partition expressions if
    2380             :      * it's a FULL JOIN.)
    2381             :      */
    2382        4080 :     for (int cnt = 0; cnt < partnatts; cnt++)
    2383             :     {
    2384             :         /* mark these const to enforce that we copy them properly */
    2385        2046 :         const List *outer_expr = outer_rel->partexprs[cnt];
    2386        2046 :         const List *outer_null_expr = outer_rel->nullable_partexprs[cnt];
    2387        2046 :         const List *inner_expr = inner_rel->partexprs[cnt];
    2388        2046 :         const List *inner_null_expr = inner_rel->nullable_partexprs[cnt];
    2389        2046 :         List       *partexpr = NIL;
    2390        2046 :         List       *nullable_partexpr = NIL;
    2391             :         ListCell   *lc;
    2392             : 
    2393        2046 :         switch (jointype)
    2394             :         {
    2395             :                 /*
    2396             :                  * A join relation resulting from an INNER join may be
    2397             :                  * regarded as partitioned by either of the inner and outer
    2398             :                  * relation keys.  For example, A INNER JOIN B ON A.a = B.b
    2399             :                  * can be regarded as partitioned on either A.a or B.b.  So we
    2400             :                  * add both keys to the joinrel's partexpr lists.  However,
    2401             :                  * anything that was already nullable still has to be treated
    2402             :                  * as nullable.
    2403             :                  */
    2404         880 :             case JOIN_INNER:
    2405         880 :                 partexpr = list_concat_copy(outer_expr, inner_expr);
    2406         880 :                 nullable_partexpr = list_concat_copy(outer_null_expr,
    2407             :                                                      inner_null_expr);
    2408         880 :                 break;
    2409             : 
    2410             :                 /*
    2411             :                  * A join relation resulting from a SEMI or ANTI join may be
    2412             :                  * regarded as partitioned by the outer relation keys.  The
    2413             :                  * inner relation's keys are no longer interesting; since they
    2414             :                  * aren't visible in the join output, nothing could join to
    2415             :                  * them.
    2416             :                  */
    2417         300 :             case JOIN_SEMI:
    2418             :             case JOIN_ANTI:
    2419         300 :                 partexpr = list_copy(outer_expr);
    2420         300 :                 nullable_partexpr = list_copy(outer_null_expr);
    2421         300 :                 break;
    2422             : 
    2423             :                 /*
    2424             :                  * A join relation resulting from a LEFT OUTER JOIN likewise
    2425             :                  * may be regarded as partitioned on the (non-nullable) outer
    2426             :                  * relation keys.  The inner (nullable) relation keys are okay
    2427             :                  * as partition keys for further joins as long as they involve
    2428             :                  * strict join operators.
    2429             :                  */
    2430         580 :             case JOIN_LEFT:
    2431         580 :                 partexpr = list_copy(outer_expr);
    2432         580 :                 nullable_partexpr = list_concat_copy(inner_expr,
    2433             :                                                      outer_null_expr);
    2434         580 :                 nullable_partexpr = list_concat(nullable_partexpr,
    2435             :                                                 inner_null_expr);
    2436         580 :                 break;
    2437             : 
    2438             :                 /*
    2439             :                  * For FULL OUTER JOINs, both relations are nullable, so the
    2440             :                  * resulting join relation may be regarded as partitioned on
    2441             :                  * either of inner and outer relation keys, but only for joins
    2442             :                  * that involve strict join operators.
    2443             :                  */
    2444         286 :             case JOIN_FULL:
    2445         286 :                 nullable_partexpr = list_concat_copy(outer_expr,
    2446             :                                                      inner_expr);
    2447         286 :                 nullable_partexpr = list_concat(nullable_partexpr,
    2448             :                                                 outer_null_expr);
    2449         286 :                 nullable_partexpr = list_concat(nullable_partexpr,
    2450             :                                                 inner_null_expr);
    2451             : 
    2452             :                 /*
    2453             :                  * Also add CoalesceExprs corresponding to each possible
    2454             :                  * full-join output variable (that is, left side coalesced to
    2455             :                  * right side), so that we can match equijoin expressions
    2456             :                  * using those variables.  We really only need these for
    2457             :                  * columns merged by JOIN USING, and only with the pairs of
    2458             :                  * input items that correspond to the data structures that
    2459             :                  * parse analysis would build for such variables.  But it's
    2460             :                  * hard to tell which those are, so just make all the pairs.
    2461             :                  * Extra items in the nullable_partexprs list won't cause big
    2462             :                  * problems.  (It's possible that such items will get matched
    2463             :                  * to user-written COALESCEs, but it should still be valid to
    2464             :                  * partition on those, since they're going to be either the
    2465             :                  * partition column or NULL; it's the same argument as for
    2466             :                  * partitionwise nesting of any outer join.)  We assume no
    2467             :                  * type coercions are needed to make the coalesce expressions,
    2468             :                  * since columns of different types won't have gotten
    2469             :                  * classified as the same PartitionScheme.  Note that we
    2470             :                  * intentionally leave out the varnullingrels decoration that
    2471             :                  * would ordinarily appear on the Vars inside these
    2472             :                  * CoalesceExprs, because have_partkey_equi_join will strip
    2473             :                  * varnullingrels from the expressions it will compare to the
    2474             :                  * partexprs.
    2475             :                  */
    2476         728 :                 foreach(lc, list_concat_copy(outer_expr, outer_null_expr))
    2477             :                 {
    2478         442 :                     Node       *larg = (Node *) lfirst(lc);
    2479             :                     ListCell   *lc2;
    2480             : 
    2481         884 :                     foreach(lc2, list_concat_copy(inner_expr, inner_null_expr))
    2482             :                     {
    2483         442 :                         Node       *rarg = (Node *) lfirst(lc2);
    2484         442 :                         CoalesceExpr *c = makeNode(CoalesceExpr);
    2485             : 
    2486         442 :                         c->coalescetype = exprType(larg);
    2487         442 :                         c->coalescecollid = exprCollation(larg);
    2488         442 :                         c->args = list_make2(larg, rarg);
    2489         442 :                         c->location = -1;
    2490         442 :                         nullable_partexpr = lappend(nullable_partexpr, c);
    2491             :                     }
    2492             :                 }
    2493         286 :                 break;
    2494             : 
    2495           0 :             default:
    2496           0 :                 elog(ERROR, "unrecognized join type: %d", (int) jointype);
    2497             :         }
    2498             : 
    2499        2046 :         joinrel->partexprs[cnt] = partexpr;
    2500        2046 :         joinrel->nullable_partexprs[cnt] = nullable_partexpr;
    2501             :     }
    2502        2034 : }
    2503             : 
    2504             : /*
    2505             :  * build_child_join_reltarget
    2506             :  *    Set up a child-join relation's reltarget from a parent-join relation.
    2507             :  */
    2508             : static void
    2509        5002 : build_child_join_reltarget(PlannerInfo *root,
    2510             :                            RelOptInfo *parentrel,
    2511             :                            RelOptInfo *childrel,
    2512             :                            int nappinfos,
    2513             :                            AppendRelInfo **appinfos)
    2514             : {
    2515             :     /* Build the targetlist */
    2516       10004 :     childrel->reltarget->exprs = (List *)
    2517        5002 :         adjust_appendrel_attrs(root,
    2518        5002 :                                (Node *) parentrel->reltarget->exprs,
    2519             :                                nappinfos, appinfos);
    2520             : 
    2521             :     /* Set the cost and width fields */
    2522        5002 :     childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
    2523        5002 :     childrel->reltarget->cost.per_tuple = parentrel->reltarget->cost.per_tuple;
    2524        5002 :     childrel->reltarget->width = parentrel->reltarget->width;
    2525        5002 : }

Generated by: LCOV version 1.16