LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - restrictinfo.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 162 162 100.0 %
Date: 2024-10-07 00:11:18 Functions: 12 12 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-2024, 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 has_clone,
      29             :                                                 bool is_clone,
      30             :                                                 bool pseudoconstant,
      31             :                                                 Index security_level,
      32             :                                                 Relids required_relids,
      33             :                                                 Relids incompatible_relids,
      34             :                                                 Relids outer_relids);
      35             : static Expr *make_sub_restrictinfos(PlannerInfo *root,
      36             :                                     Expr *clause,
      37             :                                     bool is_pushed_down,
      38             :                                     bool has_clone,
      39             :                                     bool is_clone,
      40             :                                     bool pseudoconstant,
      41             :                                     Index security_level,
      42             :                                     Relids required_relids,
      43             :                                     Relids incompatible_relids,
      44             :                                     Relids outer_relids);
      45             : 
      46             : 
      47             : /*
      48             :  * make_restrictinfo
      49             :  *
      50             :  * Build a RestrictInfo node containing the given subexpression.
      51             :  *
      52             :  * The is_pushed_down, has_clone, is_clone, and pseudoconstant flags for the
      53             :  * RestrictInfo must be supplied by the caller, as well as the correct values
      54             :  * for security_level, incompatible_relids, and outer_relids.
      55             :  * required_relids can be NULL, in which case it defaults to the actual clause
      56             :  * contents (i.e., clause_relids).
      57             :  *
      58             :  * We initialize fields that depend only on the given subexpression, leaving
      59             :  * others that depend on context (or may never be needed at all) to be filled
      60             :  * later.
      61             :  */
      62             : RestrictInfo *
      63      575080 : make_restrictinfo(PlannerInfo *root,
      64             :                   Expr *clause,
      65             :                   bool is_pushed_down,
      66             :                   bool has_clone,
      67             :                   bool is_clone,
      68             :                   bool pseudoconstant,
      69             :                   Index security_level,
      70             :                   Relids required_relids,
      71             :                   Relids incompatible_relids,
      72             :                   Relids outer_relids)
      73             : {
      74             :     /*
      75             :      * If it's an OR clause, build a modified copy with RestrictInfos inserted
      76             :      * above each subclause of the top-level AND/OR structure.
      77             :      */
      78      575080 :     if (is_orclause(clause))
      79        8082 :         return (RestrictInfo *) make_sub_restrictinfos(root,
      80             :                                                        clause,
      81             :                                                        is_pushed_down,
      82             :                                                        has_clone,
      83             :                                                        is_clone,
      84             :                                                        pseudoconstant,
      85             :                                                        security_level,
      86             :                                                        required_relids,
      87             :                                                        incompatible_relids,
      88             :                                                        outer_relids);
      89             : 
      90             :     /* Shouldn't be an AND clause, else AND/OR flattening messed up */
      91             :     Assert(!is_andclause(clause));
      92             : 
      93      566998 :     return make_restrictinfo_internal(root,
      94             :                                       clause,
      95             :                                       NULL,
      96             :                                       is_pushed_down,
      97             :                                       has_clone,
      98             :                                       is_clone,
      99             :                                       pseudoconstant,
     100             :                                       security_level,
     101             :                                       required_relids,
     102             :                                       incompatible_relids,
     103             :                                       outer_relids);
     104             : }
     105             : 
     106             : /*
     107             :  * make_restrictinfo_internal
     108             :  *
     109             :  * Common code for the main entry points and the recursive cases.
     110             :  */
     111             : static RestrictInfo *
     112      597534 : make_restrictinfo_internal(PlannerInfo *root,
     113             :                            Expr *clause,
     114             :                            Expr *orclause,
     115             :                            bool is_pushed_down,
     116             :                            bool has_clone,
     117             :                            bool is_clone,
     118             :                            bool pseudoconstant,
     119             :                            Index security_level,
     120             :                            Relids required_relids,
     121             :                            Relids incompatible_relids,
     122             :                            Relids outer_relids)
     123             : {
     124      597534 :     RestrictInfo *restrictinfo = makeNode(RestrictInfo);
     125             :     Relids      baserels;
     126             : 
     127      597534 :     restrictinfo->clause = clause;
     128      597534 :     restrictinfo->orclause = orclause;
     129      597534 :     restrictinfo->is_pushed_down = is_pushed_down;
     130      597534 :     restrictinfo->pseudoconstant = pseudoconstant;
     131      597534 :     restrictinfo->has_clone = has_clone;
     132      597534 :     restrictinfo->is_clone = is_clone;
     133      597534 :     restrictinfo->can_join = false; /* may get set below */
     134      597534 :     restrictinfo->security_level = security_level;
     135      597534 :     restrictinfo->incompatible_relids = incompatible_relids;
     136      597534 :     restrictinfo->outer_relids = outer_relids;
     137             : 
     138             :     /*
     139             :      * If it's potentially delayable by lower-level security quals, figure out
     140             :      * whether it's leakproof.  We can skip testing this for level-zero quals,
     141             :      * since they would never get delayed on security grounds anyway.
     142             :      */
     143      597534 :     if (security_level > 0)
     144        4346 :         restrictinfo->leakproof = !contain_leaked_vars((Node *) clause);
     145             :     else
     146      593188 :         restrictinfo->leakproof = false; /* really, "don't know" */
     147             : 
     148             :     /*
     149             :      * Mark volatility as unknown.  The contain_volatile_functions function
     150             :      * will determine if there are any volatile functions when called for the
     151             :      * first time with this RestrictInfo.
     152             :      */
     153      597534 :     restrictinfo->has_volatile = VOLATILITY_UNKNOWN;
     154             : 
     155             :     /*
     156             :      * If it's a binary opclause, set up left/right relids info. In any case
     157             :      * set up the total clause relids info.
     158             :      */
     159      597534 :     if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
     160             :     {
     161      501434 :         restrictinfo->left_relids = pull_varnos(root, get_leftop(clause));
     162      501434 :         restrictinfo->right_relids = pull_varnos(root, get_rightop(clause));
     163             : 
     164     1002868 :         restrictinfo->clause_relids = bms_union(restrictinfo->left_relids,
     165      501434 :                                                 restrictinfo->right_relids);
     166             : 
     167             :         /*
     168             :          * Does it look like a normal join clause, i.e., a binary operator
     169             :          * relating expressions that come from distinct relations? If so we
     170             :          * might be able to use it in a join algorithm.  Note that this is a
     171             :          * purely syntactic test that is made regardless of context.
     172             :          */
     173      501434 :         if (!bms_is_empty(restrictinfo->left_relids) &&
     174      492130 :             !bms_is_empty(restrictinfo->right_relids) &&
     175      172720 :             !bms_overlap(restrictinfo->left_relids,
     176      172720 :                          restrictinfo->right_relids))
     177             :         {
     178      170520 :             restrictinfo->can_join = true;
     179             :             /* pseudoconstant should certainly not be true */
     180             :             Assert(!restrictinfo->pseudoconstant);
     181             :         }
     182             :     }
     183             :     else
     184             :     {
     185             :         /* Not a binary opclause, so mark left/right relid sets as empty */
     186       96100 :         restrictinfo->left_relids = NULL;
     187       96100 :         restrictinfo->right_relids = NULL;
     188             :         /* and get the total relid set the hard way */
     189       96100 :         restrictinfo->clause_relids = pull_varnos(root, (Node *) clause);
     190             :     }
     191             : 
     192             :     /* required_relids defaults to clause_relids */
     193      597534 :     if (required_relids != NULL)
     194      538470 :         restrictinfo->required_relids = required_relids;
     195             :     else
     196       59064 :         restrictinfo->required_relids = restrictinfo->clause_relids;
     197             : 
     198             :     /*
     199             :      * Count the number of base rels appearing in clause_relids.  To do this,
     200             :      * we just delete rels mentioned in root->outer_join_rels and count the
     201             :      * survivors.  Because we are called during deconstruct_jointree which is
     202             :      * the same tree walk that populates outer_join_rels, this is a little bit
     203             :      * unsafe-looking; but it should be fine because the recursion in
     204             :      * deconstruct_jointree should already have visited any outer join that
     205             :      * could be mentioned in this clause.
     206             :      */
     207      597534 :     baserels = bms_difference(restrictinfo->clause_relids,
     208      597534 :                               root->outer_join_rels);
     209      597534 :     restrictinfo->num_base_rels = bms_num_members(baserels);
     210      597534 :     bms_free(baserels);
     211             : 
     212             :     /*
     213             :      * Label this RestrictInfo with a fresh serial number.
     214             :      */
     215      597534 :     restrictinfo->rinfo_serial = ++(root->last_rinfo_serial);
     216             : 
     217             :     /*
     218             :      * Fill in all the cacheable fields with "not yet set" markers. None of
     219             :      * these will be computed until/unless needed.  Note in particular that we
     220             :      * don't mark a binary opclause as mergejoinable or hashjoinable here;
     221             :      * that happens only if it appears in the right context (top level of a
     222             :      * joinclause list).
     223             :      */
     224      597534 :     restrictinfo->parent_ec = NULL;
     225             : 
     226      597534 :     restrictinfo->eval_cost.startup = -1;
     227      597534 :     restrictinfo->norm_selec = -1;
     228      597534 :     restrictinfo->outer_selec = -1;
     229             : 
     230      597534 :     restrictinfo->mergeopfamilies = NIL;
     231             : 
     232      597534 :     restrictinfo->left_ec = NULL;
     233      597534 :     restrictinfo->right_ec = NULL;
     234      597534 :     restrictinfo->left_em = NULL;
     235      597534 :     restrictinfo->right_em = NULL;
     236      597534 :     restrictinfo->scansel_cache = NIL;
     237             : 
     238      597534 :     restrictinfo->outer_is_left = false;
     239             : 
     240      597534 :     restrictinfo->hashjoinoperator = InvalidOid;
     241             : 
     242      597534 :     restrictinfo->left_bucketsize = -1;
     243      597534 :     restrictinfo->right_bucketsize = -1;
     244      597534 :     restrictinfo->left_mcvfreq = -1;
     245      597534 :     restrictinfo->right_mcvfreq = -1;
     246             : 
     247      597534 :     restrictinfo->left_hasheqoperator = InvalidOid;
     248      597534 :     restrictinfo->right_hasheqoperator = InvalidOid;
     249             : 
     250      597534 :     return restrictinfo;
     251             : }
     252             : 
     253             : /*
     254             :  * Recursively insert sub-RestrictInfo nodes into a boolean expression.
     255             :  *
     256             :  * We put RestrictInfos above simple (non-AND/OR) clauses and above
     257             :  * sub-OR clauses, but not above sub-AND clauses, because there's no need.
     258             :  * This may seem odd but it is closely related to the fact that we use
     259             :  * implicit-AND lists at top level of RestrictInfo lists.  Only ORs and
     260             :  * simple clauses are valid RestrictInfos.
     261             :  *
     262             :  * The same is_pushed_down, has_clone, is_clone, and pseudoconstant flag
     263             :  * values can be applied to all RestrictInfo nodes in the result.  Likewise
     264             :  * for security_level, incompatible_relids, and outer_relids.
     265             :  *
     266             :  * The given required_relids are attached to our top-level output,
     267             :  * but any OR-clause constituents are allowed to default to just the
     268             :  * contained rels.
     269             :  */
     270             : static Expr *
     271       33384 : make_sub_restrictinfos(PlannerInfo *root,
     272             :                        Expr *clause,
     273             :                        bool is_pushed_down,
     274             :                        bool has_clone,
     275             :                        bool is_clone,
     276             :                        bool pseudoconstant,
     277             :                        Index security_level,
     278             :                        Relids required_relids,
     279             :                        Relids incompatible_relids,
     280             :                        Relids outer_relids)
     281             : {
     282       33384 :     if (is_orclause(clause))
     283             :     {
     284        8160 :         List       *orlist = NIL;
     285             :         ListCell   *temp;
     286             : 
     287       27206 :         foreach(temp, ((BoolExpr *) clause)->args)
     288       19046 :             orlist = lappend(orlist,
     289       19046 :                              make_sub_restrictinfos(root,
     290       19046 :                                                     lfirst(temp),
     291             :                                                     is_pushed_down,
     292             :                                                     has_clone,
     293             :                                                     is_clone,
     294             :                                                     pseudoconstant,
     295             :                                                     security_level,
     296             :                                                     NULL,
     297             :                                                     incompatible_relids,
     298             :                                                     outer_relids));
     299        8160 :         return (Expr *) make_restrictinfo_internal(root,
     300             :                                                    clause,
     301             :                                                    make_orclause(orlist),
     302             :                                                    is_pushed_down,
     303             :                                                    has_clone,
     304             :                                                    is_clone,
     305             :                                                    pseudoconstant,
     306             :                                                    security_level,
     307             :                                                    required_relids,
     308             :                                                    incompatible_relids,
     309             :                                                    outer_relids);
     310             :     }
     311       25224 :     else if (is_andclause(clause))
     312             :     {
     313        2848 :         List       *andlist = NIL;
     314             :         ListCell   *temp;
     315             : 
     316        9104 :         foreach(temp, ((BoolExpr *) clause)->args)
     317        6256 :             andlist = lappend(andlist,
     318        6256 :                               make_sub_restrictinfos(root,
     319        6256 :                                                      lfirst(temp),
     320             :                                                      is_pushed_down,
     321             :                                                      has_clone,
     322             :                                                      is_clone,
     323             :                                                      pseudoconstant,
     324             :                                                      security_level,
     325             :                                                      required_relids,
     326             :                                                      incompatible_relids,
     327             :                                                      outer_relids));
     328        2848 :         return make_andclause(andlist);
     329             :     }
     330             :     else
     331       22376 :         return (Expr *) make_restrictinfo_internal(root,
     332             :                                                    clause,
     333             :                                                    NULL,
     334             :                                                    is_pushed_down,
     335             :                                                    has_clone,
     336             :                                                    is_clone,
     337             :                                                    pseudoconstant,
     338             :                                                    security_level,
     339             :                                                    required_relids,
     340             :                                                    incompatible_relids,
     341             :                                                    outer_relids);
     342             : }
     343             : 
     344             : /*
     345             :  * commute_restrictinfo
     346             :  *
     347             :  * Given a RestrictInfo containing a binary opclause, produce a RestrictInfo
     348             :  * representing the commutation of that clause.  The caller must pass the
     349             :  * OID of the commutator operator (which it's presumably looked up, else
     350             :  * it would not know this is valid).
     351             :  *
     352             :  * Beware that the result shares sub-structure with the given RestrictInfo.
     353             :  * That's okay for the intended usage with derived index quals, but might
     354             :  * be hazardous if the source is subject to change.  Also notice that we
     355             :  * assume without checking that the commutator op is a member of the same
     356             :  * btree and hash opclasses as the original op.
     357             :  */
     358             : RestrictInfo *
     359       47082 : commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op)
     360             : {
     361             :     RestrictInfo *result;
     362             :     OpExpr     *newclause;
     363       47082 :     OpExpr     *clause = castNode(OpExpr, rinfo->clause);
     364             : 
     365             :     Assert(list_length(clause->args) == 2);
     366             : 
     367             :     /* flat-copy all the fields of clause ... */
     368       47082 :     newclause = makeNode(OpExpr);
     369       47082 :     memcpy(newclause, clause, sizeof(OpExpr));
     370             : 
     371             :     /* ... and adjust those we need to change to commute it */
     372       47082 :     newclause->opno = comm_op;
     373       47082 :     newclause->opfuncid = InvalidOid;
     374       47082 :     newclause->args = list_make2(lsecond(clause->args),
     375             :                                  linitial(clause->args));
     376             : 
     377             :     /* likewise, flat-copy all the fields of rinfo ... */
     378       47082 :     result = makeNode(RestrictInfo);
     379       47082 :     memcpy(result, rinfo, sizeof(RestrictInfo));
     380             : 
     381             :     /*
     382             :      * ... and adjust those we need to change.  Note in particular that we can
     383             :      * preserve any cached selectivity or cost estimates, since those ought to
     384             :      * be the same for the new clause.  Likewise we can keep the source's
     385             :      * parent_ec.  It's also important that we keep the same rinfo_serial.
     386             :      */
     387       47082 :     result->clause = (Expr *) newclause;
     388       47082 :     result->left_relids = rinfo->right_relids;
     389       47082 :     result->right_relids = rinfo->left_relids;
     390             :     Assert(result->orclause == NULL);
     391       47082 :     result->left_ec = rinfo->right_ec;
     392       47082 :     result->right_ec = rinfo->left_ec;
     393       47082 :     result->left_em = rinfo->right_em;
     394       47082 :     result->right_em = rinfo->left_em;
     395       47082 :     result->scansel_cache = NIL; /* not worth updating this */
     396       47082 :     if (rinfo->hashjoinoperator == clause->opno)
     397       45428 :         result->hashjoinoperator = comm_op;
     398             :     else
     399        1654 :         result->hashjoinoperator = InvalidOid;
     400       47082 :     result->left_bucketsize = rinfo->right_bucketsize;
     401       47082 :     result->right_bucketsize = rinfo->left_bucketsize;
     402       47082 :     result->left_mcvfreq = rinfo->right_mcvfreq;
     403       47082 :     result->right_mcvfreq = rinfo->left_mcvfreq;
     404       47082 :     result->left_hasheqoperator = InvalidOid;
     405       47082 :     result->right_hasheqoperator = InvalidOid;
     406             : 
     407       47082 :     return result;
     408             : }
     409             : 
     410             : /*
     411             :  * restriction_is_or_clause
     412             :  *
     413             :  * Returns t iff the restrictinfo node contains an 'or' clause.
     414             :  */
     415             : bool
     416     1698266 : restriction_is_or_clause(RestrictInfo *restrictinfo)
     417             : {
     418     1698266 :     if (restrictinfo->orclause != NULL)
     419       50400 :         return true;
     420             :     else
     421     1647866 :         return false;
     422             : }
     423             : 
     424             : /*
     425             :  * restriction_is_securely_promotable
     426             :  *
     427             :  * Returns true if it's okay to evaluate this clause "early", that is before
     428             :  * other restriction clauses attached to the specified relation.
     429             :  */
     430             : bool
     431     1288914 : restriction_is_securely_promotable(RestrictInfo *restrictinfo,
     432             :                                    RelOptInfo *rel)
     433             : {
     434             :     /*
     435             :      * It's okay if there are no baserestrictinfo clauses for the rel that
     436             :      * would need to go before this one, *or* if this one is leakproof.
     437             :      */
     438     1288914 :     if (restrictinfo->security_level <= rel->baserestrict_min_security ||
     439        4562 :         restrictinfo->leakproof)
     440     1286854 :         return true;
     441             :     else
     442        2060 :         return false;
     443             : }
     444             : 
     445             : /*
     446             :  * Detect whether a RestrictInfo's clause is constant TRUE (note that it's
     447             :  * surely of type boolean).  No such WHERE clause could survive qual
     448             :  * canonicalization, but equivclass.c may generate such RestrictInfos for
     449             :  * reasons discussed therein.  We should drop them again when creating
     450             :  * the finished plan, which is handled by the next few functions.
     451             :  */
     452             : static inline bool
     453      293318 : rinfo_is_constant_true(RestrictInfo *rinfo)
     454             : {
     455      295014 :     return IsA(rinfo->clause, Const) &&
     456      294954 :         !((Const *) rinfo->clause)->constisnull &&
     457        1636 :         DatumGetBool(((Const *) rinfo->clause)->constvalue);
     458             : }
     459             : 
     460             : /*
     461             :  * get_actual_clauses
     462             :  *
     463             :  * Returns a list containing the bare clauses from 'restrictinfo_list'.
     464             :  *
     465             :  * This is only to be used in cases where none of the RestrictInfos can
     466             :  * be pseudoconstant clauses (for instance, it's OK on indexqual lists).
     467             :  */
     468             : List *
     469       57484 : get_actual_clauses(List *restrictinfo_list)
     470             : {
     471       57484 :     List       *result = NIL;
     472             :     ListCell   *l;
     473             : 
     474      118124 :     foreach(l, restrictinfo_list)
     475             :     {
     476       60640 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     477             : 
     478             :         Assert(!rinfo->pseudoconstant);
     479             :         Assert(!rinfo_is_constant_true(rinfo));
     480             : 
     481       60640 :         result = lappend(result, rinfo->clause);
     482             :     }
     483       57484 :     return result;
     484             : }
     485             : 
     486             : /*
     487             :  * extract_actual_clauses
     488             :  *
     489             :  * Extract bare clauses from 'restrictinfo_list', returning either the
     490             :  * regular ones or the pseudoconstant ones per 'pseudoconstant'.
     491             :  * Constant-TRUE clauses are dropped in any case.
     492             :  */
     493             : List *
     494      552976 : extract_actual_clauses(List *restrictinfo_list,
     495             :                        bool pseudoconstant)
     496             : {
     497      552976 :     List       *result = NIL;
     498             :     ListCell   *l;
     499             : 
     500      836992 :     foreach(l, restrictinfo_list)
     501             :     {
     502      284016 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     503             : 
     504      284016 :         if (rinfo->pseudoconstant == pseudoconstant &&
     505      262056 :             !rinfo_is_constant_true(rinfo))
     506      262056 :             result = lappend(result, rinfo->clause);
     507             :     }
     508      552976 :     return result;
     509             : }
     510             : 
     511             : /*
     512             :  * extract_actual_join_clauses
     513             :  *
     514             :  * Extract bare clauses from 'restrictinfo_list', separating those that
     515             :  * semantically match the join level from those that were pushed down.
     516             :  * Pseudoconstant and constant-TRUE clauses are excluded from the results.
     517             :  *
     518             :  * This is only used at outer joins, since for plain joins we don't care
     519             :  * about pushed-down-ness.
     520             :  */
     521             : void
     522       33276 : extract_actual_join_clauses(List *restrictinfo_list,
     523             :                             Relids joinrelids,
     524             :                             List **joinquals,
     525             :                             List **otherquals)
     526             : {
     527             :     ListCell   *l;
     528             : 
     529       33276 :     *joinquals = NIL;
     530       33276 :     *otherquals = NIL;
     531             : 
     532       64550 :     foreach(l, restrictinfo_list)
     533             :     {
     534       31274 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     535             : 
     536       31274 :         if (RINFO_IS_PUSHED_DOWN(rinfo, joinrelids))
     537             :         {
     538        2906 :             if (!rinfo->pseudoconstant &&
     539        2894 :                 !rinfo_is_constant_true(rinfo))
     540        2894 :                 *otherquals = lappend(*otherquals, rinfo->clause);
     541             :         }
     542             :         else
     543             :         {
     544             :             /* joinquals shouldn't have been marked pseudoconstant */
     545             :             Assert(!rinfo->pseudoconstant);
     546       28368 :             if (!rinfo_is_constant_true(rinfo))
     547       26852 :                 *joinquals = lappend(*joinquals, rinfo->clause);
     548             :         }
     549             :     }
     550       33276 : }
     551             : 
     552             : /*
     553             :  * join_clause_is_movable_to
     554             :  *      Test whether a join clause is a safe candidate for parameterization
     555             :  *      of a scan on the specified base relation.
     556             :  *
     557             :  * A movable join clause is one that can safely be evaluated at a rel below
     558             :  * its normal semantic level (ie, its required_relids), if the values of
     559             :  * variables that it would need from other rels are provided.
     560             :  *
     561             :  * We insist that the clause actually reference the target relation; this
     562             :  * prevents undesirable movement of degenerate join clauses, and ensures
     563             :  * that there is a unique place that a clause can be moved down to.
     564             :  *
     565             :  * We cannot move an outer-join clause into the non-nullable side of its
     566             :  * outer join, as that would change the results (rows would be suppressed
     567             :  * rather than being null-extended).
     568             :  *
     569             :  * Also there must not be an outer join below the clause that would null the
     570             :  * Vars coming from the target relation.  Otherwise the clause might give
     571             :  * results different from what it would give at its normal semantic level.
     572             :  *
     573             :  * Also, the join clause must not use any relations that have LATERAL
     574             :  * references to the target relation, since we could not put such rels on
     575             :  * the outer side of a nestloop with the target relation.
     576             :  *
     577             :  * Also, we reject is_clone versions of outer-join clauses.  This has the
     578             :  * effect of preventing us from generating variant parameterized paths
     579             :  * that differ only in which outer joins null the parameterization rel(s).
     580             :  * Generating one path from the minimally-parameterized has_clone version
     581             :  * is sufficient.
     582             :  */
     583             : bool
     584      209598 : join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel)
     585             : {
     586             :     /* Clause must physically reference target rel */
     587      209598 :     if (!bms_is_member(baserel->relid, rinfo->clause_relids))
     588       31218 :         return false;
     589             : 
     590             :     /* Cannot move an outer-join clause into the join's outer side */
     591      178380 :     if (bms_is_member(baserel->relid, rinfo->outer_relids))
     592       81302 :         return false;
     593             : 
     594             :     /*
     595             :      * Target rel's Vars must not be nulled by any outer join.  We can check
     596             :      * this without groveling through the individual Vars by seeing whether
     597             :      * clause_relids (which includes all such Vars' varnullingrels) includes
     598             :      * any outer join that can null the target rel.  You might object that
     599             :      * this could reject the clause on the basis of an OJ relid that came from
     600             :      * some other rel's Var.  However, that would still mean that the clause
     601             :      * came from above that outer join and shouldn't be pushed down; so there
     602             :      * should be no false positives.
     603             :      */
     604       97078 :     if (bms_overlap(rinfo->clause_relids, baserel->nulling_relids))
     605        5322 :         return false;
     606             : 
     607             :     /* Clause must not use any rels with LATERAL references to this rel */
     608       91756 :     if (bms_overlap(baserel->lateral_referencers, rinfo->clause_relids))
     609          42 :         return false;
     610             : 
     611             :     /* Ignore clones, too */
     612       91714 :     if (rinfo->is_clone)
     613        8106 :         return false;
     614             : 
     615       83608 :     return true;
     616             : }
     617             : 
     618             : /*
     619             :  * join_clause_is_movable_into
     620             :  *      Test whether a join clause is movable and can be evaluated within
     621             :  *      the current join context.
     622             :  *
     623             :  * currentrelids: the relids of the proposed evaluation location
     624             :  * current_and_outer: the union of currentrelids and the required_outer
     625             :  *      relids (parameterization's outer relations)
     626             :  *
     627             :  * The API would be a bit clearer if we passed the current relids and the
     628             :  * outer relids separately and did bms_union internally; but since most
     629             :  * callers need to apply this function to multiple clauses, we make the
     630             :  * caller perform the union.
     631             :  *
     632             :  * Obviously, the clause must only refer to Vars available from the current
     633             :  * relation plus the outer rels.  We also check that it does reference at
     634             :  * least one current Var, ensuring that the clause will be pushed down to
     635             :  * a unique place in a parameterized join tree.  And we check that we're
     636             :  * not pushing the clause into its outer-join outer side.
     637             :  *
     638             :  * We used to need to check that we're not pushing the clause into a lower
     639             :  * outer join's inner side.  However, now that clause_relids includes
     640             :  * references to potentially-nulling outer joins, the other tests handle that
     641             :  * concern.  If the clause references any Var coming from the inside of a
     642             :  * lower outer join, its clause_relids will mention that outer join, causing
     643             :  * the evaluability check to fail; while if it references no such Vars, the
     644             :  * references-a-target-rel check will fail.
     645             :  *
     646             :  * There's no check here equivalent to join_clause_is_movable_to's test on
     647             :  * lateral_referencers.  We assume the caller wouldn't be inquiring unless
     648             :  * it'd verified that the proposed outer rels don't have lateral references
     649             :  * to the current rel(s).  (If we are considering join paths with the outer
     650             :  * rels on the outside and the current rels on the inside, then this should
     651             :  * have been checked at the outset of such consideration; see join_is_legal
     652             :  * and the path parameterization checks in joinpath.c.)  On the other hand,
     653             :  * in join_clause_is_movable_to we are asking whether the clause could be
     654             :  * moved for some valid set of outer rels, so we don't have the benefit of
     655             :  * relying on prior checks for lateral-reference validity.
     656             :  *
     657             :  * Likewise, we don't check is_clone here: rejecting the inappropriate
     658             :  * variants of a cloned clause must be handled upstream.
     659             :  *
     660             :  * Note: if this returns true, it means that the clause could be moved to
     661             :  * this join relation, but that doesn't mean that this is the lowest join
     662             :  * it could be moved to.  Caller may need to make additional calls to verify
     663             :  * that this doesn't succeed on either of the inputs of a proposed join.
     664             :  *
     665             :  * Note: get_joinrel_parampathinfo depends on the fact that if
     666             :  * current_and_outer is NULL, this function will always return false
     667             :  * (since one or the other of the first two tests must fail).
     668             :  */
     669             : bool
     670      275354 : join_clause_is_movable_into(RestrictInfo *rinfo,
     671             :                             Relids currentrelids,
     672             :                             Relids current_and_outer)
     673             : {
     674             :     /* Clause must be evaluable given available context */
     675      275354 :     if (!bms_is_subset(rinfo->clause_relids, current_and_outer))
     676       53810 :         return false;
     677             : 
     678             :     /* Clause must physically reference at least one target rel */
     679      221544 :     if (!bms_overlap(currentrelids, rinfo->clause_relids))
     680       15520 :         return false;
     681             : 
     682             :     /* Cannot move an outer-join clause into the join's outer side */
     683      206024 :     if (bms_overlap(currentrelids, rinfo->outer_relids))
     684         892 :         return false;
     685             : 
     686      205132 :     return true;
     687             : }

Generated by: LCOV version 1.14