LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - restrictinfo.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 100.0 % 247 247
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 12 12
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 89.6 % 106 95

             Branch data     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                 :       66465 : 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         [ +  + ]:       66465 :         if (is_orclause(clause))
      68                 :        1732 :                 return (RestrictInfo *) make_sub_restrictinfos(root,
      69                 :         866 :                                                                                                            clause,
      70                 :         866 :                                                                                                            is_pushed_down,
      71                 :         866 :                                                                                                            has_clone,
      72                 :         866 :                                                                                                            is_clone,
      73                 :         866 :                                                                                                            pseudoconstant,
      74                 :         866 :                                                                                                            security_level,
      75                 :         866 :                                                                                                            required_relids,
      76                 :         866 :                                                                                                            incompatible_relids,
      77                 :         866 :                                                                                                            outer_relids);
      78                 :             : 
      79                 :             :         /* Shouldn't be an AND clause, else AND/OR flattening messed up */
      80         [ +  - ]:       65599 :         Assert(!is_andclause(clause));
      81                 :             : 
      82                 :      131198 :         return make_plain_restrictinfo(root,
      83                 :       65599 :                                                                    clause,
      84                 :             :                                                                    NULL,
      85                 :       65599 :                                                                    is_pushed_down,
      86                 :       65599 :                                                                    has_clone,
      87                 :       65599 :                                                                    is_clone,
      88                 :       65599 :                                                                    pseudoconstant,
      89                 :       65599 :                                                                    security_level,
      90                 :       65599 :                                                                    required_relids,
      91                 :       65599 :                                                                    incompatible_relids,
      92                 :       65599 :                                                                    outer_relids);
      93                 :       66465 : }
      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                 :       69090 : 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                 :       69090 :         RestrictInfo *restrictinfo = makeNode(RestrictInfo);
     116                 :       69090 :         Relids          baserels;
     117                 :             : 
     118                 :       69090 :         restrictinfo->clause = clause;
     119                 :       69090 :         restrictinfo->orclause = orclause;
     120                 :       69090 :         restrictinfo->is_pushed_down = is_pushed_down;
     121                 :       69090 :         restrictinfo->pseudoconstant = pseudoconstant;
     122                 :       69090 :         restrictinfo->has_clone = has_clone;
     123                 :       69090 :         restrictinfo->is_clone = is_clone;
     124                 :       69090 :         restrictinfo->can_join = false; /* may get set below */
     125                 :       69090 :         restrictinfo->security_level = security_level;
     126                 :       69090 :         restrictinfo->incompatible_relids = incompatible_relids;
     127                 :       69090 :         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         [ +  + ]:       69090 :         if (security_level > 0)
     135                 :         844 :                 restrictinfo->leakproof = !contain_leaked_vars((Node *) clause);
     136                 :             :         else
     137                 :       68246 :                 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                 :       69090 :         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   [ +  +  +  + ]:       69090 :         if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
     151                 :             :         {
     152                 :       58558 :                 restrictinfo->left_relids = pull_varnos(root, get_leftop(clause));
     153                 :       58558 :                 restrictinfo->right_relids = pull_varnos(root, get_rightop(clause));
     154                 :             : 
     155                 :      117116 :                 restrictinfo->clause_relids = bms_union(restrictinfo->left_relids,
     156                 :       58558 :                                                                                                 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         [ +  + ]:       58558 :                 if (!bms_is_empty(restrictinfo->left_relids) &&
     165   [ +  +  +  + ]:       57126 :                         !bms_is_empty(restrictinfo->right_relids) &&
     166                 :       44132 :                         !bms_overlap(restrictinfo->left_relids,
     167                 :       22066 :                                                  restrictinfo->right_relids))
     168                 :             :                 {
     169                 :       21700 :                         restrictinfo->can_join = true;
     170                 :             :                         /* pseudoconstant should certainly not be true */
     171         [ +  - ]:       21700 :                         Assert(!restrictinfo->pseudoconstant);
     172                 :       21700 :                 }
     173                 :       58558 :         }
     174                 :             :         else
     175                 :             :         {
     176                 :             :                 /* Not a binary opclause, so mark left/right relid sets as empty */
     177                 :       10532 :                 restrictinfo->left_relids = NULL;
     178                 :       10532 :                 restrictinfo->right_relids = NULL;
     179                 :             :                 /* and get the total relid set the hard way */
     180                 :       10532 :                 restrictinfo->clause_relids = pull_varnos(root, (Node *) clause);
     181                 :             :         }
     182                 :             : 
     183                 :             :         /* required_relids defaults to clause_relids */
     184         [ +  + ]:       69090 :         if (required_relids != NULL)
     185                 :       61275 :                 restrictinfo->required_relids = required_relids;
     186                 :             :         else
     187                 :        7815 :                 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                 :      138180 :         baserels = bms_difference(restrictinfo->clause_relids,
     199                 :       69090 :                                                           root->outer_join_rels);
     200                 :       69090 :         restrictinfo->num_base_rels = bms_num_members(baserels);
     201                 :       69090 :         bms_free(baserels);
     202                 :             : 
     203                 :             :         /*
     204                 :             :          * Label this RestrictInfo with a fresh serial number.
     205                 :             :          */
     206                 :       69090 :         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                 :       69090 :         restrictinfo->parent_ec = NULL;
     216                 :             : 
     217                 :       69090 :         restrictinfo->eval_cost.startup = -1;
     218                 :       69090 :         restrictinfo->norm_selec = -1;
     219                 :       69090 :         restrictinfo->outer_selec = -1;
     220                 :             : 
     221                 :       69090 :         restrictinfo->mergeopfamilies = NIL;
     222                 :             : 
     223                 :       69090 :         restrictinfo->left_ec = NULL;
     224                 :       69090 :         restrictinfo->right_ec = NULL;
     225                 :       69090 :         restrictinfo->left_em = NULL;
     226                 :       69090 :         restrictinfo->right_em = NULL;
     227                 :       69090 :         restrictinfo->scansel_cache = NIL;
     228                 :             : 
     229                 :       69090 :         restrictinfo->outer_is_left = false;
     230                 :             : 
     231                 :       69090 :         restrictinfo->hashjoinoperator = InvalidOid;
     232                 :             : 
     233                 :       69090 :         restrictinfo->left_bucketsize = -1;
     234                 :       69090 :         restrictinfo->right_bucketsize = -1;
     235                 :       69090 :         restrictinfo->left_mcvfreq = -1;
     236                 :       69090 :         restrictinfo->right_mcvfreq = -1;
     237                 :             : 
     238                 :       69090 :         restrictinfo->left_hasheqoperator = InvalidOid;
     239                 :       69090 :         restrictinfo->right_hasheqoperator = InvalidOid;
     240                 :             : 
     241                 :      138180 :         return restrictinfo;
     242                 :       69090 : }
     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                 :        3815 : 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         [ +  + ]:        3815 :         if (is_orclause(clause))
     274                 :             :         {
     275                 :         883 :                 List       *orlist = NIL;
     276                 :         883 :                 ListCell   *temp;
     277                 :             : 
     278   [ +  -  +  +  :        3039 :                 foreach(temp, ((BoolExpr *) clause)->args)
                   +  + ]
     279                 :        4312 :                         orlist = lappend(orlist,
     280                 :        4312 :                                                          make_sub_restrictinfos(root,
     281                 :        2156 :                                                                                                         lfirst(temp),
     282                 :        2156 :                                                                                                         is_pushed_down,
     283                 :        2156 :                                                                                                         has_clone,
     284                 :        2156 :                                                                                                         is_clone,
     285                 :        2156 :                                                                                                         pseudoconstant,
     286                 :        2156 :                                                                                                         security_level,
     287                 :             :                                                                                                         NULL,
     288                 :        2156 :                                                                                                         incompatible_relids,
     289                 :        2156 :                                                                                                         outer_relids));
     290                 :        1766 :                 return (Expr *) make_plain_restrictinfo(root,
     291                 :         883 :                                                                                                 clause,
     292                 :         883 :                                                                                                 make_orclause(orlist),
     293                 :         883 :                                                                                                 is_pushed_down,
     294                 :         883 :                                                                                                 has_clone,
     295                 :         883 :                                                                                                 is_clone,
     296                 :         883 :                                                                                                 pseudoconstant,
     297                 :         883 :                                                                                                 security_level,
     298                 :         883 :                                                                                                 required_relids,
     299                 :         883 :                                                                                                 incompatible_relids,
     300                 :         883 :                                                                                                 outer_relids);
     301                 :         883 :         }
     302         [ +  + ]:        2932 :         else if (is_andclause(clause))
     303                 :             :         {
     304                 :         376 :                 List       *andlist = NIL;
     305                 :         376 :                 ListCell   *temp;
     306                 :             : 
     307   [ +  -  +  +  :        1169 :                 foreach(temp, ((BoolExpr *) clause)->args)
                   +  + ]
     308                 :        1586 :                         andlist = lappend(andlist,
     309                 :        1586 :                                                           make_sub_restrictinfos(root,
     310                 :         793 :                                                                                                          lfirst(temp),
     311                 :         793 :                                                                                                          is_pushed_down,
     312                 :         793 :                                                                                                          has_clone,
     313                 :         793 :                                                                                                          is_clone,
     314                 :         793 :                                                                                                          pseudoconstant,
     315                 :         793 :                                                                                                          security_level,
     316                 :         793 :                                                                                                          required_relids,
     317                 :         793 :                                                                                                          incompatible_relids,
     318                 :         793 :                                                                                                          outer_relids));
     319                 :         376 :                 return make_andclause(andlist);
     320                 :         376 :         }
     321                 :             :         else
     322                 :        5112 :                 return (Expr *) make_plain_restrictinfo(root,
     323                 :        2556 :                                                                                                 clause,
     324                 :             :                                                                                                 NULL,
     325                 :        2556 :                                                                                                 is_pushed_down,
     326                 :        2556 :                                                                                                 has_clone,
     327                 :        2556 :                                                                                                 is_clone,
     328                 :        2556 :                                                                                                 pseudoconstant,
     329                 :        2556 :                                                                                                 security_level,
     330                 :        2556 :                                                                                                 required_relids,
     331                 :        2556 :                                                                                                 incompatible_relids,
     332                 :        2556 :                                                                                                 outer_relids);
     333                 :        3815 : }
     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                 :        6562 : commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op)
     351                 :             : {
     352                 :        6562 :         RestrictInfo *result;
     353                 :        6562 :         OpExpr     *newclause;
     354                 :        6562 :         OpExpr     *clause = castNode(OpExpr, rinfo->clause);
     355                 :             : 
     356         [ +  - ]:        6562 :         Assert(list_length(clause->args) == 2);
     357                 :             : 
     358                 :             :         /* flat-copy all the fields of clause ... */
     359                 :        6562 :         newclause = makeNode(OpExpr);
     360                 :        6562 :         memcpy(newclause, clause, sizeof(OpExpr));
     361                 :             : 
     362                 :             :         /* ... and adjust those we need to change to commute it */
     363                 :        6562 :         newclause->opno = comm_op;
     364                 :        6562 :         newclause->opfuncid = InvalidOid;
     365                 :        6562 :         newclause->args = list_make2(lsecond(clause->args),
     366                 :             :                                                                  linitial(clause->args));
     367                 :             : 
     368                 :             :         /* likewise, flat-copy all the fields of rinfo ... */
     369                 :        6562 :         result = makeNode(RestrictInfo);
     370                 :        6562 :         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                 :        6562 :         result->clause = (Expr *) newclause;
     379                 :        6562 :         result->left_relids = rinfo->right_relids;
     380                 :        6562 :         result->right_relids = rinfo->left_relids;
     381         [ +  - ]:        6562 :         Assert(result->orclause == NULL);
     382                 :        6562 :         result->left_ec = rinfo->right_ec;
     383                 :        6562 :         result->right_ec = rinfo->left_ec;
     384                 :        6562 :         result->left_em = rinfo->right_em;
     385                 :        6562 :         result->right_em = rinfo->left_em;
     386                 :        6562 :         result->scansel_cache = NIL; /* not worth updating this */
     387         [ +  + ]:        6562 :         if (rinfo->hashjoinoperator == clause->opno)
     388                 :        6311 :                 result->hashjoinoperator = comm_op;
     389                 :             :         else
     390                 :         251 :                 result->hashjoinoperator = InvalidOid;
     391                 :        6562 :         result->left_bucketsize = rinfo->right_bucketsize;
     392                 :        6562 :         result->right_bucketsize = rinfo->left_bucketsize;
     393                 :        6562 :         result->left_mcvfreq = rinfo->right_mcvfreq;
     394                 :        6562 :         result->right_mcvfreq = rinfo->left_mcvfreq;
     395                 :        6562 :         result->left_hasheqoperator = InvalidOid;
     396                 :        6562 :         result->right_hasheqoperator = InvalidOid;
     397                 :             : 
     398                 :       13124 :         return result;
     399                 :        6562 : }
     400                 :             : 
     401                 :             : /*
     402                 :             :  * restriction_is_or_clause
     403                 :             :  *
     404                 :             :  * Returns t iff the restrictinfo node contains an 'or' clause.
     405                 :             :  */
     406                 :             : bool
     407                 :      195307 : restriction_is_or_clause(RestrictInfo *restrictinfo)
     408                 :             : {
     409         [ +  + ]:      195307 :         if (restrictinfo->orclause != NULL)
     410                 :        6666 :                 return true;
     411                 :             :         else
     412                 :      188641 :                 return false;
     413                 :      195307 : }
     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                 :      143464 : 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   [ +  +  +  + ]:      143464 :         if (restrictinfo->security_level <= rel->baserestrict_min_security ||
     430                 :         840 :                 restrictinfo->leakproof)
     431                 :      143068 :                 return true;
     432                 :             :         else
     433                 :         396 :                 return false;
     434                 :      143464 : }
     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                 :       41060 : rinfo_is_constant_true(RestrictInfo *rinfo)
     445                 :             : {
     446         [ +  + ]:       41277 :         return IsA(rinfo->clause, Const) &&
     447         [ +  + ]:         217 :                 !((Const *) rinfo->clause)->constisnull &&
     448                 :         214 :                 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                 :        6704 : get_actual_clauses(List *restrictinfo_list)
     461                 :             : {
     462                 :        6704 :         List       *result = NIL;
     463                 :        6704 :         ListCell   *l;
     464                 :             : 
     465   [ +  +  +  +  :       13888 :         foreach(l, restrictinfo_list)
                   +  + ]
     466                 :             :         {
     467                 :        7184 :                 RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     468                 :             : 
     469         [ +  - ]:        7184 :                 Assert(!rinfo->pseudoconstant);
     470         [ +  - ]:        7184 :                 Assert(!rinfo_is_constant_true(rinfo));
     471                 :             : 
     472                 :        7184 :                 result = lappend(result, rinfo->clause);
     473                 :        7184 :         }
     474                 :       13408 :         return result;
     475                 :        6704 : }
     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                 :       71720 : extract_actual_clauses(List *restrictinfo_list,
     486                 :             :                                            bool pseudoconstant)
     487                 :             : {
     488                 :       71720 :         List       *result = NIL;
     489                 :       71720 :         ListCell   *l;
     490                 :             : 
     491   [ +  +  +  +  :      106545 :         foreach(l, restrictinfo_list)
                   +  + ]
     492                 :             :         {
     493                 :       34825 :                 RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     494                 :             : 
     495   [ +  +  -  + ]:       34825 :                 if (rinfo->pseudoconstant == pseudoconstant &&
     496                 :       30338 :                         !rinfo_is_constant_true(rinfo))
     497                 :       30338 :                         result = lappend(result, rinfo->clause);
     498                 :       34825 :         }
     499                 :      143440 :         return result;
     500                 :       71720 : }
     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                 :        3666 : extract_actual_join_clauses(List *restrictinfo_list,
     514                 :             :                                                         Relids joinrelids,
     515                 :             :                                                         List **joinquals,
     516                 :             :                                                         List **otherquals)
     517                 :             : {
     518                 :        3666 :         ListCell   *l;
     519                 :             : 
     520                 :        3666 :         *joinquals = NIL;
     521                 :        3666 :         *otherquals = NIL;
     522                 :             : 
     523   [ +  +  +  +  :        7206 :         foreach(l, restrictinfo_list)
                   +  + ]
     524                 :             :         {
     525                 :        3540 :                 RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
     526                 :             : 
     527   [ +  +  +  + ]:        3540 :                 if (RINFO_IS_PUSHED_DOWN(rinfo, joinrelids))
     528                 :             :                 {
     529   [ +  +  -  + ]:         206 :                         if (!rinfo->pseudoconstant &&
     530                 :         204 :                                 !rinfo_is_constant_true(rinfo))
     531                 :         204 :                                 *otherquals = lappend(*otherquals, rinfo->clause);
     532                 :         206 :                 }
     533                 :             :                 else
     534                 :             :                 {
     535                 :             :                         /* joinquals shouldn't have been marked pseudoconstant */
     536         [ -  + ]:        3334 :                         Assert(!rinfo->pseudoconstant);
     537         [ +  + ]:        3334 :                         if (!rinfo_is_constant_true(rinfo))
     538                 :        3138 :                                 *joinquals = lappend(*joinquals, rinfo->clause);
     539                 :             :                 }
     540                 :        3540 :         }
     541                 :        3666 : }
     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                 :       21570 : join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel)
     576                 :             : {
     577                 :             :         /* Clause must physically reference target rel */
     578         [ +  + ]:       21570 :         if (!bms_is_member(baserel->relid, rinfo->clause_relids))
     579                 :        5513 :                 return false;
     580                 :             : 
     581                 :             :         /* Cannot move an outer-join clause into the join's outer side */
     582         [ +  + ]:       16057 :         if (bms_is_member(baserel->relid, rinfo->outer_relids))
     583                 :        7755 :                 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         [ +  + ]:        8302 :         if (bms_overlap(rinfo->clause_relids, baserel->nulling_relids))
     596                 :         226 :                 return false;
     597                 :             : 
     598                 :             :         /* Clause must not use any rels with LATERAL references to this rel */
     599         [ +  + ]:        8076 :         if (bms_overlap(baserel->lateral_referencers, rinfo->clause_relids))
     600                 :           7 :                 return false;
     601                 :             : 
     602                 :             :         /* Ignore clones, too */
     603         [ +  + ]:        8069 :         if (rinfo->is_clone)
     604                 :          95 :                 return false;
     605                 :             : 
     606                 :        7974 :         return true;
     607                 :       21570 : }
     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                 :       38844 : 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         [ +  + ]:       38844 :         if (!bms_is_subset(rinfo->clause_relids, current_and_outer))
     667                 :        2978 :                 return false;
     668                 :             : 
     669                 :             :         /* Clause must physically reference at least one target rel */
     670         [ +  + ]:       35866 :         if (!bms_overlap(currentrelids, rinfo->clause_relids))
     671                 :        2982 :                 return false;
     672                 :             : 
     673                 :             :         /* Cannot move an outer-join clause into the join's outer side */
     674         [ +  + ]:       32884 :         if (bms_overlap(currentrelids, rinfo->outer_relids))
     675                 :         149 :                 return false;
     676                 :             : 
     677                 :       32735 :         return true;
     678                 :       38844 : }
        

Generated by: LCOV version 2.3.2-1