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