LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - restrictinfo.c (source / functions) Hit Total Coverage
Test: PostgreSQL 14devel Lines: 144 144 100.0 %
Date: 2021-01-26 01:06:44 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * restrictinfo.c
       4             :  *    RestrictInfo node manipulation routines.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/optimizer/util/restrictinfo.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "nodes/makefuncs.h"
      18             : #include "nodes/nodeFuncs.h"
      19             : #include "optimizer/clauses.h"
      20             : #include "optimizer/optimizer.h"
      21             : #include "optimizer/restrictinfo.h"
      22             : 
      23             : 
      24             : static RestrictInfo *make_restrictinfo_internal(PlannerInfo *root,
      25             :                                                 Expr *clause,
      26             :                                                 Expr *orclause,
      27             :                                                 bool is_pushed_down,
      28             :                                                 bool outerjoin_delayed,
      29             :                                                 bool pseudoconstant,
      30             :                                                 Index security_level,
      31             :                                                 Relids required_relids,
      32             :                                                 Relids outer_relids,
      33             :                                                 Relids nullable_relids);
      34             : static Expr *make_sub_restrictinfos(PlannerInfo *root,
      35             :                                     Expr *clause,
      36             :                                     bool is_pushed_down,
      37             :                                     bool outerjoin_delayed,
      38             :                                     bool pseudoconstant,
      39             :                                     Index security_level,
      40             :                                     Relids required_relids,
      41             :                                     Relids outer_relids,
      42             :                                     Relids nullable_relids);
      43             : 
      44             : 
      45             : /*
      46             :  * make_restrictinfo
      47             :  *
      48             :  * Build a RestrictInfo node containing the given subexpression.
      49             :  *
      50             :  * The is_pushed_down, outerjoin_delayed, and pseudoconstant flags for the
      51             :  * RestrictInfo must be supplied by the caller, as well as the correct values
      52             :  * for security_level, outer_relids, and nullable_relids.
      53             :  * required_relids can be NULL, in which case it defaults to the actual clause
      54             :  * contents (i.e., clause_relids).
      55             :  *
      56             :  * We initialize fields that depend only on the given subexpression, leaving
      57             :  * others that depend on context (or may never be needed at all) to be filled
      58             :  * later.
      59             :  */
      60             : RestrictInfo *
      61      400922 : make_restrictinfo(PlannerInfo *root,
      62             :                   Expr *clause,
      63             :                   bool is_pushed_down,
      64             :                   bool outerjoin_delayed,
      65             :                   bool pseudoconstant,
      66             :                   Index security_level,
      67             :                   Relids required_relids,
      68             :                   Relids outer_relids,
      69             :                   Relids nullable_relids)
      70             : {
      71             :     /*
      72             :      * If it's an OR clause, build a modified copy with RestrictInfos inserted
      73             :      * above each subclause of the top-level AND/OR structure.
      74             :      */
      75      400922 :     if (is_orclause(clause))
      76        5774 :         return (RestrictInfo *) make_sub_restrictinfos(root,
      77             :                                                        clause,
      78             :                                                        is_pushed_down,
      79             :                                                        outerjoin_delayed,
      80             :                                                        pseudoconstant,
      81             :                                                        security_level,
      82             :                                                        required_relids,
      83             :                                                        outer_relids,
      84             :                                                        nullable_relids);
      85             : 
      86             :     /* Shouldn't be an AND clause, else AND/OR flattening messed up */
      87             :     Assert(!is_andclause(clause));
      88             : 
      89      395148 :     return make_restrictinfo_internal(root,
      90             :                                       clause,
      91             :                                       NULL,
      92             :                                       is_pushed_down,
      93             :                                       outerjoin_delayed,
      94             :                                       pseudoconstant,
      95             :                                       security_level,
      96             :                                       required_relids,
      97             :                                       outer_relids,
      98             :                                       nullable_relids);
      99             : }
     100             : 
     101             : /*
     102             :  * make_restrictinfo_internal
     103             :  *
     104             :  * Common code for the main entry points and the recursive cases.
     105             :  */
     106             : static RestrictInfo *
     107      416184 : make_restrictinfo_internal(PlannerInfo *root,
     108             :                            Expr *clause,
     109             :                            Expr *orclause,
     110             :                            bool is_pushed_down,
     111             :                            bool outerjoin_delayed,
     112             :                            bool pseudoconstant,
     113             :                            Index security_level,
     114             :                            Relids required_relids,
     115             :                            Relids outer_relids,
     116             :                            Relids nullable_relids)
     117             : {
     118      416184 :     RestrictInfo *restrictinfo = makeNode(RestrictInfo);
     119             : 
     120      416184 :     restrictinfo->clause = clause;
     121      416184 :     restrictinfo->orclause = orclause;
     122      416184 :     restrictinfo->is_pushed_down = is_pushed_down;
     123      416184 :     restrictinfo->outerjoin_delayed = outerjoin_delayed;
     124      416184 :     restrictinfo->pseudoconstant = pseudoconstant;
     125      416184 :     restrictinfo->can_join = false; /* may get set below */
     126      416184 :     restrictinfo->security_level = security_level;
     127      416184 :     restrictinfo->outer_relids = outer_relids;
     128      416184 :     restrictinfo->nullable_relids = nullable_relids;
     129             : 
     130             :     /*
     131             :      * If it's potentially delayable by lower-level security quals, figure out
     132             :      * whether it's leakproof.  We can skip testing this for level-zero quals,
     133             :      * since they would never get delayed on security grounds anyway.
     134             :      */
     135      416184 :     if (security_level > 0)
     136        3312 :         restrictinfo->leakproof = !contain_leaked_vars((Node *) clause);
     137             :     else
     138      412872 :         restrictinfo->leakproof = false; /* really, "don't know" */
     139             : 
     140             :     /*
     141             :      * If it's a binary opclause, set up left/right relids info. In any case
     142             :      * set up the total clause relids info.
     143             :      */
     144      416184 :     if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
     145             :     {
     146      359034 :         restrictinfo->left_relids = pull_varnos(root, get_leftop(clause));
     147      359034 :         restrictinfo->right_relids = pull_varnos(root, get_rightop(clause));
     148             : 
     149      718068 :         restrictinfo->clause_relids = bms_union(restrictinfo->left_relids,
     150      359034 :                                                 restrictinfo->right_relids);
     151             : 
     152             :         /*
     153             :          * Does it look like a normal join clause, i.e., a binary operator
     154             :          * relating expressions that come from distinct relations? If so we
     155             :          * might be able to use it in a join algorithm.  Note that this is a
     156             :          * purely syntactic test that is made regardless of context.
     157             :          */
     158      712014 :         if (!bms_is_empty(restrictinfo->left_relids) &&
     159      352980 :             !bms_is_empty(restrictinfo->right_relids) &&
     160      130950 :             !bms_overlap(restrictinfo->left_relids,
     161      130950 :                          restrictinfo->right_relids))
     162             :         {
     163      129794 :             restrictinfo->can_join = true;
     164             :             /* pseudoconstant should certainly not be true */
     165             :             Assert(!restrictinfo->pseudoconstant);
     166             :         }
     167             :     }
     168             :     else
     169             :     {
     170             :         /* Not a binary opclause, so mark left/right relid sets as empty */
     171       57150 :         restrictinfo->left_relids = NULL;
     172       57150 :         restrictinfo->right_relids = NULL;
     173             :         /* and get the total relid set the hard way */
     174       57150 :         restrictinfo->clause_relids = pull_varnos(root, (Node *) clause);
     175             :     }
     176             : 
     177             :     /* required_relids defaults to clause_relids */
     178      416184 :     if (required_relids != NULL)
     179      378780 :         restrictinfo->required_relids = required_relids;
     180             :     else
     181       37404 :         restrictinfo->required_relids = restrictinfo->clause_relids;
     182             : 
     183             :     /*
     184             :      * Fill in all the cacheable fields with "not yet set" markers. None of
     185             :      * these will be computed until/unless needed.  Note in particular that we
     186             :      * don't mark a binary opclause as mergejoinable or hashjoinable here;
     187             :      * that happens only if it appears in the right context (top level of a
     188             :      * joinclause list).
     189             :      */
     190      416184 :     restrictinfo->parent_ec = NULL;
     191             : 
     192      416184 :     restrictinfo->eval_cost.startup = -1;
     193      416184 :     restrictinfo->norm_selec = -1;
     194      416184 :     restrictinfo->outer_selec = -1;
     195             : 
     196      416184 :     restrictinfo->mergeopfamilies = NIL;
     197             : 
     198      416184 :     restrictinfo->left_ec = NULL;
     199      416184 :     restrictinfo->right_ec = NULL;
     200      416184 :     restrictinfo->left_em = NULL;
     201      416184 :     restrictinfo->right_em = NULL;
     202      416184 :     restrictinfo->scansel_cache = NIL;
     203             : 
     204      416184 :     restrictinfo->outer_is_left = false;
     205             : 
     206      416184 :     restrictinfo->hashjoinoperator = InvalidOid;
     207             : 
     208      416184 :     restrictinfo->left_bucketsize = -1;
     209      416184 :     restrictinfo->right_bucketsize = -1;
     210      416184 :     restrictinfo->left_mcvfreq = -1;
     211      416184 :     restrictinfo->right_mcvfreq = -1;
     212             : 
     213      416184 :     return restrictinfo;
     214             : }
     215             : 
     216             : /*
     217             :  * Recursively insert sub-RestrictInfo nodes into a boolean expression.
     218             :  *
     219             :  * We put RestrictInfos above simple (non-AND/OR) clauses and above
     220             :  * sub-OR clauses, but not above sub-AND clauses, because there's no need.
     221             :  * This may seem odd but it is closely related to the fact that we use
     222             :  * implicit-AND lists at top level of RestrictInfo lists.  Only ORs and
     223             :  * simple clauses are valid RestrictInfos.
     224             :  *
     225             :  * The same is_pushed_down, outerjoin_delayed, and pseudoconstant flag
     226             :  * values can be applied to all RestrictInfo nodes in the result.  Likewise
     227             :  * for security_level, outer_relids, and nullable_relids.
     228             :  *
     229             :  * The given required_relids are attached to our top-level output,
     230             :  * but any OR-clause constituents are allowed to default to just the
     231             :  * contained rels.
     232             :  */
     233             : static Expr *
     234       22522 : make_sub_restrictinfos(PlannerInfo *root,
     235             :                        Expr *clause,
     236             :                        bool is_pushed_down,
     237             :                        bool outerjoin_delayed,
     238             :                        bool pseudoconstant,
     239             :                        Index security_level,
     240             :                        Relids required_relids,
     241             :                        Relids outer_relids,
     242             :                        Relids nullable_relids)
     243             : {
     244       22522 :     if (is_orclause(clause))
     245             :     {
     246        5818 :         List       *orlist = NIL;
     247             :         ListCell   *temp;
     248             : 
     249       19344 :         foreach(temp, ((BoolExpr *) clause)->args)
     250       13526 :             orlist = lappend(orlist,
     251       27052 :                              make_sub_restrictinfos(root,
     252       13526 :                                                     lfirst(temp),
     253             :                                                     is_pushed_down,
     254             :                                                     outerjoin_delayed,
     255             :                                                     pseudoconstant,
     256             :                                                     security_level,
     257             :                                                     NULL,
     258             :                                                     outer_relids,
     259             :                                                     nullable_relids));
     260        5818 :         return (Expr *) make_restrictinfo_internal(root,
     261             :                                                    clause,
     262             :                                                    make_orclause(orlist),
     263             :                                                    is_pushed_down,
     264             :                                                    outerjoin_delayed,
     265             :                                                    pseudoconstant,
     266             :                                                    security_level,
     267             :                                                    required_relids,
     268             :                                                    outer_relids,
     269             :                                                    nullable_relids);
     270             :     }
     271       16704 :     else if (is_andclause(clause))
     272             :     {
     273        1486 :         List       *andlist = NIL;
     274             :         ListCell   *temp;
     275             : 
     276        4708 :         foreach(temp, ((BoolExpr *) clause)->args)
     277        3222 :             andlist = lappend(andlist,
     278        6444 :                               make_sub_restrictinfos(root,
     279        3222 :                                                      lfirst(temp),
     280             :                                                      is_pushed_down,
     281             :                                                      outerjoin_delayed,
     282             :                                                      pseudoconstant,
     283             :                                                      security_level,
     284             :                                                      required_relids,
     285             :                                                      outer_relids,
     286             :                                                      nullable_relids));
     287        1486 :         return make_andclause(andlist);
     288             :     }
     289             :     else
     290       15218 :         return (Expr *) make_restrictinfo_internal(root,
     291             :                                                    clause,
     292             :                                                    NULL,
     293             :                                                    is_pushed_down,
     294             :                                                    outerjoin_delayed,
     295             :                                                    pseudoconstant,
     296             :                                                    security_level,
     297             :                                                    required_relids,
     298             :                                                    outer_relids,
     299             :                                                    nullable_relids);
     300             : }
     301             : 
     302             : /*
     303             :  * commute_restrictinfo
     304             :  *
     305             :  * Given a RestrictInfo containing a binary opclause, produce a RestrictInfo
     306             :  * representing the commutation of that clause.  The caller must pass the
     307             :  * OID of the commutator operator (which it's presumably looked up, else
     308             :  * it would not know this is valid).
     309             :  *
     310             :  * Beware that the result shares sub-structure with the given RestrictInfo.
     311             :  * That's okay for the intended usage with derived index quals, but might
     312             :  * be hazardous if the source is subject to change.  Also notice that we
     313             :  * assume without checking that the commutator op is a member of the same
     314             :  * btree and hash opclasses as the original op.
     315             :  */
     316             : RestrictInfo *
     317       18750 : commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op)
     318             : {
     319             :     RestrictInfo *result;
     320             :     OpExpr     *newclause;
     321       18750 :     OpExpr     *clause = castNode(OpExpr, rinfo->clause);
     322             : 
     323             :     Assert(list_length(clause->args) == 2);
     324             : 
     325             :     /* flat-copy all the fields of clause ... */
     326       18750 :     newclause = makeNode(OpExpr);
     327       18750 :     memcpy(newclause, clause, sizeof(OpExpr));
     328             : 
     329             :     /* ... and adjust those we need to change to commute it */
     330       18750 :     newclause->opno = comm_op;
     331       18750 :     newclause->opfuncid = InvalidOid;
     332       18750 :     newclause->args = list_make2(lsecond(clause->args),
     333             :                                  linitial(clause->args));
     334             : 
     335             :     /* likewise, flat-copy all the fields of rinfo ... */
     336       18750 :     result = makeNode(RestrictInfo);
     337       18750 :     memcpy(result, rinfo, sizeof(RestrictInfo));
     338             : 
     339             :     /*
     340             :      * ... and adjust those we need to change.  Note in particular that we can
     341             :      * preserve any cached selectivity or cost estimates, since those ought to
     342             :      * be the same for the new clause.  Likewise we can keep the source's
     343             :      * parent_ec.
     344             :      */
     345       18750 :     result->clause = (Expr *) newclause;
     346       18750 :     result->left_relids = rinfo->right_relids;
     347       18750 :     result->right_relids = rinfo->left_relids;
     348             :     Assert(result->orclause == NULL);
     349       18750 :     result->left_ec = rinfo->right_ec;
     350       18750 :     result->right_ec = rinfo->left_ec;
     351       18750 :     result->left_em = rinfo->right_em;
     352       18750 :     result->right_em = rinfo->left_em;
     353       18750 :     result->scansel_cache = NIL; /* not worth updating this */
     354       18750 :     if (rinfo->hashjoinoperator == clause->opno)
     355       15356 :         result->hashjoinoperator = comm_op;
     356             :     else
     357        3394 :         result->hashjoinoperator = InvalidOid;
     358       18750 :     result->left_bucketsize = rinfo->right_bucketsize;
     359       18750 :     result->right_bucketsize = rinfo->left_bucketsize;
     360       18750 :     result->left_mcvfreq = rinfo->right_mcvfreq;
     361       18750 :     result->right_mcvfreq = rinfo->left_mcvfreq;
     362             : 
     363       18750 :     return result;
     364             : }
     365             : 
     366             : /*
     367             :  * restriction_is_or_clause
     368             :  *
     369             :  * Returns t iff the restrictinfo node contains an 'or' clause.
     370             :  */
     371             : bool
     372      613360 : restriction_is_or_clause(RestrictInfo *restrictinfo)
     373             : {
     374      613360 :     if (restrictinfo->orclause != NULL)
     375       38622 :         return true;
     376             :     else
     377      574738 :         return false;
     378             : }
     379             : 
     380             : /*
     381             :  * restriction_is_securely_promotable
     382             :  *
     383             :  * Returns true if it's okay to evaluate this clause "early", that is before
     384             :  * other restriction clauses attached to the specified relation.
     385             :  */
     386             : bool
     387      887310 : restriction_is_securely_promotable(RestrictInfo *restrictinfo,
     388             :                                    RelOptInfo *rel)
     389             : {
     390             :     /*
     391             :      * It's okay if there are no baserestrictinfo clauses for the rel that
     392             :      * would need to go before this one, *or* if this one is leakproof.
     393             :      */
     394      887310 :     if (restrictinfo->security_level <= rel->baserestrict_min_security ||
     395        3480 :         restrictinfo->leakproof)
     396      885578 :         return true;
     397             :     else
     398        1732 :         return false;
     399             : }
     400             : 
     401             : /*
     402             :  * get_actual_clauses
     403             :  *
     404             :  * Returns a list containing the bare clauses from 'restrictinfo_list'.
     405             :  *
     406             :  * This is only to be used in cases where none of the RestrictInfos can
     407             :  * be pseudoconstant clauses (for instance, it's OK on indexqual lists).
     408             :  */
     409             : List *
     410       39062 : get_actual_clauses(List *restrictinfo_list)
     411             : {
     412       39062 :     List       *result = NIL;
     413             :     ListCell   *l;
     414             : 
     415       80610 :     foreach(l, restrictinfo_list)
     416             :     {
     417       41548 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     418             : 
     419             :         Assert(!rinfo->pseudoconstant);
     420             : 
     421       41548 :         result = lappend(result, rinfo->clause);
     422             :     }
     423       39062 :     return result;
     424             : }
     425             : 
     426             : /*
     427             :  * extract_actual_clauses
     428             :  *
     429             :  * Extract bare clauses from 'restrictinfo_list', returning either the
     430             :  * regular ones or the pseudoconstant ones per 'pseudoconstant'.
     431             :  */
     432             : List *
     433      338222 : extract_actual_clauses(List *restrictinfo_list,
     434             :                        bool pseudoconstant)
     435             : {
     436      338222 :     List       *result = NIL;
     437             :     ListCell   *l;
     438             : 
     439      502058 :     foreach(l, restrictinfo_list)
     440             :     {
     441      163836 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     442             : 
     443      163836 :         if (rinfo->pseudoconstant == pseudoconstant)
     444      156458 :             result = lappend(result, rinfo->clause);
     445             :     }
     446      338222 :     return result;
     447             : }
     448             : 
     449             : /*
     450             :  * extract_actual_join_clauses
     451             :  *
     452             :  * Extract bare clauses from 'restrictinfo_list', separating those that
     453             :  * semantically match the join level from those that were pushed down.
     454             :  * Pseudoconstant clauses are excluded from the results.
     455             :  *
     456             :  * This is only used at outer joins, since for plain joins we don't care
     457             :  * about pushed-down-ness.
     458             :  */
     459             : void
     460       31906 : extract_actual_join_clauses(List *restrictinfo_list,
     461             :                             Relids joinrelids,
     462             :                             List **joinquals,
     463             :                             List **otherquals)
     464             : {
     465             :     ListCell   *l;
     466             : 
     467       31906 :     *joinquals = NIL;
     468       31906 :     *otherquals = NIL;
     469             : 
     470       60874 :     foreach(l, restrictinfo_list)
     471             :     {
     472       28968 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     473             : 
     474       28968 :         if (RINFO_IS_PUSHED_DOWN(rinfo, joinrelids))
     475             :         {
     476        3460 :             if (!rinfo->pseudoconstant)
     477        1730 :                 *otherquals = lappend(*otherquals, rinfo->clause);
     478             :         }
     479             :         else
     480             :         {
     481             :             /* joinquals shouldn't have been marked pseudoconstant */
     482             :             Assert(!rinfo->pseudoconstant);
     483       27238 :             *joinquals = lappend(*joinquals, rinfo->clause);
     484             :         }
     485             :     }
     486       31906 : }
     487             : 
     488             : 
     489             : /*
     490             :  * join_clause_is_movable_to
     491             :  *      Test whether a join clause is a safe candidate for parameterization
     492             :  *      of a scan on the specified base relation.
     493             :  *
     494             :  * A movable join clause is one that can safely be evaluated at a rel below
     495             :  * its normal semantic level (ie, its required_relids), if the values of
     496             :  * variables that it would need from other rels are provided.
     497             :  *
     498             :  * We insist that the clause actually reference the target relation; this
     499             :  * prevents undesirable movement of degenerate join clauses, and ensures
     500             :  * that there is a unique place that a clause can be moved down to.
     501             :  *
     502             :  * We cannot move an outer-join clause into the non-nullable side of its
     503             :  * outer join, as that would change the results (rows would be suppressed
     504             :  * rather than being null-extended).
     505             :  *
     506             :  * Also there must not be an outer join below the clause that would null the
     507             :  * Vars coming from the target relation.  Otherwise the clause might give
     508             :  * results different from what it would give at its normal semantic level.
     509             :  *
     510             :  * Also, the join clause must not use any relations that have LATERAL
     511             :  * references to the target relation, since we could not put such rels on
     512             :  * the outer side of a nestloop with the target relation.
     513             :  */
     514             : bool
     515      155782 : join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel)
     516             : {
     517             :     /* Clause must physically reference target rel */
     518      155782 :     if (!bms_is_member(baserel->relid, rinfo->clause_relids))
     519        5170 :         return false;
     520             : 
     521             :     /* Cannot move an outer-join clause into the join's outer side */
     522      150612 :     if (bms_is_member(baserel->relid, rinfo->outer_relids))
     523       61986 :         return false;
     524             : 
     525             :     /* Target rel must not be nullable below the clause */
     526       88626 :     if (bms_is_member(baserel->relid, rinfo->nullable_relids))
     527        3500 :         return false;
     528             : 
     529             :     /* Clause must not use any rels with LATERAL references to this rel */
     530       85126 :     if (bms_overlap(baserel->lateral_referencers, rinfo->clause_relids))
     531          12 :         return false;
     532             : 
     533       85114 :     return true;
     534             : }
     535             : 
     536             : /*
     537             :  * join_clause_is_movable_into
     538             :  *      Test whether a join clause is movable and can be evaluated within
     539             :  *      the current join context.
     540             :  *
     541             :  * currentrelids: the relids of the proposed evaluation location
     542             :  * current_and_outer: the union of currentrelids and the required_outer
     543             :  *      relids (parameterization's outer relations)
     544             :  *
     545             :  * The API would be a bit clearer if we passed the current relids and the
     546             :  * outer relids separately and did bms_union internally; but since most
     547             :  * callers need to apply this function to multiple clauses, we make the
     548             :  * caller perform the union.
     549             :  *
     550             :  * Obviously, the clause must only refer to Vars available from the current
     551             :  * relation plus the outer rels.  We also check that it does reference at
     552             :  * least one current Var, ensuring that the clause will be pushed down to
     553             :  * a unique place in a parameterized join tree.  And we check that we're
     554             :  * not pushing the clause into its outer-join outer side, nor down into
     555             :  * a lower outer join's inner side.
     556             :  *
     557             :  * The check about pushing a clause down into a lower outer join's inner side
     558             :  * is only approximate; it sometimes returns "false" when actually it would
     559             :  * be safe to use the clause here because we're still above the outer join
     560             :  * in question.  This is okay as long as the answers at different join levels
     561             :  * are consistent: it just means we might sometimes fail to push a clause as
     562             :  * far down as it could safely be pushed.  It's unclear whether it would be
     563             :  * worthwhile to do this more precisely.  (But if it's ever fixed to be
     564             :  * exactly accurate, there's an Assert in get_joinrel_parampathinfo() that
     565             :  * should be re-enabled.)
     566             :  *
     567             :  * There's no check here equivalent to join_clause_is_movable_to's test on
     568             :  * lateral_referencers.  We assume the caller wouldn't be inquiring unless
     569             :  * it'd verified that the proposed outer rels don't have lateral references
     570             :  * to the current rel(s).  (If we are considering join paths with the outer
     571             :  * rels on the outside and the current rels on the inside, then this should
     572             :  * have been checked at the outset of such consideration; see join_is_legal
     573             :  * and the path parameterization checks in joinpath.c.)  On the other hand,
     574             :  * in join_clause_is_movable_to we are asking whether the clause could be
     575             :  * moved for some valid set of outer rels, so we don't have the benefit of
     576             :  * relying on prior checks for lateral-reference validity.
     577             :  *
     578             :  * Note: if this returns true, it means that the clause could be moved to
     579             :  * this join relation, but that doesn't mean that this is the lowest join
     580             :  * it could be moved to.  Caller may need to make additional calls to verify
     581             :  * that this doesn't succeed on either of the inputs of a proposed join.
     582             :  *
     583             :  * Note: get_joinrel_parampathinfo depends on the fact that if
     584             :  * current_and_outer is NULL, this function will always return false
     585             :  * (since one or the other of the first two tests must fail).
     586             :  */
     587             : bool
     588      256258 : join_clause_is_movable_into(RestrictInfo *rinfo,
     589             :                             Relids currentrelids,
     590             :                             Relids current_and_outer)
     591             : {
     592             :     /* Clause must be evaluable given available context */
     593      256258 :     if (!bms_is_subset(rinfo->clause_relids, current_and_outer))
     594       21412 :         return false;
     595             : 
     596             :     /* Clause must physically reference at least one target rel */
     597      234846 :     if (!bms_overlap(currentrelids, rinfo->clause_relids))
     598        2782 :         return false;
     599             : 
     600             :     /* Cannot move an outer-join clause into the join's outer side */
     601      232064 :     if (bms_overlap(currentrelids, rinfo->outer_relids))
     602         380 :         return false;
     603             : 
     604             :     /*
     605             :      * Target rel(s) must not be nullable below the clause.  This is
     606             :      * approximate, in the safe direction, because the current join might be
     607             :      * above the join where the nulling would happen, in which case the clause
     608             :      * would work correctly here.  But we don't have enough info to be sure.
     609             :      */
     610      231684 :     if (bms_overlap(currentrelids, rinfo->nullable_relids))
     611        1206 :         return false;
     612             : 
     613      230478 :     return true;
     614             : }

Generated by: LCOV version 1.13