diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execMain.c | 12 | ||||
-rw-r--r-- | src/backend/executor/execQual.c | 68 | ||||
-rw-r--r-- | src/backend/executor/execScan.c | 7 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 6 | ||||
-rw-r--r-- | src/backend/executor/nodeAgg.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeHash.c | 7 | ||||
-rw-r--r-- | src/backend/executor/nodeHashjoin.c | 6 | ||||
-rw-r--r-- | src/backend/executor/nodeIndexscan.c | 8 | ||||
-rw-r--r-- | src/backend/executor/nodeMergejoin.c | 26 | ||||
-rw-r--r-- | src/backend/executor/nodeNestloop.c | 6 | ||||
-rw-r--r-- | src/backend/executor/nodeResult.c | 6 |
11 files changed, 93 insertions, 63 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index fa98950ac1f..863c13b64ec 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 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; diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index 4196fb7a8a4..4803653e14c 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 d168071e1fe..4d5079ae694 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 0a95c92347f..a40fd015af3 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 1995048e2db..46307a2aa96 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 9d5034307fe..6f5d2cae194 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 b9e3cf58636..6ed14e0ad9a 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 b15e135465d..59287c0f509 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 a75e82c0b11..861df1d6e0f 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 7c8166c6f21..ac63d2af425 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) |