8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
* HISTORY
14
14
* AUTHOR DATE MAJOR EVENT
@@ -61,6 +61,10 @@ static bool contain_mutable_functions_walker(Node *node, void *context);
61
61
static bool contain_volatile_functions_walker (Node * node , void * context );
62
62
static bool contain_nonstrict_functions_walker (Node * node , void * context );
63
63
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 );
64
68
static Expr * simplify_function (Oid funcid , Oid result_type , List * args ,
65
69
bool allow_inline , List * active_fns );
66
70
static Expr * evaluate_function (Oid funcid , Oid result_type , List * args ,
@@ -249,6 +253,9 @@ make_andclause(List *andclauses)
249
253
* Variant of make_andclause for ANDing two qual conditions together.
250
254
* Qual conditions have the property that a NULL nodetree is interpreted
251
255
* 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.
252
259
*/
253
260
Node *
254
261
make_and_qual (Node * qual1 , Node * qual2 )
@@ -1210,7 +1217,6 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
1210
1217
{
1211
1218
BoolExpr * expr = (BoolExpr * ) node ;
1212
1219
List * args ;
1213
- Const * const_input ;
1214
1220
1215
1221
/*
1216
1222
* Reduce constants in the BoolExpr's arguments. We know args is
@@ -1225,124 +1231,66 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
1225
1231
{
1226
1232
case OR_EXPR :
1227
1233
{
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 ;
1240
1235
bool haveNull = false;
1241
1236
bool forceTrue = false;
1242
1237
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 );
1266
1240
if (forceTrue )
1267
1241
return MAKEBOOLCONST (true, false);
1268
1242
if (haveNull )
1269
- FastAppend ( & newargs , MAKEBOOLCONST (false, true));
1243
+ newargs = lappend ( newargs , MAKEBOOLCONST (false, true));
1270
1244
/* If all the inputs are FALSE, result is FALSE */
1271
- if (FastListValue ( & newargs ) == NIL )
1245
+ if (newargs == NIL )
1272
1246
return MAKEBOOLCONST (false, false);
1273
1247
/* 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 );
1276
1250
/* Else we still need an OR node */
1277
- return (Node * ) make_orclause (FastListValue ( & newargs ) );
1251
+ return (Node * ) make_orclause (newargs );
1278
1252
}
1279
1253
case AND_EXPR :
1280
1254
{
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 ;
1293
1256
bool haveNull = false;
1294
1257
bool forceFalse = false;
1295
1258
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 );
1319
1261
if (forceFalse )
1320
1262
return MAKEBOOLCONST (false, false);
1321
1263
if (haveNull )
1322
- FastAppend ( & newargs , MAKEBOOLCONST (false, true));
1264
+ newargs = lappend ( newargs , MAKEBOOLCONST (false, true));
1323
1265
/* If all the inputs are TRUE, result is TRUE */
1324
- if (FastListValue ( & newargs ) == NIL )
1266
+ if (newargs == NIL )
1325
1267
return MAKEBOOLCONST (true, false);
1326
1268
/* 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 );
1329
1271
/* Else we still need an AND node */
1330
- return (Node * ) make_andclause (FastListValue ( & newargs ) );
1272
+ return (Node * ) make_andclause (newargs );
1331
1273
}
1332
1274
case NOT_EXPR :
1333
1275
Assert (length (args ) == 1 );
1334
1276
if (IsA (lfirst (args ), Const ))
1335
1277
{
1336
- const_input = (Const * ) lfirst (args );
1278
+ Const * const_input = (Const * ) lfirst (args );
1279
+
1337
1280
/* NOT NULL => NULL */
1338
1281
if (const_input -> constisnull )
1339
1282
return MAKEBOOLCONST (false, true);
1340
1283
/* otherwise pretty easy */
1341
1284
return MAKEBOOLCONST (!DatumGetBool (const_input -> constvalue ),
1342
1285
false);
1343
1286
}
1287
+ else if (not_clause ((Node * ) lfirst (args )))
1288
+ {
1289
+ /* Cancel NOT/NOT */
1290
+ return (Node * ) get_notclausearg ((Expr * ) lfirst (args ));
1291
+ }
1344
1292
/* Else we still need a NOT node */
1345
- return (Node * ) make_notclause (lfirst (args ));
1293
+ return (Node * ) make_notclause (( Expr * ) lfirst (args ));
1346
1294
default :
1347
1295
elog (ERROR , "unrecognized boolop: %d" ,
1348
1296
(int ) expr -> boolop );
@@ -1579,6 +1527,128 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
1579
1527
(void * ) active_fns );
1580
1528
}
1581
1529
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
+
1582
1652
/*
1583
1653
* Subroutine for eval_const_expressions: try to simplify a function call
1584
1654
* (which might originally have been an operator; we don't care)
0 commit comments