diff options
Diffstat (limited to 'src/backend/access/hash/hashsearch.c')
| -rw-r--r-- | src/backend/access/hash/hashsearch.c | 758 |
1 files changed, 401 insertions, 357 deletions
diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c index bc67b7f5aa..0a42ad0506 100644 --- a/src/backend/access/hash/hashsearch.c +++ b/src/backend/access/hash/hashsearch.c @@ -1,423 +1,467 @@ /*------------------------------------------------------------------------- * * hashsearch.c-- - * search code for postgres hash tables + * search code for postgres hash tables * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/hash/hashsearch.c,v 1.10 1997/06/28 05:45:40 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/hash/hashsearch.c,v 1.11 1997/09/07 04:38:02 momjian Exp $ * *------------------------------------------------------------------------- */ #include <postgres.h> - + #include <access/hash.h> #include <storage/bufmgr.h> #ifndef HAVE_MEMMOVE -# include "regex/utils.h" +#include "regex/utils.h" #else -# include <string.h> -#endif +#include <string.h> +#endif /* - * _hash_search() -- Finds the page/bucket that the contains the - * scankey and loads it into *bufP. the buffer has a read lock. + * _hash_search() -- Finds the page/bucket that the contains the + * scankey and loads it into *bufP. the buffer has a read lock. */ void _hash_search(Relation rel, - int keysz, - ScanKey scankey, - Buffer *bufP, - HashMetaPage metap) + int keysz, + ScanKey scankey, + Buffer * bufP, + HashMetaPage metap) { - BlockNumber blkno; - Datum keyDatum; - Bucket bucket; - - if (scankey == (ScanKey) NULL || - (keyDatum = scankey[0].sk_argument) == (Datum) NULL) { - /* - * If the scankey argument is NULL, all tuples will satisfy - * the scan so we start the scan at the first bucket (bucket - * 0). - */ - bucket = 0; - } else { - bucket = _hash_call(rel, metap, keyDatum); - } - - blkno = BUCKET_TO_BLKNO(bucket); - - *bufP = _hash_getbuf(rel, blkno, HASH_READ); + BlockNumber blkno; + Datum keyDatum; + Bucket bucket; + + if (scankey == (ScanKey) NULL || + (keyDatum = scankey[0].sk_argument) == (Datum) NULL) + { + + /* + * If the scankey argument is NULL, all tuples will satisfy the + * scan so we start the scan at the first bucket (bucket 0). + */ + bucket = 0; + } + else + { + bucket = _hash_call(rel, metap, keyDatum); + } + + blkno = BUCKET_TO_BLKNO(bucket); + + *bufP = _hash_getbuf(rel, blkno, HASH_READ); } /* - * _hash_next() -- Get the next item in a scan. + * _hash_next() -- Get the next item in a scan. * - * On entry, we have a valid currentItemData in the scan, and a - * read lock on the page that contains that item. We do not have - * the page pinned. We return the next item in the scan. On - * exit, we have the page containing the next item locked but not - * pinned. + * On entry, we have a valid currentItemData in the scan, and a + * read lock on the page that contains that item. We do not have + * the page pinned. We return the next item in the scan. On + * exit, we have the page containing the next item locked but not + * pinned. */ RetrieveIndexResult _hash_next(IndexScanDesc scan, ScanDirection dir) { - Relation rel; - Buffer buf; - Buffer metabuf; - Page page; - OffsetNumber offnum; - RetrieveIndexResult res; - ItemPointer current; - HashItem hitem; - IndexTuple itup; - HashScanOpaque so; - - rel = scan->relation; - so = (HashScanOpaque) scan->opaque; - current = &(scan->currentItemData); - - metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ); - - /* - * XXX 10 may 91: somewhere there's a bug in our management of the - * cached buffer for this scan. wei discovered it. the following - * is a workaround so he can work until i figure out what's going on. - */ - - if (!BufferIsValid(so->hashso_curbuf)) { - so->hashso_curbuf = _hash_getbuf(rel, - ItemPointerGetBlockNumber(current), - HASH_READ); - } - - /* we still have the buffer pinned and locked */ - buf = so->hashso_curbuf; - - /* - * step to next valid tuple. note that _hash_step releases our - * lock on 'metabuf'; if we switch to a new 'buf' while looking - * for the next tuple, we come back with a lock on that buffer. - */ - if (!_hash_step(scan, &buf, dir, metabuf)) { - return ((RetrieveIndexResult) NULL); - } - - /* if we're here, _hash_step found a valid tuple */ - current = &(scan->currentItemData); - offnum = ItemPointerGetOffsetNumber(current); - page = BufferGetPage(buf); - _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE); - hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum)); - itup = &hitem->hash_itup; - res = FormRetrieveIndexResult(current, &(itup->t_tid)); - - return (res); + Relation rel; + Buffer buf; + Buffer metabuf; + Page page; + OffsetNumber offnum; + RetrieveIndexResult res; + ItemPointer current; + HashItem hitem; + IndexTuple itup; + HashScanOpaque so; + + rel = scan->relation; + so = (HashScanOpaque) scan->opaque; + current = &(scan->currentItemData); + + metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ); + + /* + * XXX 10 may 91: somewhere there's a bug in our management of the + * cached buffer for this scan. wei discovered it. the following is + * a workaround so he can work until i figure out what's going on. + */ + + if (!BufferIsValid(so->hashso_curbuf)) + { + so->hashso_curbuf = _hash_getbuf(rel, + ItemPointerGetBlockNumber(current), + HASH_READ); + } + + /* we still have the buffer pinned and locked */ + buf = so->hashso_curbuf; + + /* + * step to next valid tuple. note that _hash_step releases our lock + * on 'metabuf'; if we switch to a new 'buf' while looking for the + * next tuple, we come back with a lock on that buffer. + */ + if (!_hash_step(scan, &buf, dir, metabuf)) + { + return ((RetrieveIndexResult) NULL); + } + + /* if we're here, _hash_step found a valid tuple */ + current = &(scan->currentItemData); + offnum = ItemPointerGetOffsetNumber(current); + page = BufferGetPage(buf); + _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); + hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum)); + itup = &hitem->hash_itup; + res = FormRetrieveIndexResult(current, &(itup->t_tid)); + + return (res); } static void _hash_readnext(Relation rel, - Buffer *bufp, Page *pagep, HashPageOpaque *opaquep) + Buffer * bufp, Page * pagep, HashPageOpaque * opaquep) { - BlockNumber blkno; - - blkno = (*opaquep)->hasho_nextblkno; - _hash_relbuf(rel, *bufp, HASH_READ); - *bufp = InvalidBuffer; - if (BlockNumberIsValid(blkno)) { - *bufp = _hash_getbuf(rel, blkno, HASH_READ); - *pagep = BufferGetPage(*bufp); - _hash_checkpage(*pagep, LH_OVERFLOW_PAGE); - *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); - Assert(!PageIsEmpty(*pagep)); - } + BlockNumber blkno; + + blkno = (*opaquep)->hasho_nextblkno; + _hash_relbuf(rel, *bufp, HASH_READ); + *bufp = InvalidBuffer; + if (BlockNumberIsValid(blkno)) + { + *bufp = _hash_getbuf(rel, blkno, HASH_READ); + *pagep = BufferGetPage(*bufp); + _hash_checkpage(*pagep, LH_OVERFLOW_PAGE); + *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); + Assert(!PageIsEmpty(*pagep)); + } } static void _hash_readprev(Relation rel, - Buffer *bufp, Page *pagep, HashPageOpaque *opaquep) + Buffer * bufp, Page * pagep, HashPageOpaque * opaquep) { - BlockNumber blkno; - - blkno = (*opaquep)->hasho_prevblkno; - _hash_relbuf(rel, *bufp, HASH_READ); - *bufp = InvalidBuffer; - if (BlockNumberIsValid(blkno)) { - *bufp = _hash_getbuf(rel, blkno, HASH_READ); - *pagep = BufferGetPage(*bufp); - _hash_checkpage(*pagep, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE); - *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); - if (PageIsEmpty(*pagep)) { - Assert((*opaquep)->hasho_flag & LH_BUCKET_PAGE); - _hash_relbuf(rel, *bufp, HASH_READ); - *bufp = InvalidBuffer; + BlockNumber blkno; + + blkno = (*opaquep)->hasho_prevblkno; + _hash_relbuf(rel, *bufp, HASH_READ); + *bufp = InvalidBuffer; + if (BlockNumberIsValid(blkno)) + { + *bufp = _hash_getbuf(rel, blkno, HASH_READ); + *pagep = BufferGetPage(*bufp); + _hash_checkpage(*pagep, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); + *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); + if (PageIsEmpty(*pagep)) + { + Assert((*opaquep)->hasho_flag & LH_BUCKET_PAGE); + _hash_relbuf(rel, *bufp, HASH_READ); + *bufp = InvalidBuffer; + } } - } } /* - * _hash_first() -- Find the first item in a scan. + * _hash_first() -- Find the first item in a scan. * - * Return the RetrieveIndexResult of the first item in the tree that - * satisfies the qualificatin associated with the scan descriptor. On - * exit, the page containing the current index tuple is read locked - * and pinned, and the scan's opaque data entry is updated to - * include the buffer. + * Return the RetrieveIndexResult of the first item in the tree that + * satisfies the qualificatin associated with the scan descriptor. On + * exit, the page containing the current index tuple is read locked + * and pinned, and the scan's opaque data entry is updated to + * include the buffer. */ RetrieveIndexResult _hash_first(IndexScanDesc scan, ScanDirection dir) { - Relation rel; - Buffer buf; - Buffer metabuf; - Page page; - HashPageOpaque opaque; - HashMetaPage metap; - HashItem hitem; - IndexTuple itup; - ItemPointer current; - OffsetNumber offnum; - RetrieveIndexResult res; - HashScanOpaque so; - - rel = scan->relation; - so = (HashScanOpaque) scan->opaque; - current = &(scan->currentItemData); - - metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ); - metap = (HashMetaPage) BufferGetPage(metabuf); - _hash_checkpage((Page) metap, LH_META_PAGE); - - /* - * XXX -- The attribute number stored in the scan key is the attno - * in the heap relation. We need to transmogrify this into - * the index relation attno here. For the moment, we have - * hardwired attno == 1. - */ - - /* find the correct bucket page and load it into buf */ - _hash_search(rel, 1, scan->keyData, &buf, metap); - page = BufferGetPage(buf); - _hash_checkpage(page, LH_BUCKET_PAGE); - opaque = (HashPageOpaque) PageGetSpecialPointer(page); - - /* - * if we are scanning forward, we need to find the first non-empty - * page (if any) in the bucket chain. since overflow pages are - * never empty, this had better be either the bucket page or the - * first overflow page. - * - * if we are scanning backward, we always go all the way to the - * end of the bucket chain. - */ - if (PageIsEmpty(page)) { - if (BlockNumberIsValid(opaque->hasho_nextblkno)) { - _hash_readnext(rel, &buf, &page, &opaque); - } else { - ItemPointerSetInvalid(current); - so->hashso_curbuf = InvalidBuffer; - /* - * If there is no scankeys, all tuples will satisfy - * the scan - so we continue in _hash_step to get - * tuples from all buckets. - vadim 04/29/97 - */ - if ( scan->numberOfKeys >= 1 ) - { - _hash_relbuf(rel, buf, HASH_READ); - _hash_relbuf(rel, metabuf, HASH_READ); - return ((RetrieveIndexResult) NULL); - } + Relation rel; + Buffer buf; + Buffer metabuf; + Page page; + HashPageOpaque opaque; + HashMetaPage metap; + HashItem hitem; + IndexTuple itup; + ItemPointer current; + OffsetNumber offnum; + RetrieveIndexResult res; + HashScanOpaque so; + + rel = scan->relation; + so = (HashScanOpaque) scan->opaque; + current = &(scan->currentItemData); + + metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ); + metap = (HashMetaPage) BufferGetPage(metabuf); + _hash_checkpage((Page) metap, LH_META_PAGE); + + /* + * XXX -- The attribute number stored in the scan key is the attno in + * the heap relation. We need to transmogrify this into the index + * relation attno here. For the moment, we have hardwired attno == 1. + */ + + /* find the correct bucket page and load it into buf */ + _hash_search(rel, 1, scan->keyData, &buf, metap); + page = BufferGetPage(buf); + _hash_checkpage(page, LH_BUCKET_PAGE); + opaque = (HashPageOpaque) PageGetSpecialPointer(page); + + /* + * if we are scanning forward, we need to find the first non-empty + * page (if any) in the bucket chain. since overflow pages are never + * empty, this had better be either the bucket page or the first + * overflow page. + * + * if we are scanning backward, we always go all the way to the end of + * the bucket chain. + */ + if (PageIsEmpty(page)) + { + if (BlockNumberIsValid(opaque->hasho_nextblkno)) + { + _hash_readnext(rel, &buf, &page, &opaque); + } + else + { + ItemPointerSetInvalid(current); + so->hashso_curbuf = InvalidBuffer; + + /* + * If there is no scankeys, all tuples will satisfy the scan - + * so we continue in _hash_step to get tuples from all + * buckets. - vadim 04/29/97 + */ + if (scan->numberOfKeys >= 1) + { + _hash_relbuf(rel, buf, HASH_READ); + _hash_relbuf(rel, metabuf, HASH_READ); + return ((RetrieveIndexResult) NULL); + } + } } - } - if (ScanDirectionIsBackward(dir)) { - while (BlockNumberIsValid(opaque->hasho_nextblkno)) { - _hash_readnext(rel, &buf, &page, &opaque); + if (ScanDirectionIsBackward(dir)) + { + while (BlockNumberIsValid(opaque->hasho_nextblkno)) + { + _hash_readnext(rel, &buf, &page, &opaque); + } + } + + if (!_hash_step(scan, &buf, dir, metabuf)) + { + return ((RetrieveIndexResult) NULL); } - } - - if (!_hash_step(scan, &buf, dir, metabuf)) { - return ((RetrieveIndexResult) NULL); - } - - /* if we're here, _hash_step found a valid tuple */ - current = &(scan->currentItemData); - offnum = ItemPointerGetOffsetNumber(current); - page = BufferGetPage(buf); - _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE); - hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum)); - itup = &hitem->hash_itup; - res = FormRetrieveIndexResult(current, &(itup->t_tid)); - - return (res); + + /* if we're here, _hash_step found a valid tuple */ + current = &(scan->currentItemData); + offnum = ItemPointerGetOffsetNumber(current); + page = BufferGetPage(buf); + _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); + hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum)); + itup = &hitem->hash_itup; + res = FormRetrieveIndexResult(current, &(itup->t_tid)); + + return (res); } /* - * _hash_step() -- step to the next valid item in a scan in the bucket. + * _hash_step() -- step to the next valid item in a scan in the bucket. * - * If no valid record exists in the requested direction, return - * false. Else, return true and set the CurrentItemData for the - * scan to the right thing. - * - * 'bufP' points to the buffer which contains the current page - * that we'll step through. + * If no valid record exists in the requested direction, return + * false. Else, return true and set the CurrentItemData for the + * scan to the right thing. * - * 'metabuf' is released when this returns. + * 'bufP' points to the buffer which contains the current page + * that we'll step through. + * + * 'metabuf' is released when this returns. */ bool -_hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir, Buffer metabuf) +_hash_step(IndexScanDesc scan, Buffer * bufP, ScanDirection dir, Buffer metabuf) { - Relation rel; - ItemPointer current; - HashScanOpaque so; - int allbuckets; - HashMetaPage metap; - Buffer buf; - Page page; - HashPageOpaque opaque; - OffsetNumber maxoff; - OffsetNumber offnum; - Bucket bucket; - BlockNumber blkno; - HashItem hitem; - IndexTuple itup; - - rel = scan->relation; - current = &(scan->currentItemData); - so = (HashScanOpaque) scan->opaque; - allbuckets = (scan->numberOfKeys < 1); - - metap = (HashMetaPage) BufferGetPage(metabuf); - _hash_checkpage((Page) metap, LH_META_PAGE); - - buf = *bufP; - page = BufferGetPage(buf); - _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE); - opaque = (HashPageOpaque) PageGetSpecialPointer(page); - - /* - * If _hash_step is called from _hash_first, current will not be - * valid, so we can't dereference it. However, in that case, we - * presumably want to start at the beginning/end of the page... - */ - maxoff = PageGetMaxOffsetNumber(page); - if (ItemPointerIsValid(current)) { - offnum = ItemPointerGetOffsetNumber(current); - } else { - offnum = InvalidOffsetNumber; - } - - /* - * 'offnum' now points to the last tuple we have seen (if any). - * - * continue to step through tuples until: - * 1) we get to the end of the bucket chain or - * 2) we find a valid tuple. - */ - do { - bucket = opaque->hasho_bucket; - - switch (dir) { - case ForwardScanDirection: - if (offnum != InvalidOffsetNumber) { - offnum = OffsetNumberNext(offnum); /* move forward */ - } else { - offnum = FirstOffsetNumber; /* new page */ - } - while (offnum > maxoff) { - /* - * either this page is empty (maxoff == - * InvalidOffsetNumber) or we ran off the end. - */ - _hash_readnext(rel, &buf, &page, &opaque); - if (BufferIsInvalid(buf)) { /* end of chain */ - if (allbuckets && bucket < metap->hashm_maxbucket) { - ++bucket; - blkno = BUCKET_TO_BLKNO(bucket); - buf = _hash_getbuf(rel, blkno, HASH_READ); - page = BufferGetPage(buf); - _hash_checkpage(page, LH_BUCKET_PAGE); - opaque = (HashPageOpaque) PageGetSpecialPointer(page); - Assert(opaque->hasho_bucket == bucket); - while (PageIsEmpty(page) && - BlockNumberIsValid(opaque->hasho_nextblkno)) { - _hash_readnext(rel, &buf, &page, &opaque); + Relation rel; + ItemPointer current; + HashScanOpaque so; + int allbuckets; + HashMetaPage metap; + Buffer buf; + Page page; + HashPageOpaque opaque; + OffsetNumber maxoff; + OffsetNumber offnum; + Bucket bucket; + BlockNumber blkno; + HashItem hitem; + IndexTuple itup; + + rel = scan->relation; + current = &(scan->currentItemData); + so = (HashScanOpaque) scan->opaque; + allbuckets = (scan->numberOfKeys < 1); + + metap = (HashMetaPage) BufferGetPage(metabuf); + _hash_checkpage((Page) metap, LH_META_PAGE); + + buf = *bufP; + page = BufferGetPage(buf); + _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); + opaque = (HashPageOpaque) PageGetSpecialPointer(page); + + /* + * If _hash_step is called from _hash_first, current will not be + * valid, so we can't dereference it. However, in that case, we + * presumably want to start at the beginning/end of the page... + */ + maxoff = PageGetMaxOffsetNumber(page); + if (ItemPointerIsValid(current)) + { + offnum = ItemPointerGetOffsetNumber(current); + } + else + { + offnum = InvalidOffsetNumber; + } + + /* + * 'offnum' now points to the last tuple we have seen (if any). + * + * continue to step through tuples until: 1) we get to the end of the + * bucket chain or 2) we find a valid tuple. + */ + do + { + bucket = opaque->hasho_bucket; + + switch (dir) + { + case ForwardScanDirection: + if (offnum != InvalidOffsetNumber) + { + offnum = OffsetNumberNext(offnum); /* move forward */ } - maxoff = PageGetMaxOffsetNumber(page); - offnum = FirstOffsetNumber; - } else { - maxoff = offnum = InvalidOffsetNumber; - break; /* while */ - } - } else { - /* _hash_readnext never returns an empty page */ - maxoff = PageGetMaxOffsetNumber(page); - offnum = FirstOffsetNumber; - } - } - break; - case BackwardScanDirection: - if (offnum != InvalidOffsetNumber) { - offnum = OffsetNumberPrev(offnum); /* move back */ - } else { - offnum = maxoff; /* new page */ - } - while (offnum < FirstOffsetNumber) { - /* - * either this page is empty (offnum == - * InvalidOffsetNumber) or we ran off the end. - */ - _hash_readprev(rel, &buf, &page, &opaque); - if (BufferIsInvalid(buf)) { /* end of chain */ - if (allbuckets && bucket > 0) { - --bucket; - blkno = BUCKET_TO_BLKNO(bucket); - buf = _hash_getbuf(rel, blkno, HASH_READ); - page = BufferGetPage(buf); - _hash_checkpage(page, LH_BUCKET_PAGE); - opaque = (HashPageOpaque) PageGetSpecialPointer(page); - Assert(opaque->hasho_bucket == bucket); - while (BlockNumberIsValid(opaque->hasho_nextblkno)) { - _hash_readnext(rel, &buf, &page, &opaque); + else + { + offnum = FirstOffsetNumber; /* new page */ + } + while (offnum > maxoff) + { + + /* + * either this page is empty (maxoff == + * InvalidOffsetNumber) or we ran off the end. + */ + _hash_readnext(rel, &buf, &page, &opaque); + if (BufferIsInvalid(buf)) + { /* end of chain */ + if (allbuckets && bucket < metap->hashm_maxbucket) + { + ++bucket; + blkno = BUCKET_TO_BLKNO(bucket); + buf = _hash_getbuf(rel, blkno, HASH_READ); + page = BufferGetPage(buf); + _hash_checkpage(page, LH_BUCKET_PAGE); + opaque = (HashPageOpaque) PageGetSpecialPointer(page); + Assert(opaque->hasho_bucket == bucket); + while (PageIsEmpty(page) && + BlockNumberIsValid(opaque->hasho_nextblkno)) + { + _hash_readnext(rel, &buf, &page, &opaque); + } + maxoff = PageGetMaxOffsetNumber(page); + offnum = FirstOffsetNumber; + } + else + { + maxoff = offnum = InvalidOffsetNumber; + break; /* while */ + } + } + else + { + /* _hash_readnext never returns an empty page */ + maxoff = PageGetMaxOffsetNumber(page); + offnum = FirstOffsetNumber; + } + } + break; + case BackwardScanDirection: + if (offnum != InvalidOffsetNumber) + { + offnum = OffsetNumberPrev(offnum); /* move back */ + } + else + { + offnum = maxoff;/* new page */ } - maxoff = offnum = PageGetMaxOffsetNumber(page); - } else { - maxoff = offnum = InvalidOffsetNumber; - break; /* while */ - } - } else { - /* _hash_readprev never returns an empty page */ - maxoff = offnum = PageGetMaxOffsetNumber(page); + while (offnum < FirstOffsetNumber) + { + + /* + * either this page is empty (offnum == + * InvalidOffsetNumber) or we ran off the end. + */ + _hash_readprev(rel, &buf, &page, &opaque); + if (BufferIsInvalid(buf)) + { /* end of chain */ + if (allbuckets && bucket > 0) + { + --bucket; + blkno = BUCKET_TO_BLKNO(bucket); + buf = _hash_getbuf(rel, blkno, HASH_READ); + page = BufferGetPage(buf); + _hash_checkpage(page, LH_BUCKET_PAGE); + opaque = (HashPageOpaque) PageGetSpecialPointer(page); + Assert(opaque->hasho_bucket == bucket); + while (BlockNumberIsValid(opaque->hasho_nextblkno)) + { + _hash_readnext(rel, &buf, &page, &opaque); + } + maxoff = offnum = PageGetMaxOffsetNumber(page); + } + else + { + maxoff = offnum = InvalidOffsetNumber; + break; /* while */ + } + } + else + { + /* _hash_readprev never returns an empty page */ + maxoff = offnum = PageGetMaxOffsetNumber(page); + } + } + break; + default: + /* NoMovementScanDirection */ + /* this should not be reached */ + break; } - } - break; - default: - /* NoMovementScanDirection */ - /* this should not be reached */ - break; - } - /* we ran off the end of the world without finding a match */ - if (offnum == InvalidOffsetNumber) { - _hash_relbuf(rel, metabuf, HASH_READ); - *bufP = so->hashso_curbuf = InvalidBuffer; - ItemPointerSetInvalid(current); - return(false); - } - - /* get ready to check this tuple */ - hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum)); - itup = &hitem->hash_itup; - } while (!_hash_checkqual(scan, itup)); - - /* if we made it to here, we've found a valid tuple */ - _hash_relbuf(rel, metabuf, HASH_READ); - blkno = BufferGetBlockNumber(buf); - *bufP = so->hashso_curbuf = buf; - ItemPointerSet(current, blkno, offnum); - return(true); + /* we ran off the end of the world without finding a match */ + if (offnum == InvalidOffsetNumber) + { + _hash_relbuf(rel, metabuf, HASH_READ); + *bufP = so->hashso_curbuf = InvalidBuffer; + ItemPointerSetInvalid(current); + return (false); + } + + /* get ready to check this tuple */ + hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum)); + itup = &hitem->hash_itup; + } while (!_hash_checkqual(scan, itup)); + + /* if we made it to here, we've found a valid tuple */ + _hash_relbuf(rel, metabuf, HASH_READ); + blkno = BufferGetBlockNumber(buf); + *bufP = so->hashso_curbuf = buf; + ItemPointerSet(current, blkno, offnum); + return (true); } |
