summaryrefslogtreecommitdiff
path: root/src/backend/executor/execQual.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execQual.c')
-rw-r--r--src/backend/executor/execQual.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index ea8850e12cf..bd68554a933 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -2889,19 +2889,30 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
/*
* 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
+ * 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.
+ * is itself within a larger CASE. Furthermore, don't assign to the
+ * econtext fields until after returning from evaluation of the test
+ * expression. We used to pass &econtext->caseValue_isNull to the
+ * recursive call, but that leads to aliasing that variable within said
+ * call, which can (and did) produce bugs when the test expression itself
+ * contains a CASE.
+ *
+ * If there's no test expression, we don't actually need to save and
+ * restore these fields; but it's less code to just do so unconditionally.
*/
save_datum = econtext->caseValue_datum;
save_isNull = econtext->caseValue_isNull;
if (caseExpr->arg)
{
+ bool arg_isNull;
+
econtext->caseValue_datum = ExecEvalExpr(caseExpr->arg,
econtext,
- &econtext->caseValue_isNull,
+ &arg_isNull,
NULL);
+ econtext->caseValue_isNull = arg_isNull;
}
/*
@@ -2913,10 +2924,11 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
{
CaseWhenState *wclause = lfirst(clause);
Datum clause_value;
+ bool clause_isNull;
clause_value = ExecEvalExpr(wclause->expr,
econtext,
- isNull,
+ &clause_isNull,
NULL);
/*
@@ -2924,7 +2936,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
* statement is satisfied. A NULL result from the test is not
* considered true.
*/
- if (DatumGetBool(clause_value) && !*isNull)
+ if (DatumGetBool(clause_value) && !clause_isNull)
{
econtext->caseValue_datum = save_datum;
econtext->caseValue_isNull = save_isNull;