diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 9c9e8aeee7f0b30104dc9c9819ba8241be590f8f..edebfcbebe3799b4446bfb1865952362da709aec 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -6,7 +6,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.49 2000/01/17 23:57:41 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.50 2000/01/19 23:54:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -169,7 +169,7 @@ gistbuild(Relation heap, #ifndef OMIT_PARTIAL_INDEX /* SetSlotContents(slot, htup); */ slot->val = htup; - if (ExecQual((List *) oldPred, econtext) == true) + if (ExecQual((List *) oldPred, econtext, false)) { ni++; continue; @@ -186,7 +186,7 @@ gistbuild(Relation heap, #ifndef OMIT_PARTIAL_INDEX /* SetSlotContents(slot, htup); */ slot->val = htup; - if (ExecQual((List *) pred, econtext) == false) + if (! ExecQual((List *) pred, econtext, false)) continue; #endif /* OMIT_PARTIAL_INDEX */ } diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index fd3e3f94d50edbe36c328673f29282db206805c1..1d88bfc8bc49eaf65032cc7a40c148915d9984d0 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.33 1999/12/10 03:55:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.34 2000/01/19 23:54:47 tgl Exp $ * * NOTES * This file contains only the public interface routines. @@ -131,7 +131,7 @@ hashbuild(Relation heap, /* SetSlotContents(slot, htup); */ #ifndef OMIT_PARTIAL_INDEX slot->val = htup; - if (ExecQual((List *) oldPred, econtext) == true) + if (ExecQual((List *) oldPred, econtext, false)) { nitups++; continue; @@ -148,7 +148,7 @@ hashbuild(Relation heap, #ifndef OMIT_PARTIAL_INDEX /* SetSlotContents(slot, htup); */ slot->val = htup; - if (ExecQual((List *) pred, econtext) == false) + if (! ExecQual((List *) pred, econtext, false)) continue; #endif /* OMIT_PARTIAL_INDEX */ } diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 458b427c70d17f7a9ee811449f0b86035235d660..1be5c08f973aeb7f8726013079e1265b260258d8 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -11,7 +11,7 @@ * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.50 1999/12/10 03:55:44 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.51 2000/01/19 23:54:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -167,7 +167,7 @@ btbuild(Relation heap, /* SetSlotContents(slot, htup); */ slot->val = htup; - if (ExecQual((List *) oldPred, econtext) == true) + if (ExecQual((List *) oldPred, econtext, false)) { nitups++; continue; @@ -184,7 +184,7 @@ btbuild(Relation heap, #ifndef OMIT_PARTIAL_INDEX /* SetSlotContents(slot, htup); */ slot->val = htup; - if (ExecQual((List *) pred, econtext) == false) + if (! ExecQual((List *) pred, econtext, false)) continue; #endif /* OMIT_PARTIAL_INDEX */ } diff --git a/src/backend/access/rtree/rtree.c b/src/backend/access/rtree/rtree.c index 09930e1e340680637cd250cb73ce3544b5f4f82c..fd2a8e545a4e696d41b16faac3225ddf49f37f38 100644 --- a/src/backend/access/rtree/rtree.c +++ b/src/backend/access/rtree/rtree.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.41 1999/12/10 03:55:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.42 2000/01/19 23:54:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -163,7 +163,7 @@ rtbuild(Relation heap, #ifndef OMIT_PARTIAL_INDEX /* SetSlotContents(slot, htup); */ slot->val = htup; - if (ExecQual((List *) oldPred, econtext) == true) + if (ExecQual((List *) oldPred, econtext, false)) { ni++; continue; @@ -180,7 +180,7 @@ rtbuild(Relation heap, #ifndef OMIT_PARTIAL_INDEX /* SetSlotContents(slot, htup); */ slot->val = htup; - if (ExecQual((List *) pred, econtext) == false) + if (! ExecQual((List *) pred, econtext, false)) continue; #endif /* OMIT_PARTIAL_INDEX */ } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 84009d6282b636656099bd0396db8d3432a16fff..375aed9a00658aa1106cbdcb0e161b6656288150 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.102 2000/01/17 23:57:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.103 2000/01/19 23:54:51 tgl Exp $ * * * INTERFACE ROUTINES @@ -1590,7 +1590,7 @@ DefaultBuild(Relation heapRelation, { /* SetSlotContents(slot, heapTuple); */ slot->val = heapTuple; - if (ExecQual((List *) oldPred, econtext) == true) + if (ExecQual((List *) oldPred, econtext, false)) { indtuples++; continue; @@ -1605,7 +1605,7 @@ DefaultBuild(Relation heapRelation, { /* SetSlotContents(slot, heapTuple); */ slot->val = heapTuple; - if (ExecQual((List *) predicate, econtext) == false) + if (! ExecQual((List *) predicate, econtext, false)) continue; } #endif /* OMIT_PARTIAL_INDEX */ diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 328b2d644ebf5184757ec0887c3a679bcbd8ed35..60611398173310dcd60a48c519cf4372919081a6 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -6,7 +6,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.96 2000/01/16 21:37:50 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.97 2000/01/19 23:54:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -886,7 +886,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null */ slot->val = tuple; /* SetSlotContents(slot, tuple); */ - if (ExecQual((List *) indexPred[i], econtext) == false) + if (! ExecQual((List *) indexPred[i], econtext, false)) continue; #endif /* OMIT_PARTIAL_INDEX */ } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index fa98950ac1ff237606af513fbd5d04a360c1e3c1..863c13b64ece802a7242adf0a96bc07c1459f8a6 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.105 2000/01/17 23:57:45 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.106 2000/01/19 23:54:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1487,7 +1487,6 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) RangeTblEntry *rte = makeNode(RangeTblEntry); List *rtlist; List *qual; - bool res; int i; slot->val = tuple; @@ -1526,9 +1525,12 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) { qual = estate->es_result_relation_constraints[i]; - res = ExecQual(qual, econtext); - - if (!res) + /* + * NOTE: SQL92 specifies that a NULL result from a constraint + * expression is not to be treated as a failure. Therefore, + * tell ExecQual to return TRUE for NULL. + */ + if (! ExecQual(qual, econtext, true)) return check[i].ccname; } diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index bd546597733dbb87350b8370b3c7bc87e192ee8c..9e9cbde83bfeffc84cc427e0ae2e322e2399d5a5 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; diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index 4196fb7a8a4dbd94dd6d8ad6a63ef887d07d7b86..4803653e14cd508fba8a832f02f8d507e06f1e8b 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.9 1999/02/13 23:15:18 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.10 2000/01/19 23:54:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -137,9 +137,10 @@ ExecScan(Scan *node, /* * add a check for non-nil qual here to avoid a function call to - * ExecQual() when the qual is nil + * ExecQual() when the qual is nil ... saves only a few cycles, + * but they add up ... */ - if (!qual || ExecQual(qual, econtext) == true) + if (!qual || ExecQual(qual, econtext, false)) break; } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index d168071e1fe9d17690bf82ccbbf6f7ffeaba98a7..4d5079ae6947eb7a869e1c2828fdd1ac028f5c47 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.51 1999/12/20 10:40:42 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.52 2000/01/19 23:54:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1137,7 +1137,6 @@ ExecInsertIndexTuples(TupleTableSlot *slot, IndexInfo **indexInfoArray; IndexInfo *indexInfo; Node *predicate; - bool satisfied; ExprContext *econtext; InsertIndexResult result; int numberOfAttributes; @@ -1178,8 +1177,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot, econtext->ecxt_scantuple = slot; /* Skip this index-update if the predicate isn't satisfied */ - satisfied = ExecQual((List *) predicate, econtext); - if (satisfied == false) + if (! ExecQual((List *) predicate, econtext, false)) continue; } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 0a95c92347fb858ffd470245ef1203807364f51c..a40fd015af35ba43253c7d8d3ec64bcaaad7dc61 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -31,7 +31,7 @@ * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.60 1999/12/13 01:26:52 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.61 2000/01/19 23:54:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -580,7 +580,7 @@ ExecAgg(Agg *node) * Otherwise, return the tuple. */ } - while (! ExecQual(node->plan.qual, econtext)); + while (! ExecQual(node->plan.qual, econtext, false)); return resultSlot; } diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 1995048e2dbc8cef2077efd6a14b27e8d0db0091..46307a2aa963788f3deeac83c3d49805934e9882 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -6,7 +6,7 @@ * Copyright (c) 1994, Regents of the University of California * * - * $Id: nodeHash.c,v 1.42 2000/01/09 00:26:18 tgl Exp $ + * $Id: nodeHash.c,v 1.43 2000/01/19 23:54:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -584,7 +584,6 @@ ExecScanHashBucket(HashJoinState *hjstate, { HeapTuple heapTuple = &hashTuple->htup; TupleTableSlot *inntuple; - bool qualResult; /* insert hashtable's tuple into exec slot so ExecQual sees it */ inntuple = ExecStoreTuple(heapTuple, /* tuple to store */ @@ -593,9 +592,7 @@ ExecScanHashBucket(HashJoinState *hjstate, false); /* do not pfree this tuple */ econtext->ecxt_innertuple = inntuple; - qualResult = ExecQual(hjclauses, econtext); - - if (qualResult) + if (ExecQual(hjclauses, econtext, false)) { hjstate->hj_CurTuple = hashTuple; return heapTuple; diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 9d5034307fe34a6c33cf9538bfe14bdee17dbacc..6f5d2cae1949777a8bcbba252284b6d3afd3ceb0 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.28 1999/12/16 22:19:44 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.29 2000/01/19 23:54:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -54,7 +54,6 @@ ExecHashJoin(HashJoin *node) ExprContext *econtext; HashJoinTable hashtable; HeapTuple curtuple; - bool qualResult; TupleTableSlot *outerTupleSlot; TupleTableSlot *innerTupleSlot; Var *innerhashkey; @@ -220,14 +219,13 @@ ExecHashJoin(HashJoin *node) InvalidBuffer, false); /* don't pfree this tuple */ econtext->ecxt_innertuple = inntuple; - qualResult = ExecQual(qual, econtext); /* ---------------- * if we pass the qual, then save state for next call and * have ExecProject form the projection, store it * in the tuple table, and return the slot. * ---------------- */ - if (qualResult) + if (ExecQual(qual, econtext, false)) { ProjectionInfo *projInfo; TupleTableSlot *result; diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index b9e3cf58636832608d01f386f0f8c31e3b6f6384..6ed14e0ad9adf00bc978da1af43178772fbf927e 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.43 1999/09/24 00:24:23 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.44 2000/01/19 23:54:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -137,7 +137,8 @@ IndexNext(IndexScan *node) { scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot; if (ExecQual(nth(iptr, node->indxqualorig), - scanstate->cstate.cs_ExprContext)) + scanstate->cstate.cs_ExprContext, + false)) break; } if (iptr == numIndices) /* would not be returned by indices */ @@ -220,7 +221,8 @@ IndexNext(IndexScan *node) { scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot; if (ExecQual(nth(prev_index, node->indxqualorig), - scanstate->cstate.cs_ExprContext)) + scanstate->cstate.cs_ExprContext, + false)) { prev_matches = true; break; diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index b15e135465d1b42bd29b6c936d4b1c5db800cc35..59287c0f509d815f5663d16ccf1020e99aba8b08 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.32 1999/11/22 17:56:03 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.33 2000/01/19 23:54:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -186,12 +186,12 @@ MJFormSkipQual(List *qualList, char *replaceopname) * MergeCompare * * Compare the keys according to 'compareQual' which is of the - * form: {(key1a > key2a)(key1b > key2b) ...}. + * form: { (key1a > key2a) (key1b > key2b) ... }. * - * (actually, it could also be the form (key1a < key2a)..) + * (actually, it could also be of the form (key1a < key2a)...) * * This is different from calling ExecQual because ExecQual returns - * true only if ALL the comparisions clauses are satisfied. + * true only if ALL the comparison clauses are satisfied. * However, there is an order of significance among the keys with * the first keys being most significant. Therefore, the clauses * are evaluated in order and the 'compareQual' is satisfied @@ -217,14 +217,14 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext) /* ---------------- * for each pair of clauses, test them until - * our compare conditions are satisified + * our compare conditions are satisfied * ---------------- */ eqclause = eqQual; foreach(clause, compareQual) { /* ---------------- - * first test if our compare clause is satisified. + * first test if our compare clause is satisfied. * if so then return true. ignore isDone, don't iterate in * quals. * ---------------- @@ -255,7 +255,7 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext) /* ---------------- * if we get here then it means none of our key greater-than - * conditions were satisified so we return false. + * conditions were satisfied so we return false. * ---------------- */ return false; @@ -547,7 +547,7 @@ ExecMergeJoin(MergeJoin *node) case EXEC_MJ_JOINTEST: MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n"); - qualResult = ExecQual((List *) mergeclauses, econtext); + qualResult = ExecQual((List *) mergeclauses, econtext, false); MJ_DEBUG_QUAL(mergeclauses, qualResult); if (qualResult) @@ -558,14 +558,14 @@ ExecMergeJoin(MergeJoin *node) /* * EXEC_MJ_JOINTUPLES means we have two tuples which - * satisified the merge clause so we join them and then + * satisfied the merge clause so we join them and then * proceed to get the next inner tuple (EXEC_NEXT_INNER). */ case EXEC_MJ_JOINTUPLES: MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n"); mergestate->mj_JoinState = EXEC_MJ_NEXTINNER; - qualResult = ExecQual((List *) qual, econtext); + qualResult = ExecQual((List *) qual, econtext, false); MJ_DEBUG_QUAL(qual, qualResult); if (qualResult) @@ -693,7 +693,7 @@ ExecMergeJoin(MergeJoin *node) innerTupleSlot = econtext->ecxt_innertuple; econtext->ecxt_innertuple = mergestate->mj_MarkedTupleSlot; - qualResult = ExecQual((List *) mergeclauses, econtext); + qualResult = ExecQual((List *) mergeclauses, econtext, false); MJ_DEBUG_QUAL(mergeclauses, qualResult); if (qualResult) @@ -777,7 +777,7 @@ ExecMergeJoin(MergeJoin *node) * we update the marked tuple and go join them. * ---------------- */ - qualResult = ExecQual((List *) mergeclauses, econtext); + qualResult = ExecQual((List *) mergeclauses, econtext, false); MJ_DEBUG_QUAL(mergeclauses, qualResult); if (qualResult) @@ -886,7 +886,7 @@ ExecMergeJoin(MergeJoin *node) * we update the marked tuple and go join them. * ---------------- */ - qualResult = ExecQual((List *) mergeclauses, econtext); + qualResult = ExecQual((List *) mergeclauses, econtext, false); MJ_DEBUG_QUAL(mergeclauses, qualResult); if (qualResult) diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index a75e82c0b11895dd03100977af4587561de2bfd7..861df1d6e0fba7e46891acfd7cfabe5f7b041e4b 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.13 1999/07/16 04:58:51 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.14 2000/01/19 23:54:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -65,7 +65,6 @@ ExecNestLoop(NestLoop *node, Plan *parent) TupleTableSlot *innerTupleSlot; List *qual; - bool qualResult; ExprContext *econtext; /* ---------------- @@ -208,9 +207,8 @@ ExecNestLoop(NestLoop *node, Plan *parent) * ---------------- */ ENL1_printf("testing qualification"); - qualResult = ExecQual((List *) qual, econtext); - if (qualResult) + if (ExecQual((List *) qual, econtext, false)) { /* ---------------- * qualification was satisified so we project and diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 7c8166c6f21e7e9d82ef3ac1908d1f1fccd13c89..ac63d2af425fd6b3440ab551468012e80114e7f8 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -27,7 +27,7 @@ * SeqScan (emp.all) * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.11 1999/05/25 16:08:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.12 2000/01/19 23:54:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -79,7 +79,9 @@ ExecResult(Result *node) */ if (resstate->rs_checkqual) { - bool qualResult = ExecQual((List *) node->resconstantqual, econtext); + bool qualResult = ExecQual((List *) node->resconstantqual, + econtext, + false); resstate->rs_checkqual = false; if (qualResult == false) diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index af599330a096617e4ec5765d22387a365a093289..88dcb741b3d63d8c0e92b895cff74909278c84de 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: executor.h,v 1.40 1999/12/10 03:56:08 momjian Exp $ + * $Id: executor.h,v 1.41 2000/01/19 23:55:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,17 +24,7 @@ */ /* return: true if tuple in slot is NULL, slot is slot to test */ #define TupIsNull(slot) \ -( \ - ((slot) == NULL) ? \ - true \ - : \ - ( \ - ((slot)->val == NULL) ? \ - true \ - : \ - false \ - ) \ -) + ((slot) == NULL || (slot)->val == NULL) /* * prototypes from functions in execAmi.c @@ -88,13 +78,12 @@ extern Datum ExecExtractResult(TupleTableSlot *slot, AttrNumber attnum, extern Datum ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull); -/* stop here */ extern char *GetAttributeByNum(TupleTableSlot *slot, AttrNumber attrno, bool *isNull); extern char *GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull); extern Datum ExecEvalExpr(Node *expression, ExprContext *econtext, bool *isNull, bool *isDone); -extern bool ExecQual(List *qual, ExprContext *econtext); +extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull); extern int ExecTargetListLength(List *targetlist); extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo, bool *isDone); diff --git a/src/test/regress/input/constraints.source b/src/test/regress/input/constraints.source index 5c39c825c1b9217fbfd9fd136ebb878966364fe4..6acef5eb24106eba3fd37c31fe886327bf3661ba 100644 --- a/src/test/regress/input/constraints.source +++ b/src/test/regress/input/constraints.source @@ -89,7 +89,6 @@ CREATE TABLE INSERT_TBL (x INT DEFAULT nextval('insert_seq'), CONSTRAINT INSERT_CON CHECK (x >= 3 AND y <> 'check failed' AND x < 8), CHECK (x + z = 0)); -INSERT INTO INSERT_TBL VALUES (null, null, null); INSERT INTO INSERT_TBL(x,z) VALUES (2, -2); SELECT '' AS zero, * FROM INSERT_TBL; @@ -119,6 +118,13 @@ INSERT INTO INSERT_TBL(y) VALUES ('Y'); SELECT 'eight' AS one, currval('insert_seq'); +-- According to SQL92, it is OK to insert a record that gives rise to NULL +-- constraint-condition results. Postgres used to reject this, but it +-- was wrong: +INSERT INTO INSERT_TBL VALUES (null, null, null); + +SELECT '' AS nine, * FROM INSERT_TBL; + -- -- Check inheritance of defaults and constraints -- @@ -166,7 +172,7 @@ DROP TABLE tmp; -- Check constraints on UPDATE -- -UPDATE INSERT_TBL SET x = NULL WHERE x = 6; +UPDATE INSERT_TBL SET x = NULL WHERE x = 5; UPDATE INSERT_TBL SET x = 6 WHERE x = 6; UPDATE INSERT_TBL SET x = -z, z = -x; UPDATE INSERT_TBL SET x = z, z = x; diff --git a/src/test/regress/output/constraints.source b/src/test/regress/output/constraints.source index f1a107759df5da70592124487bd04f810f361b17..3b9bc2c56c0ea4e3ea4291010660e7d86e4269b8 100644 --- a/src/test/regress/output/constraints.source +++ b/src/test/regress/output/constraints.source @@ -106,8 +106,6 @@ CREATE TABLE INSERT_TBL (x INT DEFAULT nextval('insert_seq'), z INT DEFAULT -1 * currval('insert_seq'), CONSTRAINT INSERT_CON CHECK (x >= 3 AND y <> 'check failed' AND x < 8), CHECK (x + z = 0)); -INSERT INTO INSERT_TBL VALUES (null, null, null); -ERROR: ExecAppend: rejected due to CHECK constraint $2 INSERT INTO INSERT_TBL(x,z) VALUES (2, -2); ERROR: ExecAppend: rejected due to CHECK constraint insert_con SELECT '' AS zero, * FROM INSERT_TBL; @@ -171,6 +169,22 @@ SELECT 'eight' AS one, currval('insert_seq'); eight | 8 (1 row) +-- According to SQL92, it is OK to insert a record that gives rise to NULL +-- constraint-condition results. Postgres used to reject this, but it +-- was wrong: +INSERT INTO INSERT_TBL VALUES (null, null, null); +SELECT '' AS nine, * FROM INSERT_TBL; + nine | x | y | z +------+---+---------------+---- + | 3 | Y | -3 + | 7 | -NULL- | -7 + | 7 | !check failed | -7 + | 4 | -!NULL- | -4 + | 5 | !check failed | -5 + | 6 | -!NULL- | -6 + | | | +(7 rows) + -- -- Check inheritance of defaults and constraints -- @@ -212,7 +226,6 @@ SELECT '' AS three, * FROM INSERT_TBL; (3 rows) INSERT INTO INSERT_TBL SELECT * FROM tmp WHERE yd = 'try again'; -ERROR: ExecAppend: rejected due to CHECK constraint $2 INSERT INTO INSERT_TBL(y,z) SELECT yd, -7 FROM tmp WHERE yd = 'try again'; INSERT INTO INSERT_TBL(y,z) SELECT yd, -8 FROM tmp WHERE yd = 'try again'; ERROR: ExecAppend: rejected due to CHECK constraint insert_con @@ -222,15 +235,15 @@ SELECT '' AS four, * FROM INSERT_TBL; | 4 | Y | -4 | 5 | !check failed | -5 | 6 | try again | -6 + | | try again | | 7 | try again | -7 -(4 rows) +(5 rows) DROP TABLE tmp; -- -- Check constraints on UPDATE -- -UPDATE INSERT_TBL SET x = NULL WHERE x = 6; -ERROR: ExecReplace: rejected due to CHECK constraint $2 +UPDATE INSERT_TBL SET x = NULL WHERE x = 5; UPDATE INSERT_TBL SET x = 6 WHERE x = 6; UPDATE INSERT_TBL SET x = -z, z = -x; UPDATE INSERT_TBL SET x = z, z = x; @@ -239,10 +252,11 @@ SELECT * FROM INSERT_TBL; x | y | z ---+---------------+---- 4 | Y | -4 - 5 | !check failed | -5 + | try again | 7 | try again | -7 + 5 | !check failed | 6 | try again | -6 -(4 rows) +(5 rows) -- DROP TABLE INSERT_TBL; --