1/*--------------------------------------------------------------------------
3 * header file for postgres inverted index access method implementation.
5 * Copyright (c) 2006-2025, PostgreSQL Global Development Group
7 * src/include/access/gin_private.h
8 *--------------------------------------------------------------------------
19#include "catalog/pg_am_d.h"
25 * Storage type for GIN's reloptions
34 #define GIN_DEFAULT_USE_FASTUPDATE true
35 #define GinGetUseFastUpdate(relation) \
36 (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
37 relation->rd_rel->relam == GIN_AM_OID), \
38 (relation)->rd_options ? \
39 ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
40 #define GinGetPendingListCleanupSize(relation) \
41 (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
42 relation->rd_rel->relam == GIN_AM_OID), \
43 (relation)->rd_options && \
44 ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \
45 ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \
46 gin_pending_list_limit)
49/* Macros for buffer lock/unlock operations */
50 #define GIN_UNLOCK BUFFER_LOCK_UNLOCK
51 #define GIN_SHARE BUFFER_LOCK_SHARE
52 #define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
56 * GinState: working data structure describing the index being worked on
61 bool oneCol;
/* true if single-column index */
64 * origTupdesc is the nominal tuple descriptor of the index, ie, the i'th
65 * attribute shows the key type (not the input data type!) of the i'th
66 * index column. In a single-column index this describes the actual leaf
67 * index tuples. In a multi-column index, the actual leaf tuples contain
68 * a smallint column number followed by a key datum of the appropriate
69 * type for that column. We set up tupdesc[i] to describe the actual
70 * rowtype of the index tuples for the i'th column, ie, (int2, keytype).
71 * Note that in any case, leaf tuples contain more data than is known to
72 * the TupleDesc; see access/gin/README for details.
78 * Per-index-column opclass support functions
86 /* canPartialMatch[i] is true if comparePartialFn[i] is valid */
88 /* Collations to pass to the support functions */
137 /* predictNumber contains predicted number of pages on current level */
144/* Return codes for GinBtreeData.beginPlaceToPage method */
175 /* Search key for Entry tree */
180 /* Search key for data tree (posting tree) */
184/* This represents a tuple to be inserted to entry tree. */
188 bool isDelete;
/* delete old tuple at same offset? */
192 * This represents an itempointer, or many itempointers, to be inserted to
193 * a data (posting tree) leaf page
203 * For internal data (posting tree) pages, the insertion payload is a
208 bool rootConflictCheck);
240 * This is declared in ginvacuum.c, but is passed between ginVacuumItemPointers
241 * and ginVacuumPostingTreeLeaf and as an opaque struct, so we need a forward
242 * declaration for it.
252 * GinScanKeyData describes a single GIN index qualifier expression.
254 * From each qual expression, we extract one or more specific index search
255 * conditions, which are represented by GinScanEntryData. It's quite
256 * possible for identical search conditions to be requested by more than
257 * one qual expression, in which case we merge such conditions to have just
258 * one unique GinScanEntry --- this is particularly important for efficiency
259 * when dealing with full-index-scan entries. So there can be multiple
260 * GinScanKeyData.scanEntry pointers to the same GinScanEntryData.
262 * In each GinScanKeyData, nentries is the true number of entries, while
263 * nuserentries is the number that extractQueryFn returned (which is what
264 * we report to consistentFn). The "user" entries must come first.
272 /* Real number of entries in scanEntry[] (always > 0) */
274 /* Number of entries that extractQueryFn and consistentFn know about */
277 /* array of GinScanEntry pointers, one per extracted search condition */
281 * At least one of the entries in requiredEntries must be present for a
282 * tuple to match the overall qual.
284 * additionalEntries contains entries that are needed by the consistent
285 * function to decide if an item matches, but are not sufficient to
286 * satisfy the qual without entries from requiredEntries.
293 /* array of check flags, reported to consistentFn */
301 /* other data needed for calling consistentFn */
303 /* NB: these three arrays have only nuserentries elements! */
312 * An excludeOnly scan key is not able to enumerate all matching tuples.
313 * That is, to be semantically correct on its own, it would need to have a
314 * GIN_CAT_EMPTY_QUERY scanEntry, but it doesn't. Such a key can still be
315 * used to filter tuples returned by other scan keys, so we will get the
316 * right answers as long as there's at least one non-excludeOnly scan key
317 * for each index attribute considered by the search. For efficiency
318 * reasons we don't want to have unnecessary GIN_CAT_EMPTY_QUERY entries,
319 * so we will convert an excludeOnly scan key to non-excludeOnly (by
320 * adding a GIN_CAT_EMPTY_QUERY scanEntry) only if there are no other
321 * non-excludeOnly scan keys.
326 * Match status data. curItem is the TID most recently tested (could be a
327 * lossy-page pointer). curItemMatches is true if it passes the
328 * consistentFn test; if so, recheckCurItem is the recheck flag.
329 * isFinished means that all the input entry streams are finished, so this
330 * key cannot succeed for any later TIDs.
340 /* query key and other information from extractQueryFn */
349 /* Current page in posting tree */
352 /* current ItemPointer to heap */
355 /* for a partial-match or full-scan query, we accumulate all TIDs here */
360 * If blockno is InvalidBlockNumber, all of the other fields in the
361 * matchResult are meaningless.
367 /* used for Posting list and one page in Posting tree */
400 ScanKey orderbys,
int norderbys);
414 void *callback_state);
479/* ginpostinglist.c */
482 int maxsize,
int *nwritten);
493 * Merging the results of several gin scans compares item pointers a lot,
494 * so we want this to be inlined.
507#endif /* GIN_PRIVATE_H */
static bool validate(Port *port, const char *auth)
static Datum values[MAXATTR]
bool(* IndexBulkDeleteCallback)(ItemPointer itemptr, void *state)
int ginTraverseLock(Buffer buffer, bool searchMode)
IndexScanDesc ginbeginscan(Relation rel, int nkeys, int norderbys)
struct GinScanKeyData GinScanKeyData
void freeGinBtreeStack(GinBtreeStack *stack)
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)
void ginBeginBAScan(BuildAccumulator *accum)
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
GinScanOpaqueData * GinScanOpaque
void GinInitPage(Page page, uint32 f, Size pageSize)
struct GinOptions GinOptions
bytea * ginoptions(Datum reloptions, bool validate)
int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
void ginHeapTupleFastCollect(GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
void ginFreeScanKeys(GinScanOpaque so)
ItemPointerData * ginGetBAEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Buffer GinNewBuffer(Relation index)
BlockNumber createPostingTree(Relation index, ItemPointerData *items, uint32 nitems, GinStatsData *buildStats, Buffer entrybuffer)
bool ginvalidate(Oid opclassoid)
int ginPostingListDecodeAllSegmentsToTbm(GinPostingList *ptr, int len, TIDBitmap *tbm)
void GinInitBuffer(Buffer b, uint32 f)
void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
void ginendscan(IndexScanDesc scan)
void ginNewScanKey(IndexScanDesc scan)
void ginInsertBAEntries(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum *entries, GinNullCategory *categories, int32 nentries)
struct GinScanOpaqueData GinScanOpaqueData
Datum * ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
GinBtreeStack * ginScanBeginPostingTree(GinBtree btree, Relation index, BlockNumber rootBlkno)
void ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
void GinPageDeletePostingItem(Page page, OffsetNumber offset)
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
void ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
struct GinScanEntryData * GinScanEntry
bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, struct IndexInfo *indexInfo)
struct GinBtreeStack GinBtreeStack
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
int ginCompareAttEntries(GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
int GinDataLeafPageGetItemsToTbm(Page page, TIDBitmap *tbm)
struct GinBtreeData GinBtreeData
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
struct GinBtreeData * GinBtree
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
void GinInitMetabuffer(Buffer b)
void ginInitBA(BuildAccumulator *accum)
void ginbuildempty(Relation index)
void ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
char * ginbuildphasename(int64 phasenum)
IndexBuildResult * ginbuild(Relation heap, Relation index, struct IndexInfo *indexInfo)
void initGinState(GinState *state, Relation index)
struct GinScanKeyData * GinScanKey
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck)
IndexBulkDeleteResult * ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
IndexBulkDeleteResult * ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum, IndexTuple itup, int *nitems)
struct GinEntryAccumulator GinEntryAccumulator
int ginCompareEntries(GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
void ginadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
void ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
struct GinTupleCollector GinTupleCollector
ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged)
void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
ItemPointer GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast)
struct GinScanEntryData GinScanEntryData
#define GinItemPointerGetOffsetNumber(pointer)
signed char GinNullCategory
#define GinItemPointerGetBlockNumber(pointer)
static int pg_cmp_u64(uint64 a, uint64 b)
static const struct fns functions
GinEntryAccumulator * entryallocator
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
BlockNumber(* getLeftMostChild)(GinBtree, Page)
bool(* findItem)(GinBtree, GinBtreeStack *)
bool(* isMoveRight)(GinBtree, Page)
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
GinNullCategory entryCategory
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
struct GinBtreeStack * parent
int pendingListCleanupSize
TBMIterateResult matchResult
OffsetNumber matchOffsets[TBM_MAX_TUPLES_PER_PAGE]
TBMPrivateIterator * matchIterator
GinNullCategory queryCategory
uint32 predictNumberResult
GinScanEntry * additionalEntries
GinScanEntry * requiredEntries
FmgrInfo * triConsistentFmgrInfo
GinNullCategory * queryCategories
FmgrInfo * consistentFmgrInfo
GinTernaryValue * entryRes
GinTernaryValue(* triConsistentFn)(GinScanKey key)
bool(* boolConsistentFn)(GinScanKey key)
FmgrInfo comparePartialFn[INDEX_MAX_KEYS]
FmgrInfo extractQueryFn[INDEX_MAX_KEYS]
TupleDesc tupdesc[INDEX_MAX_KEYS]
FmgrInfo triConsistentFn[INDEX_MAX_KEYS]
FmgrInfo extractValueFn[INDEX_MAX_KEYS]
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Oid supportCollation[INDEX_MAX_KEYS]
bool canPartialMatch[INDEX_MAX_KEYS]
FmgrInfo compareFn[INDEX_MAX_KEYS]
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
#define TBM_MAX_TUPLES_PER_PAGE