1 /*--------------------------------------------------------------------------
3 * header file for postgres inverted index access method implementation.
5 * Copyright (c) 2006-2021, PostgreSQL Global Development Group
7 * src/include/access/gin_private.h
8 *--------------------------------------------------------------------------
13 #include "access/amapi.h"
14 #include "access/gin.h"
15 #include "access/ginblock.h"
16 #include "access/itup.h"
17 #include "catalog/pg_am_d.h"
19 #include "lib/rbtree.h"
20 #include "storage/bufmgr.h"
23 * Storage type for GIN's reloptions
25 typedef struct GinOptions
27 int32 vl_len_
; /* varlena header (do not touch directly!) */
28 bool useFastUpdate
; /* use fast updates? */
29 int pendingListCleanupSize
; /* maximum size of pending list */
32 #define GIN_DEFAULT_USE_FASTUPDATE true
33 #define GinGetUseFastUpdate(relation) \
34 (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
35 relation->rd_rel->relam == GIN_AM_OID), \
36 (relation)->rd_options ? \
37 ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
38 #define GinGetPendingListCleanupSize(relation) \
39 (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
40 relation->rd_rel->relam == GIN_AM_OID), \
41 (relation)->rd_options && \
42 ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \
43 ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \
44 gin_pending_list_limit)
47 /* Macros for buffer lock/unlock operations */
48 #define GIN_UNLOCK BUFFER_LOCK_UNLOCK
49 #define GIN_SHARE BUFFER_LOCK_SHARE
50 #define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
54 * GinState: working data structure describing the index being worked on
56 typedef struct GinState
59 bool oneCol
; /* true if single-column index */
62 * origTupdesc is the nominal tuple descriptor of the index, ie, the i'th
63 * attribute shows the key type (not the input data type!) of the i'th
64 * index column. In a single-column index this describes the actual leaf
65 * index tuples. In a multi-column index, the actual leaf tuples contain
66 * a smallint column number followed by a key datum of the appropriate
67 * type for that column. We set up tupdesc[i] to describe the actual
68 * rowtype of the index tuples for the i'th column, ie, (int2, keytype).
69 * Note that in any case, leaf tuples contain more data than is known to
70 * the TupleDesc; see access/gin/README for details.
72 TupleDesc origTupdesc
;
73 TupleDesc tupdesc
[INDEX_MAX_KEYS
];
76 * Per-index-column opclass support functions
78 FmgrInfo compareFn
[INDEX_MAX_KEYS
];
79 FmgrInfo extractValueFn
[INDEX_MAX_KEYS
];
80 FmgrInfo extractQueryFn
[INDEX_MAX_KEYS
];
81 FmgrInfo consistentFn
[INDEX_MAX_KEYS
];
82 FmgrInfo triConsistentFn
[INDEX_MAX_KEYS
];
83 FmgrInfo comparePartialFn
[INDEX_MAX_KEYS
]; /* optional method */
84 /* canPartialMatch[i] is true if comparePartialFn[i] is valid */
85 bool canPartialMatch
[INDEX_MAX_KEYS
];
86 /* Collations to pass to the support functions */
87 Oid supportCollation
[INDEX_MAX_KEYS
];
92 extern bytea
*ginoptions(Datum reloptions
, bool validate
);
93 extern void initGinState(GinState
*state
, Relation index
);
94 extern Buffer
GinNewBuffer(Relation index
);
95 extern void GinInitBuffer(Buffer b
, uint32 f
);
96 extern void GinInitPage(Page page
, uint32 f
, Size pageSize
);
97 extern void GinInitMetabuffer(Buffer b
);
98 extern int ginCompareEntries(GinState
*ginstate
, OffsetNumber attnum
,
99 Datum a
, GinNullCategory categorya
,
100 Datum b
, GinNullCategory categoryb
);
101 extern int ginCompareAttEntries(GinState
*ginstate
,
102 OffsetNumber attnuma
, Datum a
, GinNullCategory categorya
,
103 OffsetNumber attnumb
, Datum b
, GinNullCategory categoryb
);
104 extern Datum
*ginExtractEntries(GinState
*ginstate
, OffsetNumber attnum
,
105 Datum value
, bool isNull
,
106 int32
*nentries
, GinNullCategory
**categories
);
108 extern OffsetNumber
gintuple_get_attrnum(GinState
*ginstate
, IndexTuple tuple
);
109 extern Datum
gintuple_get_key(GinState
*ginstate
, IndexTuple tuple
,
110 GinNullCategory
*category
);
113 extern IndexBuildResult
*ginbuild(Relation heap
, Relation index
,
114 struct IndexInfo
*indexInfo
);
115 extern void ginbuildempty(Relation index
);
116 extern bool gininsert(Relation index
, Datum
*values
, bool *isnull
,
117 ItemPointer ht_ctid
, Relation heapRel
,
118 IndexUniqueCheck checkUnique
,
120 struct IndexInfo
*indexInfo
);
121 extern void ginEntryInsert(GinState
*ginstate
,
122 OffsetNumber attnum
, Datum key
, GinNullCategory category
,
123 ItemPointerData
*items
, uint32 nitem
,
124 GinStatsData
*buildStats
);
128 typedef struct GinBtreeStack
133 ItemPointerData iptr
;
134 /* predictNumber contains predicted number of pages on current level */
135 uint32 predictNumber
;
136 struct GinBtreeStack
*parent
;
139 typedef struct GinBtreeData
*GinBtree
;
141 /* Return codes for GinBtreeData.beginPlaceToPage method */
149 typedef struct GinBtreeData
152 BlockNumber (*findChildPage
) (GinBtree
, GinBtreeStack
*);
153 BlockNumber (*getLeftMostChild
) (GinBtree
, Page
);
154 bool (*isMoveRight
) (GinBtree
, Page
);
155 bool (*findItem
) (GinBtree
, GinBtreeStack
*);
158 OffsetNumber (*findChildPtr
) (GinBtree
, Page
, BlockNumber
, OffsetNumber
);
159 GinPlaceToPageRC (*beginPlaceToPage
) (GinBtree
, Buffer
, GinBtreeStack
*, void *, BlockNumber
, void **, Page
*, Page
*);
160 void (*execPlaceToPage
) (GinBtree
, Buffer
, GinBtreeStack
*, void *, BlockNumber
, void *);
161 void *(*prepareDownlink
) (GinBtree
, Buffer
);
162 void (*fillRoot
) (GinBtree
, Page
, BlockNumber
, Page
, BlockNumber
, Page
);
167 BlockNumber rootBlkno
;
168 GinState
*ginstate
; /* not valid in a data scan */
172 /* Search key for Entry tree */
173 OffsetNumber entryAttnum
;
175 GinNullCategory entryCategory
;
177 /* Search key for data tree (posting tree) */
178 ItemPointerData itemptr
;
181 /* This represents a tuple to be inserted to entry tree. */
184 IndexTuple entry
; /* tuple to insert */
185 bool isDelete
; /* delete old tuple at same offset? */
186 } GinBtreeEntryInsertData
;
189 * This represents an itempointer, or many itempointers, to be inserted to
190 * a data (posting tree) leaf page
194 ItemPointerData
*items
;
197 } GinBtreeDataLeafInsertData
;
200 * For internal data (posting tree) pages, the insertion payload is a
204 extern GinBtreeStack
*ginFindLeafPage(GinBtree btree
, bool searchMode
,
205 bool rootConflictCheck
, Snapshot snapshot
);
206 extern Buffer
ginStepRight(Buffer buffer
, Relation index
, int lockmode
);
207 extern void freeGinBtreeStack(GinBtreeStack
*stack
);
208 extern void ginInsertValue(GinBtree btree
, GinBtreeStack
*stack
,
209 void *insertdata
, GinStatsData
*buildStats
);
212 extern IndexTuple
GinFormTuple(GinState
*ginstate
,
213 OffsetNumber attnum
, Datum key
, GinNullCategory category
,
214 Pointer data
, Size dataSize
, int nipd
, bool errorTooBig
);
215 extern void ginPrepareEntryScan(GinBtree btree
, OffsetNumber attnum
,
216 Datum key
, GinNullCategory category
,
218 extern void ginEntryFillRoot(GinBtree btree
, Page root
, BlockNumber lblkno
, Page lpage
, BlockNumber rblkno
, Page rpage
);
219 extern ItemPointer
ginReadTuple(GinState
*ginstate
, OffsetNumber attnum
,
220 IndexTuple itup
, int *nitems
);
223 extern ItemPointer
GinDataLeafPageGetItems(Page page
, int *nitems
, ItemPointerData advancePast
);
224 extern int GinDataLeafPageGetItemsToTbm(Page page
, TIDBitmap
*tbm
);
225 extern BlockNumber
createPostingTree(Relation index
,
226 ItemPointerData
*items
, uint32 nitems
,
227 GinStatsData
*buildStats
, Buffer entrybuffer
);
228 extern void GinDataPageAddPostingItem(Page page
, PostingItem
*data
, OffsetNumber offset
);
229 extern void GinPageDeletePostingItem(Page page
, OffsetNumber offset
);
230 extern void ginInsertItemPointers(Relation index
, BlockNumber rootBlkno
,
231 ItemPointerData
*items
, uint32 nitem
,
232 GinStatsData
*buildStats
);
233 extern GinBtreeStack
*ginScanBeginPostingTree(GinBtree btree
, Relation index
, BlockNumber rootBlkno
, Snapshot snapshot
);
234 extern void ginDataFillRoot(GinBtree btree
, Page root
, BlockNumber lblkno
, Page lpage
, BlockNumber rblkno
, Page rpage
);
237 * This is declared in ginvacuum.c, but is passed between ginVacuumItemPointers
238 * and ginVacuumPostingTreeLeaf and as an opaque struct, so we need a forward
239 * declaration for it.
241 typedef struct GinVacuumState GinVacuumState
;
243 extern void ginVacuumPostingTreeLeaf(Relation rel
, Buffer buf
, GinVacuumState
*gvs
);
248 * GinScanKeyData describes a single GIN index qualifier expression.
250 * From each qual expression, we extract one or more specific index search
251 * conditions, which are represented by GinScanEntryData. It's quite
252 * possible for identical search conditions to be requested by more than
253 * one qual expression, in which case we merge such conditions to have just
254 * one unique GinScanEntry --- this is particularly important for efficiency
255 * when dealing with full-index-scan entries. So there can be multiple
256 * GinScanKeyData.scanEntry pointers to the same GinScanEntryData.
258 * In each GinScanKeyData, nentries is the true number of entries, while
259 * nuserentries is the number that extractQueryFn returned (which is what
260 * we report to consistentFn). The "user" entries must come first.
262 typedef struct GinScanKeyData
*GinScanKey
;
264 typedef struct GinScanEntryData
*GinScanEntry
;
266 typedef struct GinScanKeyData
268 /* Real number of entries in scanEntry[] (always > 0) */
270 /* Number of entries that extractQueryFn and consistentFn know about */
273 /* array of GinScanEntry pointers, one per extracted search condition */
274 GinScanEntry
*scanEntry
;
277 * At least one of the entries in requiredEntries must be present for a
278 * tuple to match the overall qual.
280 * additionalEntries contains entries that are needed by the consistent
281 * function to decide if an item matches, but are not sufficient to
282 * satisfy the qual without entries from requiredEntries.
284 GinScanEntry
*requiredEntries
;
286 GinScanEntry
*additionalEntries
;
289 /* array of check flags, reported to consistentFn */
290 GinTernaryValue
*entryRes
;
291 bool (*boolConsistentFn
) (GinScanKey key
);
292 GinTernaryValue (*triConsistentFn
) (GinScanKey key
);
293 FmgrInfo
*consistentFmgrInfo
;
294 FmgrInfo
*triConsistentFmgrInfo
;
297 /* other data needed for calling consistentFn */
299 /* NB: these three arrays have only nuserentries elements! */
301 GinNullCategory
*queryCategories
;
303 StrategyNumber strategy
;
308 * An excludeOnly scan key is not able to enumerate all matching tuples.
309 * That is, to be semantically correct on its own, it would need to have a
310 * GIN_CAT_EMPTY_QUERY scanEntry, but it doesn't. Such a key can still be
311 * used to filter tuples returned by other scan keys, so we will get the
312 * right answers as long as there's at least one non-excludeOnly scan key
313 * for each index attribute considered by the search. For efficiency
314 * reasons we don't want to have unnecessary GIN_CAT_EMPTY_QUERY entries,
315 * so we will convert an excludeOnly scan key to non-excludeOnly (by
316 * adding a GIN_CAT_EMPTY_QUERY scanEntry) only if there are no other
317 * non-excludeOnly scan keys.
322 * Match status data. curItem is the TID most recently tested (could be a
323 * lossy-page pointer). curItemMatches is true if it passes the
324 * consistentFn test; if so, recheckCurItem is the recheck flag.
325 * isFinished means that all the input entry streams are finished, so this
326 * key cannot succeed for any later TIDs.
328 ItemPointerData curItem
;
334 typedef struct GinScanEntryData
336 /* query key and other information from extractQueryFn */
338 GinNullCategory queryCategory
;
341 StrategyNumber strategy
;
345 /* Current page in posting tree */
348 /* current ItemPointer to heap */
349 ItemPointerData curItem
;
351 /* for a partial-match or full-scan query, we accumulate all TIDs here */
352 TIDBitmap
*matchBitmap
;
353 TBMIterator
*matchIterator
;
354 TBMIterateResult
*matchResult
;
356 /* used for Posting list and one page in Posting tree */
357 ItemPointerData
*list
;
363 uint32 predictNumberResult
;
367 typedef struct GinScanOpaqueData
369 MemoryContext tempCtx
;
372 GinScanKey keys
; /* one per scan qualifier expr */
375 GinScanEntry
*entries
; /* one per index search condition */
377 uint32 allocentries
; /* allocated length of entries[] */
379 MemoryContext keyCtx
; /* used to hold key and entry data */
381 bool isVoidRes
; /* true if query is unsatisfiable */
384 typedef GinScanOpaqueData
*GinScanOpaque
;
386 extern IndexScanDesc
ginbeginscan(Relation rel
, int nkeys
, int norderbys
);
387 extern void ginendscan(IndexScanDesc scan
);
388 extern void ginrescan(IndexScanDesc scan
, ScanKey key
, int nscankeys
,
389 ScanKey orderbys
, int norderbys
);
390 extern void ginNewScanKey(IndexScanDesc scan
);
391 extern void ginFreeScanKeys(GinScanOpaque so
);
394 extern int64
gingetbitmap(IndexScanDesc scan
, TIDBitmap
*tbm
);
397 extern void ginInitConsistentFunction(GinState
*ginstate
, GinScanKey key
);
400 extern IndexBulkDeleteResult
*ginbulkdelete(IndexVacuumInfo
*info
,
401 IndexBulkDeleteResult
*stats
,
402 IndexBulkDeleteCallback callback
,
403 void *callback_state
);
404 extern IndexBulkDeleteResult
*ginvacuumcleanup(IndexVacuumInfo
*info
,
405 IndexBulkDeleteResult
*stats
);
406 extern ItemPointer
ginVacuumItemPointers(GinVacuumState
*gvs
,
407 ItemPointerData
*items
, int nitem
, int *nremaining
);
410 extern bool ginvalidate(Oid opclassoid
);
411 extern void ginadjustmembers(Oid opfamilyoid
,
417 typedef struct GinEntryAccumulator
421 GinNullCategory category
;
424 ItemPointerData
*list
;
425 uint32 maxcount
; /* allocated size of list[] */
426 uint32 count
; /* current number of list[] entries */
427 } GinEntryAccumulator
;
432 Size allocatedMemory
;
433 GinEntryAccumulator
*entryallocator
;
436 RBTreeIterator tree_walk
;
439 extern void ginInitBA(BuildAccumulator
*accum
);
440 extern void ginInsertBAEntries(BuildAccumulator
*accum
,
441 ItemPointer heapptr
, OffsetNumber attnum
,
442 Datum
*entries
, GinNullCategory
*categories
,
444 extern void ginBeginBAScan(BuildAccumulator
*accum
);
445 extern ItemPointerData
*ginGetBAEntry(BuildAccumulator
*accum
,
446 OffsetNumber
*attnum
, Datum
*key
, GinNullCategory
*category
,
451 typedef struct GinTupleCollector
459 extern void ginHeapTupleFastInsert(GinState
*ginstate
,
460 GinTupleCollector
*collector
);
461 extern void ginHeapTupleFastCollect(GinState
*ginstate
,
462 GinTupleCollector
*collector
,
463 OffsetNumber attnum
, Datum value
, bool isNull
,
464 ItemPointer ht_ctid
);
465 extern void ginInsertCleanup(GinState
*ginstate
, bool full_clean
,
466 bool fill_fsm
, bool forceCleanup
, IndexBulkDeleteResult
*stats
);
468 /* ginpostinglist.c */
470 extern GinPostingList
*ginCompressPostingList(const ItemPointer ipd
, int nipd
,
471 int maxsize
, int *nwritten
);
472 extern int ginPostingListDecodeAllSegmentsToTbm(GinPostingList
*ptr
, int totalsize
, TIDBitmap
*tbm
);
474 extern ItemPointer
ginPostingListDecodeAllSegments(GinPostingList
*ptr
, int len
, int *ndecoded
);
475 extern ItemPointer
ginPostingListDecode(GinPostingList
*ptr
, int *ndecoded
);
476 extern ItemPointer
ginMergeItemPointers(ItemPointerData
*a
, uint32 na
,
477 ItemPointerData
*b
, uint32 nb
,
481 * Merging the results of several gin scans compares item pointers a lot,
482 * so we want this to be inlined.
485 ginCompareItemPointers(ItemPointer a
, ItemPointer b
)
487 uint64 ia
= (uint64
) GinItemPointerGetBlockNumber(a
) << 32 | GinItemPointerGetOffsetNumber(a
);
488 uint64 ib
= (uint64
) GinItemPointerGetBlockNumber(b
) << 32 | GinItemPointerGetOffsetNumber(b
);
498 extern int ginTraverseLock(Buffer buffer
, bool searchMode
);
500 #endif /* GIN_PRIVATE_H */