Commit e1a8b0f2 authored by Tom Lane's avatar Tom Lane

Fix CASE bug identified by Keith Parks: CASE didn't reliably

treat a NULL condition result as FALSE.  Clean up some bogus comments
here and there, too.
parent f9f5dfbf
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.58 1999/07/19 00:26:15 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.59 1999/09/18 23:26:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -616,8 +616,7 @@ ExecEvalFuncArgs(FunctionCachePtr fcache, ...@@ -616,8 +616,7 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
bool *argIsDone) bool *argIsDone)
{ {
int i; int i;
bool argIsNull, bool *nullVect;
*nullVect;
List *arg; List *arg;
nullVect = fcache->nullVect; nullVect = fcache->nullVect;
...@@ -631,12 +630,10 @@ ExecEvalFuncArgs(FunctionCachePtr fcache, ...@@ -631,12 +630,10 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
* as arguments but we make an exception in the case of nested dot * as arguments but we make an exception in the case of nested dot
* expressions. We have to watch out for this case here. * expressions. We have to watch out for this case here.
*/ */
argV[i] = (Datum) argV[i] = ExecEvalExpr((Node *) lfirst(arg),
ExecEvalExpr((Node *) lfirst(arg), econtext,
econtext, & nullVect[i],
&argIsNull, argIsDone);
argIsDone);
if (!(*argIsDone)) if (!(*argIsDone))
{ {
...@@ -644,10 +641,6 @@ ExecEvalFuncArgs(FunctionCachePtr fcache, ...@@ -644,10 +641,6 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
fcache->setArg = (char *) argV[0]; fcache->setArg = (char *) argV[0];
fcache->hasSetArg = true; fcache->hasSetArg = true;
} }
if (argIsNull)
nullVect[i] = true;
else
nullVect[i] = false;
i++; i++;
} }
} }
...@@ -1108,7 +1101,7 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull) ...@@ -1108,7 +1101,7 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
* ExecEvalCase * ExecEvalCase
* *
* Evaluate a CASE clause. Will have boolean expressions * Evaluate a CASE clause. Will have boolean expressions
* inside the WHEN clauses, and will have constants * inside the WHEN clauses, and will have expressions
* for results. * for results.
* - thomas 1998-11-09 * - thomas 1998-11-09
* ---------------------------------------------------------------- * ----------------------------------------------------------------
...@@ -1118,7 +1111,6 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull) ...@@ -1118,7 +1111,6 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
{ {
List *clauses; List *clauses;
List *clause; List *clause;
CaseWhen *wclause;
Datum const_value = 0; Datum const_value = 0;
bool isDone; bool isDone;
...@@ -1127,17 +1119,16 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull) ...@@ -1127,17 +1119,16 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
/* /*
* we evaluate each of the WHEN clauses in turn, as soon as one is * 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 * true we return the corresponding result. If none are true then we
* return the value of the default clause, or NULL. * return the value of the default clause, or NULL if there is none.
*/ */
foreach(clause, clauses) foreach(clause, clauses)
{ {
CaseWhen *wclause = lfirst(clause);
/* /*
* We don't iterate over sets in the quals, so pass in an isDone * We don't iterate over sets in the quals, so pass in an isDone
* flag, but ignore it. * flag, but ignore it.
*/ */
wclause = lfirst(clause);
const_value = ExecEvalExpr((Node *) wclause->expr, const_value = ExecEvalExpr((Node *) wclause->expr,
econtext, econtext,
isNull, isNull,
...@@ -1145,16 +1136,16 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull) ...@@ -1145,16 +1136,16 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
/* /*
* if we have a true test, then we return the result, since the * if we have a true test, then we return the result, since the
* case statement is satisfied. * case statement is satisfied. A NULL result from the test is
* not considered true.
*/ */
if (DatumGetInt32(const_value) != 0) if (DatumGetInt32(const_value) != 0 && ! *isNull)
{ {
const_value = ExecEvalExpr((Node *) wclause->result, const_value = ExecEvalExpr((Node *) wclause->result,
econtext, econtext,
isNull, isNull,
&isDone); &isDone);
return (Datum) const_value; return (Datum) const_value;
} }
} }
...@@ -1318,7 +1309,7 @@ ExecQualClause(Node *clause, ExprContext *econtext) ...@@ -1318,7 +1309,7 @@ ExecQualClause(Node *clause, ExprContext *econtext)
bool isNull; bool isNull;
bool isDone; bool isDone;
/* when there is a null clause, consider the qualification to be true */ /* when there is a null clause, consider the qualification to fail */
if (clause == NULL) if (clause == NULL)
return true; return true;
...@@ -1326,20 +1317,14 @@ ExecQualClause(Node *clause, ExprContext *econtext) ...@@ -1326,20 +1317,14 @@ ExecQualClause(Node *clause, ExprContext *econtext)
* pass isDone, but ignore it. We don't iterate over multiple returns * pass isDone, but ignore it. We don't iterate over multiple returns
* in the qualifications. * in the qualifications.
*/ */
expr_value = (Datum) expr_value = ExecEvalExpr(clause, econtext, &isNull, &isDone);
ExecEvalExpr(clause, econtext, &isNull, &isDone);
/* /*
* this is interesting behaviour here. When a clause evaluates to * remember, we return true when the qualification fails;
* null, then we consider this as passing the qualification. it seems * NULL is considered failure.
* kind of like, if the qual is NULL, then there's no qual..
*/ */
if (isNull) if (isNull)
return true; return true;
/*
* remember, we return true when the qualification fails..
*/
if (DatumGetInt32(expr_value) == 0) if (DatumGetInt32(expr_value) == 0)
return true; return true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment