1996-08-26 22:02:12 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* gistget.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* fetch tuples from a GiST scan.
|
1996-08-26 22:02:12 +02:00
|
|
|
*
|
|
|
|
*
|
2001-05-30 21:53:40 +02:00
|
|
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-08-26 22:02:12 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2002-05-21 01:51:44 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistget.c,v 1.33 2002/05/20 23:51:41 tgl Exp $
|
1996-08-26 22:02:12 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "postgres.h"
|
1996-10-31 09:09:47 +01:00
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "access/gist.h"
|
|
|
|
#include "executor/execdebug.h"
|
1996-10-21 07:11:00 +02:00
|
|
|
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
static OffsetNumber gistfindnext(IndexScanDesc s, Page p, OffsetNumber n,
|
1997-09-07 07:04:48 +02:00
|
|
|
ScanDirection dir);
|
2002-05-21 01:51:44 +02:00
|
|
|
static bool gistscancache(IndexScanDesc s, ScanDirection dir);
|
|
|
|
static bool gistfirst(IndexScanDesc s, ScanDirection dir);
|
|
|
|
static bool gistnext(IndexScanDesc s, ScanDirection dir);
|
2002-03-05 06:30:40 +01:00
|
|
|
static bool gistindex_keytest(IndexTuple tuple,
|
1997-09-08 23:56:23 +02:00
|
|
|
int scanKeySize, ScanKey key, GISTSTATE *giststate,
|
1997-09-07 07:04:48 +02:00
|
|
|
Relation r, Page p, OffsetNumber offset);
|
1996-08-26 22:02:12 +02:00
|
|
|
|
|
|
|
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
gistgettuple(PG_FUNCTION_ARGS)
|
1996-08-26 22:02:12 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
|
|
|
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
2002-05-21 01:51:44 +02:00
|
|
|
bool res;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* if we have it cached in the scan desc, just return the value */
|
2002-05-21 01:51:44 +02:00
|
|
|
if (gistscancache(s, dir))
|
|
|
|
PG_RETURN_BOOL(true);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* not cached, so we'll have to do some work */
|
|
|
|
if (ItemPointerIsValid(&(s->currentItemData)))
|
|
|
|
res = gistnext(s, dir);
|
|
|
|
else
|
|
|
|
res = gistfirst(s, dir);
|
2002-05-21 01:51:44 +02:00
|
|
|
PG_RETURN_BOOL(res);
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
static bool
|
1996-08-26 22:02:12 +02:00
|
|
|
gistfirst(IndexScanDesc s, ScanDirection dir)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Buffer b;
|
|
|
|
Page p;
|
|
|
|
OffsetNumber n;
|
|
|
|
OffsetNumber maxoff;
|
|
|
|
GISTPageOpaque po;
|
|
|
|
GISTScanOpaque so;
|
|
|
|
GISTSTACK *stk;
|
|
|
|
BlockNumber blk;
|
|
|
|
IndexTuple it;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
b = ReadBuffer(s->indexRelation, GISTP_ROOT);
|
1997-09-07 07:04:48 +02:00
|
|
|
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)
|
2002-05-21 01:51:44 +02:00
|
|
|
return false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
stk = so->s_stack;
|
2002-05-21 01:51:44 +02:00
|
|
|
b = ReadBuffer(s->indexRelation, stk->gs_blk);
|
1997-09-07 07:04:48 +02:00
|
|
|
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));
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
s->xs_ctup.t_self = it->t_tid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
ReleaseBuffer(b);
|
2002-05-21 01:51:44 +02:00
|
|
|
return true;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
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);
|
2002-05-21 01:51:44 +02:00
|
|
|
b = ReadBuffer(s->indexRelation, blk);
|
1997-09-07 07:04:48 +02:00
|
|
|
p = BufferGetPage(b);
|
|
|
|
po = (GISTPageOpaque) PageGetSpecialPointer(p);
|
|
|
|
}
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
static bool
|
1996-08-26 22:02:12 +02:00
|
|
|
gistnext(IndexScanDesc s, ScanDirection dir)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Buffer b;
|
|
|
|
Page p;
|
|
|
|
OffsetNumber n;
|
|
|
|
OffsetNumber maxoff;
|
|
|
|
GISTPageOpaque po;
|
|
|
|
GISTScanOpaque so;
|
|
|
|
GISTSTACK *stk;
|
|
|
|
BlockNumber blk;
|
|
|
|
IndexTuple it;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
blk = ItemPointerGetBlockNumber(&(s->currentItemData));
|
|
|
|
n = ItemPointerGetOffsetNumber(&(s->currentItemData));
|
|
|
|
|
|
|
|
if (ScanDirectionIsForward(dir))
|
|
|
|
n = OffsetNumberNext(n);
|
|
|
|
else
|
|
|
|
n = OffsetNumberPrev(n);
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
b = ReadBuffer(s->indexRelation, blk);
|
1997-09-07 07:04:48 +02:00
|
|
|
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)
|
2002-05-21 01:51:44 +02:00
|
|
|
return false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
stk = so->s_stack;
|
2002-05-21 01:51:44 +02:00
|
|
|
b = ReadBuffer(s->indexRelation, stk->gs_blk);
|
1997-09-07 07:04:48 +02:00
|
|
|
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));
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
s->xs_ctup.t_self = it->t_tid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
ReleaseBuffer(b);
|
2002-05-21 01:51:44 +02:00
|
|
|
return true;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
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);
|
2002-05-21 01:51:44 +02:00
|
|
|
b = ReadBuffer(s->indexRelation, blk);
|
1997-09-07 07:04:48 +02:00
|
|
|
p = BufferGetPage(b);
|
|
|
|
po = (GISTPageOpaque) PageGetSpecialPointer(p);
|
|
|
|
|
|
|
|
if (ScanDirectionIsBackward(dir))
|
|
|
|
n = PageGetMaxOffsetNumber(p);
|
|
|
|
else
|
|
|
|
n = FirstOffsetNumber;
|
|
|
|
}
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Similar to index_keytest, but decompresses the key in the IndexTuple */
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
1996-08-26 22:02:12 +02:00
|
|
|
gistindex_keytest(IndexTuple tuple,
|
1997-09-07 07:04:48 +02:00
|
|
|
int scanKeySize,
|
|
|
|
ScanKey key,
|
1997-09-08 23:56:23 +02:00
|
|
|
GISTSTATE *giststate,
|
1997-09-07 07:04:48 +02:00
|
|
|
Relation r,
|
|
|
|
Page p,
|
|
|
|
OffsetNumber offset)
|
1996-08-26 22:02:12 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
bool isNull;
|
|
|
|
Datum datum;
|
2000-05-30 06:25:00 +02:00
|
|
|
Datum test;
|
1997-09-08 04:41:22 +02:00
|
|
|
GISTENTRY de;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
IncrIndexProcessed();
|
|
|
|
|
|
|
|
while (scanKeySize > 0)
|
|
|
|
{
|
|
|
|
datum = index_getattr(tuple,
|
2001-05-31 20:16:55 +02:00
|
|
|
key[0].sk_attno,
|
2001-08-22 20:24:26 +02:00
|
|
|
giststate->tupdesc,
|
1997-09-07 07:04:48 +02:00
|
|
|
&isNull);
|
2001-05-31 20:16:55 +02:00
|
|
|
if (isNull)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
/* XXX eventually should check if SK_ISNULL */
|
1998-09-01 05:29:17 +02:00
|
|
|
return false;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-05-31 20:16:55 +02:00
|
|
|
/* this code from backend/access/common/indexvalid.c. But why and what???
|
|
|
|
if (key[0].sk_flags & SK_ISNULL)
|
|
|
|
return false;
|
|
|
|
*/
|
2001-10-25 07:50:21 +02:00
|
|
|
gistdentryinit(giststate, key[0].sk_attno - 1, &de,
|
2001-05-31 20:16:55 +02:00
|
|
|
datum, r, p, offset,
|
2001-05-15 16:14:49 +02:00
|
|
|
IndexTupleSize(tuple) - sizeof(IndexTupleData),
|
2001-08-10 16:34:28 +02:00
|
|
|
FALSE, isNull);
|
2001-05-15 16:14:49 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (key[0].sk_flags & SK_COMMUTE)
|
|
|
|
{
|
2000-05-30 06:25:00 +02:00
|
|
|
test = FunctionCall3(&key[0].sk_func,
|
|
|
|
key[0].sk_argument,
|
|
|
|
PointerGetDatum(&de),
|
|
|
|
ObjectIdGetDatum(key[0].sk_procedure));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-05-30 06:25:00 +02:00
|
|
|
test = FunctionCall3(&key[0].sk_func,
|
|
|
|
PointerGetDatum(&de),
|
|
|
|
key[0].sk_argument,
|
|
|
|
ObjectIdGetDatum(key[0].sk_procedure));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
if (de.key != datum && !isAttByVal(giststate, key[0].sk_attno - 1))
|
|
|
|
if (DatumGetPointer(de.key) != NULL)
|
|
|
|
pfree(DatumGetPointer(de.key));
|
2001-05-15 16:14:49 +02:00
|
|
|
|
2000-05-30 06:25:00 +02:00
|
|
|
if (DatumGetBool(test) == !!(key[0].sk_flags & SK_NEGATE))
|
1998-09-01 05:29:17 +02:00
|
|
|
return false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-05-31 20:16:55 +02:00
|
|
|
scanKeySize--;
|
1997-09-07 07:04:48 +02:00
|
|
|
key++;
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
1998-09-01 05:29:17 +02:00
|
|
|
return true;
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static OffsetNumber
|
1996-08-26 22:02:12 +02:00
|
|
|
gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
OffsetNumber maxoff;
|
2001-05-31 20:16:55 +02:00
|
|
|
IndexTuple it;
|
1997-09-08 04:41:22 +02:00
|
|
|
GISTPageOpaque po;
|
|
|
|
GISTScanOpaque so;
|
|
|
|
GISTSTATE *giststate;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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);
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
while (n >= FirstOffsetNumber && n <= maxoff)
|
|
|
|
{
|
2001-05-31 20:16:55 +02:00
|
|
|
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
|
|
|
|
if (gistindex_keytest(it,
|
1997-09-07 07:04:48 +02:00
|
|
|
s->numberOfKeys, s->keyData, giststate,
|
2002-05-21 01:51:44 +02:00
|
|
|
s->indexRelation, p, n))
|
1997-09-07 07:04:48 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (ScanDirectionIsBackward(dir))
|
|
|
|
n = OffsetNumberPrev(n);
|
|
|
|
else
|
|
|
|
n = OffsetNumberNext(n);
|
|
|
|
}
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return n;
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
static bool
|
1996-08-26 22:02:12 +02:00
|
|
|
gistscancache(IndexScanDesc s, ScanDirection dir)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Buffer b;
|
|
|
|
Page p;
|
|
|
|
OffsetNumber n;
|
2002-05-21 01:51:44 +02:00
|
|
|
IndexTuple it;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
if (!(ScanDirectionIsNoMovement(dir)
|
|
|
|
&& ItemPointerIsValid(&(s->currentItemData))))
|
|
|
|
return false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
b = ReadBuffer(s->indexRelation,
|
|
|
|
ItemPointerGetBlockNumber(&(s->currentItemData)));
|
|
|
|
p = BufferGetPage(b);
|
|
|
|
n = ItemPointerGetOffsetNumber(&(s->currentItemData));
|
|
|
|
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
|
|
|
|
s->xs_ctup.t_self = it->t_tid;
|
|
|
|
ReleaseBuffer(b);
|
|
|
|
|
|
|
|
return true;
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|