1 /*-------------------------------------------------------------------------
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
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
)
46 key
->nentries
= nEntryValues
;
47 key
->entryRes
= (bool *) palloc0(sizeof(bool) * nEntryValues
);
48 key
->scanEntry
= (GinScanEntry
) palloc(sizeof(GinScanEntryData
) * nEntryValues
);
49 key
->strategy
= strategy
;
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
;
84 resetScanKeys(GinScanKey keys
, uint32 nkeys
)
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
;
117 freeScanKeys(GinScanKey keys
, uint32 nkeys
, bool removeRes
)
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
);
140 pfree(key
->entryRes
);
141 pfree(key
->scanEntry
);
148 newScanKey(IndexScanDesc scan
)
150 ScanKey scankey
= scan
->keyData
;
151 GinScanOpaque so
= (GinScanOpaque
) scan
->opaque
;
155 so
->keys
= (GinScanKey
) palloc(scan
->numberOfKeys
* sizeof(GinScanKeyData
));
157 if (scan
->numberOfKeys
< 1)
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
++)
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;
192 * extractQueryFn signals that everything matches
194 if (entryValues
== NULL
|| nEntryValues
== 0)
198 fillScanKey(&so
->ginstate
, &(so
->keys
[nkeys
]), scankey
[i
].sk_attno
, scankey
[i
].sk_argument
,
199 entryValues
, partial_matches
, nEntryValues
, scankey
[i
].sk_strategy
);
205 if (so
->nkeys
== 0 && !so
->isVoidRes
)
207 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
208 errmsg("GIN index does not support search with void query")));
210 pgstat_count_index_scan(scan
->indexRelation
);
214 ginrescan(PG_FUNCTION_ARGS
)
216 IndexScanDesc scan
= (IndexScanDesc
) PG_GETARG_POINTER(0);
217 ScanKey scankey
= (ScanKey
) PG_GETARG_POINTER(1);
220 so
= (GinScanOpaque
) scan
->opaque
;
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
);
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
));
253 ginendscan(PG_FUNCTION_ARGS
)
255 IndexScanDesc scan
= (IndexScanDesc
) PG_GETARG_POINTER(0);
256 GinScanOpaque so
= (GinScanOpaque
) scan
->opaque
;
260 freeScanKeys(so
->keys
, so
->nkeys
, TRUE
);
261 freeScanKeys(so
->markPos
, so
->nkeys
, FALSE
);
263 MemoryContextDelete(so
->tempCtx
);
272 copyScanKeys(GinScanKey keys
, uint32 nkeys
, bool restart
)
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
;
298 ginrestartentry( &keys
[i
].scanEntry
[j
] );
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
);
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
);