~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/access/gist/gistget.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * gistget.c
 
4
 *        fetch tuples from a GiST scan.
 
5
 *
 
6
 *
 
7
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
8
 * Portions Copyright (c) 1994, Regents of the University of California
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.43 2004-12-31 21:59:10 pgsql Exp $
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include "access/gist.h"
 
18
#include "executor/execdebug.h"
 
19
 
 
20
 
 
21
static OffsetNumber gistfindnext(IndexScanDesc s, Page p, OffsetNumber n,
 
22
                         ScanDirection dir);
 
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);
 
29
 
 
30
 
 
31
Datum
 
32
gistgettuple(PG_FUNCTION_ARGS)
 
33
{
 
34
        IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
 
35
        ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
 
36
        bool            res;
 
37
 
 
38
        /* if we have it cached in the scan desc, just return the value */
 
39
        if (gistscancache(s, dir))
 
40
                PG_RETURN_BOOL(true);
 
41
 
 
42
        /* not cached, so we'll have to do some work */
 
43
        if (ItemPointerIsValid(&(s->currentItemData)))
 
44
                res = gistnext(s, dir);
 
45
        else
 
46
                res = gistfirst(s, dir);
 
47
        PG_RETURN_BOOL(res);
 
48
}
 
49
 
 
50
static bool
 
51
gistfirst(IndexScanDesc s, ScanDirection dir)
 
52
{
 
53
        Buffer          b;
 
54
        Page            p;
 
55
        OffsetNumber n;
 
56
        OffsetNumber maxoff;
 
57
        GISTPageOpaque po;
 
58
        GISTScanOpaque so;
 
59
        GISTSTACK  *stk;
 
60
        BlockNumber blk;
 
61
        IndexTuple      it;
 
62
 
 
63
        b = ReadBuffer(s->indexRelation, GISTP_ROOT);
 
64
        p = BufferGetPage(b);
 
65
        po = (GISTPageOpaque) PageGetSpecialPointer(p);
 
66
        so = (GISTScanOpaque) s->opaque;
 
67
 
 
68
        for (;;)
 
69
        {
 
70
                maxoff = PageGetMaxOffsetNumber(p);
 
71
                if (ScanDirectionIsBackward(dir))
 
72
                        n = gistfindnext(s, p, maxoff, dir);
 
73
                else
 
74
                        n = gistfindnext(s, p, FirstOffsetNumber, dir);
 
75
 
 
76
                while (n < FirstOffsetNumber || n > maxoff)
 
77
                {
 
78
                        ReleaseBuffer(b);
 
79
                        if (so->s_stack == NULL)
 
80
                                return false;
 
81
 
 
82
                        stk = so->s_stack;
 
83
                        b = ReadBuffer(s->indexRelation, stk->gs_blk);
 
84
                        p = BufferGetPage(b);
 
85
                        po = (GISTPageOpaque) PageGetSpecialPointer(p);
 
86
                        maxoff = PageGetMaxOffsetNumber(p);
 
87
 
 
88
                        if (ScanDirectionIsBackward(dir))
 
89
                                n = OffsetNumberPrev(stk->gs_child);
 
90
                        else
 
91
                                n = OffsetNumberNext(stk->gs_child);
 
92
                        so->s_stack = stk->gs_parent;
 
93
                        pfree(stk);
 
94
 
 
95
                        n = gistfindnext(s, p, n, dir);
 
96
                }
 
97
                if (po->flags & F_LEAF)
 
98
                {
 
99
                        ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
 
100
 
 
101
                        it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
 
102
 
 
103
                        s->xs_ctup.t_self = it->t_tid;
 
104
 
 
105
                        ReleaseBuffer(b);
 
106
                        return true;
 
107
                }
 
108
                else
 
109
                {
 
110
                        stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
 
111
                        stk->gs_child = n;
 
112
                        stk->gs_blk = BufferGetBlockNumber(b);
 
113
                        stk->gs_parent = so->s_stack;
 
114
                        so->s_stack = stk;
 
115
 
 
116
                        it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
 
117
                        blk = ItemPointerGetBlockNumber(&(it->t_tid));
 
118
 
 
119
                        ReleaseBuffer(b);
 
120
                        b = ReadBuffer(s->indexRelation, blk);
 
121
                        p = BufferGetPage(b);
 
122
                        po = (GISTPageOpaque) PageGetSpecialPointer(p);
 
123
                }
 
124
        }
 
125
}
 
126
 
 
127
static bool
 
128
gistnext(IndexScanDesc s, ScanDirection dir)
 
129
{
 
130
        Buffer          b;
 
131
        Page            p;
 
132
        OffsetNumber n;
 
133
        OffsetNumber maxoff;
 
134
        GISTPageOpaque po;
 
135
        GISTScanOpaque so;
 
136
        GISTSTACK  *stk;
 
137
        BlockNumber blk;
 
138
        IndexTuple      it;
 
139
 
 
140
        blk = ItemPointerGetBlockNumber(&(s->currentItemData));
 
141
        n = ItemPointerGetOffsetNumber(&(s->currentItemData));
 
142
 
 
143
        if (ScanDirectionIsForward(dir))
 
144
                n = OffsetNumberNext(n);
 
145
        else
 
146
                n = OffsetNumberPrev(n);
 
147
 
 
148
        b = ReadBuffer(s->indexRelation, blk);
 
149
        p = BufferGetPage(b);
 
150
        po = (GISTPageOpaque) PageGetSpecialPointer(p);
 
151
        so = (GISTScanOpaque) s->opaque;
 
152
 
 
153
        for (;;)
 
154
        {
 
155
                maxoff = PageGetMaxOffsetNumber(p);
 
156
                n = gistfindnext(s, p, n, dir);
 
157
 
 
158
                while (n < FirstOffsetNumber || n > maxoff)
 
159
                {
 
160
                        ReleaseBuffer(b);
 
161
                        if (so->s_stack == NULL)
 
162
                                return false;
 
163
 
 
164
                        stk = so->s_stack;
 
165
                        b = ReadBuffer(s->indexRelation, stk->gs_blk);
 
166
                        p = BufferGetPage(b);
 
167
                        maxoff = PageGetMaxOffsetNumber(p);
 
168
                        po = (GISTPageOpaque) PageGetSpecialPointer(p);
 
169
 
 
170
                        if (ScanDirectionIsBackward(dir))
 
171
                                n = OffsetNumberPrev(stk->gs_child);
 
172
                        else
 
173
                                n = OffsetNumberNext(stk->gs_child);
 
174
                        so->s_stack = stk->gs_parent;
 
175
                        pfree(stk);
 
176
 
 
177
                        n = gistfindnext(s, p, n, dir);
 
178
                }
 
179
                if (po->flags & F_LEAF)
 
180
                {
 
181
                        ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
 
182
 
 
183
                        it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
 
184
 
 
185
                        s->xs_ctup.t_self = it->t_tid;
 
186
 
 
187
                        ReleaseBuffer(b);
 
188
                        return true;
 
189
                }
 
190
                else
 
191
                {
 
192
                        stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
 
193
                        stk->gs_child = n;
 
194
                        stk->gs_blk = BufferGetBlockNumber(b);
 
195
                        stk->gs_parent = so->s_stack;
 
196
                        so->s_stack = stk;
 
197
 
 
198
                        it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
 
199
                        blk = ItemPointerGetBlockNumber(&(it->t_tid));
 
200
 
 
201
                        ReleaseBuffer(b);
 
202
                        b = ReadBuffer(s->indexRelation, blk);
 
203
                        p = BufferGetPage(b);
 
204
                        po = (GISTPageOpaque) PageGetSpecialPointer(p);
 
205
 
 
206
                        if (ScanDirectionIsBackward(dir))
 
207
                                n = PageGetMaxOffsetNumber(p);
 
208
                        else
 
209
                                n = FirstOffsetNumber;
 
210
                }
 
211
        }
 
212
}
 
213
 
 
214
/* Similar to index_keytest, but decompresses the key in the IndexTuple */
 
215
static bool
 
216
gistindex_keytest(IndexTuple tuple,
 
217
                                  int scanKeySize,
 
218
                                  ScanKey key,
 
219
                                  GISTSTATE *giststate,
 
220
                                  Relation r,
 
221
                                  Page p,
 
222
                                  OffsetNumber offset)
 
223
{
 
224
        IncrIndexProcessed();
 
225
 
 
226
        while (scanKeySize > 0)
 
227
        {
 
228
                Datum           datum;
 
229
                bool            isNull;
 
230
                Datum           test;
 
231
                GISTENTRY       de;
 
232
 
 
233
                datum = index_getattr(tuple,
 
234
                                                          key->sk_attno,
 
235
                                                          giststate->tupdesc,
 
236
                                                          &isNull);
 
237
                /* is the index entry NULL? */
 
238
                if (isNull)
 
239
                {
 
240
                        /* XXX eventually should check if SK_ISNULL */
 
241
                        return false;
 
242
                }
 
243
                /* is the compared-to datum NULL? */
 
244
                if (key->sk_flags & SK_ISNULL)
 
245
                        return false;
 
246
 
 
247
                gistdentryinit(giststate, key->sk_attno - 1, &de,
 
248
                                           datum, r, p, offset,
 
249
                                           IndexTupleSize(tuple) - sizeof(IndexTupleData),
 
250
                                           FALSE, isNull);
 
251
 
 
252
                /*
 
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.
 
257
                 *
 
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.)
 
260
                 */
 
261
                test = FunctionCall4(&key->sk_func,
 
262
                                                         PointerGetDatum(&de),
 
263
                                                         key->sk_argument,
 
264
                                                         Int32GetDatum(key->sk_strategy),
 
265
                                                         ObjectIdGetDatum(key->sk_subtype));
 
266
 
 
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));
 
271
 
 
272
                if (!DatumGetBool(test))
 
273
                        return false;
 
274
 
 
275
                scanKeySize--;
 
276
                key++;
 
277
        }
 
278
 
 
279
        return true;
 
280
}
 
281
 
 
282
 
 
283
static OffsetNumber
 
284
gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
 
285
{
 
286
        OffsetNumber maxoff;
 
287
        IndexTuple      it;
 
288
        GISTPageOpaque po;
 
289
        GISTScanOpaque so;
 
290
        GISTSTATE  *giststate;
 
291
 
 
292
        maxoff = PageGetMaxOffsetNumber(p);
 
293
        po = (GISTPageOpaque) PageGetSpecialPointer(p);
 
294
        so = (GISTScanOpaque) s->opaque;
 
295
        giststate = so->giststate;
 
296
 
 
297
        /*
 
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.
 
300
         */
 
301
 
 
302
        if (so->s_flags & GS_CURBEFORE)
 
303
        {
 
304
                so->s_flags &= ~GS_CURBEFORE;
 
305
                n = OffsetNumberPrev(n);
 
306
        }
 
307
 
 
308
        while (n >= FirstOffsetNumber && n <= maxoff)
 
309
        {
 
310
                it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
 
311
                if (gistindex_keytest(it,
 
312
                                                          s->numberOfKeys, s->keyData, giststate,
 
313
                                                          s->indexRelation, p, n))
 
314
                        break;
 
315
 
 
316
                if (ScanDirectionIsBackward(dir))
 
317
                        n = OffsetNumberPrev(n);
 
318
                else
 
319
                        n = OffsetNumberNext(n);
 
320
        }
 
321
 
 
322
        return n;
 
323
}
 
324
 
 
325
static bool
 
326
gistscancache(IndexScanDesc s, ScanDirection dir)
 
327
{
 
328
        Buffer          b;
 
329
        Page            p;
 
330
        OffsetNumber n;
 
331
        IndexTuple      it;
 
332
 
 
333
        if (!(ScanDirectionIsNoMovement(dir)
 
334
                  && ItemPointerIsValid(&(s->currentItemData))))
 
335
                return false;
 
336
 
 
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;
 
343
        ReleaseBuffer(b);
 
344
 
 
345
        return true;
 
346
}