LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - restrictinfo.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 121 121 100.0 %
Date: 2017-09-29 13:40:31 Functions: 10 10 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-2017, 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 "optimizer/clauses.h"
      18             : #include "optimizer/restrictinfo.h"
      19             : #include "optimizer/var.h"
      20             : 
      21             : 
      22             : static RestrictInfo *make_restrictinfo_internal(Expr *clause,
      23             :                            Expr *orclause,
      24             :                            bool is_pushed_down,
      25             :                            bool outerjoin_delayed,
      26             :                            bool pseudoconstant,
      27             :                            Index security_level,
      28             :                            Relids required_relids,
      29             :                            Relids outer_relids,
      30             :                            Relids nullable_relids);
      31             : static Expr *make_sub_restrictinfos(Expr *clause,
      32             :                        bool is_pushed_down,
      33             :                        bool outerjoin_delayed,
      34             :                        bool pseudoconstant,
      35             :                        Index security_level,
      36             :                        Relids required_relids,
      37             :                        Relids outer_relids,
      38             :                        Relids nullable_relids);
      39             : 
      40             : 
      41             : /*
      42             :  * make_restrictinfo
      43             :  *
      44             :  * Build a RestrictInfo node containing the given subexpression.
      45             :  *
      46             :  * The is_pushed_down, outerjoin_delayed, and pseudoconstant flags for the
      47             :  * RestrictInfo must be supplied by the caller, as well as the correct values
      48             :  * for security_level, outer_relids, and nullable_relids.
      49             :  * required_relids can be NULL, in which case it defaults to the actual clause
      50             :  * contents (i.e., clause_relids).
      51             :  *
      52             :  * We initialize fields that depend only on the given subexpression, leaving
      53             :  * others that depend on context (or may never be needed at all) to be filled
      54             :  * later.
      55             :  */
      56             : RestrictInfo *
      57       24109 : make_restrictinfo(Expr *clause,
      58             :                   bool is_pushed_down,
      59             :                   bool outerjoin_delayed,
      60             :                   bool pseudoconstant,
      61             :                   Index security_level,
      62             :                   Relids required_relids,
      63             :                   Relids outer_relids,
      64             :                   Relids nullable_relids)
      65             : {
      66             :     /*
      67             :      * If it's an OR clause, build a modified copy with RestrictInfos inserted
      68             :      * above each subclause of the top-level AND/OR structure.
      69             :      */
      70       24109 :     if (or_clause((Node *) clause))
      71         334 :         return (RestrictInfo *) make_sub_restrictinfos(clause,
      72             :                                                        is_pushed_down,
      73             :                                                        outerjoin_delayed,
      74             :                                                        pseudoconstant,
      75             :                                                        security_level,
      76             :                                                        required_relids,
      77             :                                                        outer_relids,
      78             :                                                        nullable_relids);
      79             : 
      80             :     /* Shouldn't be an AND clause, else AND/OR flattening messed up */
      81       23775 :     Assert(!and_clause((Node *) clause));
      82             : 
      83       23775 :     return make_restrictinfo_internal(clause,
      84             :                                       NULL,
      85             :                                       is_pushed_down,
      86             :                                       outerjoin_delayed,
      87             :                                       pseudoconstant,
      88             :                                       security_level,
      89             :                                       required_relids,
      90             :                                       outer_relids,
      91             :                                       nullable_relids);
      92             : }
      93             : 
      94             : /*
      95             :  * make_restrictinfo_internal
      96             :  *
      97             :  * Common code for the main entry points and the recursive cases.
      98             :  */
      99             : static RestrictInfo *
     100       25107 : make_restrictinfo_internal(Expr *clause,
     101             :                            Expr *orclause,
     102             :                            bool is_pushed_down,
     103             :                            bool outerjoin_delayed,
     104             :                            bool pseudoconstant,
     105             :                            Index security_level,
     106             :                            Relids required_relids,
     107             :                            Relids outer_relids,
     108             :                            Relids nullable_relids)
     109             : {
     110       25107 :     RestrictInfo *restrictinfo = makeNode(RestrictInfo);
     111             : 
     112       25107 :     restrictinfo->clause = clause;
     113       25107 :     restrictinfo->orclause = orclause;
     114       25107 :     restrictinfo->is_pushed_down = is_pushed_down;
     115       25107 :     restrictinfo->outerjoin_delayed = outerjoin_delayed;
     116       25107 :     restrictinfo->pseudoconstant = pseudoconstant;
     117       25107 :     restrictinfo->can_join = false; /* may get set below */
     118       25107 :     restrictinfo->security_level = security_level;
     119       25107 :     restrictinfo->outer_relids = outer_relids;
     120       25107 :     restrictinfo->nullable_relids = nullable_relids;
     121             : 
     122             :     /*
     123             :      * If it's potentially delayable by lower-level security quals, figure out
     124             :      * whether it's leakproof.  We can skip testing this for level-zero quals,
     125             :      * since they would never get delayed on security grounds anyway.
     126             :      */
     127       25107 :     if (security_level > 0)
     128         594 :         restrictinfo->leakproof = !contain_leaked_vars((Node *) clause);
     129             :     else
     130       24513 :         restrictinfo->leakproof = false; /* really, "don't know" */
     131             : 
     132             :     /*
     133             :      * If it's a binary opclause, set up left/right relids info. In any case
     134             :      * set up the total clause relids info.
     135             :      */
     136       25107 :     if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
     137             :     {
     138       21086 :         restrictinfo->left_relids = pull_varnos(get_leftop(clause));
     139       21086 :         restrictinfo->right_relids = pull_varnos(get_rightop(clause));
     140             : 
     141       21086 :         restrictinfo->clause_relids = bms_union(restrictinfo->left_relids,
     142       21086 :                                                 restrictinfo->right_relids);
     143             : 
     144             :         /*
     145             :          * Does it look like a normal join clause, i.e., a binary operator
     146             :          * relating expressions that come from distinct relations? If so we
     147             :          * might be able to use it in a join algorithm.  Note that this is a
     148             :          * purely syntactic test that is made regardless of context.
     149             :          */
     150       62591 :         if (!bms_is_empty(restrictinfo->left_relids) &&
     151       28135 :             !bms_is_empty(restrictinfo->right_relids) &&
     152        7716 :             !bms_overlap(restrictinfo->left_relids,
     153        7716 :                          restrictinfo->right_relids))
     154             :         {
     155        7587 :             restrictinfo->can_join = true;
     156             :             /* pseudoconstant should certainly not be true */
     157        7587 :             Assert(!restrictinfo->pseudoconstant);
     158             :         }
     159             :     }
     160             :     else
     161             :     {
     162             :         /* Not a binary opclause, so mark left/right relid sets as empty */
     163        4021 :         restrictinfo->left_relids = NULL;
     164        4021 :         restrictinfo->right_relids = NULL;
     165             :         /* and get the total relid set the hard way */
     166        4021 :         restrictinfo->clause_relids = pull_varnos((Node *) clause);
     167             :     }
     168             : 
     169             :     /* required_relids defaults to clause_relids */
     170       25107 :     if (required_relids != NULL)
     171       22490 :         restrictinfo->required_relids = required_relids;
     172             :     else
     173        2617 :         restrictinfo->required_relids = restrictinfo->clause_relids;
     174             : 
     175             :     /*
     176             :      * Fill in all the cacheable fields with "not yet set" markers. None of
     177             :      * these will be computed until/unless needed.  Note in particular that we
     178             :      * don't mark a binary opclause as mergejoinable or hashjoinable here;
     179             :      * that happens only if it appears in the right context (top level of a
     180             :      * joinclause list).
     181             :      */
     182       25107 :     restrictinfo->parent_ec = NULL;
     183             : 
     184       25107 :     restrictinfo->eval_cost.startup = -1;
     185       25107 :     restrictinfo->norm_selec = -1;
     186       25107 :     restrictinfo->outer_selec = -1;
     187             : 
     188       25107 :     restrictinfo->mergeopfamilies = NIL;
     189             : 
     190       25107 :     restrictinfo->left_ec = NULL;
     191       25107 :     restrictinfo->right_ec = NULL;
     192       25107 :     restrictinfo->left_em = NULL;
     193       25107 :     restrictinfo->right_em = NULL;
     194       25107 :     restrictinfo->scansel_cache = NIL;
     195             : 
     196       25107 :     restrictinfo->outer_is_left = false;
     197             : 
     198       25107 :     restrictinfo->hashjoinoperator = InvalidOid;
     199             : 
     200       25107 :     restrictinfo->left_bucketsize = -1;
     201       25107 :     restrictinfo->right_bucketsize = -1;
     202       25107 :     restrictinfo->left_mcvfreq = -1;
     203       25107 :     restrictinfo->right_mcvfreq = -1;
     204             : 
     205       25107 :     return restrictinfo;
     206             : }
     207             : 
     208             : /*
     209             :  * Recursively insert sub-RestrictInfo nodes into a boolean expression.
     210             :  *
     211             :  * We put RestrictInfos above simple (non-AND/OR) clauses and above
     212             :  * sub-OR clauses, but not above sub-AND clauses, because there's no need.
     213             :  * This may seem odd but it is closely related to the fact that we use
     214             :  * implicit-AND lists at top level of RestrictInfo lists.  Only ORs and
     215             :  * simple clauses are valid RestrictInfos.
     216             :  *
     217             :  * The same is_pushed_down, outerjoin_delayed, and pseudoconstant flag
     218             :  * values can be applied to all RestrictInfo nodes in the result.  Likewise
     219             :  * for security_level, outer_relids, and nullable_relids.
     220             :  *
     221             :  * The given required_relids are attached to our top-level output,
     222             :  * but any OR-clause constituents are allowed to default to just the
     223             :  * contained rels.
     224             :  */
     225             : static Expr *
     226        1400 : make_sub_restrictinfos(Expr *clause,
     227             :                        bool is_pushed_down,
     228             :                        bool outerjoin_delayed,
     229             :                        bool pseudoconstant,
     230             :                        Index security_level,
     231             :                        Relids required_relids,
     232             :                        Relids outer_relids,
     233             :                        Relids nullable_relids)
     234             : {
     235        1400 :     if (or_clause((Node *) clause))
     236             :     {
     237         343 :         List       *orlist = NIL;
     238             :         ListCell   *temp;
     239             : 
     240        1271 :         foreach(temp, ((BoolExpr *) clause)->args)
     241         928 :             orlist = lappend(orlist,
     242         928 :                              make_sub_restrictinfos(lfirst(temp),
     243             :                                                     is_pushed_down,
     244             :                                                     outerjoin_delayed,
     245             :                                                     pseudoconstant,
     246             :                                                     security_level,
     247             :                                                     NULL,
     248             :                                                     outer_relids,
     249             :                                                     nullable_relids));
     250         343 :         return (Expr *) make_restrictinfo_internal(clause,
     251             :                                                    make_orclause(orlist),
     252             :                                                    is_pushed_down,
     253             :                                                    outerjoin_delayed,
     254             :                                                    pseudoconstant,
     255             :                                                    security_level,
     256             :                                                    required_relids,
     257             :                                                    outer_relids,
     258             :                                                    nullable_relids);
     259             :     }
     260        1057 :     else if (and_clause((Node *) clause))
     261             :     {
     262          68 :         List       *andlist = NIL;
     263             :         ListCell   *temp;
     264             : 
     265         206 :         foreach(temp, ((BoolExpr *) clause)->args)
     266         138 :             andlist = lappend(andlist,
     267         138 :                               make_sub_restrictinfos(lfirst(temp),
     268             :                                                      is_pushed_down,
     269             :                                                      outerjoin_delayed,
     270             :                                                      pseudoconstant,
     271             :                                                      security_level,
     272             :                                                      required_relids,
     273             :                                                      outer_relids,
     274             :                                                      nullable_relids));
     275          68 :         return make_andclause(andlist);
     276             :     }
     277             :     else
     278         989 :         return (Expr *) make_restrictinfo_internal(clause,
     279             :                                                    NULL,
     280             :                                                    is_pushed_down,
     281             :                                                    outerjoin_delayed,
     282             :                                                    pseudoconstant,
     283             :                                                    security_level,
     284             :                                                    required_relids,
     285             :                                                    outer_relids,
     286             :                                                    nullable_relids);
     287             : }
     288             : 
     289             : /*
     290             :  * restriction_is_or_clause
     291             :  *
     292             :  * Returns t iff the restrictinfo node contains an 'or' clause.
     293             :  */
     294             : bool
     295       19125 : restriction_is_or_clause(RestrictInfo *restrictinfo)
     296             : {
     297       19125 :     if (restrictinfo->orclause != NULL)
     298        1141 :         return true;
     299             :     else
     300       17984 :         return false;
     301             : }
     302             : 
     303             : /*
     304             :  * restriction_is_securely_promotable
     305             :  *
     306             :  * Returns true if it's okay to evaluate this clause "early", that is before
     307             :  * other restriction clauses attached to the specified relation.
     308             :  */
     309             : bool
     310       43983 : restriction_is_securely_promotable(RestrictInfo *restrictinfo,
     311             :                                    RelOptInfo *rel)
     312             : {
     313             :     /*
     314             :      * It's okay if there are no baserestrictinfo clauses for the rel that
     315             :      * would need to go before this one, *or* if this one is leakproof.
     316             :      */
     317       44530 :     if (restrictinfo->security_level <= rel->baserestrict_min_security ||
     318         547 :         restrictinfo->leakproof)
     319       43710 :         return true;
     320             :     else
     321         273 :         return false;
     322             : }
     323             : 
     324             : /*
     325             :  * get_actual_clauses
     326             :  *
     327             :  * Returns a list containing the bare clauses from 'restrictinfo_list'.
     328             :  *
     329             :  * This is only to be used in cases where none of the RestrictInfos can
     330             :  * be pseudoconstant clauses (for instance, it's OK on indexqual lists).
     331             :  */
     332             : List *
     333       14868 : get_actual_clauses(List *restrictinfo_list)
     334             : {
     335       14868 :     List       *result = NIL;
     336             :     ListCell   *l;
     337             : 
     338       31686 :     foreach(l, restrictinfo_list)
     339             :     {
     340       16818 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     341             : 
     342       16818 :         Assert(!rinfo->pseudoconstant);
     343             : 
     344       16818 :         result = lappend(result, rinfo->clause);
     345             :     }
     346       14868 :     return result;
     347             : }
     348             : 
     349             : /*
     350             :  * extract_actual_clauses
     351             :  *
     352             :  * Extract bare clauses from 'restrictinfo_list', returning either the
     353             :  * regular ones or the pseudoconstant ones per 'pseudoconstant'.
     354             :  */
     355             : List *
     356       23376 : extract_actual_clauses(List *restrictinfo_list,
     357             :                        bool pseudoconstant)
     358             : {
     359       23376 :     List       *result = NIL;
     360             :     ListCell   *l;
     361             : 
     362       34386 :     foreach(l, restrictinfo_list)
     363             :     {
     364       11010 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     365             : 
     366       11010 :         if (rinfo->pseudoconstant == pseudoconstant)
     367        9914 :             result = lappend(result, rinfo->clause);
     368             :     }
     369       23376 :     return result;
     370             : }
     371             : 
     372             : /*
     373             :  * extract_actual_join_clauses
     374             :  *
     375             :  * Extract bare clauses from 'restrictinfo_list', separating those that
     376             :  * syntactically match the join level from those that were pushed down.
     377             :  * Pseudoconstant clauses are excluded from the results.
     378             :  *
     379             :  * This is only used at outer joins, since for plain joins we don't care
     380             :  * about pushed-down-ness.
     381             :  */
     382             : void
     383        1034 : extract_actual_join_clauses(List *restrictinfo_list,
     384             :                             List **joinquals,
     385             :                             List **otherquals)
     386             : {
     387             :     ListCell   *l;
     388             : 
     389        1034 :     *joinquals = NIL;
     390        1034 :     *otherquals = NIL;
     391             : 
     392        1908 :     foreach(l, restrictinfo_list)
     393             :     {
     394         874 :         RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     395             : 
     396         874 :         if (rinfo->is_pushed_down)
     397             :         {
     398          35 :             if (!rinfo->pseudoconstant)
     399          35 :                 *otherquals = lappend(*otherquals, rinfo->clause);
     400             :         }
     401             :         else
     402             :         {
     403             :             /* joinquals shouldn't have been marked pseudoconstant */
     404         839 :             Assert(!rinfo->pseudoconstant);
     405         839 :             *joinquals = lappend(*joinquals, rinfo->clause);
     406             :         }
     407             :     }
     408        1034 : }
     409             : 
     410             : 
     411             : /*
     412             :  * join_clause_is_movable_to
     413             :  *      Test whether a join clause is a safe candidate for parameterization
     414             :  *      of a scan on the specified base relation.
     415             :  *
     416             :  * A movable join clause is one that can safely be evaluated at a rel below
     417             :  * its normal semantic level (ie, its required_relids), if the values of
     418             :  * variables that it would need from other rels are provided.
     419             :  *
     420             :  * We insist that the clause actually reference the target relation; this
     421             :  * prevents undesirable movement of degenerate join clauses, and ensures
     422             :  * that there is a unique place that a clause can be moved down to.
     423             :  *
     424             :  * We cannot move an outer-join clause into the non-nullable side of its
     425             :  * outer join, as that would change the results (rows would be suppressed
     426             :  * rather than being null-extended).
     427             :  *
     428             :  * Also there must not be an outer join below the clause that would null the
     429             :  * Vars coming from the target relation.  Otherwise the clause might give
     430             :  * results different from what it would give at its normal semantic level.
     431             :  *
     432             :  * Also, the join clause must not use any relations that have LATERAL
     433             :  * references to the target relation, since we could not put such rels on
     434             :  * the outer side of a nestloop with the target relation.
     435             :  */
     436             : bool
     437        5916 : join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel)
     438             : {
     439             :     /* Clause must physically reference target rel */
     440        5916 :     if (!bms_is_member(baserel->relid, rinfo->clause_relids))
     441         527 :         return false;
     442             : 
     443             :     /* Cannot move an outer-join clause into the join's outer side */
     444        5389 :     if (bms_is_member(baserel->relid, rinfo->outer_relids))
     445        2308 :         return false;
     446             : 
     447             :     /* Target rel must not be nullable below the clause */
     448        3081 :     if (bms_is_member(baserel->relid, rinfo->nullable_relids))
     449          88 :         return false;
     450             : 
     451             :     /* Clause must not use any rels with LATERAL references to this rel */
     452        2993 :     if (bms_overlap(baserel->lateral_referencers, rinfo->clause_relids))
     453           3 :         return false;
     454             : 
     455        2990 :     return true;
     456             : }
     457             : 
     458             : /*
     459             :  * join_clause_is_movable_into
     460             :  *      Test whether a join clause is movable and can be evaluated within
     461             :  *      the current join context.
     462             :  *
     463             :  * currentrelids: the relids of the proposed evaluation location
     464             :  * current_and_outer: the union of currentrelids and the required_outer
     465             :  *      relids (parameterization's outer relations)
     466             :  *
     467             :  * The API would be a bit clearer if we passed the current relids and the
     468             :  * outer relids separately and did bms_union internally; but since most
     469             :  * callers need to apply this function to multiple clauses, we make the
     470             :  * caller perform the union.
     471             :  *
     472             :  * Obviously, the clause must only refer to Vars available from the current
     473             :  * relation plus the outer rels.  We also check that it does reference at
     474             :  * least one current Var, ensuring that the clause will be pushed down to
     475             :  * a unique place in a parameterized join tree.  And we check that we're
     476             :  * not pushing the clause into its outer-join outer side, nor down into
     477             :  * a lower outer join's inner side.
     478             :  *
     479             :  * The check about pushing a clause down into a lower outer join's inner side
     480             :  * is only approximate; it sometimes returns "false" when actually it would
     481             :  * be safe to use the clause here because we're still above the outer join
     482             :  * in question.  This is okay as long as the answers at different join levels
     483             :  * are consistent: it just means we might sometimes fail to push a clause as
     484             :  * far down as it could safely be pushed.  It's unclear whether it would be
     485             :  * worthwhile to do this more precisely.  (But if it's ever fixed to be
     486             :  * exactly accurate, there's an Assert in get_joinrel_parampathinfo() that
     487             :  * should be re-enabled.)
     488             :  *
     489             :  * There's no check here equivalent to join_clause_is_movable_to's test on
     490             :  * lateral_referencers.  We assume the caller wouldn't be inquiring unless
     491             :  * it'd verified that the proposed outer rels don't have lateral references
     492             :  * to the current rel(s).  (If we are considering join paths with the outer
     493             :  * rels on the outside and the current rels on the inside, then this should
     494             :  * have been checked at the outset of such consideration; see join_is_legal
     495             :  * and the path parameterization checks in joinpath.c.)  On the other hand,
     496             :  * in join_clause_is_movable_to we are asking whether the clause could be
     497             :  * moved for some valid set of outer rels, so we don't have the benefit of
     498             :  * relying on prior checks for lateral-reference validity.
     499             :  *
     500             :  * Note: if this returns true, it means that the clause could be moved to
     501             :  * this join relation, but that doesn't mean that this is the lowest join
     502             :  * it could be moved to.  Caller may need to make additional calls to verify
     503             :  * that this doesn't succeed on either of the inputs of a proposed join.
     504             :  *
     505             :  * Note: get_joinrel_parampathinfo depends on the fact that if
     506             :  * current_and_outer is NULL, this function will always return false
     507             :  * (since one or the other of the first two tests must fail).
     508             :  */
     509             : bool
     510       13034 : join_clause_is_movable_into(RestrictInfo *rinfo,
     511             :                             Relids currentrelids,
     512             :                             Relids current_and_outer)
     513             : {
     514             :     /* Clause must be evaluable given available context */
     515       13034 :     if (!bms_is_subset(rinfo->clause_relids, current_and_outer))
     516        1357 :         return false;
     517             : 
     518             :     /* Clause must physically reference at least one target rel */
     519       11677 :     if (!bms_overlap(currentrelids, rinfo->clause_relids))
     520         499 :         return false;
     521             : 
     522             :     /* Cannot move an outer-join clause into the join's outer side */
     523       11178 :     if (bms_overlap(currentrelids, rinfo->outer_relids))
     524          90 :         return false;
     525             : 
     526             :     /*
     527             :      * Target rel(s) must not be nullable below the clause.  This is
     528             :      * approximate, in the safe direction, because the current join might be
     529             :      * above the join where the nulling would happen, in which case the clause
     530             :      * would work correctly here.  But we don't have enough info to be sure.
     531             :      */
     532       11088 :     if (bms_overlap(currentrelids, rinfo->nullable_relids))
     533          43 :         return false;
     534             : 
     535       11045 :     return true;
     536             : }

Generated by: LCOV version 1.11