mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
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.
This commit is contained in:
@ -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,10 +1812,29 @@ 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
|
||||
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user