Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit56c8877

Browse files
committed
Turns out that my recent elimination of the 'redundant' flatten_andors()
code in prepqual.c had a small drawback: the flatten_andors code wasable to cope with deeply nested AND/OR structures (like 10000 ORs ina row), whereas eval_const_expressions tends to recurse until itoverruns the stack. Revise eval_const_expressions so that it doesn'tchoke on deeply nested ANDs or ORs.
1 parent25434e3 commit56c8877

File tree

1 file changed

+157
-66
lines changed

1 file changed

+157
-66
lines changed

‎src/backend/optimizer/util/clauses.c

Lines changed: 157 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
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
* AUTHORDATEMAJOR EVENT
@@ -73,8 +73,10 @@ static bool set_coercionform_dontcare_walker(Node *node, void *context);
7373
staticNode*eval_const_expressions_mutator(Node*node,
7474
eval_const_expressions_context*context);
7575
staticList*simplify_or_arguments(List*args,
76+
eval_const_expressions_context*context,
7677
bool*haveNull,bool*forceTrue);
7778
staticList*simplify_and_arguments(List*args,
79+
eval_const_expressions_context*context,
7880
bool*haveNull,bool*forceFalse);
7981
staticExpr*simplify_boolean_equality(List*args);
8082
staticExpr*simplify_function(Oidfuncid,Oidresult_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
boolhaveNull= false;
14861478
boolforceTrue= false;
14871479

1488-
newargs=simplify_or_arguments(args,
1480+
newargs=simplify_or_arguments(expr->args,context,
14891481
&haveNull,&forceTrue);
14901482
if (forceTrue)
14911483
returnmakeBoolConst(true, false);
@@ -1506,7 +1498,7 @@ eval_const_expressions_mutator(Node *node,
15061498
boolhaveNull= false;
15071499
boolforceFalse= false;
15081500

1509-
newargs=simplify_and_arguments(args,
1501+
newargs=simplify_and_arguments(expr->args,context,
15101502
&haveNull,&forceFalse);
15111503
if (forceFalse)
15121504
returnmakeBoolConst(false, false);
@@ -1522,25 +1514,31 @@ eval_const_expressions_mutator(Node *node,
15221514
return (Node*)make_andclause(newargs);
15231515
}
15241516
caseNOT_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-
returnmakeBoolConst(false, true);
1533-
/* otherwise pretty easy */
1534-
returnmakeBoolConst(!DatumGetBool(const_input->constvalue),
1535-
false);
1536-
}
1537-
elseif (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+
returnmakeBoolConst(false, true);
1530+
/* otherwise pretty easy */
1531+
returnmakeBoolConst(!DatumGetBool(const_input->constvalue),
1532+
false);
1533+
}
1534+
elseif (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
*/
18891888
staticList*
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
returnNIL;
19151967
}
19161968
/* otherwise, we can drop the constant-false input */
1969+
continue;
19171970
}
1918-
elseif (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
returnnewargs;
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
*/
19491998
staticList*
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
returnNIL;
19752070
}
19762071
/* otherwise, we can drop the constant-true input */
2072+
continue;
19772073
}
1978-
elseif (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
returnnewargs;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp