1
/*-------------------------------------------------------------------------
4
* routines to manage scans inverted index relations
7
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8
* Portions Copyright (c) 1994, Regents of the University of California
12
*-------------------------------------------------------------------------
17
#include "access/gin.h"
18
#include "access/relscan.h"
20
#include "storage/bufmgr.h"
21
#include "utils/memutils.h"
22
#include "utils/rel.h"
26
ginbeginscan(PG_FUNCTION_ARGS)
28
Relation rel = (Relation) PG_GETARG_POINTER(0);
29
int keysz = PG_GETARG_INT32(1);
30
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
33
scan = RelationGetIndexScan(rel, keysz, scankey);
35
PG_RETURN_POINTER(scan);
39
fillScanKey(GinState *ginstate, GinScanKey key, OffsetNumber attnum, Datum query,
40
Datum *entryValues, bool *partial_matches, uint32 nEntryValues,
41
StrategyNumber strategy, Pointer *extra_data)
46
key->nentries = nEntryValues;
47
key->entryRes = (bool *) palloc0(sizeof(bool) * nEntryValues);
48
key->scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * nEntryValues);
49
key->strategy = strategy;
51
key->extra_data = extra_data;
53
key->firstCall = TRUE;
54
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
56
for (i = 0; i < nEntryValues; i++)
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;
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)
79
key->scanEntry[i].master = key->scanEntry + j;
88
resetScanKeys(GinScanKey keys, uint32 nkeys)
96
for (i = 0; i < nkeys; i++)
98
GinScanKey key = keys + i;
100
key->firstCall = TRUE;
101
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
103
for (j = 0; j < key->nentries; j++)
105
if (key->scanEntry[j].buffer != InvalidBuffer)
106
ReleaseBuffer(key->scanEntry[i].buffer);
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;
122
freeScanKeys(GinScanKey keys, uint32 nkeys)
130
for (i = 0; i < nkeys; i++)
132
GinScanKey key = keys + i;
134
for (j = 0; j < key->nentries; j++)
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);
146
pfree(key->entryRes);
147
pfree(key->scanEntry);
154
newScanKey(IndexScanDesc scan)
156
ScanKey scankey = scan->keyData;
157
GinScanOpaque so = (GinScanOpaque) scan->opaque;
161
if (scan->numberOfKeys < 1)
163
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
164
errmsg("GIN indexes do not support whole-index scans")));
166
so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData));
168
so->isVoidRes = false;
170
for (i = 0; i < scan->numberOfKeys; i++)
172
ScanKey skey = &scankey[i];
174
int32 nEntryValues = 0;
175
bool *partial_matches = NULL;
176
Pointer *extra_data = NULL;
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)
182
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
183
errmsg("GIN indexes do not support NULL scan keys")));
185
entryValues = (Datum *)
186
DatumGetPointer(FunctionCall5(&so->ginstate.extractQueryFn[skey->sk_attno - 1],
188
PointerGetDatum(&nEntryValues),
189
UInt16GetDatum(skey->sk_strategy),
190
PointerGetDatum(&partial_matches),
191
PointerGetDatum(&extra_data)));
193
if (nEntryValues < 0)
196
* extractQueryFn signals that nothing can match, so we can
197
* just set isVoidRes flag. No need to examine any more keys.
199
so->isVoidRes = true;
203
if (entryValues == NULL || nEntryValues == 0)
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.
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);
221
if (nkeys == 0 && !so->isVoidRes)
223
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
224
errmsg("GIN indexes do not support whole-index scans")));
228
pgstat_count_index_scan(scan->indexRelation);
232
ginrescan(PG_FUNCTION_ARGS)
234
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
235
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
238
so = (GinScanOpaque) scan->opaque;
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);
254
freeScanKeys(so->keys, so->nkeys);
259
if (scankey && scan->numberOfKeys > 0)
261
memmove(scan->keyData, scankey,
262
scan->numberOfKeys * sizeof(ScanKeyData));
270
ginendscan(PG_FUNCTION_ARGS)
272
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
273
GinScanOpaque so = (GinScanOpaque) scan->opaque;
277
freeScanKeys(so->keys, so->nkeys);
279
MemoryContextDelete(so->tempCtx);
288
ginmarkpos(PG_FUNCTION_ARGS)
290
elog(ERROR, "GIN does not support mark/restore");
295
ginrestrpos(PG_FUNCTION_ARGS)
297
elog(ERROR, "GIN does not support mark/restore");