1
/*-------------------------------------------------------------------------
4
* fetch tuples from a GiST scan.
7
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
8
* Portions Copyright (c) 1994, Regents of the University of California
11
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.43 2004-12-31 21:59:10 pgsql Exp $
13
*-------------------------------------------------------------------------
17
#include "access/gist.h"
18
#include "executor/execdebug.h"
21
static OffsetNumber gistfindnext(IndexScanDesc s, Page p, OffsetNumber n,
23
static bool gistscancache(IndexScanDesc s, ScanDirection dir);
24
static bool gistfirst(IndexScanDesc s, ScanDirection dir);
25
static bool gistnext(IndexScanDesc s, ScanDirection dir);
26
static bool gistindex_keytest(IndexTuple tuple,
27
int scanKeySize, ScanKey key, GISTSTATE *giststate,
28
Relation r, Page p, OffsetNumber offset);
32
gistgettuple(PG_FUNCTION_ARGS)
34
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
35
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
38
/* if we have it cached in the scan desc, just return the value */
39
if (gistscancache(s, dir))
42
/* not cached, so we'll have to do some work */
43
if (ItemPointerIsValid(&(s->currentItemData)))
44
res = gistnext(s, dir);
46
res = gistfirst(s, dir);
51
gistfirst(IndexScanDesc s, ScanDirection dir)
63
b = ReadBuffer(s->indexRelation, GISTP_ROOT);
65
po = (GISTPageOpaque) PageGetSpecialPointer(p);
66
so = (GISTScanOpaque) s->opaque;
70
maxoff = PageGetMaxOffsetNumber(p);
71
if (ScanDirectionIsBackward(dir))
72
n = gistfindnext(s, p, maxoff, dir);
74
n = gistfindnext(s, p, FirstOffsetNumber, dir);
76
while (n < FirstOffsetNumber || n > maxoff)
79
if (so->s_stack == NULL)
83
b = ReadBuffer(s->indexRelation, stk->gs_blk);
85
po = (GISTPageOpaque) PageGetSpecialPointer(p);
86
maxoff = PageGetMaxOffsetNumber(p);
88
if (ScanDirectionIsBackward(dir))
89
n = OffsetNumberPrev(stk->gs_child);
91
n = OffsetNumberNext(stk->gs_child);
92
so->s_stack = stk->gs_parent;
95
n = gistfindnext(s, p, n, dir);
97
if (po->flags & F_LEAF)
99
ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
101
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
103
s->xs_ctup.t_self = it->t_tid;
110
stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
112
stk->gs_blk = BufferGetBlockNumber(b);
113
stk->gs_parent = so->s_stack;
116
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
117
blk = ItemPointerGetBlockNumber(&(it->t_tid));
120
b = ReadBuffer(s->indexRelation, blk);
121
p = BufferGetPage(b);
122
po = (GISTPageOpaque) PageGetSpecialPointer(p);
128
gistnext(IndexScanDesc s, ScanDirection dir)
140
blk = ItemPointerGetBlockNumber(&(s->currentItemData));
141
n = ItemPointerGetOffsetNumber(&(s->currentItemData));
143
if (ScanDirectionIsForward(dir))
144
n = OffsetNumberNext(n);
146
n = OffsetNumberPrev(n);
148
b = ReadBuffer(s->indexRelation, blk);
149
p = BufferGetPage(b);
150
po = (GISTPageOpaque) PageGetSpecialPointer(p);
151
so = (GISTScanOpaque) s->opaque;
155
maxoff = PageGetMaxOffsetNumber(p);
156
n = gistfindnext(s, p, n, dir);
158
while (n < FirstOffsetNumber || n > maxoff)
161
if (so->s_stack == NULL)
165
b = ReadBuffer(s->indexRelation, stk->gs_blk);
166
p = BufferGetPage(b);
167
maxoff = PageGetMaxOffsetNumber(p);
168
po = (GISTPageOpaque) PageGetSpecialPointer(p);
170
if (ScanDirectionIsBackward(dir))
171
n = OffsetNumberPrev(stk->gs_child);
173
n = OffsetNumberNext(stk->gs_child);
174
so->s_stack = stk->gs_parent;
177
n = gistfindnext(s, p, n, dir);
179
if (po->flags & F_LEAF)
181
ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
183
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
185
s->xs_ctup.t_self = it->t_tid;
192
stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
194
stk->gs_blk = BufferGetBlockNumber(b);
195
stk->gs_parent = so->s_stack;
198
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
199
blk = ItemPointerGetBlockNumber(&(it->t_tid));
202
b = ReadBuffer(s->indexRelation, blk);
203
p = BufferGetPage(b);
204
po = (GISTPageOpaque) PageGetSpecialPointer(p);
206
if (ScanDirectionIsBackward(dir))
207
n = PageGetMaxOffsetNumber(p);
209
n = FirstOffsetNumber;
214
/* Similar to index_keytest, but decompresses the key in the IndexTuple */
216
gistindex_keytest(IndexTuple tuple,
219
GISTSTATE *giststate,
224
IncrIndexProcessed();
226
while (scanKeySize > 0)
233
datum = index_getattr(tuple,
237
/* is the index entry NULL? */
240
/* XXX eventually should check if SK_ISNULL */
243
/* is the compared-to datum NULL? */
244
if (key->sk_flags & SK_ISNULL)
247
gistdentryinit(giststate, key->sk_attno - 1, &de,
249
IndexTupleSize(tuple) - sizeof(IndexTupleData),
253
* Call the Consistent function to evaluate the test. The
254
* arguments are the index datum (as a GISTENTRY*), the comparison
255
* datum, and the comparison operator's strategy number and
256
* subtype from pg_amop.
258
* (Presently there's no need to pass the subtype since it'll always
259
* be zero, but might as well pass it for possible future use.)
261
test = FunctionCall4(&key->sk_func,
262
PointerGetDatum(&de),
264
Int32GetDatum(key->sk_strategy),
265
ObjectIdGetDatum(key->sk_subtype));
267
/* if index datum had to be decompressed, free it */
268
if (de.key != datum && !isAttByVal(giststate, key->sk_attno - 1))
269
if (DatumGetPointer(de.key) != NULL)
270
pfree(DatumGetPointer(de.key));
272
if (!DatumGetBool(test))
284
gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
290
GISTSTATE *giststate;
292
maxoff = PageGetMaxOffsetNumber(p);
293
po = (GISTPageOpaque) PageGetSpecialPointer(p);
294
so = (GISTScanOpaque) s->opaque;
295
giststate = so->giststate;
298
* If we modified the index during the scan, we may have a pointer to
299
* a ghost tuple, before the scan. If this is the case, back up one.
302
if (so->s_flags & GS_CURBEFORE)
304
so->s_flags &= ~GS_CURBEFORE;
305
n = OffsetNumberPrev(n);
308
while (n >= FirstOffsetNumber && n <= maxoff)
310
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
311
if (gistindex_keytest(it,
312
s->numberOfKeys, s->keyData, giststate,
313
s->indexRelation, p, n))
316
if (ScanDirectionIsBackward(dir))
317
n = OffsetNumberPrev(n);
319
n = OffsetNumberNext(n);
326
gistscancache(IndexScanDesc s, ScanDirection dir)
333
if (!(ScanDirectionIsNoMovement(dir)
334
&& ItemPointerIsValid(&(s->currentItemData))))
337
b = ReadBuffer(s->indexRelation,
338
ItemPointerGetBlockNumber(&(s->currentItemData)));
339
p = BufferGetPage(b);
340
n = ItemPointerGetOffsetNumber(&(s->currentItemData));
341
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
342
s->xs_ctup.t_self = it->t_tid;