Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6d1efd7

Browse files
committed
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.
1 parent 08fb737 commit 6d1efd7

File tree

20 files changed

+143
-104
lines changed

20 files changed

+143
-104
lines changed

src/backend/access/gist/gist.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
*
88
* IDENTIFICATION
9-
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.49 2000/01/17 23:57:41 tgl Exp $
9+
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.50 2000/01/19 23:54:46 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -169,7 +169,7 @@ gistbuild(Relation heap,
169169
#ifndef OMIT_PARTIAL_INDEX
170170
/* SetSlotContents(slot, htup); */
171171
slot->val = htup;
172-
if (ExecQual((List *) oldPred, econtext) == true)
172+
if (ExecQual((List *) oldPred, econtext, false))
173173
{
174174
ni++;
175175
continue;
@@ -186,7 +186,7 @@ gistbuild(Relation heap,
186186
#ifndef OMIT_PARTIAL_INDEX
187187
/* SetSlotContents(slot, htup); */
188188
slot->val = htup;
189-
if (ExecQual((List *) pred, econtext) == false)
189+
if (! ExecQual((List *) pred, econtext, false))
190190
continue;
191191
#endif /* OMIT_PARTIAL_INDEX */
192192
}

src/backend/access/hash/hash.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.33 1999/12/10 03:55:43 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.34 2000/01/19 23:54:47 tgl Exp $
1111
*
1212
* NOTES
1313
* This file contains only the public interface routines.
@@ -131,7 +131,7 @@ hashbuild(Relation heap,
131131
/* SetSlotContents(slot, htup); */
132132
#ifndef OMIT_PARTIAL_INDEX
133133
slot->val = htup;
134-
if (ExecQual((List *) oldPred, econtext) == true)
134+
if (ExecQual((List *) oldPred, econtext, false))
135135
{
136136
nitups++;
137137
continue;
@@ -148,7 +148,7 @@ hashbuild(Relation heap,
148148
#ifndef OMIT_PARTIAL_INDEX
149149
/* SetSlotContents(slot, htup); */
150150
slot->val = htup;
151-
if (ExecQual((List *) pred, econtext) == false)
151+
if (! ExecQual((List *) pred, econtext, false))
152152
continue;
153153
#endif /* OMIT_PARTIAL_INDEX */
154154
}

src/backend/access/nbtree/nbtree.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Copyright (c) 1994, Regents of the University of California
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.50 1999/12/10 03:55:44 momjian Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.51 2000/01/19 23:54:48 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -167,7 +167,7 @@ btbuild(Relation heap,
167167

168168
/* SetSlotContents(slot, htup); */
169169
slot->val = htup;
170-
if (ExecQual((List *) oldPred, econtext) == true)
170+
if (ExecQual((List *) oldPred, econtext, false))
171171
{
172172
nitups++;
173173
continue;
@@ -184,7 +184,7 @@ btbuild(Relation heap,
184184
#ifndef OMIT_PARTIAL_INDEX
185185
/* SetSlotContents(slot, htup); */
186186
slot->val = htup;
187-
if (ExecQual((List *) pred, econtext) == false)
187+
if (! ExecQual((List *) pred, econtext, false))
188188
continue;
189189
#endif /* OMIT_PARTIAL_INDEX */
190190
}

src/backend/access/rtree/rtree.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.41 1999/12/10 03:55:45 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.42 2000/01/19 23:54:50 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -163,7 +163,7 @@ rtbuild(Relation heap,
163163
#ifndef OMIT_PARTIAL_INDEX
164164
/* SetSlotContents(slot, htup); */
165165
slot->val = htup;
166-
if (ExecQual((List *) oldPred, econtext) == true)
166+
if (ExecQual((List *) oldPred, econtext, false))
167167
{
168168
ni++;
169169
continue;
@@ -180,7 +180,7 @@ rtbuild(Relation heap,
180180
#ifndef OMIT_PARTIAL_INDEX
181181
/* SetSlotContents(slot, htup); */
182182
slot->val = htup;
183-
if (ExecQual((List *) pred, econtext) == false)
183+
if (! ExecQual((List *) pred, econtext, false))
184184
continue;
185185
#endif /* OMIT_PARTIAL_INDEX */
186186
}

src/backend/catalog/index.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.102 2000/01/17 23:57:43 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.103 2000/01/19 23:54:51 tgl Exp $
1111
*
1212
*
1313
* INTERFACE ROUTINES
@@ -1590,7 +1590,7 @@ DefaultBuild(Relation heapRelation,
15901590
{
15911591
/* SetSlotContents(slot, heapTuple); */
15921592
slot->val = heapTuple;
1593-
if (ExecQual((List *) oldPred, econtext) == true)
1593+
if (ExecQual((List *) oldPred, econtext, false))
15941594
{
15951595
indtuples++;
15961596
continue;
@@ -1605,7 +1605,7 @@ DefaultBuild(Relation heapRelation,
16051605
{
16061606
/* SetSlotContents(slot, heapTuple); */
16071607
slot->val = heapTuple;
1608-
if (ExecQual((List *) predicate, econtext) == false)
1608+
if (! ExecQual((List *) predicate, econtext, false))
16091609
continue;
16101610
}
16111611
#endif /* OMIT_PARTIAL_INDEX */

src/backend/commands/copy.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
*
88
* IDENTIFICATION
9-
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.96 2000/01/16 21:37:50 tgl Exp $
9+
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.97 2000/01/19 23:54:56 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -886,7 +886,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
886886
*/
887887
slot->val = tuple;
888888
/* SetSlotContents(slot, tuple); */
889-
if (ExecQual((List *) indexPred[i], econtext) == false)
889+
if (! ExecQual((List *) indexPred[i], econtext, false))
890890
continue;
891891
#endif /* OMIT_PARTIAL_INDEX */
892892
}

src/backend/executor/execMain.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
*
2828
* IDENTIFICATION
29-
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.105 2000/01/17 23:57:45 tgl Exp $
29+
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.106 2000/01/19 23:54:53 tgl Exp $
3030
*
3131
*-------------------------------------------------------------------------
3232
*/
@@ -1487,7 +1487,6 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
14871487
RangeTblEntry *rte = makeNode(RangeTblEntry);
14881488
List *rtlist;
14891489
List *qual;
1490-
bool res;
14911490
int i;
14921491

14931492
slot->val = tuple;
@@ -1526,9 +1525,12 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
15261525
{
15271526
qual = estate->es_result_relation_constraints[i];
15281527

1529-
res = ExecQual(qual, econtext);
1530-
1531-
if (!res)
1528+
/*
1529+
* NOTE: SQL92 specifies that a NULL result from a constraint
1530+
* expression is not to be treated as a failure. Therefore,
1531+
* tell ExecQual to return TRUE for NULL.
1532+
*/
1533+
if (! ExecQual(qual, econtext, true))
15321534
return check[i].ccname;
15331535
}
15341536

src/backend/executor/execQual.c

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.65 2000/01/10 17:14:34 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.66 2000/01/19 23:54:54 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1283,12 +1283,33 @@ ExecEvalExpr(Node *expression,
12831283
/* ----------------------------------------------------------------
12841284
* ExecQual
12851285
*
1286-
* Evaluates a conjunctive boolean expression and returns t
1287-
* iff none of the subexpressions are false (or null).
1286+
* Evaluates a conjunctive boolean expression (qual list) and
1287+
* returns true iff none of the subexpressions are false.
1288+
* (We also return true if the list is empty.)
1289+
*
1290+
* If some of the subexpressions yield NULL but none yield FALSE,
1291+
* then the result of the conjunction is NULL (ie, unknown)
1292+
* according to three-valued boolean logic. In this case,
1293+
* we return the value specified by the "resultForNull" parameter.
1294+
*
1295+
* Callers evaluating WHERE clauses should pass resultForNull=FALSE,
1296+
* since SQL specifies that tuples with null WHERE results do not
1297+
* get selected. On the other hand, callers evaluating constraint
1298+
* conditions should pass resultForNull=TRUE, since SQL also specifies
1299+
* that NULL constraint conditions are not failures.
1300+
*
1301+
* NOTE: it would not be correct to use this routine to evaluate an
1302+
* AND subclause of a boolean expression; for that purpose, a NULL
1303+
* result must be returned as NULL so that it can be properly treated
1304+
* in the next higher operator (cf. ExecEvalAnd and ExecEvalOr).
1305+
* This routine is only used in contexts where a complete expression
1306+
* is being evaluated and we know that NULL can be treated the same
1307+
* as one boolean result or the other.
1308+
*
12881309
* ----------------------------------------------------------------
12891310
*/
12901311
bool
1291-
ExecQual(List *qual, ExprContext *econtext)
1312+
ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
12921313
{
12931314
List *qlist;
12941315

@@ -1302,37 +1323,48 @@ ExecQual(List *qual, ExprContext *econtext)
13021323
IncrProcessed();
13031324

13041325
/*
1305-
* a "qual" is a list of clauses. To evaluate the qual, we evaluate
1306-
* each of the clauses in the list. (For an empty list, we'll return
1307-
* TRUE.)
1326+
* Evaluate the qual conditions one at a time. If we find a FALSE
1327+
* result, we can stop evaluating and return FALSE --- the AND result
1328+
* must be FALSE. Also, if we find a NULL result when resultForNull
1329+
* is FALSE, we can stop and return FALSE --- the AND result must be
1330+
* FALSE or NULL in that case, and the caller doesn't care which.
13081331
*
1309-
* If any of the clauses return NULL, we treat this as FALSE. This
1310-
* is correct per the SQL spec: if any ANDed conditions are NULL, then
1311-
* the AND result is either FALSE or NULL, and in either case the
1312-
* WHERE condition fails. NOTE: it would NOT be correct to use this
1313-
* simplified logic in a sub-clause; ExecEvalAnd must do the full
1314-
* three-state condition evaluation. We can get away with simpler
1315-
* logic here because we know how the result will be used.
1332+
* If we get to the end of the list, we can return TRUE. This will
1333+
* happen when the AND result is indeed TRUE, or when the AND result
1334+
* is NULL (one or more NULL subresult, with all the rest TRUE) and
1335+
* the caller has specified resultForNull = TRUE.
13161336
*/
1337+
13171338
foreach(qlist, qual)
13181339
{
13191340
Node *clause = (Node *) lfirst(qlist);
13201341
Datum expr_value;
13211342
bool isNull;
13221343
bool isDone;
13231344

1324-
/* if there is a null clause, consider the qualification to fail */
1345+
/*
1346+
* If there is a null clause, consider the qualification to fail.
1347+
* XXX is this still correct for constraints? It probably shouldn't
1348+
* happen at all ...
1349+
*/
13251350
if (clause == NULL)
13261351
return false;
13271352
/*
13281353
* pass isDone, but ignore it. We don't iterate over multiple returns
13291354
* in the qualifications.
13301355
*/
13311356
expr_value = ExecEvalExpr(clause, econtext, &isNull, &isDone);
1357+
13321358
if (isNull)
1333-
return false; /* treat NULL as FALSE */
1334-
if (DatumGetInt32(expr_value) == 0)
1335-
return false;
1359+
{
1360+
if (resultForNull == false)
1361+
return false; /* treat NULL as FALSE */
1362+
}
1363+
else
1364+
{
1365+
if (DatumGetInt32(expr_value) == 0)
1366+
return false; /* definitely FALSE */
1367+
}
13361368
}
13371369

13381370
return true;

src/backend/executor/execScan.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.9 1999/02/13 23:15:18 momjian Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.10 2000/01/19 23:54:54 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -137,9 +137,10 @@ ExecScan(Scan *node,
137137

138138
/*
139139
* add a check for non-nil qual here to avoid a function call to
140-
* ExecQual() when the qual is nil
140+
* ExecQual() when the qual is nil ... saves only a few cycles,
141+
* but they add up ...
141142
*/
142-
if (!qual || ExecQual(qual, econtext) == true)
143+
if (!qual || ExecQual(qual, econtext, false))
143144
break;
144145
}
145146

src/backend/executor/execUtils.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.51 1999/12/20 10:40:42 wieck Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.52 2000/01/19 23:54:54 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1137,7 +1137,6 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
11371137
IndexInfo **indexInfoArray;
11381138
IndexInfo *indexInfo;
11391139
Node *predicate;
1140-
bool satisfied;
11411140
ExprContext *econtext;
11421141
InsertIndexResult result;
11431142
int numberOfAttributes;
@@ -1178,8 +1177,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
11781177
econtext->ecxt_scantuple = slot;
11791178

11801179
/* Skip this index-update if the predicate isn't satisfied */
1181-
satisfied = ExecQual((List *) predicate, econtext);
1182-
if (satisfied == false)
1180+
if (! ExecQual((List *) predicate, econtext, false))
11831181
continue;
11841182
}
11851183

src/backend/executor/nodeAgg.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* Copyright (c) 1994, Regents of the University of California
3232
*
3333
* IDENTIFICATION
34-
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.60 1999/12/13 01:26:52 tgl Exp $
34+
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.61 2000/01/19 23:54:54 tgl Exp $
3535
*
3636
*-------------------------------------------------------------------------
3737
*/
@@ -580,7 +580,7 @@ ExecAgg(Agg *node)
580580
* Otherwise, return the tuple.
581581
*/
582582
}
583-
while (! ExecQual(node->plan.qual, econtext));
583+
while (! ExecQual(node->plan.qual, econtext, false));
584584

585585
return resultSlot;
586586
}

src/backend/executor/nodeHash.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Copyright (c) 1994, Regents of the University of California
77
*
88
*
9-
* $Id: nodeHash.c,v 1.42 2000/01/09 00:26:18 tgl Exp $
9+
* $Id: nodeHash.c,v 1.43 2000/01/19 23:54:55 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -584,7 +584,6 @@ ExecScanHashBucket(HashJoinState *hjstate,
584584
{
585585
HeapTuple heapTuple = &hashTuple->htup;
586586
TupleTableSlot *inntuple;
587-
bool qualResult;
588587

589588
/* insert hashtable's tuple into exec slot so ExecQual sees it */
590589
inntuple = ExecStoreTuple(heapTuple, /* tuple to store */
@@ -593,9 +592,7 @@ ExecScanHashBucket(HashJoinState *hjstate,
593592
false); /* do not pfree this tuple */
594593
econtext->ecxt_innertuple = inntuple;
595594

596-
qualResult = ExecQual(hjclauses, econtext);
597-
598-
if (qualResult)
595+
if (ExecQual(hjclauses, econtext, false))
599596
{
600597
hjstate->hj_CurTuple = hashTuple;
601598
return heapTuple;

0 commit comments

Comments
 (0)