1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Fix ExecSubPlan to handle nulls per the SQL spec --- it didn't combine

nulls with non-nulls using proper three-valued boolean logic.  Also clean
up ExecQual to make it clearer that ExecQual *does* follow the SQL spec
for boolean nulls.  See '[BUGS] (null) != (null)' thread around 10/26/99
for more detail.
This commit is contained in:
Tom Lane
1999-11-12 06:39:34 +00:00
parent 6b99fcf3e2
commit ac61a04a71
3 changed files with 147 additions and 106 deletions

View File

@ -7,14 +7,14 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.63 1999/10/08 03:49:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.64 1999/11/12 06:39:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecEvalExpr - evaluate an expression and return a datum
* ExecQual - return true/false if qualification is satisified
* ExecQual - return true/false if qualification is satisfied
* ExecTargetList - form a new tuple by projecting the given tuple
*
* NOTES
@ -71,7 +71,6 @@ static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);
static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
static Datum ExecMakeFunctionResult(Node *node, List *arguments,
ExprContext *econtext, bool *isNull, bool *isDone);
static bool ExecQualClause(Node *clause, ExprContext *econtext);
/*
* ExecEvalArrayRef
@ -1253,7 +1252,9 @@ ExecEvalExpr(Node *expression,
retDatum = (Datum) ExecEvalNot(expr, econtext, isNull);
break;
case SUBPLAN_EXPR:
retDatum = (Datum) ExecSubPlan((SubPlan *) expr->oper, expr->args, econtext);
retDatum = (Datum) ExecSubPlan((SubPlan *) expr->oper,
expr->args, econtext,
isNull);
break;
default:
elog(ERROR, "ExecEvalExpr: unknown expression type %d", expr->opType);
@ -1279,46 +1280,6 @@ ExecEvalExpr(Node *expression,
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* ExecQualClause
*
* this is a workhorse for ExecQual. ExecQual has to deal
* with a list of qualifications, so it passes each qualification
* in the list to this function one at a time. ExecQualClause
* returns true when the qualification *fails* and false if
* the qualification succeeded (meaning we have to test the
* rest of the qualification)
* ----------------------------------------------------------------
*/
static bool
ExecQualClause(Node *clause, ExprContext *econtext)
{
Datum expr_value;
bool isNull;
bool isDone;
/* when there is a null clause, consider the qualification to fail */
if (clause == NULL)
return true;
/*
* pass isDone, but ignore it. We don't iterate over multiple returns
* in the qualifications.
*/
expr_value = ExecEvalExpr(clause, econtext, &isNull, &isDone);
/*
* remember, we return true when the qualification fails;
* NULL is considered failure.
*/
if (isNull)
return true;
if (DatumGetInt32(expr_value) == 0)
return true;
return false;
}
/* ----------------------------------------------------------------
* ExecQual
*
@ -1329,7 +1290,7 @@ ExecQualClause(Node *clause, ExprContext *econtext)
bool
ExecQual(List *qual, ExprContext *econtext)
{
List *clause;
List *qlist;
/*
* debugging stuff
@ -1340,25 +1301,38 @@ ExecQual(List *qual, ExprContext *econtext)
IncrProcessed();
/*
* return true immediately if no qual
*/
if (qual == NIL)
return true;
/*
* a "qual" is a list of clauses. To evaluate the qual, we evaluate
* each of the clauses in the list.
* each of the clauses in the list. (For an empty list, we'll return
* TRUE.)
*
* ExecQualClause returns true when we know the qualification *failed*
* so we just pass each clause in qual to it until we know the qual
* failed or there are no more clauses.
* If any of the clauses return NULL, we treat this as FALSE. This
* is correct per the SQL spec: if any ANDed conditions are NULL, then
* the AND result is either FALSE or NULL, and in either case the
* WHERE condition fails. NOTE: it would NOT be correct to use this
* simplified logic in a sub-clause; ExecEvalAnd must do the full
* three-state condition evaluation. We can get away with simpler
* logic here because we know how the result will be used.
*/
foreach(clause, qual)
foreach(qlist, qual)
{
if (ExecQualClause((Node *) lfirst(clause), econtext))
return false; /* qual failed, so return false */
Node *clause = (Node *) lfirst(qlist);
Datum expr_value;
bool isNull;
bool isDone;
/* if there is a null clause, consider the qualification to fail */
if (clause == NULL)
return false;
/*
* pass isDone, but ignore it. We don't iterate over multiple returns
* in the qualifications.
*/
expr_value = ExecEvalExpr(clause, econtext, &isNull, &isDone);
if (isNull)
return false; /* treat NULL as FALSE */
if (DatumGetInt32(expr_value) == 0)
return false;
}
return true;