88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.161 2004/01/10 18:13:53 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.162 2004/01/12 20:48:15 tgl Exp $
1212 *
1313 * HISTORY
1414 * AUTHORDATEMAJOR EVENT
@@ -61,6 +61,10 @@ static bool contain_mutable_functions_walker(Node *node, void *context);
6161static bool contain_volatile_functions_walker (Node * node ,void * context );
6262static bool contain_nonstrict_functions_walker (Node * node ,void * context );
6363static Node * eval_const_expressions_mutator (Node * node ,List * active_fns );
64+ static List * simplify_or_arguments (List * args ,
65+ bool * haveNull ,bool * forceTrue );
66+ static List * simplify_and_arguments (List * args ,
67+ bool * haveNull ,bool * forceFalse );
6468static Expr * simplify_function (Oid funcid ,Oid result_type ,List * args ,
6569bool allow_inline ,List * active_fns );
6670static Expr * evaluate_function (Oid funcid ,Oid result_type ,List * args ,
@@ -249,6 +253,9 @@ make_andclause(List *andclauses)
249253 * Variant of make_andclause for ANDing two qual conditions together.
250254 * Qual conditions have the property that a NULL nodetree is interpreted
251255 * as 'true'.
256+ *
257+ * NB: this makes no attempt to preserve AND/OR flatness; so it should not
258+ * be used on a qual that has already been run through prepqual.c.
252259 */
253260Node *
254261make_and_qual (Node * qual1 ,Node * qual2 )
@@ -1210,7 +1217,6 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
12101217{
12111218BoolExpr * expr = (BoolExpr * )node ;
12121219List * args ;
1213- Const * const_input ;
12141220
12151221/*
12161222 * Reduce constants in the BoolExpr's arguments. We know args is
@@ -1225,124 +1231,66 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
12251231{
12261232case OR_EXPR :
12271233{
1228- /*----------
1229- * OR arguments are handled as follows:
1230- *non constant: keep
1231- *FALSE: drop (does not affect result)
1232- *TRUE: force result to TRUE
1233- *NULL: keep only one
1234- * We keep one NULL input because ExecEvalOr returns NULL
1235- * when no input is TRUE and at least one is NULL.
1236- *----------
1237- */
1238- FastList newargs ;
1239- List * arg ;
1234+ List * newargs ;
12401235bool haveNull = false;
12411236bool forceTrue = false;
12421237
1243- FastListInit (& newargs );
1244- foreach (arg ,args )
1245- {
1246- if (!IsA (lfirst (arg ),Const ))
1247- {
1248- FastAppend (& newargs ,lfirst (arg ));
1249- continue ;
1250- }
1251- const_input = (Const * )lfirst (arg );
1252- if (const_input -> constisnull )
1253- haveNull = true;
1254- else if (DatumGetBool (const_input -> constvalue ))
1255- forceTrue = true;
1256- /* otherwise, we can drop the constant-false input */
1257- }
1258-
1259- /*
1260- * We could return TRUE before falling out of the
1261- * loop, but this coding method will be easier to
1262- * adapt if we ever add a notion of non-removable
1263- * functions. We'd need to check all the inputs for
1264- * non-removability.
1265- */
1238+ newargs = simplify_or_arguments (args ,
1239+ & haveNull ,& forceTrue );
12661240if (forceTrue )
12671241return MAKEBOOLCONST (true, false);
12681242if (haveNull )
1269- FastAppend ( & newargs ,MAKEBOOLCONST (false, true));
1243+ newargs = lappend ( newargs ,MAKEBOOLCONST (false, true));
12701244/* If all the inputs are FALSE, result is FALSE */
1271- if (FastListValue ( & newargs ) == NIL )
1245+ if (newargs == NIL )
12721246return MAKEBOOLCONST (false, false);
12731247/* If only one nonconst-or-NULL input, it's the result */
1274- if (lnext (FastListValue ( & newargs ) )== NIL )
1275- return (Node * )lfirst (FastListValue ( & newargs ) );
1248+ if (lnext (newargs )== NIL )
1249+ return (Node * )lfirst (newargs );
12761250/* Else we still need an OR node */
1277- return (Node * )make_orclause (FastListValue ( & newargs ) );
1251+ return (Node * )make_orclause (newargs );
12781252}
12791253case AND_EXPR :
12801254{
1281- /*----------
1282- * AND arguments are handled as follows:
1283- *non constant: keep
1284- *TRUE: drop (does not affect result)
1285- *FALSE: force result to FALSE
1286- *NULL: keep only one
1287- * We keep one NULL input because ExecEvalAnd returns NULL
1288- * when no input is FALSE and at least one is NULL.
1289- *----------
1290- */
1291- FastList newargs ;
1292- List * arg ;
1255+ List * newargs ;
12931256bool haveNull = false;
12941257bool forceFalse = false;
12951258
1296- FastListInit (& newargs );
1297- foreach (arg ,args )
1298- {
1299- if (!IsA (lfirst (arg ),Const ))
1300- {
1301- FastAppend (& newargs ,lfirst (arg ));
1302- continue ;
1303- }
1304- const_input = (Const * )lfirst (arg );
1305- if (const_input -> constisnull )
1306- haveNull = true;
1307- else if (!DatumGetBool (const_input -> constvalue ))
1308- forceFalse = true;
1309- /* otherwise, we can drop the constant-true input */
1310- }
1311-
1312- /*
1313- * We could return FALSE before falling out of the
1314- * loop, but this coding method will be easier to
1315- * adapt if we ever add a notion of non-removable
1316- * functions. We'd need to check all the inputs for
1317- * non-removability.
1318- */
1259+ newargs = simplify_and_arguments (args ,
1260+ & haveNull ,& forceFalse );
13191261if (forceFalse )
13201262return MAKEBOOLCONST (false, false);
13211263if (haveNull )
1322- FastAppend ( & newargs ,MAKEBOOLCONST (false, true));
1264+ newargs = lappend ( newargs ,MAKEBOOLCONST (false, true));
13231265/* If all the inputs are TRUE, result is TRUE */
1324- if (FastListValue ( & newargs ) == NIL )
1266+ if (newargs == NIL )
13251267return MAKEBOOLCONST (true, false);
13261268/* If only one nonconst-or-NULL input, it's the result */
1327- if (lnext (FastListValue ( & newargs ) )== NIL )
1328- return (Node * )lfirst (FastListValue ( & newargs ) );
1269+ if (lnext (newargs )== NIL )
1270+ return (Node * )lfirst (newargs );
13291271/* Else we still need an AND node */
1330- return (Node * )make_andclause (FastListValue ( & newargs ) );
1272+ return (Node * )make_andclause (newargs );
13311273}
13321274case NOT_EXPR :
13331275Assert (length (args )== 1 );
13341276if (IsA (lfirst (args ),Const ))
13351277{
1336- const_input = (Const * )lfirst (args );
1278+ Const * const_input = (Const * )lfirst (args );
1279+
13371280/* NOT NULL => NULL */
13381281if (const_input -> constisnull )
13391282return MAKEBOOLCONST (false, true);
13401283/* otherwise pretty easy */
13411284return MAKEBOOLCONST (!DatumGetBool (const_input -> constvalue ),
13421285 false);
13431286}
1287+ else if (not_clause ((Node * )lfirst (args )))
1288+ {
1289+ /* Cancel NOT/NOT */
1290+ return (Node * )get_notclausearg ((Expr * )lfirst (args ));
1291+ }
13441292/* Else we still need a NOT node */
1345- return (Node * )make_notclause (lfirst (args ));
1293+ return (Node * )make_notclause (( Expr * ) lfirst (args ));
13461294default :
13471295elog (ERROR ,"unrecognized boolop: %d" ,
13481296 (int )expr -> boolop );
@@ -1579,6 +1527,128 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
15791527 (void * )active_fns );
15801528}
15811529
1530+ /*
1531+ * Subroutine for eval_const_expressions: scan the arguments of an OR clause
1532+ *
1533+ * OR arguments are handled as follows:
1534+ *non constant: keep
1535+ *FALSE: drop (does not affect result)
1536+ *TRUE: force result to TRUE
1537+ *NULL: keep only one
1538+ * We must keep one NULL input because ExecEvalOr returns NULL when no input
1539+ * is TRUE and at least one is NULL.
1540+ *
1541+ * This is split out as a subroutine so that we can recurse to fold sub-ORs
1542+ * into the upper OR clause, thereby preserving AND/OR flatness.
1543+ *
1544+ * The output arguments *haveNull and *forceTrue must be initialized FALSE
1545+ * by the caller. They will be set TRUE if a null constant or true constant,
1546+ * respectively, is detected anywhere in the argument list.
1547+ */
1548+ static List *
1549+ simplify_or_arguments (List * args ,bool * haveNull ,bool * forceTrue )
1550+ {
1551+ List * newargs = NIL ;
1552+ List * larg ;
1553+
1554+ foreach (larg ,args )
1555+ {
1556+ Node * arg = (Node * )lfirst (larg );
1557+
1558+ if (IsA (arg ,Const ))
1559+ {
1560+ Const * const_input = (Const * )arg ;
1561+
1562+ if (const_input -> constisnull )
1563+ * haveNull = true;
1564+ else if (DatumGetBool (const_input -> constvalue ))
1565+ {
1566+ * forceTrue = true;
1567+ /*
1568+ * Once we detect a TRUE result we can just exit the loop
1569+ * immediately. However, if we ever add a notion of
1570+ * non-removable functions, we'd need to keep scanning.
1571+ */
1572+ return NIL ;
1573+ }
1574+ /* otherwise, we can drop the constant-false input */
1575+ }
1576+ else if (or_clause (arg ))
1577+ {
1578+ newargs = nconc (newargs ,
1579+ simplify_or_arguments (((BoolExpr * )arg )-> args ,
1580+ haveNull ,forceTrue ));
1581+ }
1582+ else
1583+ {
1584+ newargs = lappend (newargs ,arg );
1585+ }
1586+ }
1587+
1588+ return newargs ;
1589+ }
1590+
1591+ /*
1592+ * Subroutine for eval_const_expressions: scan the arguments of an AND clause
1593+ *
1594+ * AND arguments are handled as follows:
1595+ *non constant: keep
1596+ *TRUE: drop (does not affect result)
1597+ *FALSE: force result to FALSE
1598+ *NULL: keep only one
1599+ * We must keep one NULL input because ExecEvalAnd returns NULL when no input
1600+ * is FALSE and at least one is NULL.
1601+ *
1602+ * This is split out as a subroutine so that we can recurse to fold sub-ANDs
1603+ * into the upper AND clause, thereby preserving AND/OR flatness.
1604+ *
1605+ * The output arguments *haveNull and *forceFalse must be initialized FALSE
1606+ * by the caller. They will be set TRUE if a null constant or false constant,
1607+ * respectively, is detected anywhere in the argument list.
1608+ */
1609+ static List *
1610+ simplify_and_arguments (List * args ,bool * haveNull ,bool * forceFalse )
1611+ {
1612+ List * newargs = NIL ;
1613+ List * larg ;
1614+
1615+ foreach (larg ,args )
1616+ {
1617+ Node * arg = (Node * )lfirst (larg );
1618+
1619+ if (IsA (arg ,Const ))
1620+ {
1621+ Const * const_input = (Const * )arg ;
1622+
1623+ if (const_input -> constisnull )
1624+ * haveNull = true;
1625+ else if (!DatumGetBool (const_input -> constvalue ))
1626+ {
1627+ * forceFalse = true;
1628+ /*
1629+ * Once we detect a FALSE result we can just exit the loop
1630+ * immediately. However, if we ever add a notion of
1631+ * non-removable functions, we'd need to keep scanning.
1632+ */
1633+ return NIL ;
1634+ }
1635+ /* otherwise, we can drop the constant-true input */
1636+ }
1637+ else if (and_clause (arg ))
1638+ {
1639+ newargs = nconc (newargs ,
1640+ simplify_and_arguments (((BoolExpr * )arg )-> args ,
1641+ haveNull ,forceFalse ));
1642+ }
1643+ else
1644+ {
1645+ newargs = lappend (newargs ,arg );
1646+ }
1647+ }
1648+
1649+ return newargs ;
1650+ }
1651+
15821652/*
15831653 * Subroutine for eval_const_expressions: try to simplify a function call
15841654 * (which might originally have been an operator; we don't care)