Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 55f7c33

Browse files
committed
Reimplement CASE val WHEN compval1 THEN ... WHEN compval2 THEN ... END
so that the 'val' is computed only once, per recent discussion. The speedup is not much when 'val' is just a simple variable, but could be significant for larger expressions. More importantly this avoids issues with multiple evaluations of a volatile 'val', and it allows the CASE expression to be reverse-listed in its original form by ruleutils.c.
1 parent 8c702ea commit 55f7c33

File tree

16 files changed

+248
-55
lines changed

16 files changed

+248
-55
lines changed

src/backend/executor/execQual.c

+49-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.155 2004/03/17 01:02:23 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.156 2004/03/17 20:48:42 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -81,6 +81,9 @@ static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
8181
bool *isNull, ExprDoneCond *isDone);
8282
static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
8383
bool *isNull, ExprDoneCond *isDone);
84+
static Datum ExecEvalCaseTestExpr(ExprState *exprstate,
85+
ExprContext *econtext,
86+
bool *isNull, ExprDoneCond *isDone);
8487
static Datum ExecEvalArray(ArrayExprState *astate,
8588
ExprContext *econtext,
8689
bool *isNull, ExprDoneCond *isDone);
@@ -1809,10 +1812,29 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
18091812
{
18101813
List *clauses = caseExpr->args;
18111814
List *clause;
1815+
Datum save_datum;
1816+
bool save_isNull;
18121817

18131818
if (isDone)
18141819
*isDone = ExprSingleResult;
18151820

1821+
/*
1822+
* If there's a test expression, we have to evaluate it and save
1823+
* the value where the CaseTestExpr placeholders can find it.
1824+
* We must save and restore prior setting of econtext's caseValue fields,
1825+
* in case this node is itself within a larger CASE.
1826+
*/
1827+
save_datum = econtext->caseValue_datum;
1828+
save_isNull = econtext->caseValue_isNull;
1829+
1830+
if (caseExpr->arg)
1831+
{
1832+
econtext->caseValue_datum = ExecEvalExpr(caseExpr->arg,
1833+
econtext,
1834+
&econtext->caseValue_isNull,
1835+
NULL);
1836+
}
1837+
18161838
/*
18171839
* we evaluate each of the WHEN clauses in turn, as soon as one is
18181840
* true we return the corresponding result. If none are true then we
@@ -1835,13 +1857,18 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
18351857
*/
18361858
if (DatumGetBool(clause_value) && !*isNull)
18371859
{
1860+
econtext->caseValue_datum = save_datum;
1861+
econtext->caseValue_isNull = save_isNull;
18381862
return ExecEvalExpr(wclause->result,
18391863
econtext,
18401864
isNull,
18411865
isDone);
18421866
}
18431867
}
18441868

1869+
econtext->caseValue_datum = save_datum;
1870+
econtext->caseValue_isNull = save_isNull;
1871+
18451872
if (caseExpr->defresult)
18461873
{
18471874
return ExecEvalExpr(caseExpr->defresult,
@@ -1854,6 +1881,22 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
18541881
return (Datum) 0;
18551882
}
18561883

1884+
/*
1885+
* ExecEvalCaseTestExpr
1886+
*
1887+
* Return the value stored by CASE.
1888+
*/
1889+
static Datum
1890+
ExecEvalCaseTestExpr(ExprState *exprstate,
1891+
ExprContext *econtext,
1892+
bool *isNull, ExprDoneCond *isDone)
1893+
{
1894+
if (isDone)
1895+
*isDone = ExprSingleResult;
1896+
*isNull = econtext->caseValue_isNull;
1897+
return econtext->caseValue_datum;
1898+
}
1899+
18571900
/* ----------------------------------------------------------------
18581901
* ExecEvalArray - ARRAY[] expressions
18591902
*
@@ -2478,6 +2521,10 @@ ExecInitExpr(Expr *node, PlanState *parent)
24782521
state = (ExprState *) makeNode(ExprState);
24792522
state->evalfunc = ExecEvalCoerceToDomainValue;
24802523
break;
2524+
case T_CaseTestExpr:
2525+
state = (ExprState *) makeNode(ExprState);
2526+
state->evalfunc = ExecEvalCaseTestExpr;
2527+
break;
24812528
case T_Aggref:
24822529
{
24832530
Aggref *aggref = (Aggref *) node;
@@ -2666,6 +2713,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
26662713
List *inlist;
26672714

26682715
cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCase;
2716+
cstate->arg = ExecInitExpr(caseexpr->arg, parent);
26692717
FastListInit(&outlist);
26702718
foreach(inlist, caseexpr->args)
26712719
{
@@ -2680,8 +2728,6 @@ ExecInitExpr(Expr *node, PlanState *parent)
26802728
FastAppend(&outlist, wstate);
26812729
}
26822730
cstate->args = FastListValue(&outlist);
2683-
/* caseexpr->arg should be null by now */
2684-
Assert(caseexpr->arg == NULL);
26852731
cstate->defresult = ExecInitExpr(caseexpr->defresult, parent);
26862732
state = (ExprState *) cstate;
26872733
}

src/backend/executor/execUtils.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.109 2004/01/22 02:23:21 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.110 2004/03/17 20:48:42 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -306,6 +306,9 @@ CreateExprContext(EState *estate)
306306
econtext->ecxt_aggvalues = NULL;
307307
econtext->ecxt_aggnulls = NULL;
308308

309+
econtext->caseValue_datum = (Datum) 0;
310+
econtext->caseValue_isNull = true;
311+
309312
econtext->domainValue_datum = (Datum) 0;
310313
econtext->domainValue_isNull = true;
311314

src/backend/nodes/copyfuncs.c

+18-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1994, Regents of the University of California
1616
*
1717
* IDENTIFICATION
18-
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.278 2004/03/11 01:47:35 ishii Exp $
18+
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.279 2004/03/17 20:48:42 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -968,6 +968,20 @@ _copyCaseWhen(CaseWhen *from)
968968
return newnode;
969969
}
970970

971+
/*
972+
* _copyCaseTestExpr
973+
*/
974+
static CaseTestExpr *
975+
_copyCaseTestExpr(CaseTestExpr *from)
976+
{
977+
CaseTestExpr *newnode = makeNode(CaseTestExpr);
978+
979+
COPY_SCALAR_FIELD(typeId);
980+
COPY_SCALAR_FIELD(typeMod);
981+
982+
return newnode;
983+
}
984+
971985
/*
972986
* _copyArrayExpr
973987
*/
@@ -2643,6 +2657,9 @@ copyObject(void *from)
26432657
case T_CaseWhen:
26442658
retval = _copyCaseWhen(from);
26452659
break;
2660+
case T_CaseTestExpr:
2661+
retval = _copyCaseTestExpr(from);
2662+
break;
26462663
case T_ArrayExpr:
26472664
retval = _copyArrayExpr(from);
26482665
break;

src/backend/nodes/equalfuncs.c

+13-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* Portions Copyright (c) 1994, Regents of the University of California
1919
*
2020
* IDENTIFICATION
21-
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.217 2004/03/14 23:41:26 tgl Exp $
21+
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.218 2004/03/17 20:48:42 tgl Exp $
2222
*
2323
*-------------------------------------------------------------------------
2424
*/
@@ -403,6 +403,15 @@ _equalCaseWhen(CaseWhen *a, CaseWhen *b)
403403
return true;
404404
}
405405

406+
static bool
407+
_equalCaseTestExpr(CaseTestExpr *a, CaseTestExpr *b)
408+
{
409+
COMPARE_SCALAR_FIELD(typeId);
410+
COMPARE_SCALAR_FIELD(typeMod);
411+
412+
return true;
413+
}
414+
406415
static bool
407416
_equalArrayExpr(ArrayExpr *a, ArrayExpr *b)
408417
{
@@ -1724,6 +1733,9 @@ equal(void *a, void *b)
17241733
case T_CaseWhen:
17251734
retval = _equalCaseWhen(a, b);
17261735
break;
1736+
case T_CaseTestExpr:
1737+
retval = _equalCaseTestExpr(a, b);
1738+
break;
17271739
case T_ArrayExpr:
17281740
retval = _equalArrayExpr(a, b);
17291741
break;

src/backend/nodes/outfuncs.c

+13-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.232 2004/01/31 05:09:40 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.233 2004/03/17 20:48:42 tgl Exp $
1212
*
1313
* NOTES
1414
* Every node type that can appear in stored rules' parsetrees *must*
@@ -805,6 +805,15 @@ _outCaseWhen(StringInfo str, CaseWhen *node)
805805
WRITE_NODE_FIELD(result);
806806
}
807807

808+
static void
809+
_outCaseTestExpr(StringInfo str, CaseTestExpr *node)
810+
{
811+
WRITE_NODE_TYPE("CASETESTEXPR");
812+
813+
WRITE_OID_FIELD(typeId);
814+
WRITE_INT_FIELD(typeMod);
815+
}
816+
808817
static void
809818
_outArrayExpr(StringInfo str, ArrayExpr *node)
810819
{
@@ -1701,6 +1710,9 @@ _outNode(StringInfo str, void *obj)
17011710
case T_CaseWhen:
17021711
_outCaseWhen(str, obj);
17031712
break;
1713+
case T_CaseTestExpr:
1714+
_outCaseTestExpr(str, obj);
1715+
break;
17041716
case T_ArrayExpr:
17051717
_outArrayExpr(str, obj);
17061718
break;

src/backend/nodes/readfuncs.c

+17-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.165 2004/01/14 23:01:55 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.166 2004/03/17 20:48:42 tgl Exp $
1212
*
1313
* NOTES
1414
* Path and Plan nodes do not have any readfuncs support, because we
@@ -648,6 +648,20 @@ _readCaseWhen(void)
648648
READ_DONE();
649649
}
650650

651+
/*
652+
* _readCaseTestExpr
653+
*/
654+
static CaseTestExpr *
655+
_readCaseTestExpr(void)
656+
{
657+
READ_LOCALS(CaseTestExpr);
658+
659+
READ_OID_FIELD(typeId);
660+
READ_INT_FIELD(typeMod);
661+
662+
READ_DONE();
663+
}
664+
651665
/*
652666
* _readArrayExpr
653667
*/
@@ -1010,6 +1024,8 @@ parseNodeString(void)
10101024
return_value = _readCaseExpr();
10111025
else if (MATCH("WHEN", 4))
10121026
return_value = _readCaseWhen();
1027+
else if (MATCH("CASETESTEXPR", 12))
1028+
return_value = _readCaseTestExpr();
10131029
else if (MATCH("ARRAY", 5))
10141030
return_value = _readArrayExpr();
10151031
else if (MATCH("COALESCE", 8))

src/backend/optimizer/util/clauses.c

+21-7
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.164 2004/03/14 23:41:27 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.165 2004/03/17 20:48:42 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHOR DATE MAJOR EVENT
@@ -1397,15 +1397,29 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
13971397
* simplify the entire CASE to that alternative's expression.
13981398
* If there are no non-FALSE alternatives, we simplify the entire
13991399
* CASE to the default result (ELSE result).
1400+
*
1401+
* If we have a simple-form CASE with constant test expression and
1402+
* one or more constant comparison expressions, we could run the
1403+
* implied comparisons and potentially reduce those arms to constants.
1404+
* This is not yet implemented, however. At present, the
1405+
* CaseTestExpr placeholder will always act as a non-constant node
1406+
* and prevent the comparison boolean expressions from being reduced
1407+
* to Const nodes.
14001408
*----------
14011409
*/
14021410
CaseExpr *caseexpr = (CaseExpr *) node;
14031411
CaseExpr *newcase;
1412+
Node *newarg;
14041413
FastList newargs;
14051414
Node *defresult;
14061415
Const *const_input;
14071416
List *arg;
14081417

1418+
/* Simplify the test expression, if any */
1419+
newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
1420+
active_fns);
1421+
1422+
/* Simplify the WHEN clauses */
14091423
FastListInit(&newargs);
14101424
foreach(arg, caseexpr->args)
14111425
{
@@ -1454,7 +1468,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
14541468
/* Otherwise we need a new CASE node */
14551469
newcase = makeNode(CaseExpr);
14561470
newcase->casetype = caseexpr->casetype;
1457-
newcase->arg = NULL;
1471+
newcase->arg = (Expr *) newarg;
14581472
newcase->args = FastListValue(&newargs);
14591473
newcase->defresult = (Expr *) defresult;
14601474
return (Node *) newcase;
@@ -2319,6 +2333,7 @@ expression_tree_walker(Node *node,
23192333
case T_Const:
23202334
case T_Param:
23212335
case T_CoerceToDomainValue:
2336+
case T_CaseTestExpr:
23222337
case T_SetToDefault:
23232338
case T_RangeTblRef:
23242339
/* primitive node types with no subnodes */
@@ -2425,6 +2440,8 @@ expression_tree_walker(Node *node,
24252440
{
24262441
CaseExpr *caseexpr = (CaseExpr *) node;
24272442

2443+
if (walker(caseexpr->arg, context))
2444+
return true;
24282445
/* we assume walker doesn't care about CaseWhens, either */
24292446
foreach(temp, caseexpr->args)
24302447
{
@@ -2436,9 +2453,6 @@ expression_tree_walker(Node *node,
24362453
if (walker(when->result, context))
24372454
return true;
24382455
}
2439-
/* caseexpr->arg should be null, but we'll check it anyway */
2440-
if (walker(caseexpr->arg, context))
2441-
return true;
24422456
if (walker(caseexpr->defresult, context))
24432457
return true;
24442458
}
@@ -2692,6 +2706,7 @@ expression_tree_mutator(Node *node,
26922706
case T_Const:
26932707
case T_Param:
26942708
case T_CoerceToDomainValue:
2709+
case T_CaseTestExpr:
26952710
case T_SetToDefault:
26962711
case T_RangeTblRef:
26972712
/* primitive node types with no subnodes */
@@ -2829,9 +2844,8 @@ expression_tree_mutator(Node *node,
28292844
CaseExpr *newnode;
28302845

28312846
FLATCOPY(newnode, caseexpr, CaseExpr);
2832-
MUTATE(newnode->args, caseexpr->args, List *);
2833-
/* caseexpr->arg should be null, but we'll check it anyway */
28342847
MUTATE(newnode->arg, caseexpr->arg, Expr *);
2848+
MUTATE(newnode->args, caseexpr->args, List *);
28352849
MUTATE(newnode->defresult, caseexpr->defresult, Expr *);
28362850
return (Node *) newnode;
28372851
}

src/backend/parser/gram.y

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.448 2004/03/11 01:47:37 ishii Exp $
14+
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.449 2004/03/17 20:48:42 tgl Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -6965,6 +6965,7 @@ in_expr: select_with_parens
69656965
case_expr: CASE case_arg when_clause_list case_default END_P
69666966
{
69676967
CaseExpr *c = makeNode(CaseExpr);
6968+
c->casetype = InvalidOid; /* not analyzed yet */
69686969
c->arg = (Expr *) $2;
69696970
c->args = $3;
69706971
c->defresult = (Expr *) $4;

0 commit comments

Comments
 (0)