1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-30 06:01:21 +03:00

+ NULLs handling

Actually required by multi-column indices support.
	We still don't use btree for 'A is (not) null', but
	now btree keep items with NULL attrs using single rule
	for placing/finding items on pages:
	NULLs greater NOT_NULLs and NULL = NULL.
+ Bulkload code (nbtsort.c) support for multi-column indices
	building and NULLs.
+ Fix for btendscan()->pfree(scanopaque) from Chris Dunlop.
This commit is contained in:
Vadim B. Mikheev
1997-03-24 08:48:16 +00:00
parent 427a87911d
commit 14f6b387b1
5 changed files with 434 additions and 109 deletions

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.15 1997/03/18 18:38:41 scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.16 1997/03/24 08:48:12 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,6 +19,7 @@
#include <storage/bufpage.h>
#include <storage/bufmgr.h>
#include <access/nbtree.h>
#include <catalog/pg_proc.h>
#ifndef HAVE_MEMMOVE
# include <regex/utils.h>
@@ -238,7 +239,20 @@ _bt_skeycmp(Relation rel,
Datum keyDatum;
bool compare;
bool isNull;
bool useEqual = false;
bool keyNull;
if ( strat == BTLessEqualStrategyNumber )
{
useEqual = true;
strat = BTLessStrategyNumber;
}
else if ( strat == BTGreaterEqualStrategyNumber )
{
useEqual = true;
strat = BTGreaterStrategyNumber;
}
item = (BTItem) PageGetItem(page, itemid);
indexTuple = &(item->bti_itup);
@@ -248,27 +262,60 @@ _bt_skeycmp(Relation rel,
for (i=1; i <= keysz; i++) {
entry = &scankey[i-1];
Assert ( entry->sk_attno == i );
attrDatum = index_getattr(indexTuple,
entry->sk_attno,
tupDes,
&isNull);
keyDatum = entry->sk_argument;
/*
* This may happen in a nested loop if an attribute used
* as scan key is null. DZ 29-10-1996
*/
if ((entry->sk_flags & SK_ISNULL) || (isNull)) {
if ((entry->sk_flags & SK_ISNULL) && (isNull)) {
return (true);
} else {
return (false);
}
/* see comments about NULLs handling in btbuild */
if ( entry->sk_flags & SK_ISNULL ) /* key is NULL */
{
Assert ( entry->sk_procedure == NullValueRegProcedure );
keyNull = true;
if ( isNull )
compare = ( strat == BTEqualStrategyNumber ) ? true : false;
else
compare = ( strat == BTGreaterStrategyNumber ) ? true : false;
}
else if ( isNull ) /* key is NOT_NULL and item is NULL */
{
keyNull = false;
compare = ( strat == BTLessStrategyNumber ) ? true : false;
}
else
{
keyNull = false;
compare = _bt_invokestrat(rel, i, strat, keyDatum, attrDatum);
}
compare = _bt_invokestrat(rel, i, strat, keyDatum, attrDatum);
if (!compare)
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 ( keyNull || isNull )
compare = ( keyNull && isNull ) ? true : false;
else
compare = _bt_invokestrat(rel, i, BTEqualStrategyNumber,
keyDatum, attrDatum);
if ( compare ) /* key' and item' attributes are equal */
continue; /* - try to compare next attributes */
}
return (false);
}
}
return (true);
@@ -520,20 +567,24 @@ _bt_compare(Relation rel,
attno = entry->sk_attno;
datum = index_getattr(itup, attno, itupdesc, &null);
/*
* This may happen in a nested loop if an attribute used
* as scan key is null. DZ 29-10-1996
*/
if ((entry->sk_flags & SK_ISNULL) || (null)) {
if ((entry->sk_flags & SK_ISNULL) && (null)) {
return (0);
} else {
return (null ? +1 : -1);
}
/* see comments about NULLs handling in btbuild */
if ( entry->sk_flags & SK_ISNULL ) /* key is NULL */
{
Assert ( entry->sk_procedure == NullValueRegProcedure );
if ( null )
tmpres = (long) 0; /* NULL "=" NULL */
else
tmpres = (long) 1; /* NULL ">" NOT_NULL */
}
else if ( null ) /* key is NOT_NULL and item is NULL */
{
tmpres = (long) -1; /* NOT_NULL "<" NULL */
}
else
{
tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
entry->sk_argument, datum);
}
tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
entry->sk_argument, datum);
result = tmpres;
/* if the keys are unequal, return the difference */
@@ -566,6 +617,7 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
BTItem btitem;
IndexTuple itup;
BTScanOpaque so;
Size keysok;
rel = scan->relation;
so = (BTScanOpaque) scan->opaque;
@@ -596,8 +648,9 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
itup = &btitem->bti_itup;
if (_bt_checkqual(scan, itup))
if ( _bt_checkkeys (scan, itup, &keysok) )
{
Assert (keysok == so->numberOfKeys);
res = FormRetrieveIndexResult(current, &(itup->t_tid));
/* remember which buffer we have pinned and locked */
@@ -605,7 +658,7 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
return (res);
}
} while ( _bt_checkforkeys (scan, itup, so->numberOfFirstKeys) );
} while ( keysok >= so->numberOfFirstKeys );
ItemPointerSetInvalid(current);
so->btso_curbuf = InvalidBuffer;
@@ -644,6 +697,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
int result;
BTScanOpaque so;
ScanKeyData skdata;
Size keysok;
so = (BTScanOpaque) scan->opaque;
if ( so->qual_ok == 0 ) /* may be set by _bt_orderkeys */
@@ -663,6 +717,12 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
* ordered to take advantage of index ordering) to position ourselves
* at the right place in the scan.
*/
/* _bt_orderkeys disallows it, but it's place to add some code latter */
if ( so->keyData[0].sk_flags & SK_ISNULL )
{
elog (WARN, "_bt_first: btree doesn't support is(not)null, yet");
return ((RetrieveIndexResult) NULL);
}
proc = index_getprocid(rel, 1, BTORDER_PROC);
ScanKeyEntryInitialize(&skdata, so->keyData[0].sk_flags, 1, proc,
so->keyData[0].sk_argument);
@@ -706,6 +766,9 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
*/
result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
/* it's yet other place to add some code latter for is(not)null */
strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure);
switch (strat) {
@@ -798,14 +861,14 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
itup = &btitem->bti_itup;
if ( _bt_checkqual(scan, itup) )
if ( _bt_checkkeys (scan, itup, &keysok) )
{
res = FormRetrieveIndexResult(current, &(itup->t_tid));
/* remember which buffer we have pinned */
so->btso_curbuf = buf;
}
else if ( _bt_checkforkeys (scan, itup, so->numberOfFirstKeys) )
else if ( keysok >= so->numberOfFirstKeys )
{
so->btso_curbuf = buf;
return (_bt_next (scan, dir));
@@ -1081,6 +1144,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
IndexTuple itup;
BTScanOpaque so;
RetrieveIndexResult res;
Size keysok;
rel = scan->relation;
current = &(scan->currentItemData);
@@ -1223,13 +1287,14 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
itup = &(btitem->bti_itup);
/* see if we picked a winner */
if (_bt_checkqual(scan, itup)) {
if ( _bt_checkkeys (scan, itup, &keysok) )
{
res = FormRetrieveIndexResult(current, &(itup->t_tid));
/* remember which buffer we have pinned */
so->btso_curbuf = buf;
}
else if ( _bt_checkforkeys (scan, itup, so->numberOfFirstKeys) )
else if ( keysok >= so->numberOfFirstKeys )
{
so->btso_curbuf = buf;
return (_bt_next (scan, dir));