diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-01-19 23:55:03 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-01-19 23:55:03 +0000 |
commit | 6d1efd76fb9852b8bc242dcaf35916090d7c5899 (patch) | |
tree | f827384a43f7dc18532337d555038e02498368b0 /src/backend/executor/execQual.c | |
parent | 08fb7375e35863e0ba2b8bb6a6c75802ca13fe85 (diff) | |
download | postgresql-6d1efd76fb9852b8bc242dcaf35916090d7c5899.tar.gz postgresql-6d1efd76fb9852b8bc242dcaf35916090d7c5899.zip |
Fix handling of NULL constraint conditions: per SQL92 spec, a NULL result
from a constraint condition does not violate the constraint (cf. discussion
on pghackers 12/9/99). Implemented by adding a parameter to ExecQual,
specifying whether to return TRUE or FALSE when the qual result is
really NULL in three-valued boolean logic. Currently, ExecRelCheck is
the only caller that asks for TRUE, but if we find any other places that
have the wrong response to NULL, it'll be easy to fix them.
Diffstat (limited to 'src/backend/executor/execQual.c')
-rw-r--r-- | src/backend/executor/execQual.c | 68 |
1 files changed, 50 insertions, 18 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index bd546597733..9e9cbde83bf 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.65 2000/01/10 17:14:34 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.66 2000/01/19 23:54:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1283,12 +1283,33 @@ ExecEvalExpr(Node *expression, /* ---------------------------------------------------------------- * ExecQual * - * Evaluates a conjunctive boolean expression and returns t - * iff none of the subexpressions are false (or null). + * Evaluates a conjunctive boolean expression (qual list) and + * returns true iff none of the subexpressions are false. + * (We also return true if the list is empty.) + * + * If some of the subexpressions yield NULL but none yield FALSE, + * then the result of the conjunction is NULL (ie, unknown) + * according to three-valued boolean logic. In this case, + * we return the value specified by the "resultForNull" parameter. + * + * Callers evaluating WHERE clauses should pass resultForNull=FALSE, + * since SQL specifies that tuples with null WHERE results do not + * get selected. On the other hand, callers evaluating constraint + * conditions should pass resultForNull=TRUE, since SQL also specifies + * that NULL constraint conditions are not failures. + * + * NOTE: it would not be correct to use this routine to evaluate an + * AND subclause of a boolean expression; for that purpose, a NULL + * result must be returned as NULL so that it can be properly treated + * in the next higher operator (cf. ExecEvalAnd and ExecEvalOr). + * This routine is only used in contexts where a complete expression + * is being evaluated and we know that NULL can be treated the same + * as one boolean result or the other. + * * ---------------------------------------------------------------- */ bool -ExecQual(List *qual, ExprContext *econtext) +ExecQual(List *qual, ExprContext *econtext, bool resultForNull) { List *qlist; @@ -1302,18 +1323,18 @@ ExecQual(List *qual, ExprContext *econtext) IncrProcessed(); /* - * a "qual" is a list of clauses. To evaluate the qual, we evaluate - * each of the clauses in the list. (For an empty list, we'll return - * TRUE.) + * Evaluate the qual conditions one at a time. If we find a FALSE + * result, we can stop evaluating and return FALSE --- the AND result + * must be FALSE. Also, if we find a NULL result when resultForNull + * is FALSE, we can stop and return FALSE --- the AND result must be + * FALSE or NULL in that case, and the caller doesn't care which. * - * 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. + * If we get to the end of the list, we can return TRUE. This will + * happen when the AND result is indeed TRUE, or when the AND result + * is NULL (one or more NULL subresult, with all the rest TRUE) and + * the caller has specified resultForNull = TRUE. */ + foreach(qlist, qual) { Node *clause = (Node *) lfirst(qlist); @@ -1321,7 +1342,11 @@ ExecQual(List *qual, ExprContext *econtext) bool isNull; bool isDone; - /* if there is a null clause, consider the qualification to fail */ + /* + * If there is a null clause, consider the qualification to fail. + * XXX is this still correct for constraints? It probably shouldn't + * happen at all ... + */ if (clause == NULL) return false; /* @@ -1329,10 +1354,17 @@ ExecQual(List *qual, ExprContext *econtext) * 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; + { + if (resultForNull == false) + return false; /* treat NULL as FALSE */ + } + else + { + if (DatumGetInt32(expr_value) == 0) + return false; /* definitely FALSE */ + } } return true; |