LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/prep - prepqual.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 66.1 % 221 146 75 146
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 6 6 6
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 66.1 % 221 146 75 146
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 6 6 6

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * prepqual.c
                                  4                 :  *    Routines for preprocessing qualification expressions
                                  5                 :  *
                                  6                 :  *
                                  7                 :  * While the parser will produce flattened (N-argument) AND/OR trees from
                                  8                 :  * simple sequences of AND'ed or OR'ed clauses, there might be an AND clause
                                  9                 :  * directly underneath another AND, or OR underneath OR, if the input was
                                 10                 :  * oddly parenthesized.  Also, rule expansion and subquery flattening could
                                 11                 :  * produce such parsetrees.  The planner wants to flatten all such cases
                                 12                 :  * to ensure consistent optimization behavior.
                                 13                 :  *
                                 14                 :  * Formerly, this module was responsible for doing the initial flattening,
                                 15                 :  * but now we leave it to eval_const_expressions to do that since it has to
                                 16                 :  * make a complete pass over the expression tree anyway.  Instead, we just
                                 17                 :  * have to ensure that our manipulations preserve AND/OR flatness.
                                 18                 :  * pull_ands() and pull_ors() are used to maintain flatness of the AND/OR
                                 19                 :  * tree after local transformations that might introduce nested AND/ORs.
                                 20                 :  *
                                 21                 :  *
                                 22                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                 23                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 24                 :  *
                                 25                 :  *
                                 26                 :  * IDENTIFICATION
                                 27                 :  *    src/backend/optimizer/prep/prepqual.c
                                 28                 :  *
                                 29                 :  *-------------------------------------------------------------------------
                                 30                 :  */
                                 31                 : 
                                 32                 : #include "postgres.h"
                                 33                 : 
                                 34                 : #include "nodes/makefuncs.h"
                                 35                 : #include "nodes/nodeFuncs.h"
                                 36                 : #include "optimizer/optimizer.h"
                                 37                 : #include "optimizer/prep.h"
                                 38                 : #include "utils/lsyscache.h"
                                 39                 : 
                                 40                 : 
                                 41                 : static List *pull_ands(List *andlist);
                                 42                 : static List *pull_ors(List *orlist);
                                 43                 : static Expr *find_duplicate_ors(Expr *qual, bool is_check);
                                 44                 : static Expr *process_duplicate_ors(List *orlist);
                                 45                 : 
                                 46                 : 
                                 47                 : /*
                                 48                 :  * negate_clause
                                 49                 :  *    Negate a Boolean expression.
                                 50                 :  *
                                 51                 :  * Input is a clause to be negated (e.g., the argument of a NOT clause).
                                 52                 :  * Returns a new clause equivalent to the negation of the given clause.
                                 53                 :  *
                                 54                 :  * Although this can be invoked on its own, it's mainly intended as a helper
                                 55                 :  * for eval_const_expressions(), and that context drives several design
                                 56                 :  * decisions.  In particular, if the input is already AND/OR flat, we must
                                 57                 :  * preserve that property.  We also don't bother to recurse in situations
                                 58                 :  * where we can assume that lower-level executions of eval_const_expressions
                                 59                 :  * would already have simplified sub-clauses of the input.
                                 60                 :  *
                                 61                 :  * The difference between this and a simple make_notclause() is that this
                                 62                 :  * tries to get rid of the NOT node by logical simplification.  It's clearly
                                 63                 :  * always a win if the NOT node can be eliminated altogether.  However, our
                                 64                 :  * use of DeMorgan's laws could result in having more NOT nodes rather than
                                 65                 :  * fewer.  We do that unconditionally anyway, because in WHERE clauses it's
                                 66                 :  * important to expose as much top-level AND/OR structure as possible.
                                 67                 :  * Also, eliminating an intermediate NOT may allow us to flatten two levels
                                 68                 :  * of AND or OR together that we couldn't have otherwise.  Finally, one of
                                 69                 :  * the motivations for doing this is to ensure that logically equivalent
                                 70                 :  * expressions will be seen as physically equal(), so we should always apply
                                 71                 :  * the same transformations.
                                 72                 :  */
                                 73                 : Node *
 4564 tgl                        74 CBC        9913 : negate_clause(Node *node)
                                 75                 : {
                                 76            9913 :     if (node == NULL)           /* should not happen */
 4564 tgl                        77 UBC           0 :         elog(ERROR, "can't negate an empty subexpression");
 4564 tgl                        78 CBC        9913 :     switch (nodeTag(node))
                                 79                 :     {
                                 80              45 :         case T_Const:
                                 81                 :             {
                                 82              45 :                 Const      *c = (Const *) node;
                                 83                 : 
                                 84                 :                 /* NOT NULL is still NULL */
                                 85              45 :                 if (c->constisnull)
 4564 tgl                        86 UBC           0 :                     return makeBoolConst(false, true);
                                 87                 :                 /* otherwise pretty easy */
 4564 tgl                        88 CBC          45 :                 return makeBoolConst(!DatumGetBool(c->constvalue), false);
                                 89                 :             }
                                 90                 :             break;
                                 91            3060 :         case T_OpExpr:
                                 92                 :             {
                                 93                 :                 /*
                                 94                 :                  * Negate operator if possible: (NOT (< A B)) => (>= A B)
                                 95                 :                  */
                                 96            3060 :                 OpExpr     *opexpr = (OpExpr *) node;
                                 97            3060 :                 Oid         negator = get_negator(opexpr->opno);
                                 98                 : 
                                 99            3060 :                 if (negator)
                                100                 :                 {
                                101            2961 :                     OpExpr     *newopexpr = makeNode(OpExpr);
                                102                 : 
                                103            2961 :                     newopexpr->opno = negator;
                                104            2961 :                     newopexpr->opfuncid = InvalidOid;
                                105            2961 :                     newopexpr->opresulttype = opexpr->opresulttype;
                                106            2961 :                     newopexpr->opretset = opexpr->opretset;
 4398                           107            2961 :                     newopexpr->opcollid = opexpr->opcollid;
                                108            2961 :                     newopexpr->inputcollid = opexpr->inputcollid;
 4564                           109            2961 :                     newopexpr->args = opexpr->args;
                                110            2961 :                     newopexpr->location = opexpr->location;
                                111            2961 :                     return (Node *) newopexpr;
                                112                 :                 }
                                113                 :             }
                                114              99 :             break;
                                115             206 :         case T_ScalarArrayOpExpr:
                                116                 :             {
                                117                 :                 /*
                                118                 :                  * Negate a ScalarArrayOpExpr if its operator has a negator;
                                119                 :                  * for example x = ANY (list) becomes x <> ALL (list)
                                120                 :                  */
                                121             206 :                 ScalarArrayOpExpr *saopexpr = (ScalarArrayOpExpr *) node;
                                122             206 :                 Oid         negator = get_negator(saopexpr->opno);
                                123                 : 
                                124             206 :                 if (negator)
                                125                 :                 {
                                126             206 :                     ScalarArrayOpExpr *newopexpr = makeNode(ScalarArrayOpExpr);
                                127                 : 
                                128             206 :                     newopexpr->opno = negator;
                                129             206 :                     newopexpr->opfuncid = InvalidOid;
  731 drowley                   130             206 :                     newopexpr->hashfuncid = InvalidOid;
  641                           131             206 :                     newopexpr->negfuncid = InvalidOid;
 4564 tgl                       132             206 :                     newopexpr->useOr = !saopexpr->useOr;
 4398                           133             206 :                     newopexpr->inputcollid = saopexpr->inputcollid;
 4564                           134             206 :                     newopexpr->args = saopexpr->args;
                                135             206 :                     newopexpr->location = saopexpr->location;
                                136             206 :                     return (Node *) newopexpr;
                                137                 :                 }
                                138                 :             }
 4564 tgl                       139 UBC           0 :             break;
 4564 tgl                       140 CBC        1878 :         case T_BoolExpr:
                                141                 :             {
                                142            1878 :                 BoolExpr   *expr = (BoolExpr *) node;
                                143                 : 
                                144            1878 :                 switch (expr->boolop)
                                145                 :                 {
                                146                 :                         /*--------------------
                                147                 :                          * Apply DeMorgan's Laws:
                                148                 :                          *      (NOT (AND A B)) => (OR (NOT A) (NOT B))
                                149                 :                          *      (NOT (OR A B))  => (AND (NOT A) (NOT B))
                                150                 :                          * i.e., swap AND for OR and negate each subclause.
                                151                 :                          *
                                152                 :                          * If the input is already AND/OR flat and has no NOT
                                153                 :                          * directly above AND or OR, this transformation preserves
                                154                 :                          * those properties.  For example, if no direct child of
                                155                 :                          * the given AND clause is an AND or a NOT-above-OR, then
                                156                 :                          * the recursive calls of negate_clause() can't return any
                                157                 :                          * OR clauses.  So we needn't call pull_ors() before
                                158                 :                          * building a new OR clause.  Similarly for the OR case.
                                159                 :                          *--------------------
                                160                 :                          */
                                161            1539 :                     case AND_EXPR:
                                162                 :                         {
                                163            1539 :                             List       *nargs = NIL;
                                164                 :                             ListCell   *lc;
                                165                 : 
                                166            5426 :                             foreach(lc, expr->args)
                                167                 :                             {
                                168            3887 :                                 nargs = lappend(nargs,
                                169            3887 :                                                 negate_clause(lfirst(lc)));
                                170                 :                             }
                                171            1539 :                             return (Node *) make_orclause(nargs);
                                172                 :                         }
                                173                 :                         break;
                                174             306 :                     case OR_EXPR:
                                175                 :                         {
                                176             306 :                             List       *nargs = NIL;
                                177                 :                             ListCell   *lc;
                                178                 : 
                                179            1298 :                             foreach(lc, expr->args)
                                180                 :                             {
                                181             992 :                                 nargs = lappend(nargs,
                                182             992 :                                                 negate_clause(lfirst(lc)));
                                183                 :                             }
                                184             306 :                             return (Node *) make_andclause(nargs);
                                185                 :                         }
                                186                 :                         break;
                                187              33 :                     case NOT_EXPR:
                                188                 : 
                                189                 :                         /*
                                190                 :                          * NOT underneath NOT: they cancel.  We assume the
                                191                 :                          * input is already simplified, so no need to recurse.
                                192                 :                          */
                                193              33 :                         return (Node *) linitial(expr->args);
 4564 tgl                       194 UBC           0 :                     default:
                                195               0 :                         elog(ERROR, "unrecognized boolop: %d",
                                196                 :                              (int) expr->boolop);
                                197                 :                         break;
                                198                 :                 }
                                199                 :             }
                                200                 :             break;
 4564 tgl                       201 CBC         772 :         case T_NullTest:
                                202                 :             {
                                203             772 :                 NullTest   *expr = (NullTest *) node;
                                204                 : 
                                205                 :                 /*
                                206                 :                  * In the rowtype case, the two flavors of NullTest are *not*
                                207                 :                  * logical inverses, so we can't simplify.  But it does work
                                208                 :                  * for scalar datatypes.
                                209                 :                  */
                                210             772 :                 if (!expr->argisrow)
                                211                 :                 {
                                212             772 :                     NullTest   *newexpr = makeNode(NullTest);
                                213                 : 
                                214             772 :                     newexpr->arg = expr->arg;
                                215             772 :                     newexpr->nulltesttype = (expr->nulltesttype == IS_NULL ?
                                216             772 :                                              IS_NOT_NULL : IS_NULL);
                                217             772 :                     newexpr->argisrow = expr->argisrow;
 2968                           218             772 :                     newexpr->location = expr->location;
 4564                           219             772 :                     return (Node *) newexpr;
                                220                 :                 }
                                221                 :             }
 4564 tgl                       222 UBC           0 :             break;
                                223               0 :         case T_BooleanTest:
                                224                 :             {
 4382 bruce                     225               0 :                 BooleanTest *expr = (BooleanTest *) node;
                                226               0 :                 BooleanTest *newexpr = makeNode(BooleanTest);
                                227                 : 
 4564 tgl                       228               0 :                 newexpr->arg = expr->arg;
                                229               0 :                 switch (expr->booltesttype)
                                230                 :                 {
                                231               0 :                     case IS_TRUE:
                                232               0 :                         newexpr->booltesttype = IS_NOT_TRUE;
                                233               0 :                         break;
                                234               0 :                     case IS_NOT_TRUE:
                                235               0 :                         newexpr->booltesttype = IS_TRUE;
                                236               0 :                         break;
                                237               0 :                     case IS_FALSE:
                                238               0 :                         newexpr->booltesttype = IS_NOT_FALSE;
                                239               0 :                         break;
                                240               0 :                     case IS_NOT_FALSE:
                                241               0 :                         newexpr->booltesttype = IS_FALSE;
                                242               0 :                         break;
                                243               0 :                     case IS_UNKNOWN:
                                244               0 :                         newexpr->booltesttype = IS_NOT_UNKNOWN;
                                245               0 :                         break;
                                246               0 :                     case IS_NOT_UNKNOWN:
                                247               0 :                         newexpr->booltesttype = IS_UNKNOWN;
                                248               0 :                         break;
                                249               0 :                     default:
                                250               0 :                         elog(ERROR, "unrecognized booltesttype: %d",
                                251                 :                              (int) expr->booltesttype);
                                252                 :                         break;
                                253                 :                 }
 2968                           254               0 :                 newexpr->location = expr->location;
 4564                           255               0 :                 return (Node *) newexpr;
                                256                 :             }
                                257                 :             break;
 4564 tgl                       258 CBC        3952 :         default:
                                259                 :             /* else fall through */
                                260            3952 :             break;
                                261                 :     }
                                262                 : 
                                263                 :     /*
                                264                 :      * Otherwise we don't know how to simplify this, so just tack on an
                                265                 :      * explicit NOT node.
                                266                 :      */
                                267            4051 :     return (Node *) make_notclause((Expr *) node);
                                268                 : }
                                269                 : 
                                270                 : 
                                271                 : /*
                                272                 :  * canonicalize_qual
                                273                 :  *    Convert a qualification expression to the most useful form.
                                274                 :  *
                                275                 :  * This is primarily intended to be used on top-level WHERE (or JOIN/ON)
                                276                 :  * clauses.  It can also be used on top-level CHECK constraints, for which
                                277                 :  * pass is_check = true.  DO NOT call it on any expression that is not known
                                278                 :  * to be one or the other, as it might apply inappropriate simplifications.
                                279                 :  *
                                280                 :  * The name of this routine is a holdover from a time when it would try to
                                281                 :  * force the expression into canonical AND-of-ORs or OR-of-ANDs form.
                                282                 :  * Eventually, we recognized that that had more theoretical purity than
                                283                 :  * actual usefulness, and so now the transformation doesn't involve any
                                284                 :  * notion of reaching a canonical form.
                                285                 :  *
                                286                 :  * NOTE: we assume the input has already been through eval_const_expressions
                                287                 :  * and therefore possesses AND/OR flatness.  Formerly this function included
                                288                 :  * its own flattening logic, but that requires a useless extra pass over the
                                289                 :  * tree.
                                290                 :  *
                                291                 :  * Returns the modified qualification.
                                292                 :  */
                                293                 : Expr *
 1855                           294          127491 : canonicalize_qual(Expr *qual, bool is_check)
                                295                 : {
                                296                 :     Expr       *newqual;
                                297                 : 
                                298                 :     /* Quick exit for empty qual */
 8609                           299          127491 :     if (qual == NULL)
 7042 tgl                       300 UBC           0 :         return NULL;
                                301                 : 
                                302                 :     /* This should not be invoked on quals in implicit-AND format */
 1855 tgl                       303 CBC      127491 :     Assert(!IsA(qual, List));
                                304                 : 
                                305                 :     /*
                                306                 :      * Pull up redundant subclauses in OR-of-AND trees.  We do this only
                                307                 :      * within the top-level AND/OR structure; there's no point in looking
                                308                 :      * deeper.  Also remove any NULL constants in the top-level structure.
                                309                 :      */
                                310          127491 :     newqual = find_duplicate_ors(qual, is_check);
                                311                 : 
 7042                           312          127491 :     return newqual;
                                313                 : }
                                314                 : 
                                315                 : 
                                316                 : /*
                                317                 :  * pull_ands
                                318                 :  *    Recursively flatten nested AND clauses into a single and-clause list.
                                319                 :  *
                                320                 :  * Input is the arglist of an AND clause.
                                321                 :  * Returns the rebuilt arglist (note original list structure is not touched).
                                322                 :  */
                                323                 : static List *
 8610                           324           43379 : pull_ands(List *andlist)
                                325                 : {
 6886                           326           43379 :     List       *out_list = NIL;
                                327                 :     ListCell   *arg;
                                328                 : 
 8610                           329          160779 :     foreach(arg, andlist)
                                330                 :     {
 7042                           331          117400 :         Node       *subexpr = (Node *) lfirst(arg);
                                332                 : 
 1531                           333          117400 :         if (is_andclause(subexpr))
 6886 tgl                       334 UBC           0 :             out_list = list_concat(out_list,
 6385 bruce                     335               0 :                                    pull_ands(((BoolExpr *) subexpr)->args));
                                336                 :         else
 6886 tgl                       337 CBC      117400 :             out_list = lappend(out_list, subexpr);
                                338                 :     }
                                339           43379 :     return out_list;
                                340                 : }
                                341                 : 
                                342                 : /*
                                343                 :  * pull_ors
                                344                 :  *    Recursively flatten nested OR clauses into a single or-clause list.
                                345                 :  *
                                346                 :  * Input is the arglist of an OR clause.
                                347                 :  * Returns the rebuilt arglist (note original list structure is not touched).
                                348                 :  */
                                349                 : static List *
 7256                           350            3404 : pull_ors(List *orlist)
                                351                 : {
 6886                           352            3404 :     List       *out_list = NIL;
                                353                 :     ListCell   *arg;
                                354                 : 
 7256                           355           11635 :     foreach(arg, orlist)
                                356                 :     {
 7042                           357            8231 :         Node       *subexpr = (Node *) lfirst(arg);
                                358                 : 
 1531                           359            8231 :         if (is_orclause(subexpr))
 6886 tgl                       360 UBC           0 :             out_list = list_concat(out_list,
 6385 bruce                     361               0 :                                    pull_ors(((BoolExpr *) subexpr)->args));
                                362                 :         else
 6886 tgl                       363 CBC        8231 :             out_list = lappend(out_list, subexpr);
                                364                 :     }
                                365            3404 :     return out_list;
                                366                 : }
                                367                 : 
                                368                 : 
                                369                 : /*--------------------
                                370                 :  * The following code attempts to apply the inverse OR distributive law:
                                371                 :  *      ((A AND B) OR (A AND C))  =>  (A AND (B OR C))
                                372                 :  * That is, locate OR clauses in which every subclause contains an
                                373                 :  * identical term, and pull out the duplicated terms.
                                374                 :  *
                                375                 :  * This may seem like a fairly useless activity, but it turns out to be
                                376                 :  * applicable to many machine-generated queries, and there are also queries
                                377                 :  * in some of the TPC benchmarks that need it.  This was in fact almost the
                                378                 :  * sole useful side-effect of the old prepqual code that tried to force
                                379                 :  * the query into canonical AND-of-ORs form: the canonical equivalent of
                                380                 :  *      ((A AND B) OR (A AND C))
                                381                 :  * is
                                382                 :  *      ((A OR A) AND (A OR C) AND (B OR A) AND (B OR C))
                                383                 :  * which the code was able to simplify to
                                384                 :  *      (A AND (A OR C) AND (B OR A) AND (B OR C))
                                385                 :  * thus successfully extracting the common condition A --- but at the cost
                                386                 :  * of cluttering the qual with many redundant clauses.
                                387                 :  *--------------------
                                388                 :  */
                                389                 : 
                                390                 : /*
                                391                 :  * find_duplicate_ors
                                392                 :  *    Given a qualification tree with the NOTs pushed down, search for
                                393                 :  *    OR clauses to which the inverse OR distributive law might apply.
                                394                 :  *    Only the top-level AND/OR structure is searched.
                                395                 :  *
                                396                 :  * While at it, we remove any NULL constants within the top-level AND/OR
                                397                 :  * structure, eg in a WHERE clause, "x OR NULL::boolean" is reduced to "x".
                                398                 :  * In general that would change the result, so eval_const_expressions can't
                                399                 :  * do it; but at top level of WHERE, we don't need to distinguish between
                                400                 :  * FALSE and NULL results, so it's valid to treat NULL::boolean the same
                                401                 :  * as FALSE and then simplify AND/OR accordingly.  Conversely, in a top-level
                                402                 :  * CHECK constraint, we may treat a NULL the same as TRUE.
                                403                 :  *
                                404                 :  * Returns the modified qualification.  AND/OR flatness is preserved.
                                405                 :  */
                                406                 : static Expr *
 1855                           407          253131 : find_duplicate_ors(Expr *qual, bool is_check)
                                408                 : {
 1531                           409          253131 :     if (is_orclause(qual))
                                410                 :     {
 7040                           411            3407 :         List       *orlist = NIL;
                                412                 :         ListCell   *temp;
                                413                 : 
                                414                 :         /* Recurse */
 7423                           415           11644 :         foreach(temp, ((BoolExpr *) qual)->args)
                                416                 :         {
 3267                           417            8240 :             Expr       *arg = (Expr *) lfirst(temp);
                                418                 : 
 1855                           419            8240 :             arg = find_duplicate_ors(arg, is_check);
                                420                 : 
                                421                 :             /* Get rid of any constant inputs */
 3267                           422            8240 :             if (arg && IsA(arg, Const))
                                423                 :             {
                                424               6 :                 Const      *carg = (Const *) arg;
                                425                 : 
 1855                           426               6 :                 if (is_check)
                                427                 :                 {
                                428                 :                     /* Within OR in CHECK, drop constant FALSE */
                                429               3 :                     if (!carg->constisnull && !DatumGetBool(carg->constvalue))
 1855 tgl                       430 UBC           0 :                         continue;
                                431                 :                     /* Constant TRUE or NULL, so OR reduces to TRUE */
 1855 tgl                       432 CBC           3 :                     return (Expr *) makeBoolConst(true, false);
                                433                 :                 }
                                434                 :                 else
                                435                 :                 {
                                436                 :                     /* Within OR in WHERE, drop constant FALSE or NULL */
                                437               3 :                     if (carg->constisnull || !DatumGetBool(carg->constvalue))
                                438               3 :                         continue;
                                439                 :                     /* Constant TRUE, so OR reduces to TRUE */
 1855 tgl                       440 UBC           0 :                     return arg;
                                441                 :                 }
                                442                 :             }
                                443                 : 
 3267 tgl                       444 CBC        8234 :             orlist = lappend(orlist, arg);
                                445                 :         }
                                446                 : 
                                447                 :         /* Flatten any ORs pulled up to just below here */
                                448            3404 :         orlist = pull_ors(orlist);
                                449                 : 
                                450                 :         /* Now we can look for duplicate ORs */
 7040                           451            3404 :         return process_duplicate_ors(orlist);
                                452                 :     }
 1531                           453          249724 :     else if (is_andclause(qual))
                                454                 :     {
 7040                           455           43379 :         List       *andlist = NIL;
                                456                 :         ListCell   *temp;
                                457                 : 
                                458                 :         /* Recurse */
 7423                           459          160779 :         foreach(temp, ((BoolExpr *) qual)->args)
                                460                 :         {
 3267                           461          117400 :             Expr       *arg = (Expr *) lfirst(temp);
                                462                 : 
 1855                           463          117400 :             arg = find_duplicate_ors(arg, is_check);
                                464                 : 
                                465                 :             /* Get rid of any constant inputs */
 3267                           466          117400 :             if (arg && IsA(arg, Const))
                                467                 :             {
 3267 tgl                       468 UBC           0 :                 Const      *carg = (Const *) arg;
                                469                 : 
 1855                           470               0 :                 if (is_check)
                                471                 :                 {
                                472                 :                     /* Within AND in CHECK, drop constant TRUE or NULL */
                                473               0 :                     if (carg->constisnull || DatumGetBool(carg->constvalue))
                                474               0 :                         continue;
                                475                 :                     /* Constant FALSE, so AND reduces to FALSE */
                                476               0 :                     return arg;
                                477                 :                 }
                                478                 :                 else
                                479                 :                 {
                                480                 :                     /* Within AND in WHERE, drop constant TRUE */
                                481               0 :                     if (!carg->constisnull && DatumGetBool(carg->constvalue))
                                482               0 :                         continue;
                                483                 :                     /* Constant FALSE or NULL, so AND reduces to FALSE */
                                484               0 :                     return (Expr *) makeBoolConst(false, false);
                                485                 :                 }
                                486                 :             }
                                487                 : 
 3267 tgl                       488 CBC      117400 :             andlist = lappend(andlist, arg);
                                489                 :         }
                                490                 : 
                                491                 :         /* Flatten any ANDs introduced just below here */
 7040                           492           43379 :         andlist = pull_ands(andlist);
                                493                 : 
                                494                 :         /* AND of no inputs reduces to TRUE */
 3267                           495           43379 :         if (andlist == NIL)
 3267 tgl                       496 UBC           0 :             return (Expr *) makeBoolConst(true, false);
                                497                 : 
                                498                 :         /* Single-expression AND just reduces to that expression */
 3267 tgl                       499 CBC       43379 :         if (list_length(andlist) == 1)
 3267 tgl                       500 UBC           0 :             return (Expr *) linitial(andlist);
                                501                 : 
                                502                 :         /* Else we still need an AND node */
 7040 tgl                       503 CBC       43379 :         return make_andclause(andlist);
                                504                 :     }
                                505                 :     else
 8953 bruce                     506          206345 :         return qual;
                                507                 : }
                                508                 : 
                                509                 : /*
                                510                 :  * process_duplicate_ors
                                511                 :  *    Given a list of exprs which are ORed together, try to apply
                                512                 :  *    the inverse OR distributive law.
                                513                 :  *
                                514                 :  * Returns the resulting expression (could be an AND clause, an OR
                                515                 :  * clause, or maybe even a single subexpression).
                                516                 :  */
                                517                 : static Expr *
 7040 tgl                       518            3404 : process_duplicate_ors(List *orlist)
                                519                 : {
                                520            3404 :     List       *reference = NIL;
                                521            3404 :     int         num_subclauses = 0;
                                522                 :     List       *winners;
                                523                 :     List       *neworlist;
                                524                 :     ListCell   *temp;
                                525                 : 
                                526                 :     /* OR of no inputs reduces to FALSE */
 8610                           527            3404 :     if (orlist == NIL)
 3267 tgl                       528 UBC           0 :         return (Expr *) makeBoolConst(false, false);
                                529                 : 
                                530                 :     /* Single-expression OR just reduces to that expression */
 3267 tgl                       531 CBC        3404 :     if (list_length(orlist) == 1)
                                532               3 :         return (Expr *) linitial(orlist);
                                533                 : 
                                534                 :     /*
                                535                 :      * Choose the shortest AND clause as the reference list --- obviously, any
                                536                 :      * subclause not in this clause isn't in all the clauses. If we find a
                                537                 :      * clause that's not an AND, we can treat it as a one-element AND clause,
                                538                 :      * which necessarily wins as shortest.
                                539                 :      */
 8610                           540            3864 :     foreach(temp, orlist)
                                541                 :     {
 6892 neilc                     542            3723 :         Expr       *clause = (Expr *) lfirst(temp);
                                543                 : 
 1531 tgl                       544            3723 :         if (is_andclause(clause))
                                545                 :         {
 7040                           546             463 :             List       *subclauses = ((BoolExpr *) clause)->args;
 6888 neilc                     547             463 :             int         nclauses = list_length(subclauses);
                                548                 : 
 7040 tgl                       549             463 :             if (reference == NIL || nclauses < num_subclauses)
                                550                 :             {
                                551             320 :                 reference = subclauses;
 8610                           552             320 :                 num_subclauses = nclauses;
                                553                 :             }
                                554                 :         }
                                555                 :         else
                                556                 :         {
 6888 neilc                     557            3260 :             reference = list_make1(clause);
 7040 tgl                       558            3260 :             break;
                                559                 :         }
                                560                 :     }
                                561                 : 
                                562                 :     /*
                                563                 :      * Just in case, eliminate any duplicates in the reference list.
                                564                 :      */
 6888 neilc                     565            3401 :     reference = list_union(NIL, reference);
                                566                 : 
                                567                 :     /*
                                568                 :      * Check each element of the reference list to see if it's in all the OR
                                569                 :      * clauses.  Build a new list of winning clauses.
                                570                 :      */
 7040 tgl                       571            3401 :     winners = NIL;
                                572            6949 :     foreach(temp, reference)
                                573                 :     {
 6892 neilc                     574            3548 :         Expr       *refclause = (Expr *) lfirst(temp);
 7040 tgl                       575            3548 :         bool        win = true;
                                576                 :         ListCell   *temp2;
                                577                 : 
                                578            6904 :         foreach(temp2, orlist)
                                579                 :         {
 6892 neilc                     580            6904 :             Expr       *clause = (Expr *) lfirst(temp2);
                                581                 : 
 1531 tgl                       582            6904 :             if (is_andclause(clause))
                                583                 :             {
 6888 neilc                     584             833 :                 if (!list_member(((BoolExpr *) clause)->args, refclause))
                                585                 :                 {
 7040 tgl                       586             589 :                     win = false;
                                587             589 :                     break;
                                588                 :                 }
                                589                 :             }
                                590                 :             else
                                591                 :             {
                                592            6071 :                 if (!equal(refclause, clause))
                                593                 :                 {
                                594            2959 :                     win = false;
                                595            2959 :                     break;
                                596                 :                 }
                                597                 :             }
                                598                 :         }
                                599                 : 
                                600            3548 :         if (win)
 7040 tgl                       601 UBC           0 :             winners = lappend(winners, refclause);
                                602                 :     }
                                603                 : 
                                604                 :     /*
                                605                 :      * If no winners, we can't transform the OR
                                606                 :      */
 7040 tgl                       607 CBC        3401 :     if (winners == NIL)
                                608            3401 :         return make_orclause(orlist);
                                609                 : 
                                610                 :     /*
                                611                 :      * Generate new OR list consisting of the remaining sub-clauses.
                                612                 :      *
                                613                 :      * If any clause degenerates to empty, then we have a situation like (A
                                614                 :      * AND B) OR (A), which can be reduced to just A --- that is, the
                                615                 :      * additional conditions in other arms of the OR are irrelevant.
                                616                 :      *
                                617                 :      * Note that because we use list_difference, any multiple occurrences of a
                                618                 :      * winning clause in an AND sub-clause will be removed automatically.
                                619                 :      */
 7040 tgl                       620 UBC           0 :     neworlist = NIL;
                                621               0 :     foreach(temp, orlist)
                                622                 :     {
 6892 neilc                     623               0 :         Expr       *clause = (Expr *) lfirst(temp);
                                624                 : 
 1531 tgl                       625               0 :         if (is_andclause(clause))
                                626                 :         {
 7040                           627               0 :             List       *subclauses = ((BoolExpr *) clause)->args;
                                628                 : 
 6888 neilc                     629               0 :             subclauses = list_difference(subclauses, winners);
 7040 tgl                       630               0 :             if (subclauses != NIL)
                                631                 :             {
 6888 neilc                     632               0 :                 if (list_length(subclauses) == 1)
 6892                           633               0 :                     neworlist = lappend(neworlist, linitial(subclauses));
                                634                 :                 else
 7040 tgl                       635               0 :                     neworlist = lappend(neworlist, make_andclause(subclauses));
                                636                 :             }
                                637                 :             else
                                638                 :             {
 6797 bruce                     639               0 :                 neworlist = NIL;    /* degenerate case, see above */
 7040 tgl                       640               0 :                 break;
                                641                 :             }
                                642                 :         }
                                643                 :         else
                                644                 :         {
 6888 neilc                     645               0 :             if (!list_member(winners, clause))
 7040 tgl                       646               0 :                 neworlist = lappend(neworlist, clause);
                                647                 :             else
                                648                 :             {
 6797 bruce                     649               0 :                 neworlist = NIL;    /* degenerate case, see above */
 7040 tgl                       650               0 :                 break;
                                651                 :             }
                                652                 :         }
                                653                 :     }
                                654                 : 
                                655                 :     /*
                                656                 :      * Append reduced OR to the winners list, if it's not degenerate, handling
                                657                 :      * the special case of one element correctly (can that really happen?).
                                658                 :      * Also be careful to maintain AND/OR flatness in case we pulled up a
                                659                 :      * sub-sub-OR-clause.
                                660                 :      */
                                661               0 :     if (neworlist != NIL)
                                662                 :     {
 6888 neilc                     663               0 :         if (list_length(neworlist) == 1)
 6892                           664               0 :             winners = lappend(winners, linitial(neworlist));
                                665                 :         else
 7040 tgl                       666               0 :             winners = lappend(winners, make_orclause(pull_ors(neworlist)));
                                667                 :     }
                                668                 : 
                                669                 :     /*
                                670                 :      * And return the constructed AND clause, again being wary of a single
                                671                 :      * element and AND/OR flatness.
                                672                 :      */
 6888 neilc                     673               0 :     if (list_length(winners) == 1)
 6892                           674               0 :         return (Expr *) linitial(winners);
                                675                 :     else
 7040 tgl                       676               0 :         return make_andclause(pull_ands(winners));
                                677                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a