diff options
Diffstat (limited to 'src/backend/access/nbtree/nbtinsert.c')
-rw-r--r-- | src/backend/access/nbtree/nbtinsert.c | 120 |
1 files changed, 112 insertions, 8 deletions
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 89a80c23970..06c54a456dc 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.10 1997/01/25 21:08:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.11 1997/03/24 08:48:09 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include <access/nbtree.h> #include <access/heapam.h> #include <storage/bufmgr.h> +#include <fmgr.h> #ifndef HAVE_MEMMOVE # include <regex/utils.h> @@ -33,6 +34,7 @@ static void _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf); static OffsetNumber _bt_pgaddtup(Relation rel, Buffer buf, int keysz, ScanKey itup_scankey, Size itemsize, BTItem btitem, BTItem afteritem); static bool _bt_goesonpg(Relation rel, Buffer buf, Size keysz, ScanKey scankey, BTItem afteritem); static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, Oid bti_oid, BTItem newItem); +static bool _bt_isequal (TupleDesc itupdesc, Page page, OffsetNumber offnum, int keysz, ScanKey scankey); /* * _bt_doinsert() -- Handle insertion of a single btitem in the tree. @@ -104,8 +106,16 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, Relation heapRel itupdesc = RelationGetTupleDescriptor(rel); nbuf = InvalidBuffer; opaque = (BTPageOpaque) PageGetSpecialPointer(page); + /* + * _bt_compare returns 0 for (1,NULL) and (1,NULL) - + * this's how we handling NULLs - and so we must not use + * _bt_compare in real comparison, but only for + * ordering/finding items on pages. - vadim 03/24/97 + while ( !_bt_compare (rel, itupdesc, page, natts, itup_scankey, offset) ) + */ + while ( _bt_isequal (itupdesc, page, offset, natts, itup_scankey) ) { /* they're equal */ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offset)); itup = &(btitem->bti_itup); @@ -123,8 +133,8 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, Relation heapRel { /* move right ? */ if ( P_RIGHTMOST (opaque) ) break; - if ( _bt_compare (rel, itupdesc, page, - natts, itup_scankey, P_HIKEY) ) + if ( !_bt_isequal (itupdesc, page, P_HIKEY, + natts, itup_scankey) ) break; /* * min key of the right page is the same, @@ -939,18 +949,70 @@ _bt_itemcmp(Relation rel, IndexTuple indexTuple1, indexTuple2; Datum attrDatum1, attrDatum2; int i; - bool isNull; + bool isFirstNull, isSecondNull; bool compare; + bool useEqual = false; + + if ( strat == BTLessEqualStrategyNumber ) + { + useEqual = true; + strat = BTLessStrategyNumber; + } + else if ( strat == BTGreaterEqualStrategyNumber ) + { + useEqual = true; + strat = BTGreaterStrategyNumber; + } tupDes = RelationGetTupleDescriptor(rel); indexTuple1 = &(item1->bti_itup); indexTuple2 = &(item2->bti_itup); for (i = 1; i <= keysz; i++) { - attrDatum1 = index_getattr(indexTuple1, i, tupDes, &isNull); - attrDatum2 = index_getattr(indexTuple2, i, tupDes, &isNull); - compare = _bt_invokestrat(rel, i, strat, attrDatum1, attrDatum2); - if (!compare) { + attrDatum1 = index_getattr(indexTuple1, i, tupDes, &isFirstNull); + attrDatum2 = index_getattr(indexTuple2, i, tupDes, &isSecondNull); + + /* see comments about NULLs handling in btbuild */ + if ( isFirstNull ) /* attr in item1 is NULL */ + { + if ( isSecondNull ) /* attr in item2 is NULL too */ + compare = ( strat == BTEqualStrategyNumber ) ? true : false; + else + compare = ( strat == BTGreaterStrategyNumber ) ? true : false; + } + else if ( isSecondNull ) /* attr in item1 is NOT_NULL and */ + { /* and attr in item2 is NULL */ + compare = ( strat == BTLessStrategyNumber ) ? true : false; + } + else + { + compare = _bt_invokestrat(rel, i, strat, attrDatum1, attrDatum2); + } + + if ( compare ) /* true for one of ">, <, =" */ + { + if ( strat != BTEqualStrategyNumber ) + return (true); + } + else /* false for one of ">, <, =" */ + { + if ( strat == BTEqualStrategyNumber ) + return (false); + /* + * if original strat was "<=, >=" OR + * "<, >" but some attribute(s) left + * - need to test for Equality + */ + if ( useEqual || i < keysz ) + { + if ( isFirstNull || isSecondNull ) + compare = ( isFirstNull && isSecondNull ) ? true : false; + else + compare = _bt_invokestrat(rel, i, BTEqualStrategyNumber, + attrDatum1, attrDatum2); + if ( compare ) /* item1' and item2' attributes are equal */ + continue; /* - try to compare next attributes */ + } return (false); } } @@ -1015,3 +1077,45 @@ _bt_updateitem(Relation rel, ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid)); } + +/* + * _bt_isequal - used in _bt_doinsert in check for duplicates. + * + * Rule is simple: NOT_NULL not equal NULL, NULL not_equal NULL too. + */ +static bool +_bt_isequal (TupleDesc itupdesc, Page page, OffsetNumber offnum, + int keysz, ScanKey scankey) +{ + Datum datum; + BTItem btitem; + IndexTuple itup; + ScanKey entry; + AttrNumber attno; + long result; + int i; + bool null; + + btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum)); + itup = &(btitem->bti_itup); + + for (i = 1; i <= keysz; i++) + { + entry = &scankey[i - 1]; + attno = entry->sk_attno; + Assert (attno == i); + datum = index_getattr(itup, attno, itupdesc, &null); + + /* NULLs are not equal */ + if ( entry->sk_flags & SK_ISNULL || null ) + return (false); + + result = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure, + entry->sk_argument, datum); + if (result != 0) + return (false); + } + + /* by here, the keys are equal */ + return (true); +} |