diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-08-26 20:02:12 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-08-26 20:02:12 +0000 |
commit | e78fe652f48f9dbb67a21f616741e7b446204cbe (patch) | |
tree | dcf94f3d8d6b1ff4923486c24e15ace811e82d38 /src/backend/access/gist/gistget.c | |
parent | 2fd6061e1c8c91f3d1398826ddfddbcefce477e8 (diff) | |
download | postgresql-e78fe652f48f9dbb67a21f616741e7b446204cbe.tar.gz |
Oops, thanks to Dan McGuirk for pointing out that I missed part of
the commit :(
Here's the rest of the GiST code thta was missing...
Diffstat (limited to 'src/backend/access/gist/gistget.c')
-rw-r--r-- | src/backend/access/gist/gistget.c | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c new file mode 100644 index 0000000000..d60b0a1194 --- /dev/null +++ b/src/backend/access/gist/gistget.c @@ -0,0 +1,374 @@ +/*------------------------------------------------------------------------- + * + * gistget.c-- + * fetch tuples from a GiST scan. + * + * + * + * IDENTIFICATION + * /usr/local/devel/pglite/cvs/src/backend/access/gisr/gistget.c,v 1.9 1995/08/01 20:16:02 jolly Exp + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "storage/bufmgr.h" +#include "storage/bufpage.h" + +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/rel.h" + +#include "access/heapam.h" +#include "access/genam.h" +#include "access/iqual.h" +#include "access/gist.h" +#include "access/sdir.h" + +#include "executor/execdebug.h" + +static OffsetNumber gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, + ScanDirection dir); +static RetrieveIndexResult gistscancache(IndexScanDesc s, ScanDirection dir); +static RetrieveIndexResult gistfirst(IndexScanDesc s, ScanDirection dir); +static RetrieveIndexResult gistnext(IndexScanDesc s, ScanDirection dir); +static ItemPointer gistheapptr(Relation r, ItemPointer itemp); + + +RetrieveIndexResult +gistgettuple(IndexScanDesc s, ScanDirection dir) +{ + RetrieveIndexResult res; + + /* if we have it cached in the scan desc, just return the value */ + if ((res = gistscancache(s, dir)) != (RetrieveIndexResult) NULL) + return (res); + + /* not cached, so we'll have to do some work */ + if (ItemPointerIsValid(&(s->currentItemData))) { + res = gistnext(s, dir); + } else { + res = gistfirst(s, dir); + } + return (res); +} + +static RetrieveIndexResult +gistfirst(IndexScanDesc s, ScanDirection dir) +{ + Buffer b; + Page p; + OffsetNumber n; + OffsetNumber maxoff; + RetrieveIndexResult res; + GISTPageOpaque po; + GISTScanOpaque so; + GISTSTACK *stk; + BlockNumber blk; + IndexTuple it; + ItemPointer ip; + + b = ReadBuffer(s->relation, GISTP_ROOT); + p = BufferGetPage(b); + po = (GISTPageOpaque) PageGetSpecialPointer(p); + so = (GISTScanOpaque) s->opaque; + + for (;;) { + maxoff = PageGetMaxOffsetNumber(p); + if (ScanDirectionIsBackward(dir)) + n = gistfindnext(s, p, maxoff, dir); + else + n = gistfindnext(s, p, FirstOffsetNumber, dir); + + while (n < FirstOffsetNumber || n > maxoff) { + + ReleaseBuffer(b); + if (so->s_stack == (GISTSTACK *) NULL) + return ((RetrieveIndexResult) NULL); + + stk = so->s_stack; + b = ReadBuffer(s->relation, stk->gs_blk); + p = BufferGetPage(b); + po = (GISTPageOpaque) PageGetSpecialPointer(p); + maxoff = PageGetMaxOffsetNumber(p); + + if (ScanDirectionIsBackward(dir)) { + n = OffsetNumberPrev(stk->gs_child); + } else { + n = OffsetNumberNext(stk->gs_child); + } + so->s_stack = stk->gs_parent; + pfree(stk); + + n = gistfindnext(s, p, n, dir); + } + if (po->flags & F_LEAF) { + ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n); + + it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n)); + ip = (ItemPointer) palloc(sizeof(ItemPointerData)); + memmove((char *) ip, (char *) &(it->t_tid), + sizeof(ItemPointerData)); + ReleaseBuffer(b); + + res = FormRetrieveIndexResult(&(s->currentItemData), ip); + + return (res); + } else { + stk = (GISTSTACK *) palloc(sizeof(GISTSTACK)); + stk->gs_child = n; + stk->gs_blk = BufferGetBlockNumber(b); + stk->gs_parent = so->s_stack; + so->s_stack = stk; + + it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n)); + blk = ItemPointerGetBlockNumber(&(it->t_tid)); + + ReleaseBuffer(b); + b = ReadBuffer(s->relation, blk); + p = BufferGetPage(b); + po = (GISTPageOpaque) PageGetSpecialPointer(p); + } + } +} + +static RetrieveIndexResult +gistnext(IndexScanDesc s, ScanDirection dir) +{ + Buffer b; + Page p; + OffsetNumber n; + OffsetNumber maxoff; + RetrieveIndexResult res; + GISTPageOpaque po; + GISTScanOpaque so; + GISTSTACK *stk; + BlockNumber blk; + IndexTuple it; + ItemPointer ip; + + blk = ItemPointerGetBlockNumber(&(s->currentItemData)); + n = ItemPointerGetOffsetNumber(&(s->currentItemData)); + + if (ScanDirectionIsForward(dir)) { + n = OffsetNumberNext(n); + } else { + n = OffsetNumberPrev(n); + } + + b = ReadBuffer(s->relation, blk); + p = BufferGetPage(b); + po = (GISTPageOpaque) PageGetSpecialPointer(p); + so = (GISTScanOpaque) s->opaque; + + for (;;) { + maxoff = PageGetMaxOffsetNumber(p); + n = gistfindnext(s, p, n, dir); + + while (n < FirstOffsetNumber || n > maxoff) { + + ReleaseBuffer(b); + if (so->s_stack == (GISTSTACK *) NULL) + return ((RetrieveIndexResult) NULL); + + stk = so->s_stack; + b = ReadBuffer(s->relation, stk->gs_blk); + p = BufferGetPage(b); + maxoff = PageGetMaxOffsetNumber(p); + po = (GISTPageOpaque) PageGetSpecialPointer(p); + + if (ScanDirectionIsBackward(dir)) { + n = OffsetNumberPrev(stk->gs_child); + } else { + n = OffsetNumberNext(stk->gs_child); + } + so->s_stack = stk->gs_parent; + pfree(stk); + + n = gistfindnext(s, p, n, dir); + } + if (po->flags & F_LEAF) { + ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n); + + it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n)); + ip = (ItemPointer) palloc(sizeof(ItemPointerData)); + memmove((char *) ip, (char *) &(it->t_tid), + sizeof(ItemPointerData)); + ReleaseBuffer(b); + + res = FormRetrieveIndexResult(&(s->currentItemData), ip); + + return (res); + } else { + stk = (GISTSTACK *) palloc(sizeof(GISTSTACK)); + stk->gs_child = n; + stk->gs_blk = BufferGetBlockNumber(b); + stk->gs_parent = so->s_stack; + so->s_stack = stk; + + it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n)); + blk = ItemPointerGetBlockNumber(&(it->t_tid)); + + ReleaseBuffer(b); + b = ReadBuffer(s->relation, blk); + p = BufferGetPage(b); + po = (GISTPageOpaque) PageGetSpecialPointer(p); + + if (ScanDirectionIsBackward(dir)) { + n = PageGetMaxOffsetNumber(p); + } else { + n = FirstOffsetNumber; + } + } + } +} + +/* Similar to index_keytest, but decompresses the key in the IndexTuple */ +bool +gistindex_keytest(IndexTuple tuple, + TupleDesc tupdesc, + int scanKeySize, + ScanKey key, + GISTSTATE *giststate, + Relation r, + Page p, + OffsetNumber offset) +{ + bool isNull; + Datum datum; + int test; + GISTENTRY de; + + IncrIndexProcessed(); + + + while (scanKeySize > 0) { + datum = index_getattr(tuple, + 1, + tupdesc, + &isNull); + gistdentryinit(giststate, &de, (char *)datum, r, p, offset, + IndexTupleSize(tuple) - sizeof(IndexTupleData), + FALSE); + + if (isNull) { + /* XXX eventually should check if SK_ISNULL */ + return (false); + } + + if (key[0].sk_flags & SK_COMMUTE) { + test = (int) (*(key[0].sk_func)) + (DatumGetPointer(key[0].sk_argument), + &de, key[0].sk_procedure); + } else { + test = (int) (*(key[0].sk_func)) + (&de, + DatumGetPointer(key[0].sk_argument), + key[0].sk_procedure); + } + + if (!test == !(key[0].sk_flags & SK_NEGATE)) { + return (false); + } + + scanKeySize -= 1; + key++; + } + + return (true); +} + + +static OffsetNumber +gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir) +{ + OffsetNumber maxoff; + char *it; + GISTPageOpaque po; + GISTScanOpaque so; + GISTENTRY de; + GISTSTATE *giststate; + + maxoff = PageGetMaxOffsetNumber(p); + po = (GISTPageOpaque) PageGetSpecialPointer(p); + so = (GISTScanOpaque) s->opaque; + giststate = so->giststate; + + /* + * If we modified the index during the scan, we may have a pointer to + * a ghost tuple, before the scan. If this is the case, back up one. + */ + + if (so->s_flags & GS_CURBEFORE) { + so->s_flags &= ~GS_CURBEFORE; + n = OffsetNumberPrev(n); + } + + while (n >= FirstOffsetNumber && n <= maxoff) { + it = (char *) PageGetItem(p, PageGetItemId(p, n)); + if (gistindex_keytest((IndexTuple) it, + RelationGetTupleDescriptor(s->relation), + s->numberOfKeys, s->keyData, giststate, + s->relation, p, n)) + break; + + if (ScanDirectionIsBackward(dir)) { + n = OffsetNumberPrev(n); + } else { + n = OffsetNumberNext(n); + } + } + + return (n); +} + +static RetrieveIndexResult +gistscancache(IndexScanDesc s, ScanDirection dir) +{ + RetrieveIndexResult res; + ItemPointer ip; + + if (!(ScanDirectionIsNoMovement(dir) + && ItemPointerIsValid(&(s->currentItemData)))) { + + return ((RetrieveIndexResult) NULL); + } + + ip = gistheapptr(s->relation, &(s->currentItemData)); + + if (ItemPointerIsValid(ip)) + res = FormRetrieveIndexResult(&(s->currentItemData), ip); + else + res = (RetrieveIndexResult) NULL; + + return (res); +} + +/* + * gistheapptr returns the item pointer to the tuple in the heap relation + * for which itemp is the index relation item pointer. + */ +static ItemPointer +gistheapptr(Relation r, ItemPointer itemp) +{ + Buffer b; + Page p; + IndexTuple it; + ItemPointer ip; + OffsetNumber n; + + ip = (ItemPointer) palloc(sizeof(ItemPointerData)); + if (ItemPointerIsValid(itemp)) { + b = ReadBuffer(r, ItemPointerGetBlockNumber(itemp)); + p = BufferGetPage(b); + n = ItemPointerGetOffsetNumber(itemp); + it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n)); + memmove((char *) ip, (char *) &(it->t_tid), + sizeof(ItemPointerData)); + ReleaseBuffer(b); + } else { + ItemPointerSetInvalid(ip); + } + + return (ip); +} |