1/*--------------------------------------------------------------------------
2 * gin_private.h
3 * header file for postgres inverted index access method implementation.
4 *
5 * Copyright (c) 2006-2019, PostgreSQL Global Development Group
6 *
7 * src/include/access/gin_private.h
8 *--------------------------------------------------------------------------
9 */
10#ifndef GIN_PRIVATE_H
11#define GIN_PRIVATE_H
12
13#include "access/amapi.h"
14#include "access/gin.h"
15#include "access/ginblock.h"
16#include "access/itup.h"
17#include "fmgr.h"
18#include "storage/bufmgr.h"
19#include "lib/rbtree.h"
20
21/*
22 * Storage type for GIN's reloptions
23 */
24typedef struct GinOptions
25{
26 int32 vl_len_; /* varlena header (do not touch directly!) */
27 bool useFastUpdate; /* use fast updates? */
28 int pendingListCleanupSize; /* maximum size of pending list */
29} GinOptions;
30
31#define GIN_DEFAULT_USE_FASTUPDATE true
32#define GinGetUseFastUpdate(relation) \
33 ((relation)->rd_options ? \
34 ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
35#define GinGetPendingListCleanupSize(relation) \
36 ((relation)->rd_options && \
37 ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \
38 ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \
39 gin_pending_list_limit)
40
41
42/* Macros for buffer lock/unlock operations */
43#define GIN_UNLOCK BUFFER_LOCK_UNLOCK
44#define GIN_SHARE BUFFER_LOCK_SHARE
45#define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
46
47
48/*
49 * GinState: working data structure describing the index being worked on
50 */
51typedef struct GinState
52{
53 Relation index;
54 bool oneCol; /* true if single-column index */
55
56 /*
57 * origTupDesc is the nominal tuple descriptor of the index, ie, the i'th
58 * attribute shows the key type (not the input data type!) of the i'th
59 * index column. In a single-column index this describes the actual leaf
60 * index tuples. In a multi-column index, the actual leaf tuples contain
61 * a smallint column number followed by a key datum of the appropriate
62 * type for that column. We set up tupdesc[i] to describe the actual
63 * rowtype of the index tuples for the i'th column, ie, (int2, keytype).
64 * Note that in any case, leaf tuples contain more data than is known to
65 * the TupleDesc; see access/gin/README for details.
66 */
67 TupleDesc origTupdesc;
68 TupleDesc tupdesc[INDEX_MAX_KEYS];
69
70 /*
71 * Per-index-column opclass support functions
72 */
73 FmgrInfo compareFn[INDEX_MAX_KEYS];
74 FmgrInfo extractValueFn[INDEX_MAX_KEYS];
75 FmgrInfo extractQueryFn[INDEX_MAX_KEYS];
76 FmgrInfo consistentFn[INDEX_MAX_KEYS];
77 FmgrInfo triConsistentFn[INDEX_MAX_KEYS];
78 FmgrInfo comparePartialFn[INDEX_MAX_KEYS]; /* optional method */
79 /* canPartialMatch[i] is true if comparePartialFn[i] is valid */
80 bool canPartialMatch[INDEX_MAX_KEYS];
81 /* Collations to pass to the support functions */
82 Oid supportCollation[INDEX_MAX_KEYS];
83} GinState;
84
85
86/* ginutil.c */
87extern bytea *ginoptions(Datum reloptions, bool validate);
88extern void initGinState(GinState *state, Relation index);
89extern Buffer GinNewBuffer(Relation index);
90extern void GinInitBuffer(Buffer b, uint32 f);
91extern void GinInitPage(Page page, uint32 f, Size pageSize);
92extern void GinInitMetabuffer(Buffer b);
93extern int ginCompareEntries(GinState *ginstate, OffsetNumber attnum,
94 Datum a, GinNullCategory categorya,
95 Datum b, GinNullCategory categoryb);
96extern int ginCompareAttEntries(GinState *ginstate,
97 OffsetNumber attnuma, Datum a, GinNullCategory categorya,
98 OffsetNumber attnumb, Datum b, GinNullCategory categoryb);
99extern Datum *ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
100 Datum value, bool isNull,
101 int32 *nentries, GinNullCategory **categories);
102
103extern OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple);
104extern Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple,
105 GinNullCategory *category);
106
107/* gininsert.c */
108extern IndexBuildResult *ginbuild(Relation heap, Relation index,
109 struct IndexInfo *indexInfo);
110extern void ginbuildempty(Relation index);
111extern bool gininsert(Relation index, Datum *values, bool *isnull,
112 ItemPointer ht_ctid, Relation heapRel,
113 IndexUniqueCheck checkUnique,
114 struct IndexInfo *indexInfo);
115extern void ginEntryInsert(GinState *ginstate,
116 OffsetNumber attnum, Datum key, GinNullCategory category,
117 ItemPointerData *items, uint32 nitem,
118 GinStatsData *buildStats);
119
120/* ginbtree.c */
121
122typedef struct GinBtreeStack
123{
124 BlockNumber blkno;
125 Buffer buffer;
126 OffsetNumber off;
127 ItemPointerData iptr;
128 /* predictNumber contains predicted number of pages on current level */
129 uint32 predictNumber;
130 struct GinBtreeStack *parent;
131} GinBtreeStack;
132
133typedef struct GinBtreeData *GinBtree;
134
135/* Return codes for GinBtreeData.beginPlaceToPage method */
136typedef enum
137{
138 GPTP_NO_WORK,
139 GPTP_INSERT,
140 GPTP_SPLIT
141} GinPlaceToPageRC;
142
143typedef struct GinBtreeData
144{
145 /* search methods */
146 BlockNumber (*findChildPage) (GinBtree, GinBtreeStack *);
147 BlockNumber (*getLeftMostChild) (GinBtree, Page);
148 bool (*isMoveRight) (GinBtree, Page);
149 bool (*findItem) (GinBtree, GinBtreeStack *);
150
151 /* insert methods */
152 OffsetNumber (*findChildPtr) (GinBtree, Page, BlockNumber, OffsetNumber);
153 GinPlaceToPageRC (*beginPlaceToPage) (GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *);
154 void (*execPlaceToPage) (GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *);
155 void *(*prepareDownlink) (GinBtree, Buffer);
156 void (*fillRoot) (GinBtree, Page, BlockNumber, Page, BlockNumber, Page);
157
158 bool isData;
159
160 Relation index;
161 BlockNumber rootBlkno;
162 GinState *ginstate; /* not valid in a data scan */
163 bool fullScan;
164 bool isBuild;
165
166 /* Search key for Entry tree */
167 OffsetNumber entryAttnum;
168 Datum entryKey;
169 GinNullCategory entryCategory;
170
171 /* Search key for data tree (posting tree) */
172 ItemPointerData itemptr;
173} GinBtreeData;
174
175/* This represents a tuple to be inserted to entry tree. */
176typedef struct
177{
178 IndexTuple entry; /* tuple to insert */
179 bool isDelete; /* delete old tuple at same offset? */
180} GinBtreeEntryInsertData;
181
182/*
183 * This represents an itempointer, or many itempointers, to be inserted to
184 * a data (posting tree) leaf page
185 */
186typedef struct
187{
188 ItemPointerData *items;
189 uint32 nitem;
190 uint32 curitem;
191} GinBtreeDataLeafInsertData;
192
193/*
194 * For internal data (posting tree) pages, the insertion payload is a
195 * PostingItem
196 */
197
198extern GinBtreeStack *ginFindLeafPage(GinBtree btree, bool searchMode,
199 bool rootConflictCheck, Snapshot snapshot);
200extern Buffer ginStepRight(Buffer buffer, Relation index, int lockmode);
201extern void freeGinBtreeStack(GinBtreeStack *stack);
202extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack,
203 void *insertdata, GinStatsData *buildStats);
204
205/* ginentrypage.c */
206extern IndexTuple GinFormTuple(GinState *ginstate,
207 OffsetNumber attnum, Datum key, GinNullCategory category,
208 Pointer data, Size dataSize, int nipd, bool errorTooBig);
209extern void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum,
210 Datum key, GinNullCategory category,
211 GinState *ginstate);
212extern void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage);
213extern ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum,
214 IndexTuple itup, int *nitems);
215
216/* gindatapage.c */
217extern ItemPointer GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast);
218extern int GinDataLeafPageGetItemsToTbm(Page page, TIDBitmap *tbm);
219extern BlockNumber createPostingTree(Relation index,
220 ItemPointerData *items, uint32 nitems,
221 GinStatsData *buildStats, Buffer entrybuffer);
222extern void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset);
223extern void GinPageDeletePostingItem(Page page, OffsetNumber offset);
224extern void ginInsertItemPointers(Relation index, BlockNumber rootBlkno,
225 ItemPointerData *items, uint32 nitem,
226 GinStatsData *buildStats);
227extern GinBtreeStack *ginScanBeginPostingTree(GinBtree btree, Relation index, BlockNumber rootBlkno, Snapshot snapshot);
228extern void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage);
229
230/*
231 * This is declared in ginvacuum.c, but is passed between ginVacuumItemPointers
232 * and ginVacuumPostingTreeLeaf and as an opaque struct, so we need a forward
233 * declaration for it.
234 */
235typedef struct GinVacuumState GinVacuumState;
236
237extern void ginVacuumPostingTreeLeaf(Relation rel, Buffer buf, GinVacuumState *gvs);
238
239/* ginscan.c */
240
241/*
242 * GinScanKeyData describes a single GIN index qualifier expression.
243 *
244 * From each qual expression, we extract one or more specific index search
245 * conditions, which are represented by GinScanEntryData. It's quite
246 * possible for identical search conditions to be requested by more than
247 * one qual expression, in which case we merge such conditions to have just
248 * one unique GinScanEntry --- this is particularly important for efficiency
249 * when dealing with full-index-scan entries. So there can be multiple
250 * GinScanKeyData.scanEntry pointers to the same GinScanEntryData.
251 *
252 * In each GinScanKeyData, nentries is the true number of entries, while
253 * nuserentries is the number that extractQueryFn returned (which is what
254 * we report to consistentFn). The "user" entries must come first.
255 */
256typedef struct GinScanKeyData *GinScanKey;
257
258typedef struct GinScanEntryData *GinScanEntry;
259
260typedef struct GinScanKeyData
261{
262 /* Real number of entries in scanEntry[] (always > 0) */
263 uint32 nentries;
264 /* Number of entries that extractQueryFn and consistentFn know about */
265 uint32 nuserentries;
266
267 /* array of GinScanEntry pointers, one per extracted search condition */
268 GinScanEntry *scanEntry;
269
270 /*
271 * At least one of the entries in requiredEntries must be present for a
272 * tuple to match the overall qual.
273 *
274 * additionalEntries contains entries that are needed by the consistent
275 * function to decide if an item matches, but are not sufficient to
276 * satisfy the qual without entries from requiredEntries.
277 */
278 GinScanEntry *requiredEntries;
279 int nrequired;
280 GinScanEntry *additionalEntries;
281 int nadditional;
282
283 /* array of check flags, reported to consistentFn */
284 GinTernaryValue *entryRes;
285 bool (*boolConsistentFn) (GinScanKey key);
286 GinTernaryValue (*triConsistentFn) (GinScanKey key);
287 FmgrInfo *consistentFmgrInfo;
288 FmgrInfo *triConsistentFmgrInfo;
289 Oid collation;
290
291 /* other data needed for calling consistentFn */
292 Datum query;
293 /* NB: these three arrays have only nuserentries elements! */
294 Datum *queryValues;
295 GinNullCategory *queryCategories;
296 Pointer *extra_data;
297 StrategyNumber strategy;
298 int32 searchMode;
299 OffsetNumber attnum;
300
301 /*
302 * Match status data. curItem is the TID most recently tested (could be a
303 * lossy-page pointer). curItemMatches is true if it passes the
304 * consistentFn test; if so, recheckCurItem is the recheck flag.
305 * isFinished means that all the input entry streams are finished, so this
306 * key cannot succeed for any later TIDs.
307 */
308 ItemPointerData curItem;
309 bool curItemMatches;
310 bool recheckCurItem;
311 bool isFinished;
312} GinScanKeyData;
313
314typedef struct GinScanEntryData
315{
316 /* query key and other information from extractQueryFn */
317 Datum queryKey;
318 GinNullCategory queryCategory;
319 bool isPartialMatch;
320 Pointer extra_data;
321 StrategyNumber strategy;
322 int32 searchMode;
323 OffsetNumber attnum;
324
325 /* Current page in posting tree */
326 Buffer buffer;
327
328 /* current ItemPointer to heap */
329 ItemPointerData curItem;
330
331 /* for a partial-match or full-scan query, we accumulate all TIDs here */
332 TIDBitmap *matchBitmap;
333 TBMIterator *matchIterator;
334 TBMIterateResult *matchResult;
335
336 /* used for Posting list and one page in Posting tree */
337 ItemPointerData *list;
338 int nlist;
339 OffsetNumber offset;
340
341 bool isFinished;
342 bool reduceResult;
343 uint32 predictNumberResult;
344 GinBtreeData btree;
345} GinScanEntryData;
346
347typedef struct GinScanOpaqueData
348{
349 MemoryContext tempCtx;
350 GinState ginstate;
351
352 GinScanKey keys; /* one per scan qualifier expr */
353 uint32 nkeys;
354
355 GinScanEntry *entries; /* one per index search condition */
356 uint32 totalentries;
357 uint32 allocentries; /* allocated length of entries[] */
358
359 MemoryContext keyCtx; /* used to hold key and entry data */
360
361 bool isVoidRes; /* true if query is unsatisfiable */
362} GinScanOpaqueData;
363
364typedef GinScanOpaqueData *GinScanOpaque;
365
366extern IndexScanDesc ginbeginscan(Relation rel, int nkeys, int norderbys);
367extern void ginendscan(IndexScanDesc scan);
368extern void ginrescan(IndexScanDesc scan, ScanKey key, int nscankeys,
369 ScanKey orderbys, int norderbys);
370extern void ginNewScanKey(IndexScanDesc scan);
371extern void ginFreeScanKeys(GinScanOpaque so);
372
373/* ginget.c */
374extern int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
375
376/* ginlogic.c */
377extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key);
378
379/* ginvacuum.c */
380extern IndexBulkDeleteResult *ginbulkdelete(IndexVacuumInfo *info,
381 IndexBulkDeleteResult *stats,
382 IndexBulkDeleteCallback callback,
383 void *callback_state);
384extern IndexBulkDeleteResult *ginvacuumcleanup(IndexVacuumInfo *info,
385 IndexBulkDeleteResult *stats);
386extern ItemPointer ginVacuumItemPointers(GinVacuumState *gvs,
387 ItemPointerData *items, int nitem, int *nremaining);
388
389/* ginvalidate.c */
390extern bool ginvalidate(Oid opclassoid);
391
392/* ginbulk.c */
393typedef struct GinEntryAccumulator
394{
395 RBTNode rbtnode;
396 Datum key;
397 GinNullCategory category;
398 OffsetNumber attnum;
399 bool shouldSort;
400 ItemPointerData *list;
401 uint32 maxcount; /* allocated size of list[] */
402 uint32 count; /* current number of list[] entries */
403} GinEntryAccumulator;
404
405typedef struct
406{
407 GinState *ginstate;
408 Size allocatedMemory;
409 GinEntryAccumulator *entryallocator;
410 uint32 eas_used;
411 RBTree *tree;
412 RBTreeIterator tree_walk;
413} BuildAccumulator;
414
415extern void ginInitBA(BuildAccumulator *accum);
416extern void ginInsertBAEntries(BuildAccumulator *accum,
417 ItemPointer heapptr, OffsetNumber attnum,
418 Datum *entries, GinNullCategory *categories,
419 int32 nentries);
420extern void ginBeginBAScan(BuildAccumulator *accum);
421extern ItemPointerData *ginGetBAEntry(BuildAccumulator *accum,
422 OffsetNumber *attnum, Datum *key, GinNullCategory *category,
423 uint32 *n);
424
425/* ginfast.c */
426
427typedef struct GinTupleCollector
428{
429 IndexTuple *tuples;
430 uint32 ntuples;
431 uint32 lentuples;
432 uint32 sumsize;
433} GinTupleCollector;
434
435extern void ginHeapTupleFastInsert(GinState *ginstate,
436 GinTupleCollector *collector);
437extern void ginHeapTupleFastCollect(GinState *ginstate,
438 GinTupleCollector *collector,
439 OffsetNumber attnum, Datum value, bool isNull,
440 ItemPointer ht_ctid);
441extern void ginInsertCleanup(GinState *ginstate, bool full_clean,
442 bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats);
443
444/* ginpostinglist.c */
445
446extern GinPostingList *ginCompressPostingList(const ItemPointer ptrs, int nptrs,
447 int maxsize, int *nwritten);
448extern int ginPostingListDecodeAllSegmentsToTbm(GinPostingList *ptr, int totalsize, TIDBitmap *tbm);
449
450extern ItemPointer ginPostingListDecodeAllSegments(GinPostingList *ptr, int len, int *ndecoded);
451extern ItemPointer ginPostingListDecode(GinPostingList *ptr, int *ndecoded);
452extern ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na,
453 ItemPointerData *b, uint32 nb,
454 int *nmerged);
455
456/*
457 * Merging the results of several gin scans compares item pointers a lot,
458 * so we want this to be inlined.
459 */
460static inline int
461ginCompareItemPointers(ItemPointer a, ItemPointer b)
462{
463 uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
464 uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
465
466 if (ia == ib)
467 return 0;
468 else if (ia > ib)
469 return 1;
470 else
471 return -1;
472}
473
474extern int ginTraverseLock(Buffer buffer, bool searchMode);
475
476#endif /* GIN_PRIVATE_H */
477