~ubuntu-branches/ubuntu/lucid/postgresql-8.4/lucid-proposed

« back to all changes in this revision

Viewing changes to src/backend/access/gin/ginscan.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * ginscan.c
 
4
 *        routines to manage scans inverted index relations
 
5
 *
 
6
 *
 
7
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 
8
 * Portions Copyright (c) 1994, Regents of the University of California
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *                      $PostgreSQL$
 
12
 *-------------------------------------------------------------------------
 
13
 */
 
14
 
 
15
#include "postgres.h"
 
16
 
 
17
#include "access/gin.h"
 
18
#include "access/relscan.h"
 
19
#include "pgstat.h"
 
20
#include "storage/bufmgr.h"
 
21
#include "utils/memutils.h"
 
22
#include "utils/rel.h"
 
23
 
 
24
 
 
25
Datum
 
26
ginbeginscan(PG_FUNCTION_ARGS)
 
27
{
 
28
        Relation        rel = (Relation) PG_GETARG_POINTER(0);
 
29
        int                     keysz = PG_GETARG_INT32(1);
 
30
        ScanKey         scankey = (ScanKey) PG_GETARG_POINTER(2);
 
31
        IndexScanDesc scan;
 
32
 
 
33
        scan = RelationGetIndexScan(rel, keysz, scankey);
 
34
 
 
35
        PG_RETURN_POINTER(scan);
 
36
}
 
37
 
 
38
static void
 
39
fillScanKey(GinState *ginstate, GinScanKey key, OffsetNumber attnum, Datum query,
 
40
                        Datum *entryValues, bool *partial_matches, uint32 nEntryValues, 
 
41
                        StrategyNumber strategy, Pointer *extra_data)
 
42
{
 
43
        uint32          i,
 
44
                                j;
 
45
 
 
46
        key->nentries = nEntryValues;
 
47
        key->entryRes = (bool *) palloc0(sizeof(bool) * nEntryValues);
 
48
        key->scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * nEntryValues);
 
49
        key->strategy = strategy;
 
50
        key->attnum = attnum;
 
51
        key->extra_data = extra_data;
 
52
        key->query = query;
 
53
        key->firstCall = TRUE;
 
54
        ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
 
55
 
 
56
        for (i = 0; i < nEntryValues; i++)
 
57
        {
 
58
                key->scanEntry[i].pval = key->entryRes + i;
 
59
                key->scanEntry[i].entry = entryValues[i];
 
60
                key->scanEntry[i].attnum = attnum;
 
61
                key->scanEntry[i].extra_data = (extra_data) ? extra_data[i] : NULL;
 
62
                ItemPointerSet(&(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber);
 
63
                key->scanEntry[i].offset = InvalidOffsetNumber;
 
64
                key->scanEntry[i].buffer = InvalidBuffer;
 
65
                key->scanEntry[i].partialMatch = NULL;
 
66
                key->scanEntry[i].partialMatchIterator = NULL;
 
67
                key->scanEntry[i].partialMatchResult = NULL;
 
68
                key->scanEntry[i].strategy = strategy;
 
69
                key->scanEntry[i].list = NULL;
 
70
                key->scanEntry[i].nlist = 0;
 
71
                key->scanEntry[i].isPartialMatch = ( ginstate->canPartialMatch[attnum - 1] && partial_matches ) 
 
72
                                                                                                ? partial_matches[i] : false;
 
73
 
 
74
                /* link to the equals entry in current scan key */
 
75
                key->scanEntry[i].master = NULL;
 
76
                for (j = 0; j < i; j++)
 
77
                        if (compareEntries(ginstate, attnum, entryValues[i], entryValues[j]) == 0)
 
78
                        {
 
79
                                key->scanEntry[i].master = key->scanEntry + j;
 
80
                                break;
 
81
                        }
 
82
        }
 
83
}
 
84
 
 
85
#ifdef NOT_USED
 
86
 
 
87
static void
 
88
resetScanKeys(GinScanKey keys, uint32 nkeys)
 
89
{
 
90
        uint32          i,
 
91
                                j;
 
92
 
 
93
        if (keys == NULL)
 
94
                return;
 
95
 
 
96
        for (i = 0; i < nkeys; i++)
 
97
        {
 
98
                GinScanKey      key = keys + i;
 
99
 
 
100
                key->firstCall = TRUE;
 
101
                ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
 
102
 
 
103
                for (j = 0; j < key->nentries; j++)
 
104
                {
 
105
                        if (key->scanEntry[j].buffer != InvalidBuffer)
 
106
                                ReleaseBuffer(key->scanEntry[i].buffer);
 
107
 
 
108
                        ItemPointerSet(&(key->scanEntry[j].curItem), InvalidBlockNumber, InvalidOffsetNumber);
 
109
                        key->scanEntry[j].offset = InvalidOffsetNumber;
 
110
                        key->scanEntry[j].buffer = InvalidBuffer;
 
111
                        key->scanEntry[j].list = NULL;
 
112
                        key->scanEntry[j].nlist = 0;
 
113
                        key->scanEntry[j].partialMatch = NULL;
 
114
                        key->scanEntry[j].partialMatchIterator = NULL;
 
115
                        key->scanEntry[j].partialMatchResult = NULL;
 
116
                }
 
117
        }
 
118
}
 
119
#endif
 
120
 
 
121
static void
 
122
freeScanKeys(GinScanKey keys, uint32 nkeys)
 
123
{
 
124
        uint32          i,
 
125
                                j;
 
126
 
 
127
        if (keys == NULL)
 
128
                return;
 
129
 
 
130
        for (i = 0; i < nkeys; i++)
 
131
        {
 
132
                GinScanKey      key = keys + i;
 
133
 
 
134
                for (j = 0; j < key->nentries; j++)
 
135
                {
 
136
                        if (key->scanEntry[j].buffer != InvalidBuffer)
 
137
                                ReleaseBuffer(key->scanEntry[j].buffer);
 
138
                        if (key->scanEntry[j].list)
 
139
                                pfree(key->scanEntry[j].list);
 
140
                        if (key->scanEntry[j].partialMatchIterator)
 
141
                                tbm_end_iterate(key->scanEntry[j].partialMatchIterator);
 
142
                        if (key->scanEntry[j].partialMatch)
 
143
                                tbm_free(key->scanEntry[j].partialMatch);
 
144
                }
 
145
 
 
146
                pfree(key->entryRes);
 
147
                pfree(key->scanEntry);
 
148
        }
 
149
 
 
150
        pfree(keys);
 
151
}
 
152
 
 
153
void
 
154
newScanKey(IndexScanDesc scan)
 
155
{
 
156
        ScanKey         scankey = scan->keyData;
 
157
        GinScanOpaque so = (GinScanOpaque) scan->opaque;
 
158
        int                     i;
 
159
        uint32          nkeys = 0;
 
160
 
 
161
        if (scan->numberOfKeys < 1)
 
162
                ereport(ERROR,
 
163
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
164
                                 errmsg("GIN indexes do not support whole-index scans")));
 
165
 
 
166
        so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData));
 
167
 
 
168
        so->isVoidRes = false;
 
169
 
 
170
        for (i = 0; i < scan->numberOfKeys; i++)
 
171
        {
 
172
                ScanKey         skey = &scankey[i];
 
173
                Datum      *entryValues;
 
174
                int32           nEntryValues = 0;
 
175
                bool            *partial_matches = NULL;
 
176
                Pointer         *extra_data = NULL;
 
177
 
 
178
                /* XXX can't we treat nulls by just setting isVoidRes? */
 
179
                /* This would amount to assuming that all GIN operators are strict */
 
180
                if (skey->sk_flags & SK_ISNULL)
 
181
                        ereport(ERROR,
 
182
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
183
                                         errmsg("GIN indexes do not support NULL scan keys")));
 
184
 
 
185
                entryValues = (Datum *)
 
186
                        DatumGetPointer(FunctionCall5(&so->ginstate.extractQueryFn[skey->sk_attno - 1],
 
187
                                                                                  skey->sk_argument,
 
188
                                                                                  PointerGetDatum(&nEntryValues),
 
189
                                                                                  UInt16GetDatum(skey->sk_strategy),
 
190
                                                                                  PointerGetDatum(&partial_matches),
 
191
                                                                                  PointerGetDatum(&extra_data)));
 
192
 
 
193
                if (nEntryValues < 0)
 
194
                {
 
195
                        /*
 
196
                         * extractQueryFn signals that nothing can match, so we can
 
197
                         * just set isVoidRes flag.  No need to examine any more keys.
 
198
                         */
 
199
                        so->isVoidRes = true;
 
200
                        break;
 
201
                }
 
202
 
 
203
                if (entryValues == NULL || nEntryValues == 0)
 
204
                {
 
205
                        /*
 
206
                         * extractQueryFn signals that everything matches.  This would
 
207
                         * require a full scan, which we can't do, but perhaps there
 
208
                         * is another scankey that provides a restriction to use.  So
 
209
                         * we keep going and check only at the end.
 
210
                         */
 
211
                        continue;
 
212
                }
 
213
 
 
214
                fillScanKey(&so->ginstate, &(so->keys[nkeys]),
 
215
                                        skey->sk_attno, skey->sk_argument,
 
216
                                        entryValues, partial_matches, nEntryValues,
 
217
                                        skey->sk_strategy, extra_data);
 
218
                nkeys++;
 
219
        }
 
220
 
 
221
        if (nkeys == 0 && !so->isVoidRes)
 
222
                ereport(ERROR,
 
223
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
224
                                 errmsg("GIN indexes do not support whole-index scans")));
 
225
 
 
226
        so->nkeys = nkeys;
 
227
 
 
228
        pgstat_count_index_scan(scan->indexRelation);
 
229
}
 
230
 
 
231
Datum
 
232
ginrescan(PG_FUNCTION_ARGS)
 
233
{
 
234
        IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
 
235
        ScanKey         scankey = (ScanKey) PG_GETARG_POINTER(1);
 
236
        GinScanOpaque so;
 
237
 
 
238
        so = (GinScanOpaque) scan->opaque;
 
239
 
 
240
        if (so == NULL)
 
241
        {
 
242
                /* if called from ginbeginscan */
 
243
                so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
 
244
                so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
 
245
                                                                                        "Gin scan temporary context",
 
246
                                                                                        ALLOCSET_DEFAULT_MINSIZE,
 
247
                                                                                        ALLOCSET_DEFAULT_INITSIZE,
 
248
                                                                                        ALLOCSET_DEFAULT_MAXSIZE);
 
249
                initGinState(&so->ginstate, scan->indexRelation);
 
250
                scan->opaque = so;
 
251
        }
 
252
        else
 
253
        {
 
254
                freeScanKeys(so->keys, so->nkeys);
 
255
        }
 
256
 
 
257
        so->keys = NULL;
 
258
 
 
259
        if (scankey && scan->numberOfKeys > 0)
 
260
        {
 
261
                memmove(scan->keyData, scankey,
 
262
                                scan->numberOfKeys * sizeof(ScanKeyData));
 
263
        }
 
264
 
 
265
        PG_RETURN_VOID();
 
266
}
 
267
 
 
268
 
 
269
Datum
 
270
ginendscan(PG_FUNCTION_ARGS)
 
271
{
 
272
        IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
 
273
        GinScanOpaque so = (GinScanOpaque) scan->opaque;
 
274
 
 
275
        if (so != NULL)
 
276
        {
 
277
                freeScanKeys(so->keys, so->nkeys);
 
278
 
 
279
                MemoryContextDelete(so->tempCtx);
 
280
 
 
281
                pfree(so);
 
282
        }
 
283
 
 
284
        PG_RETURN_VOID();
 
285
}
 
286
 
 
287
Datum
 
288
ginmarkpos(PG_FUNCTION_ARGS)
 
289
{
 
290
        elog(ERROR, "GIN does not support mark/restore");
 
291
        PG_RETURN_VOID();
 
292
}
 
293
 
 
294
Datum
 
295
ginrestrpos(PG_FUNCTION_ARGS)
 
296
{
 
297
        elog(ERROR, "GIN does not support mark/restore");
 
298
        PG_RETURN_VOID();
 
299
}