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

Generated by: LCOV version 2.0-1