Skip to content

Commit 5590be0

Browse files
committed
Preserve AND/OR flatness during eval_const_expressions(). This seems a
useful improvement in any case, and it keeps the new logic for restrictinfo structures happy. Per report from Kris Jurka.
1 parent 1c15812 commit 5590be0

File tree

1 file changed

+154
-84
lines changed

1 file changed

+154
-84
lines changed

src/backend/optimizer/util/clauses.c

Lines changed: 154 additions & 84 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.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
* AUTHOR DATE MAJOR EVENT
@@ -61,6 +61,10 @@ static bool contain_mutable_functions_walker(Node *node, void *context);
6161
static bool contain_volatile_functions_walker(Node *node, void *context);
6262
static bool contain_nonstrict_functions_walker(Node *node, void *context);
6363
static 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);
6468
static Expr *simplify_function(Oid funcid, Oid result_type, List *args,
6569
bool allow_inline, List *active_fns);
6670
static 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
*/
253260
Node *
254261
make_and_qual(Node *qual1, Node *qual2)
@@ -1210,7 +1217,6 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
12101217
{
12111218
BoolExpr *expr = (BoolExpr *) node;
12121219
List *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
{
12261232
case 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;
12401235
bool haveNull = false;
12411236
bool 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);
12661240
if (forceTrue)
12671241
return MAKEBOOLCONST(true, false);
12681242
if (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)
12721246
return 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
}
12791253
case 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;
12931256
bool haveNull = false;
12941257
bool 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);
13191261
if (forceFalse)
13201262
return MAKEBOOLCONST(false, false);
13211263
if (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)
13251267
return 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
}
13321274
case NOT_EXPR:
13331275
Assert(length(args) == 1);
13341276
if (IsA(lfirst(args), Const))
13351277
{
1336-
const_input = (Const *) lfirst(args);
1278+
Const *const_input = (Const *) lfirst(args);
1279+
13371280
/* NOT NULL => NULL */
13381281
if (const_input->constisnull)
13391282
return MAKEBOOLCONST(false, true);
13401283
/* otherwise pretty easy */
13411284
return 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));
13461294
default:
13471295
elog(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)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy