aboutsummaryrefslogtreecommitdiff
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 69bf65d00bf..cbb76d1f1cd 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -2970,19 +2970,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;
}
/*
@@ -2994,10 +3005,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);
/*
@@ -3005,7 +3017,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;