summaryrefslogtreecommitdiff
path: root/src/backend/access/gist/gistget.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-08-26 20:02:12 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-08-26 20:02:12 +0000
commite78fe652f48f9dbb67a21f616741e7b446204cbe (patch)
treedcf94f3d8d6b1ff4923486c24e15ace811e82d38 /src/backend/access/gist/gistget.c
parent2fd6061e1c8c91f3d1398826ddfddbcefce477e8 (diff)
downloadpostgresql-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.c374
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);
+}