88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.195 2005/04/14 21:44:09 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.196 2005/04/23 04:42:53 tgl Exp $
1212 *
1313 * HISTORY
1414 * AUTHOR DATE MAJOR EVENT
@@ -73,8 +73,10 @@ static bool set_coercionform_dontcare_walker(Node *node, void *context);
7373static Node * eval_const_expressions_mutator (Node * node ,
7474 eval_const_expressions_context * context );
7575static List * simplify_or_arguments (List * args ,
76+ eval_const_expressions_context * context ,
7677 bool * haveNull , bool * forceTrue );
7778static List * simplify_and_arguments (List * args ,
79+ eval_const_expressions_context * context ,
7880 bool * haveNull , bool * forceFalse );
7981static Expr * simplify_boolean_equality (List * args );
8082static Expr * simplify_function (Oid funcid , Oid result_type , List * args ,
@@ -1466,16 +1468,6 @@ eval_const_expressions_mutator(Node *node,
14661468 if (IsA (node , BoolExpr ))
14671469 {
14681470 BoolExpr * expr = (BoolExpr * ) node ;
1469- List * args ;
1470-
1471- /*
1472- * Reduce constants in the BoolExpr's arguments. We know args is
1473- * either NIL or a List node, so we can call
1474- * expression_tree_mutator directly rather than recursing to self.
1475- */
1476- args = (List * ) expression_tree_mutator ((Node * ) expr -> args ,
1477- eval_const_expressions_mutator ,
1478- (void * ) context );
14791471
14801472 switch (expr -> boolop )
14811473 {
@@ -1485,7 +1477,7 @@ eval_const_expressions_mutator(Node *node,
14851477 bool haveNull = false;
14861478 bool forceTrue = false;
14871479
1488- newargs = simplify_or_arguments (args ,
1480+ newargs = simplify_or_arguments (expr -> args , context ,
14891481 & haveNull , & forceTrue );
14901482 if (forceTrue )
14911483 return makeBoolConst (true, false);
@@ -1506,7 +1498,7 @@ eval_const_expressions_mutator(Node *node,
15061498 bool haveNull = false;
15071499 bool forceFalse = false;
15081500
1509- newargs = simplify_and_arguments (args ,
1501+ newargs = simplify_and_arguments (expr -> args , context ,
15101502 & haveNull , & forceFalse );
15111503 if (forceFalse )
15121504 return makeBoolConst (false, false);
@@ -1522,25 +1514,31 @@ eval_const_expressions_mutator(Node *node,
15221514 return (Node * ) make_andclause (newargs );
15231515 }
15241516 case NOT_EXPR :
1525- Assert (list_length (args ) == 1 );
1526- if (IsA (linitial (args ), Const ))
1527- {
1528- Const * const_input = (Const * ) linitial (args );
1529-
1530- /* NOT NULL => NULL */
1531- if (const_input -> constisnull )
1532- return makeBoolConst (false, true);
1533- /* otherwise pretty easy */
1534- return makeBoolConst (!DatumGetBool (const_input -> constvalue ),
1535- false);
1536- }
1537- else if (not_clause ((Node * ) linitial (args )))
15381517 {
1539- /* Cancel NOT/NOT */
1540- return (Node * ) get_notclausearg ((Expr * ) linitial (args ));
1518+ Node * arg ;
1519+
1520+ Assert (list_length (expr -> args ) == 1 );
1521+ arg = eval_const_expressions_mutator (linitial (expr -> args ),
1522+ context );
1523+ if (IsA (arg , Const ))
1524+ {
1525+ Const * const_input = (Const * ) arg ;
1526+
1527+ /* NOT NULL => NULL */
1528+ if (const_input -> constisnull )
1529+ return makeBoolConst (false, true);
1530+ /* otherwise pretty easy */
1531+ return makeBoolConst (!DatumGetBool (const_input -> constvalue ),
1532+ false);
1533+ }
1534+ else if (not_clause (arg ))
1535+ {
1536+ /* Cancel NOT/NOT */
1537+ return (Node * ) get_notclausearg ((Expr * ) arg );
1538+ }
1539+ /* Else we still need a NOT node */
1540+ return (Node * ) make_notclause ((Expr * ) arg );
15411541 }
1542- /* Else we still need a NOT node */
1543- return (Node * ) make_notclause ((Expr * ) linitial (args ));
15441542 default :
15451543 elog (ERROR , "unrecognized boolop: %d" ,
15461544 (int ) expr -> boolop );
@@ -1869,33 +1867,87 @@ eval_const_expressions_mutator(Node *node,
18691867}
18701868
18711869/*
1872- * Subroutine for eval_const_expressions: scan the arguments of an OR clause
1870+ * Subroutine for eval_const_expressions: process arguments of an OR clause
1871+ *
1872+ * This includes flattening of nested ORs as well as recursion to
1873+ * eval_const_expressions to simplify the OR arguments.
18731874 *
1874- * OR arguments are handled as follows:
1875+ * After simplification, OR arguments are handled as follows:
18751876 * non constant: keep
18761877 * FALSE: drop (does not affect result)
18771878 * TRUE: force result to TRUE
18781879 * NULL: keep only one
18791880 * We must keep one NULL input because ExecEvalOr returns NULL when no input
1880- * is TRUE and at least one is NULL.
1881- *
1882- * This is split out as a subroutine so that we can recurse to fold sub-ORs
1883- * into the upper OR clause, thereby ensuring that nested ORs are flattened.
1881+ * is TRUE and at least one is NULL. We don't actually include the NULL
1882+ * here, that's supposed to be done by the caller.
18841883 *
18851884 * The output arguments *haveNull and *forceTrue must be initialized FALSE
18861885 * by the caller. They will be set TRUE if a null constant or true constant,
18871886 * respectively, is detected anywhere in the argument list.
18881887 */
18891888static List *
1890- simplify_or_arguments (List * args , bool * haveNull , bool * forceTrue )
1889+ simplify_or_arguments (List * args ,
1890+ eval_const_expressions_context * context ,
1891+ bool * haveNull , bool * forceTrue )
18911892{
18921893 List * newargs = NIL ;
1893- ListCell * larg ;
1894+ List * unprocessed_args ;
18941895
1895- foreach (larg , args )
1896+ /*
1897+ * Since the parser considers OR to be a binary operator, long OR lists
1898+ * become deeply nested expressions. We must flatten these into long
1899+ * argument lists of a single OR operator. To avoid blowing out the stack
1900+ * with recursion of eval_const_expressions, we resort to some tenseness
1901+ * here: we keep a list of not-yet-processed inputs, and handle flattening
1902+ * of nested ORs by prepending to the to-do list instead of recursing.
1903+ */
1904+ unprocessed_args = list_copy (args );
1905+ while (unprocessed_args )
18961906 {
1897- Node * arg = (Node * ) lfirst (larg );
1907+ Node * arg = (Node * ) linitial (unprocessed_args );
1908+
1909+ unprocessed_args = list_delete_first (unprocessed_args );
1910+
1911+ /* flatten nested ORs as per above comment */
1912+ if (or_clause (arg ))
1913+ {
1914+ List * subargs = list_copy (((BoolExpr * ) arg )-> args );
1915+
1916+ /* overly tense code to avoid leaking unused list header */
1917+ if (!unprocessed_args )
1918+ unprocessed_args = subargs ;
1919+ else
1920+ {
1921+ List * oldhdr = unprocessed_args ;
1922+
1923+ unprocessed_args = list_concat (subargs , unprocessed_args );
1924+ pfree (oldhdr );
1925+ }
1926+ continue ;
1927+ }
1928+
1929+ /* If it's not an OR, simplify it */
1930+ arg = eval_const_expressions_mutator (arg , context );
1931+
1932+ /*
1933+ * It is unlikely but not impossible for simplification of a
1934+ * non-OR clause to produce an OR. Recheck, but don't be
1935+ * too tense about it since it's not a mainstream case.
1936+ * In particular we don't worry about const-simplifying
1937+ * the input twice.
1938+ */
1939+ if (or_clause (arg ))
1940+ {
1941+ List * subargs = list_copy (((BoolExpr * ) arg )-> args );
1942+
1943+ unprocessed_args = list_concat (subargs , unprocessed_args );
1944+ continue ;
1945+ }
18981946
1947+ /*
1948+ * OK, we have a const-simplified non-OR argument. Process it
1949+ * per comments above.
1950+ */
18991951 if (IsA (arg , Const ))
19001952 {
19011953 Const * const_input = (Const * ) arg ;
@@ -1914,48 +1966,91 @@ simplify_or_arguments(List *args, bool *haveNull, bool *forceTrue)
19141966 return NIL ;
19151967 }
19161968 /* otherwise, we can drop the constant-false input */
1969+ continue ;
19171970 }
1918- else if (or_clause (arg ))
1919- {
1920- newargs = list_concat (newargs ,
1921- simplify_or_arguments (((BoolExpr * ) arg )-> args ,
1922- haveNull , forceTrue ));
1923- }
1924- else
1925- newargs = lappend (newargs , arg );
1971+
1972+ /* else emit the simplified arg into the result list */
1973+ newargs = lappend (newargs , arg );
19261974 }
19271975
19281976 return newargs ;
19291977}
19301978
19311979/*
1932- * Subroutine for eval_const_expressions: scan the arguments of an AND clause
1980+ * Subroutine for eval_const_expressions: process arguments of an AND clause
19331981 *
1934- * AND arguments are handled as follows:
1982+ * This includes flattening of nested ANDs as well as recursion to
1983+ * eval_const_expressions to simplify the AND arguments.
1984+ *
1985+ * After simplification, AND arguments are handled as follows:
19351986 * non constant: keep
19361987 * TRUE: drop (does not affect result)
19371988 * FALSE: force result to FALSE
19381989 * NULL: keep only one
19391990 * We must keep one NULL input because ExecEvalAnd returns NULL when no input
1940- * is FALSE and at least one is NULL.
1941- *
1942- * This is split out as a subroutine so that we can recurse to fold sub-ANDs
1943- * into the upper AND clause, thereby ensuring that nested ANDs are flattened.
1991+ * is FALSE and at least one is NULL. We don't actually include the NULL
1992+ * here, that's supposed to be done by the caller.
19441993 *
19451994 * The output arguments *haveNull and *forceFalse must be initialized FALSE
19461995 * by the caller. They will be set TRUE if a null constant or false constant,
19471996 * respectively, is detected anywhere in the argument list.
19481997 */
19491998static List *
1950- simplify_and_arguments (List * args , bool * haveNull , bool * forceFalse )
1999+ simplify_and_arguments (List * args ,
2000+ eval_const_expressions_context * context ,
2001+ bool * haveNull , bool * forceFalse )
19512002{
19522003 List * newargs = NIL ;
1953- ListCell * larg ;
2004+ List * unprocessed_args ;
19542005
1955- foreach (larg , args )
2006+ /* See comments in simplify_or_arguments */
2007+ unprocessed_args = list_copy (args );
2008+ while (unprocessed_args )
19562009 {
1957- Node * arg = (Node * ) lfirst (larg );
2010+ Node * arg = (Node * ) linitial (unprocessed_args );
2011+
2012+ unprocessed_args = list_delete_first (unprocessed_args );
2013+
2014+ /* flatten nested ANDs as per above comment */
2015+ if (and_clause (arg ))
2016+ {
2017+ List * subargs = list_copy (((BoolExpr * ) arg )-> args );
2018+
2019+ /* overly tense code to avoid leaking unused list header */
2020+ if (!unprocessed_args )
2021+ unprocessed_args = subargs ;
2022+ else
2023+ {
2024+ List * oldhdr = unprocessed_args ;
2025+
2026+ unprocessed_args = list_concat (subargs , unprocessed_args );
2027+ pfree (oldhdr );
2028+ }
2029+ continue ;
2030+ }
2031+
2032+ /* If it's not an AND, simplify it */
2033+ arg = eval_const_expressions_mutator (arg , context );
2034+
2035+ /*
2036+ * It is unlikely but not impossible for simplification of a
2037+ * non-AND clause to produce an AND. Recheck, but don't be
2038+ * too tense about it since it's not a mainstream case.
2039+ * In particular we don't worry about const-simplifying
2040+ * the input twice.
2041+ */
2042+ if (and_clause (arg ))
2043+ {
2044+ List * subargs = list_copy (((BoolExpr * ) arg )-> args );
19582045
2046+ unprocessed_args = list_concat (subargs , unprocessed_args );
2047+ continue ;
2048+ }
2049+
2050+ /*
2051+ * OK, we have a const-simplified non-AND argument. Process it
2052+ * per comments above.
2053+ */
19592054 if (IsA (arg , Const ))
19602055 {
19612056 Const * const_input = (Const * ) arg ;
@@ -1974,15 +2069,11 @@ simplify_and_arguments(List *args, bool *haveNull, bool *forceFalse)
19742069 return NIL ;
19752070 }
19762071 /* otherwise, we can drop the constant-true input */
2072+ continue ;
19772073 }
1978- else if (and_clause (arg ))
1979- {
1980- newargs = list_concat (newargs ,
1981- simplify_and_arguments (((BoolExpr * ) arg )-> args ,
1982- haveNull , forceFalse ));
1983- }
1984- else
1985- newargs = lappend (newargs , arg );
2074+
2075+ /* else emit the simplified arg into the result list */
2076+ newargs = lappend (newargs , arg );
19862077 }
19872078
19882079 return newargs ;
0 commit comments