Skip to content

Commit 40f6524

Browse files
committed
Implement constant-expression simplification per Bernard
Frankpitt, plus some improvements from yours truly. The simplifier depends on the proiscachable field of pg_proc to tell it whether a function is safe to pre-evaluate --- things like nextval() are not, for example. Update pg_proc.h to contain reasonable cacheability information; as of 6.5.* hardly any functions were marked cacheable. I may have erred too far in the other direction; see recent mail to pghackers for more info. This update does not force an initdb, exactly, but you won't see much benefit from the simplifier until you do one.
1 parent 95d3d46 commit 40f6524

File tree

7 files changed

+1358
-937
lines changed

7 files changed

+1358
-937
lines changed

src/backend/executor/execQual.c

Lines changed: 67 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.60 1999/09/24 00:24:23 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.61 1999/09/26 02:28:15 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -956,8 +956,8 @@ ExecEvalFunc(Expr *funcClause,
956956
static Datum
957957
ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull)
958958
{
959-
Datum expr_value;
960959
Node *clause;
960+
Datum expr_value;
961961
bool isDone;
962962

963963
clause = lfirst(notclause->args);
@@ -995,67 +995,47 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
995995
List *clauses;
996996
List *clause;
997997
bool isDone;
998-
bool IsNull;
999-
Datum const_value = 0;
998+
bool AnyNull;
999+
Datum clause_value;
10001000

1001-
IsNull = false;
10021001
clauses = orExpr->args;
1002+
AnyNull = false;
10031003

10041004
/*
1005-
* we use three valued logic functions here... we evaluate each of the
1006-
* clauses in turn, as soon as one is true we return that value. If
1007-
* none is true and none of the clauses evaluate to NULL we return
1008-
* the value of the last clause evaluated (which should be false) with
1009-
* *isNull set to false else if none is true and at least one clause
1010-
* evaluated to NULL we set *isNull flag to true -
1005+
* If any of the clauses is TRUE, the OR result is TRUE regardless
1006+
* of the states of the rest of the clauses, so we can stop evaluating
1007+
* and return TRUE immediately. If none are TRUE and one or more is
1008+
* NULL, we return NULL; otherwise we return FALSE. This makes sense
1009+
* when you interpret NULL as "don't know": if we have a TRUE then the
1010+
* OR is TRUE even if we aren't sure about some of the other inputs.
1011+
* If all the known inputs are FALSE, but we have one or more "don't
1012+
* knows", then we have to report that we "don't know" what the OR's
1013+
* result should be --- perhaps one of the "don't knows" would have been
1014+
* TRUE if we'd known its value. Only when all the inputs are known
1015+
* to be FALSE can we state confidently that the OR's result is FALSE.
10111016
*/
10121017
foreach(clause, clauses)
10131018
{
1014-
10151019
/*
10161020
* We don't iterate over sets in the quals, so pass in an isDone
10171021
* flag, but ignore it.
10181022
*/
1019-
const_value = ExecEvalExpr((Node *) lfirst(clause),
1020-
econtext,
1021-
isNull,
1022-
&isDone);
1023-
1023+
clause_value = ExecEvalExpr((Node *) lfirst(clause),
1024+
econtext,
1025+
isNull,
1026+
&isDone);
10241027
/*
1025-
* if the expression evaluates to null, then we remember it in the
1026-
* local IsNull flag, if none of the clauses are true then we need
1027-
* to set *isNull to true again.
1028+
* if we have a non-null true result, then return it.
10281029
*/
10291030
if (*isNull)
1030-
{
1031-
IsNull = *isNull;
1032-
1033-
/*
1034-
* Many functions don't (or can't!) check if an argument is
1035-
* NULL or NOT_NULL and may return TRUE (1) with *isNull TRUE
1036-
* (an_int4_column <> 1: int4ne returns TRUE for NULLs). Not
1037-
* having time to fix the function manager I want to fix OR:
1038-
* if we had 'x <> 1 OR x isnull' then when x is NULL TRUE was
1039-
* returned by the 'x <> 1' clause ... but ExecQualClause says
1040-
* that the qualification should *fail* if isnull is TRUE for
1041-
* any value returned by ExecEvalExpr. So, force this rule
1042-
* here: if isnull is TRUE then the clause failed. Note:
1043-
* nullvalue() & nonnullvalue() always sets isnull to FALSE
1044-
* for NULLs. - vadim 09/22/97
1045-
*/
1046-
const_value = 0;
1047-
}
1048-
1049-
/*
1050-
* if we have a true result, then we return it.
1051-
*/
1052-
if (DatumGetInt32(const_value) != 0)
1053-
return const_value;
1031+
AnyNull = true; /* remember we got a null */
1032+
else if (DatumGetInt32(clause_value) != 0)
1033+
return clause_value;
10541034
}
10551035

1056-
/* IsNull is true if at least one clause evaluated to NULL */
1057-
*isNull = IsNull;
1058-
return const_value;
1036+
/* AnyNull is true if at least one clause evaluated to NULL */
1037+
*isNull = AnyNull;
1038+
return (Datum) false;
10591039
}
10601040

10611041
/* ----------------------------------------------------------------
@@ -1067,49 +1047,43 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
10671047
{
10681048
List *clauses;
10691049
List *clause;
1070-
Datum const_value = 0;
10711050
bool isDone;
1072-
bool IsNull;
1073-
1074-
IsNull = false;
1051+
bool AnyNull;
1052+
Datum clause_value;
10751053

10761054
clauses = andExpr->args;
1055+
AnyNull = false;
10771056

10781057
/*
1079-
* we evaluate each of the clauses in turn, as soon as one is false we
1080-
* return that value. If none are false or NULL then we return the
1081-
* value of the last clause evaluated, which should be true.
1058+
* If any of the clauses is FALSE, the AND result is FALSE regardless
1059+
* of the states of the rest of the clauses, so we can stop evaluating
1060+
* and return FALSE immediately. If none are FALSE and one or more is
1061+
* NULL, we return NULL; otherwise we return TRUE. This makes sense
1062+
* when you interpret NULL as "don't know", using the same sort of
1063+
* reasoning as for OR, above.
10821064
*/
10831065
foreach(clause, clauses)
10841066
{
1085-
10861067
/*
10871068
* We don't iterate over sets in the quals, so pass in an isDone
10881069
* flag, but ignore it.
10891070
*/
1090-
const_value = ExecEvalExpr((Node *) lfirst(clause),
1091-
econtext,
1092-
isNull,
1093-
&isDone);
1094-
1071+
clause_value = ExecEvalExpr((Node *) lfirst(clause),
1072+
econtext,
1073+
isNull,
1074+
&isDone);
10951075
/*
1096-
* if the expression evaluates to null, then we remember it in
1097-
* IsNull, if none of the clauses after this evaluates to false we
1098-
* will have to set *isNull to true again.
1076+
* if we have a non-null false result, then return it.
10991077
*/
11001078
if (*isNull)
1101-
IsNull = *isNull;
1102-
1103-
/*
1104-
* if we have a false result, then we return it, since the
1105-
* conjunction must be false.
1106-
*/
1107-
if (DatumGetInt32(const_value) == 0)
1108-
return const_value;
1079+
AnyNull = true; /* remember we got a null */
1080+
else if (DatumGetInt32(clause_value) == 0)
1081+
return clause_value;
11091082
}
11101083

1111-
*isNull = IsNull;
1112-
return const_value;
1084+
/* AnyNull is true if at least one clause evaluated to NULL */
1085+
*isNull = AnyNull;
1086+
return (Datum) (! AnyNull);
11131087
}
11141088

11151089
/* ----------------------------------------------------------------
@@ -1126,7 +1100,7 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
11261100
{
11271101
List *clauses;
11281102
List *clause;
1129-
Datum const_value = 0;
1103+
Datum clause_value;
11301104
bool isDone;
11311105

11321106
clauses = caseExpr->args;
@@ -1144,37 +1118,35 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
11441118
* We don't iterate over sets in the quals, so pass in an isDone
11451119
* flag, but ignore it.
11461120
*/
1147-
const_value = ExecEvalExpr((Node *) wclause->expr,
1148-
econtext,
1149-
isNull,
1150-
&isDone);
1121+
clause_value = ExecEvalExpr(wclause->expr,
1122+
econtext,
1123+
isNull,
1124+
&isDone);
11511125

11521126
/*
11531127
* if we have a true test, then we return the result, since the
11541128
* case statement is satisfied. A NULL result from the test is
11551129
* not considered true.
11561130
*/
1157-
if (DatumGetInt32(const_value) != 0 && ! *isNull)
1131+
if (DatumGetInt32(clause_value) != 0 && ! *isNull)
11581132
{
1159-
const_value = ExecEvalExpr((Node *) wclause->result,
1160-
econtext,
1161-
isNull,
1162-
&isDone);
1163-
return (Datum) const_value;
1133+
return ExecEvalExpr(wclause->result,
1134+
econtext,
1135+
isNull,
1136+
&isDone);
11641137
}
11651138
}
11661139

11671140
if (caseExpr->defresult)
11681141
{
1169-
const_value = ExecEvalExpr((Node *) caseExpr->defresult,
1170-
econtext,
1171-
isNull,
1172-
&isDone);
1142+
return ExecEvalExpr(caseExpr->defresult,
1143+
econtext,
1144+
isNull,
1145+
&isDone);
11731146
}
1174-
else
1175-
*isNull = true;
11761147

1177-
return const_value;
1148+
*isNull = true;
1149+
return (Datum) 0;
11781150
}
11791151

11801152
/* ----------------------------------------------------------------
@@ -1357,7 +1329,6 @@ bool
13571329
ExecQual(List *qual, ExprContext *econtext)
13581330
{
13591331
List *clause;
1360-
bool result;
13611332

13621333
/*
13631334
* debugging stuff
@@ -1378,27 +1349,17 @@ ExecQual(List *qual, ExprContext *econtext)
13781349
* a "qual" is a list of clauses. To evaluate the qual, we evaluate
13791350
* each of the clauses in the list.
13801351
*
1381-
* ExecQualClause returns true when we know the qualification *failed* so
1382-
* we just pass each clause in qual to it until we know the qual
1352+
* ExecQualClause returns true when we know the qualification *failed*
1353+
* so we just pass each clause in qual to it until we know the qual
13831354
* failed or there are no more clauses.
13841355
*/
1385-
result = false;
13861356

13871357
foreach(clause, qual)
13881358
{
1389-
result = ExecQualClause((Node *) lfirst(clause), econtext);
1390-
if (result == true)
1391-
break;
1359+
if (ExecQualClause((Node *) lfirst(clause), econtext))
1360+
return false; /* qual failed, so return false */
13921361
}
13931362

1394-
/*
1395-
* if result is true, then it means a clause failed so we return
1396-
* false. if result is false then it means no clause failed so we
1397-
* return true.
1398-
*/
1399-
if (result == true)
1400-
return false;
1401-
14021363
return true;
14031364
}
14041365

src/backend/nodes/equalfuncs.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.48 1999/08/21 03:48:57 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.49 1999/09/26 02:28:21 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -223,6 +223,22 @@ _equalAggref(Aggref *a, Aggref *b)
223223
return true;
224224
}
225225

226+
static bool
227+
_equalSubLink(SubLink *a, SubLink *b)
228+
{
229+
if (a->subLinkType != b->subLinkType)
230+
return false;
231+
if (a->useor != b->useor)
232+
return false;
233+
if (!equal(a->lefthand, b->lefthand))
234+
return false;
235+
if (!equal(a->oper, b->oper))
236+
return false;
237+
if (!equal(a->subselect, b->subselect))
238+
return false;
239+
return true;
240+
}
241+
226242
static bool
227243
_equalArray(Array *a, Array *b)
228244
{
@@ -393,7 +409,7 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
393409
if (a->plan_id != b->plan_id)
394410
return false;
395411

396-
if (!equal(a->sublink->oper, b->sublink->oper))
412+
if (!equal(a->sublink, b->sublink))
397413
return false;
398414

399415
return true;
@@ -713,6 +729,9 @@ equal(void *a, void *b)
713729
case T_Aggref:
714730
retval = _equalAggref(a, b);
715731
break;
732+
case T_SubLink:
733+
retval = _equalSubLink(a, b);
734+
break;
716735
case T_Func:
717736
retval = _equalFunc(a, b);
718737
break;

src/backend/optimizer/plan/planmain.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.44 1999/09/13 00:17:25 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.45 1999/09/26 02:28:27 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -66,24 +66,41 @@ query_planner(Query *root,
6666
List *level_tlist;
6767
Plan *subplan;
6868

69+
/*
70+
* Simplify constant expressions in both targetlist and qual.
71+
*
72+
* Note that at this point the qual has not yet been converted to
73+
* implicit-AND form, so we can apply eval_const_expressions directly.
74+
* Also note that we need to do this before SS_process_sublinks,
75+
* because that routine inserts bogus "Const" nodes.
76+
*/
77+
tlist = (List *) eval_const_expressions((Node *) tlist);
78+
qual = (List *) eval_const_expressions((Node *) qual);
79+
80+
/*
81+
* Canonicalize the qual, and convert it to implicit-AND format.
82+
*/
83+
qual = canonicalize_qual((Expr *) qual, true);
84+
#ifdef OPTIMIZER_DEBUG
85+
printf("After canonicalize_qual()\n");
86+
pprint(qual);
87+
#endif
88+
89+
/* Replace uplevel vars with Param nodes */
6990
if (PlannerQueryLevel > 1)
7091
{
71-
/* should copy be made ? */
7292
tlist = (List *) SS_replace_correlation_vars((Node *) tlist);
7393
qual = (List *) SS_replace_correlation_vars((Node *) qual);
7494
}
95+
/* Expand SubLinks to SubPlans */
7596
if (root->hasSubLinks)
7697
qual = (List *) SS_process_sublinks((Node *) qual);
7798

78-
qual = canonicalize_qual((Expr *) qual, true);
79-
#ifdef OPTIMIZER_DEBUG
80-
printf("After canonicalize_qual()\n");
81-
pprint(qual);
82-
#endif
83-
8499
/*
85100
* Pull out any non-variable qualifications so these can be put in the
86-
* topmost result node.
101+
* topmost result node. (Any *really* non-variable quals will probably
102+
* have been optimized away by eval_const_expressions(). What we're
103+
* looking for here is quals that depend only on outer-level vars...)
87104
*/
88105
qual = pull_constant_clauses(qual, &constant_qual);
89106

0 commit comments

Comments
 (0)