diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-03-17 20:48:43 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-03-17 20:48:43 +0000 |
commit | 55f7c3300d164d370d28b127210223d078da524d (patch) | |
tree | e5c91b7d50eef3b40dd395e3ecce877bb6663636 /src/backend/executor/execQual.c | |
parent | 8c702ea7ace30026dfff4f2e514027cd4d6d7579 (diff) | |
download | postgresql-55f7c3300d164d370d28b127210223d078da524d.tar.gz postgresql-55f7c3300d164d370d28b127210223d078da524d.zip |
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.
Diffstat (limited to 'src/backend/executor/execQual.c')
-rw-r--r-- | src/backend/executor/execQual.c | 52 |
1 files changed, 49 insertions, 3 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 94a5c110d41..fc16cccdda9 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.155 2004/03/17 01:02:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.156 2004/03/17 20:48:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -81,6 +81,9 @@ static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalCaseTestExpr(ExprState *exprstate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); @@ -1809,11 +1812,30 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, { List *clauses = caseExpr->args; List *clause; + Datum save_datum; + bool save_isNull; if (isDone) *isDone = ExprSingleResult; /* + * If there's a test expression, we have to evaluate it and save + * the value where the CaseTestExpr placeholders can find it. + * We must save and restore prior setting of econtext's caseValue fields, + * in case this node is itself within a larger CASE. + */ + save_datum = econtext->caseValue_datum; + save_isNull = econtext->caseValue_isNull; + + if (caseExpr->arg) + { + econtext->caseValue_datum = ExecEvalExpr(caseExpr->arg, + econtext, + &econtext->caseValue_isNull, + NULL); + } + + /* * we evaluate each of the WHEN clauses in turn, as soon as one is * true we return the corresponding result. If none are true then we * return the value of the default clause, or NULL if there is none. @@ -1835,6 +1857,8 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, */ if (DatumGetBool(clause_value) && !*isNull) { + econtext->caseValue_datum = save_datum; + econtext->caseValue_isNull = save_isNull; return ExecEvalExpr(wclause->result, econtext, isNull, @@ -1842,6 +1866,9 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, } } + econtext->caseValue_datum = save_datum; + econtext->caseValue_isNull = save_isNull; + if (caseExpr->defresult) { return ExecEvalExpr(caseExpr->defresult, @@ -1854,6 +1881,22 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, return (Datum) 0; } +/* + * ExecEvalCaseTestExpr + * + * Return the value stored by CASE. + */ +static Datum +ExecEvalCaseTestExpr(ExprState *exprstate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone) +{ + if (isDone) + *isDone = ExprSingleResult; + *isNull = econtext->caseValue_isNull; + return econtext->caseValue_datum; +} + /* ---------------------------------------------------------------- * ExecEvalArray - ARRAY[] expressions * @@ -2478,6 +2521,10 @@ ExecInitExpr(Expr *node, PlanState *parent) state = (ExprState *) makeNode(ExprState); state->evalfunc = ExecEvalCoerceToDomainValue; break; + case T_CaseTestExpr: + state = (ExprState *) makeNode(ExprState); + state->evalfunc = ExecEvalCaseTestExpr; + break; case T_Aggref: { Aggref *aggref = (Aggref *) node; @@ -2666,6 +2713,7 @@ ExecInitExpr(Expr *node, PlanState *parent) List *inlist; cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCase; + cstate->arg = ExecInitExpr(caseexpr->arg, parent); FastListInit(&outlist); foreach(inlist, caseexpr->args) { @@ -2680,8 +2728,6 @@ ExecInitExpr(Expr *node, PlanState *parent) FastAppend(&outlist, wstate); } cstate->args = FastListValue(&outlist); - /* caseexpr->arg should be null by now */ - Assert(caseexpr->arg == NULL); cstate->defresult = ExecInitExpr(caseexpr->defresult, parent); state = (ExprState *) cstate; } |