Pass down "logically unchanged index" hint.
[pgsql.git] / src / include / access / gin_private.h
blob670a40b4bee8dc430f196175dc15f9fd65c89319
1 /*--------------------------------------------------------------------------
2 * gin_private.h
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 *--------------------------------------------------------------------------
9 */
10 #ifndef GIN_PRIVATE_H
11 #define GIN_PRIVATE_H
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"
18 #include "fmgr.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 */
30 } GinOptions;
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
58 Relation index;
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];
88 } GinState;
91 /* ginutil.c */
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);
112 /* gininsert.c */
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,
119 bool indexUnchanged,
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);
126 /* ginbtree.c */
128 typedef struct GinBtreeStack
130 BlockNumber blkno;
131 Buffer buffer;
132 OffsetNumber off;
133 ItemPointerData iptr;
134 /* predictNumber contains predicted number of pages on current level */
135 uint32 predictNumber;
136 struct GinBtreeStack *parent;
137 } GinBtreeStack;
139 typedef struct GinBtreeData *GinBtree;
141 /* Return codes for GinBtreeData.beginPlaceToPage method */
142 typedef enum
144 GPTP_NO_WORK,
145 GPTP_INSERT,
146 GPTP_SPLIT
147 } GinPlaceToPageRC;
149 typedef struct GinBtreeData
151 /* search methods */
152 BlockNumber (*findChildPage) (GinBtree, GinBtreeStack *);
153 BlockNumber (*getLeftMostChild) (GinBtree, Page);
154 bool (*isMoveRight) (GinBtree, Page);
155 bool (*findItem) (GinBtree, GinBtreeStack *);
157 /* insert methods */
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);
164 bool isData;
166 Relation index;
167 BlockNumber rootBlkno;
168 GinState *ginstate; /* not valid in a data scan */
169 bool fullScan;
170 bool isBuild;
172 /* Search key for Entry tree */
173 OffsetNumber entryAttnum;
174 Datum entryKey;
175 GinNullCategory entryCategory;
177 /* Search key for data tree (posting tree) */
178 ItemPointerData itemptr;
179 } GinBtreeData;
181 /* This represents a tuple to be inserted to entry tree. */
182 typedef struct
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
192 typedef struct
194 ItemPointerData *items;
195 uint32 nitem;
196 uint32 curitem;
197 } GinBtreeDataLeafInsertData;
200 * For internal data (posting tree) pages, the insertion payload is a
201 * PostingItem
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);
211 /* ginentrypage.c */
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,
217 GinState *ginstate);
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);
222 /* gindatapage.c */
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);
245 /* ginscan.c */
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) */
269 uint32 nentries;
270 /* Number of entries that extractQueryFn and consistentFn know about */
271 uint32 nuserentries;
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;
285 int nrequired;
286 GinScanEntry *additionalEntries;
287 int nadditional;
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;
295 Oid collation;
297 /* other data needed for calling consistentFn */
298 Datum query;
299 /* NB: these three arrays have only nuserentries elements! */
300 Datum *queryValues;
301 GinNullCategory *queryCategories;
302 Pointer *extra_data;
303 StrategyNumber strategy;
304 int32 searchMode;
305 OffsetNumber attnum;
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.
319 bool excludeOnly;
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;
329 bool curItemMatches;
330 bool recheckCurItem;
331 bool isFinished;
332 } GinScanKeyData;
334 typedef struct GinScanEntryData
336 /* query key and other information from extractQueryFn */
337 Datum queryKey;
338 GinNullCategory queryCategory;
339 bool isPartialMatch;
340 Pointer extra_data;
341 StrategyNumber strategy;
342 int32 searchMode;
343 OffsetNumber attnum;
345 /* Current page in posting tree */
346 Buffer buffer;
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;
358 int nlist;
359 OffsetNumber offset;
361 bool isFinished;
362 bool reduceResult;
363 uint32 predictNumberResult;
364 GinBtreeData btree;
365 } GinScanEntryData;
367 typedef struct GinScanOpaqueData
369 MemoryContext tempCtx;
370 GinState ginstate;
372 GinScanKey keys; /* one per scan qualifier expr */
373 uint32 nkeys;
375 GinScanEntry *entries; /* one per index search condition */
376 uint32 totalentries;
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 */
382 } GinScanOpaqueData;
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);
393 /* ginget.c */
394 extern int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
396 /* ginlogic.c */
397 extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key);
399 /* ginvacuum.c */
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);
409 /* ginvalidate.c */
410 extern bool ginvalidate(Oid opclassoid);
411 extern void ginadjustmembers(Oid opfamilyoid,
412 Oid opclassoid,
413 List *operators,
414 List *functions);
416 /* ginbulk.c */
417 typedef struct GinEntryAccumulator
419 RBTNode rbtnode;
420 Datum key;
421 GinNullCategory category;
422 OffsetNumber attnum;
423 bool shouldSort;
424 ItemPointerData *list;
425 uint32 maxcount; /* allocated size of list[] */
426 uint32 count; /* current number of list[] entries */
427 } GinEntryAccumulator;
429 typedef struct
431 GinState *ginstate;
432 Size allocatedMemory;
433 GinEntryAccumulator *entryallocator;
434 uint32 eas_used;
435 RBTree *tree;
436 RBTreeIterator tree_walk;
437 } BuildAccumulator;
439 extern void ginInitBA(BuildAccumulator *accum);
440 extern void ginInsertBAEntries(BuildAccumulator *accum,
441 ItemPointer heapptr, OffsetNumber attnum,
442 Datum *entries, GinNullCategory *categories,
443 int32 nentries);
444 extern void ginBeginBAScan(BuildAccumulator *accum);
445 extern ItemPointerData *ginGetBAEntry(BuildAccumulator *accum,
446 OffsetNumber *attnum, Datum *key, GinNullCategory *category,
447 uint32 *n);
449 /* ginfast.c */
451 typedef struct GinTupleCollector
453 IndexTuple *tuples;
454 uint32 ntuples;
455 uint32 lentuples;
456 uint32 sumsize;
457 } 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,
478 int *nmerged);
481 * Merging the results of several gin scans compares item pointers a lot,
482 * so we want this to be inlined.
484 static inline int
485 ginCompareItemPointers(ItemPointer a, ItemPointer b)
487 uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
488 uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
490 if (ia == ib)
491 return 0;
492 else if (ia > ib)
493 return 1;
494 else
495 return -1;
498 extern int ginTraverseLock(Buffer buffer, bool searchMode);
500 #endif /* GIN_PRIVATE_H */