summaryrefslogtreecommitdiffstats
path: root/src/include/access/gin_private.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/access/gin_private.h')
-rw-r--r--src/include/access/gin_private.h500
1 files changed, 500 insertions, 0 deletions
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
new file mode 100644
index 0000000..670a40b
--- /dev/null
+++ b/src/include/access/gin_private.h
@@ -0,0 +1,500 @@
+/*--------------------------------------------------------------------------
+ * gin_private.h
+ * header file for postgres inverted index access method implementation.
+ *
+ * Copyright (c) 2006-2021, PostgreSQL Global Development Group
+ *
+ * src/include/access/gin_private.h
+ *--------------------------------------------------------------------------
+ */
+#ifndef GIN_PRIVATE_H
+#define GIN_PRIVATE_H
+
+#include "access/amapi.h"
+#include "access/gin.h"
+#include "access/ginblock.h"
+#include "access/itup.h"
+#include "catalog/pg_am_d.h"
+#include "fmgr.h"
+#include "lib/rbtree.h"
+#include "storage/bufmgr.h"
+
+/*
+ * Storage type for GIN's reloptions
+ */
+typedef struct GinOptions
+{
+ int32 vl_len_; /* varlena header (do not touch directly!) */
+ bool useFastUpdate; /* use fast updates? */
+ int pendingListCleanupSize; /* maximum size of pending list */
+} GinOptions;
+
+#define GIN_DEFAULT_USE_FASTUPDATE true
+#define GinGetUseFastUpdate(relation) \
+ (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
+ relation->rd_rel->relam == GIN_AM_OID), \
+ (relation)->rd_options ? \
+ ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
+#define GinGetPendingListCleanupSize(relation) \
+ (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
+ relation->rd_rel->relam == GIN_AM_OID), \
+ (relation)->rd_options && \
+ ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \
+ ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \
+ gin_pending_list_limit)
+
+
+/* Macros for buffer lock/unlock operations */
+#define GIN_UNLOCK BUFFER_LOCK_UNLOCK
+#define GIN_SHARE BUFFER_LOCK_SHARE
+#define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
+
+
+/*
+ * GinState: working data structure describing the index being worked on
+ */
+typedef struct GinState
+{
+ Relation index;
+ bool oneCol; /* true if single-column index */
+
+ /*
+ * origTupdesc is the nominal tuple descriptor of the index, ie, the i'th
+ * attribute shows the key type (not the input data type!) of the i'th
+ * index column. In a single-column index this describes the actual leaf
+ * index tuples. In a multi-column index, the actual leaf tuples contain
+ * a smallint column number followed by a key datum of the appropriate
+ * type for that column. We set up tupdesc[i] to describe the actual
+ * rowtype of the index tuples for the i'th column, ie, (int2, keytype).
+ * Note that in any case, leaf tuples contain more data than is known to
+ * the TupleDesc; see access/gin/README for details.
+ */
+ TupleDesc origTupdesc;
+ TupleDesc tupdesc[INDEX_MAX_KEYS];
+
+ /*
+ * Per-index-column opclass support functions
+ */
+ FmgrInfo compareFn[INDEX_MAX_KEYS];
+ FmgrInfo extractValueFn[INDEX_MAX_KEYS];
+ FmgrInfo extractQueryFn[INDEX_MAX_KEYS];
+ FmgrInfo consistentFn[INDEX_MAX_KEYS];
+ FmgrInfo triConsistentFn[INDEX_MAX_KEYS];
+ FmgrInfo comparePartialFn[INDEX_MAX_KEYS]; /* optional method */
+ /* canPartialMatch[i] is true if comparePartialFn[i] is valid */
+ bool canPartialMatch[INDEX_MAX_KEYS];
+ /* Collations to pass to the support functions */
+ Oid supportCollation[INDEX_MAX_KEYS];
+} GinState;
+
+
+/* ginutil.c */
+extern bytea *ginoptions(Datum reloptions, bool validate);
+extern void initGinState(GinState *state, Relation index);
+extern Buffer GinNewBuffer(Relation index);
+extern void GinInitBuffer(Buffer b, uint32 f);
+extern void GinInitPage(Page page, uint32 f, Size pageSize);
+extern void GinInitMetabuffer(Buffer b);
+extern int ginCompareEntries(GinState *ginstate, OffsetNumber attnum,
+ Datum a, GinNullCategory categorya,
+ Datum b, GinNullCategory categoryb);
+extern int ginCompareAttEntries(GinState *ginstate,
+ OffsetNumber attnuma, Datum a, GinNullCategory categorya,
+ OffsetNumber attnumb, Datum b, GinNullCategory categoryb);
+extern Datum *ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
+ Datum value, bool isNull,
+ int32 *nentries, GinNullCategory **categories);
+
+extern OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple);
+extern Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple,
+ GinNullCategory *category);
+
+/* gininsert.c */
+extern IndexBuildResult *ginbuild(Relation heap, Relation index,
+ struct IndexInfo *indexInfo);
+extern void ginbuildempty(Relation index);
+extern bool gininsert(Relation index, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
+ struct IndexInfo *indexInfo);
+extern void ginEntryInsert(GinState *ginstate,
+ OffsetNumber attnum, Datum key, GinNullCategory category,
+ ItemPointerData *items, uint32 nitem,
+ GinStatsData *buildStats);
+
+/* ginbtree.c */
+
+typedef struct GinBtreeStack
+{
+ BlockNumber blkno;
+ Buffer buffer;
+ OffsetNumber off;
+ ItemPointerData iptr;
+ /* predictNumber contains predicted number of pages on current level */
+ uint32 predictNumber;
+ struct GinBtreeStack *parent;
+} GinBtreeStack;
+
+typedef struct GinBtreeData *GinBtree;
+
+/* Return codes for GinBtreeData.beginPlaceToPage method */
+typedef enum
+{
+ GPTP_NO_WORK,
+ GPTP_INSERT,
+ GPTP_SPLIT
+} GinPlaceToPageRC;
+
+typedef struct GinBtreeData
+{
+ /* search methods */
+ BlockNumber (*findChildPage) (GinBtree, GinBtreeStack *);
+ BlockNumber (*getLeftMostChild) (GinBtree, Page);
+ bool (*isMoveRight) (GinBtree, Page);
+ bool (*findItem) (GinBtree, GinBtreeStack *);
+
+ /* insert methods */
+ OffsetNumber (*findChildPtr) (GinBtree, Page, BlockNumber, OffsetNumber);
+ GinPlaceToPageRC (*beginPlaceToPage) (GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *);
+ void (*execPlaceToPage) (GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *);
+ void *(*prepareDownlink) (GinBtree, Buffer);
+ void (*fillRoot) (GinBtree, Page, BlockNumber, Page, BlockNumber, Page);
+
+ bool isData;
+
+ Relation index;
+ BlockNumber rootBlkno;
+ GinState *ginstate; /* not valid in a data scan */
+ bool fullScan;
+ bool isBuild;
+
+ /* Search key for Entry tree */
+ OffsetNumber entryAttnum;
+ Datum entryKey;
+ GinNullCategory entryCategory;
+
+ /* Search key for data tree (posting tree) */
+ ItemPointerData itemptr;
+} GinBtreeData;
+
+/* This represents a tuple to be inserted to entry tree. */
+typedef struct
+{
+ IndexTuple entry; /* tuple to insert */
+ bool isDelete; /* delete old tuple at same offset? */
+} GinBtreeEntryInsertData;
+
+/*
+ * This represents an itempointer, or many itempointers, to be inserted to
+ * a data (posting tree) leaf page
+ */
+typedef struct
+{
+ ItemPointerData *items;
+ uint32 nitem;
+ uint32 curitem;
+} GinBtreeDataLeafInsertData;
+
+/*
+ * For internal data (posting tree) pages, the insertion payload is a
+ * PostingItem
+ */
+
+extern GinBtreeStack *ginFindLeafPage(GinBtree btree, bool searchMode,
+ bool rootConflictCheck, Snapshot snapshot);
+extern Buffer ginStepRight(Buffer buffer, Relation index, int lockmode);
+extern void freeGinBtreeStack(GinBtreeStack *stack);
+extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack,
+ void *insertdata, GinStatsData *buildStats);
+
+/* ginentrypage.c */
+extern IndexTuple GinFormTuple(GinState *ginstate,
+ OffsetNumber attnum, Datum key, GinNullCategory category,
+ Pointer data, Size dataSize, int nipd, bool errorTooBig);
+extern void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum,
+ Datum key, GinNullCategory category,
+ GinState *ginstate);
+extern void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage);
+extern ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum,
+ IndexTuple itup, int *nitems);
+
+/* gindatapage.c */
+extern ItemPointer GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast);
+extern int GinDataLeafPageGetItemsToTbm(Page page, TIDBitmap *tbm);
+extern BlockNumber createPostingTree(Relation index,
+ ItemPointerData *items, uint32 nitems,
+ GinStatsData *buildStats, Buffer entrybuffer);
+extern void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset);
+extern void GinPageDeletePostingItem(Page page, OffsetNumber offset);
+extern void ginInsertItemPointers(Relation index, BlockNumber rootBlkno,
+ ItemPointerData *items, uint32 nitem,
+ GinStatsData *buildStats);
+extern GinBtreeStack *ginScanBeginPostingTree(GinBtree btree, Relation index, BlockNumber rootBlkno, Snapshot snapshot);
+extern void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage);
+
+/*
+ * This is declared in ginvacuum.c, but is passed between ginVacuumItemPointers
+ * and ginVacuumPostingTreeLeaf and as an opaque struct, so we need a forward
+ * declaration for it.
+ */
+typedef struct GinVacuumState GinVacuumState;
+
+extern void ginVacuumPostingTreeLeaf(Relation rel, Buffer buf, GinVacuumState *gvs);
+
+/* ginscan.c */
+
+/*
+ * GinScanKeyData describes a single GIN index qualifier expression.
+ *
+ * From each qual expression, we extract one or more specific index search
+ * conditions, which are represented by GinScanEntryData. It's quite
+ * possible for identical search conditions to be requested by more than
+ * one qual expression, in which case we merge such conditions to have just
+ * one unique GinScanEntry --- this is particularly important for efficiency
+ * when dealing with full-index-scan entries. So there can be multiple
+ * GinScanKeyData.scanEntry pointers to the same GinScanEntryData.
+ *
+ * In each GinScanKeyData, nentries is the true number of entries, while
+ * nuserentries is the number that extractQueryFn returned (which is what
+ * we report to consistentFn). The "user" entries must come first.
+ */
+typedef struct GinScanKeyData *GinScanKey;
+
+typedef struct GinScanEntryData *GinScanEntry;
+
+typedef struct GinScanKeyData
+{
+ /* Real number of entries in scanEntry[] (always > 0) */
+ uint32 nentries;
+ /* Number of entries that extractQueryFn and consistentFn know about */
+ uint32 nuserentries;
+
+ /* array of GinScanEntry pointers, one per extracted search condition */
+ GinScanEntry *scanEntry;
+
+ /*
+ * At least one of the entries in requiredEntries must be present for a
+ * tuple to match the overall qual.
+ *
+ * additionalEntries contains entries that are needed by the consistent
+ * function to decide if an item matches, but are not sufficient to
+ * satisfy the qual without entries from requiredEntries.
+ */
+ GinScanEntry *requiredEntries;
+ int nrequired;
+ GinScanEntry *additionalEntries;
+ int nadditional;
+
+ /* array of check flags, reported to consistentFn */
+ GinTernaryValue *entryRes;
+ bool (*boolConsistentFn) (GinScanKey key);
+ GinTernaryValue (*triConsistentFn) (GinScanKey key);
+ FmgrInfo *consistentFmgrInfo;
+ FmgrInfo *triConsistentFmgrInfo;
+ Oid collation;
+
+ /* other data needed for calling consistentFn */
+ Datum query;
+ /* NB: these three arrays have only nuserentries elements! */
+ Datum *queryValues;
+ GinNullCategory *queryCategories;
+ Pointer *extra_data;
+ StrategyNumber strategy;
+ int32 searchMode;
+ OffsetNumber attnum;
+
+ /*
+ * An excludeOnly scan key is not able to enumerate all matching tuples.
+ * That is, to be semantically correct on its own, it would need to have a
+ * GIN_CAT_EMPTY_QUERY scanEntry, but it doesn't. Such a key can still be
+ * used to filter tuples returned by other scan keys, so we will get the
+ * right answers as long as there's at least one non-excludeOnly scan key
+ * for each index attribute considered by the search. For efficiency
+ * reasons we don't want to have unnecessary GIN_CAT_EMPTY_QUERY entries,
+ * so we will convert an excludeOnly scan key to non-excludeOnly (by
+ * adding a GIN_CAT_EMPTY_QUERY scanEntry) only if there are no other
+ * non-excludeOnly scan keys.
+ */
+ bool excludeOnly;
+
+ /*
+ * Match status data. curItem is the TID most recently tested (could be a
+ * lossy-page pointer). curItemMatches is true if it passes the
+ * consistentFn test; if so, recheckCurItem is the recheck flag.
+ * isFinished means that all the input entry streams are finished, so this
+ * key cannot succeed for any later TIDs.
+ */
+ ItemPointerData curItem;
+ bool curItemMatches;
+ bool recheckCurItem;
+ bool isFinished;
+} GinScanKeyData;
+
+typedef struct GinScanEntryData
+{
+ /* query key and other information from extractQueryFn */
+ Datum queryKey;
+ GinNullCategory queryCategory;
+ bool isPartialMatch;
+ Pointer extra_data;
+ StrategyNumber strategy;
+ int32 searchMode;
+ OffsetNumber attnum;
+
+ /* Current page in posting tree */
+ Buffer buffer;
+
+ /* current ItemPointer to heap */
+ ItemPointerData curItem;
+
+ /* for a partial-match or full-scan query, we accumulate all TIDs here */
+ TIDBitmap *matchBitmap;
+ TBMIterator *matchIterator;
+ TBMIterateResult *matchResult;
+
+ /* used for Posting list and one page in Posting tree */
+ ItemPointerData *list;
+ int nlist;
+ OffsetNumber offset;
+
+ bool isFinished;
+ bool reduceResult;
+ uint32 predictNumberResult;
+ GinBtreeData btree;
+} GinScanEntryData;
+
+typedef struct GinScanOpaqueData
+{
+ MemoryContext tempCtx;
+ GinState ginstate;
+
+ GinScanKey keys; /* one per scan qualifier expr */
+ uint32 nkeys;
+
+ GinScanEntry *entries; /* one per index search condition */
+ uint32 totalentries;
+ uint32 allocentries; /* allocated length of entries[] */
+
+ MemoryContext keyCtx; /* used to hold key and entry data */
+
+ bool isVoidRes; /* true if query is unsatisfiable */
+} GinScanOpaqueData;
+
+typedef GinScanOpaqueData *GinScanOpaque;
+
+extern IndexScanDesc ginbeginscan(Relation rel, int nkeys, int norderbys);
+extern void ginendscan(IndexScanDesc scan);
+extern void ginrescan(IndexScanDesc scan, ScanKey key, int nscankeys,
+ ScanKey orderbys, int norderbys);
+extern void ginNewScanKey(IndexScanDesc scan);
+extern void ginFreeScanKeys(GinScanOpaque so);
+
+/* ginget.c */
+extern int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
+
+/* ginlogic.c */
+extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key);
+
+/* ginvacuum.c */
+extern IndexBulkDeleteResult *ginbulkdelete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+extern IndexBulkDeleteResult *ginvacuumcleanup(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+extern ItemPointer ginVacuumItemPointers(GinVacuumState *gvs,
+ ItemPointerData *items, int nitem, int *nremaining);
+
+/* ginvalidate.c */
+extern bool ginvalidate(Oid opclassoid);
+extern void ginadjustmembers(Oid opfamilyoid,
+ Oid opclassoid,
+ List *operators,
+ List *functions);
+
+/* ginbulk.c */
+typedef struct GinEntryAccumulator
+{
+ RBTNode rbtnode;
+ Datum key;
+ GinNullCategory category;
+ OffsetNumber attnum;
+ bool shouldSort;
+ ItemPointerData *list;
+ uint32 maxcount; /* allocated size of list[] */
+ uint32 count; /* current number of list[] entries */
+} GinEntryAccumulator;
+
+typedef struct
+{
+ GinState *ginstate;
+ Size allocatedMemory;
+ GinEntryAccumulator *entryallocator;
+ uint32 eas_used;
+ RBTree *tree;
+ RBTreeIterator tree_walk;
+} BuildAccumulator;
+
+extern void ginInitBA(BuildAccumulator *accum);
+extern void ginInsertBAEntries(BuildAccumulator *accum,
+ ItemPointer heapptr, OffsetNumber attnum,
+ Datum *entries, GinNullCategory *categories,
+ int32 nentries);
+extern void ginBeginBAScan(BuildAccumulator *accum);
+extern ItemPointerData *ginGetBAEntry(BuildAccumulator *accum,
+ OffsetNumber *attnum, Datum *key, GinNullCategory *category,
+ uint32 *n);
+
+/* ginfast.c */
+
+typedef struct GinTupleCollector
+{
+ IndexTuple *tuples;
+ uint32 ntuples;
+ uint32 lentuples;
+ uint32 sumsize;
+} GinTupleCollector;
+
+extern void ginHeapTupleFastInsert(GinState *ginstate,
+ GinTupleCollector *collector);
+extern void ginHeapTupleFastCollect(GinState *ginstate,
+ GinTupleCollector *collector,
+ OffsetNumber attnum, Datum value, bool isNull,
+ ItemPointer ht_ctid);
+extern void ginInsertCleanup(GinState *ginstate, bool full_clean,
+ bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats);
+
+/* ginpostinglist.c */
+
+extern GinPostingList *ginCompressPostingList(const ItemPointer ipd, int nipd,
+ int maxsize, int *nwritten);
+extern int ginPostingListDecodeAllSegmentsToTbm(GinPostingList *ptr, int totalsize, TIDBitmap *tbm);
+
+extern ItemPointer ginPostingListDecodeAllSegments(GinPostingList *ptr, int len, int *ndecoded);
+extern ItemPointer ginPostingListDecode(GinPostingList *ptr, int *ndecoded);
+extern ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na,
+ ItemPointerData *b, uint32 nb,
+ int *nmerged);
+
+/*
+ * Merging the results of several gin scans compares item pointers a lot,
+ * so we want this to be inlined.
+ */
+static inline int
+ginCompareItemPointers(ItemPointer a, ItemPointer b)
+{
+ uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
+ uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
+
+ if (ia == ib)
+ return 0;
+ else if (ia > ib)
+ return 1;
+ else
+ return -1;
+}
+
+extern int ginTraverseLock(Buffer buffer, bool searchMode);
+
+#endif /* GIN_PRIVATE_H */