Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / access / gin / ginscan.c
blob1ebbc2ab788bdecca3effbd1845d9ddb861b8c53
1 /*-------------------------------------------------------------------------
3 * ginscan.c
4 * routines to manage scans inverted index relations
7 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * $PostgreSQL$
12 *-------------------------------------------------------------------------
15 #include "postgres.h"
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"
25 Datum
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);
31 IndexScanDesc scan;
33 scan = RelationGetIndexScan(rel, keysz, scankey);
35 PG_RETURN_POINTER(scan);
38 static void
39 fillScanKey(GinState *ginstate, GinScanKey key, OffsetNumber attnum, Datum query,
40 Datum *entryValues, bool *partial_matches, uint32 nEntryValues,
41 StrategyNumber strategy)
43 uint32 i,
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->query = query;
52 key->firstCall = TRUE;
53 ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
55 for (i = 0; i < nEntryValues; i++)
57 key->scanEntry[i].pval = key->entryRes + i;
58 key->scanEntry[i].entry = entryValues[i];
59 key->scanEntry[i].attnum = attnum;
60 ItemPointerSet(&(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber);
61 key->scanEntry[i].offset = InvalidOffsetNumber;
62 key->scanEntry[i].buffer = InvalidBuffer;
63 key->scanEntry[i].partialMatch = NULL;
64 key->scanEntry[i].strategy = strategy;
65 key->scanEntry[i].list = NULL;
66 key->scanEntry[i].nlist = 0;
67 key->scanEntry[i].isPartialMatch = ( ginstate->canPartialMatch[attnum - 1] && partial_matches )
68 ? partial_matches[i] : false;
70 /* link to the equals entry in current scan key */
71 key->scanEntry[i].master = NULL;
72 for (j = 0; j < i; j++)
73 if (compareEntries(ginstate, attnum, entryValues[i], entryValues[j]) == 0)
75 key->scanEntry[i].master = key->scanEntry + j;
76 break;
81 #ifdef NOT_USED
83 static void
84 resetScanKeys(GinScanKey keys, uint32 nkeys)
86 uint32 i,
89 if (keys == NULL)
90 return;
92 for (i = 0; i < nkeys; i++)
94 GinScanKey key = keys + i;
96 key->firstCall = TRUE;
97 ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
99 for (j = 0; j < key->nentries; j++)
101 if (key->scanEntry[j].buffer != InvalidBuffer)
102 ReleaseBuffer(key->scanEntry[i].buffer);
104 ItemPointerSet(&(key->scanEntry[j].curItem), InvalidBlockNumber, InvalidOffsetNumber);
105 key->scanEntry[j].offset = InvalidOffsetNumber;
106 key->scanEntry[j].buffer = InvalidBuffer;
107 key->scanEntry[j].list = NULL;
108 key->scanEntry[j].nlist = 0;
109 key->scanEntry[j].partialMatch = NULL;
110 key->scanEntry[j].partialMatchResult = NULL;
114 #endif
116 static void
117 freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes)
119 uint32 i,
122 if (keys == NULL)
123 return;
125 for (i = 0; i < nkeys; i++)
127 GinScanKey key = keys + i;
129 for (j = 0; j < key->nentries; j++)
131 if (key->scanEntry[j].buffer != InvalidBuffer)
132 ReleaseBuffer(key->scanEntry[j].buffer);
133 if (removeRes && key->scanEntry[j].list)
134 pfree(key->scanEntry[j].list);
135 if (removeRes && key->scanEntry[j].partialMatch)
136 tbm_free(key->scanEntry[j].partialMatch);
139 if (removeRes)
140 pfree(key->entryRes);
141 pfree(key->scanEntry);
144 pfree(keys);
147 void
148 newScanKey(IndexScanDesc scan)
150 ScanKey scankey = scan->keyData;
151 GinScanOpaque so = (GinScanOpaque) scan->opaque;
152 int i;
153 uint32 nkeys = 0;
155 so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData));
157 if (scan->numberOfKeys < 1)
158 ereport(ERROR,
159 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
160 errmsg("GIN indexes do not support whole-index scans")));
162 so->isVoidRes = false;
164 for (i = 0; i < scan->numberOfKeys; i++)
166 Datum *entryValues;
167 int32 nEntryValues;
168 bool *partial_matches = NULL;
170 /* XXX can't we treat nulls by just setting isVoidRes? */
171 /* This would amount to assuming that all GIN operators are strict */
172 if (scankey[i].sk_flags & SK_ISNULL)
173 elog(ERROR, "GIN doesn't support NULL as scan key");
175 entryValues = (Datum *) DatumGetPointer(FunctionCall4(
176 &so->ginstate.extractQueryFn[scankey[i].sk_attno - 1],
177 scankey[i].sk_argument,
178 PointerGetDatum(&nEntryValues),
179 UInt16GetDatum(scankey[i].sk_strategy),
180 PointerGetDatum(&partial_matches)));
181 if (nEntryValues < 0)
184 * extractQueryFn signals that nothing will be found, so we can
185 * just set isVoidRes flag...
187 so->isVoidRes = true;
188 break;
192 * extractQueryFn signals that everything matches
194 if (entryValues == NULL || nEntryValues == 0)
195 /* full scan... */
196 continue;
198 fillScanKey(&so->ginstate, &(so->keys[nkeys]), scankey[i].sk_attno, scankey[i].sk_argument,
199 entryValues, partial_matches, nEntryValues, scankey[i].sk_strategy);
200 nkeys++;
203 so->nkeys = nkeys;
205 if (so->nkeys == 0 && !so->isVoidRes)
206 ereport(ERROR,
207 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
208 errmsg("GIN index does not support search with void query")));
210 pgstat_count_index_scan(scan->indexRelation);
213 Datum
214 ginrescan(PG_FUNCTION_ARGS)
216 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
217 ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
218 GinScanOpaque so;
220 so = (GinScanOpaque) scan->opaque;
222 if (so == NULL)
224 /* if called from ginbeginscan */
225 so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
226 so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
227 "Gin scan temporary context",
228 ALLOCSET_DEFAULT_MINSIZE,
229 ALLOCSET_DEFAULT_INITSIZE,
230 ALLOCSET_DEFAULT_MAXSIZE);
231 initGinState(&so->ginstate, scan->indexRelation);
232 scan->opaque = so;
234 else
236 freeScanKeys(so->keys, so->nkeys, TRUE);
237 freeScanKeys(so->markPos, so->nkeys, FALSE);
240 so->markPos = so->keys = NULL;
242 if (scankey && scan->numberOfKeys > 0)
244 memmove(scan->keyData, scankey,
245 scan->numberOfKeys * sizeof(ScanKeyData));
248 PG_RETURN_VOID();
252 Datum
253 ginendscan(PG_FUNCTION_ARGS)
255 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
256 GinScanOpaque so = (GinScanOpaque) scan->opaque;
258 if (so != NULL)
260 freeScanKeys(so->keys, so->nkeys, TRUE);
261 freeScanKeys(so->markPos, so->nkeys, FALSE);
263 MemoryContextDelete(so->tempCtx);
265 pfree(so);
268 PG_RETURN_VOID();
271 static GinScanKey
272 copyScanKeys(GinScanKey keys, uint32 nkeys, bool restart)
274 GinScanKey newkeys;
275 uint32 i,
278 newkeys = (GinScanKey) palloc(sizeof(GinScanKeyData) * nkeys);
279 memcpy(newkeys, keys, sizeof(GinScanKeyData) * nkeys);
281 for (i = 0; i < nkeys; i++)
283 newkeys[i].scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * keys[i].nentries);
284 memcpy(newkeys[i].scanEntry, keys[i].scanEntry, sizeof(GinScanEntryData) * keys[i].nentries);
286 for (j = 0; j < keys[i].nentries; j++)
288 if (keys[i].scanEntry[j].buffer != InvalidBuffer)
289 IncrBufferRefCount(keys[i].scanEntry[j].buffer);
290 if (keys[i].scanEntry[j].master)
292 int masterN = keys[i].scanEntry[j].master - keys[i].scanEntry;
294 newkeys[i].scanEntry[j].master = newkeys[i].scanEntry + masterN;
297 if ( restart )
298 ginrestartentry( &keys[i].scanEntry[j] );
302 return newkeys;
305 Datum
306 ginmarkpos(PG_FUNCTION_ARGS)
308 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
309 GinScanOpaque so = (GinScanOpaque) scan->opaque;
311 freeScanKeys(so->markPos, so->nkeys, FALSE);
312 so->markPos = copyScanKeys(so->keys, so->nkeys, FALSE);
314 PG_RETURN_VOID();
317 Datum
318 ginrestrpos(PG_FUNCTION_ARGS)
320 IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
321 GinScanOpaque so = (GinScanOpaque) scan->opaque;
323 freeScanKeys(so->keys, so->nkeys, FALSE);
324 so->keys = copyScanKeys(so->markPos, so->nkeys, TRUE);
326 PG_RETURN_VOID();