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:
@ -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;
|
||||
|
Reference in New Issue
Block a user