aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c12
-rw-r--r--src/backend/executor/execQual.c68
-rw-r--r--src/backend/executor/execScan.c7
-rw-r--r--src/backend/executor/execUtils.c6
-rw-r--r--src/backend/executor/nodeAgg.c4
-rw-r--r--src/backend/executor/nodeHash.c7
-rw-r--r--src/backend/executor/nodeHashjoin.c6
-rw-r--r--src/backend/executor/nodeIndexscan.c8
-rw-r--r--src/backend/executor/nodeMergejoin.c26
-rw-r--r--src/backend/executor/nodeNestloop.c6
-rw-r--r--src/backend/executor/nodeResult.c6
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)