1 /*--------------------------------------------------------------------------
3 * header file for postgres inverted index access method implementation.
5 * Copyright (c) 2006-2008, PostgreSQL Global Development Group
8 *--------------------------------------------------------------------------
15 #include "access/genam.h"
16 #include "access/itup.h"
17 #include "access/xlog.h"
19 #include "nodes/tidbitmap.h"
20 #include "storage/block.h"
21 #include "storage/buf.h"
22 #include "storage/off.h"
23 #include "storage/relfilenode.h"
27 * amproc indexes for inverted indexes.
29 #define GIN_COMPARE_PROC 1
30 #define GIN_EXTRACTVALUE_PROC 2
31 #define GIN_EXTRACTQUERY_PROC 3
32 #define GIN_CONSISTENT_PROC 4
33 #define GIN_COMPARE_PARTIAL_PROC 5
37 * Page opaque data in a inverted index page.
39 * Note: GIN does not include a page ID word as do the other index types.
40 * This is OK because the opaque data is only 8 bytes and so can be reliably
41 * distinguished by size. Revisit this if the size ever increases.
43 typedef struct GinPageOpaqueData
45 BlockNumber rightlink
; /* next page if any */
46 OffsetNumber maxoff
; /* number entries on GIN_DATA page: number of
47 * heap ItemPointer on GIN_DATA|GIN_LEAF page
48 * and number of records on GIN_DATA &
50 uint16 flags
; /* see bit definitions below */
53 typedef GinPageOpaqueData
*GinPageOpaque
;
55 #define GIN_ROOT_BLKNO (0)
57 #define GIN_DATA (1 << 0)
58 #define GIN_LEAF (1 << 1)
59 #define GIN_DELETED (1 << 2)
64 #define GinPageGetOpaque(page) ( (GinPageOpaque) PageGetSpecialPointer(page) )
66 #define GinPageIsLeaf(page) ( GinPageGetOpaque(page)->flags & GIN_LEAF )
67 #define GinPageSetLeaf(page) ( GinPageGetOpaque(page)->flags |= GIN_LEAF )
68 #define GinPageSetNonLeaf(page) ( GinPageGetOpaque(page)->flags &= ~GIN_LEAF )
69 #define GinPageIsData(page) ( GinPageGetOpaque(page)->flags & GIN_DATA )
70 #define GinPageSetData(page) ( GinPageGetOpaque(page)->flags |= GIN_DATA )
72 #define GinPageIsDeleted(page) ( GinPageGetOpaque(page)->flags & GIN_DELETED)
73 #define GinPageSetDeleted(page) ( GinPageGetOpaque(page)->flags |= GIN_DELETED)
74 #define GinPageSetNonDeleted(page) ( GinPageGetOpaque(page)->flags &= ~GIN_DELETED)
76 #define GinPageRightMost(page) ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber)
79 * Define our ItemPointerGet(BlockNumber|GetOffsetNumber)
83 #define GinItemPointerGetBlockNumber(pointer) \
84 BlockIdGetBlockNumber(&(pointer)->ip_blkid)
86 #define GinItemPointerGetOffsetNumber(pointer) \
91 BlockIdData child_blkno
; /* use it instead of BlockNumber to save space
96 #define PostingItemGetBlockNumber(pointer) \
97 BlockIdGetBlockNumber(&(pointer)->child_blkno)
99 #define PostingItemSetBlockNumber(pointer, blockNumber) \
100 BlockIdSet(&((pointer)->child_blkno), (blockNumber))
103 * Support work on IndexTuple on leaf pages
105 #define GinGetNPosting(itup) GinItemPointerGetOffsetNumber(&(itup)->t_tid)
106 #define GinSetNPosting(itup,n) ItemPointerSetOffsetNumber(&(itup)->t_tid,(n))
107 #define GIN_TREE_POSTING ((OffsetNumber)0xffff)
108 #define GinIsPostingTree(itup) ( GinGetNPosting(itup)==GIN_TREE_POSTING )
109 #define GinSetPostingTree(itup, blkno) ( GinSetNPosting((itup),GIN_TREE_POSTING ), ItemPointerSetBlockNumber(&(itup)->t_tid, blkno) )
110 #define GinGetPostingTree(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid)
112 #define GinGetOrigSizePosting(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid)
113 #define GinSetOrigSizePosting(itup,n) ItemPointerSetBlockNumber(&(itup)->t_tid,(n))
114 #define GinGetPosting(itup) ( (ItemPointer)(( ((char*)(itup)) + SHORTALIGN(GinGetOrigSizePosting(itup)) )) )
116 #define GinMaxItemSize \
117 ((BLCKSZ - SizeOfPageHeaderData - \
118 MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData))
122 * Data (posting tree) pages
124 #define GinDataPageGetRightBound(page) ((ItemPointer) PageGetContents(page))
125 #define GinDataPageGetData(page) \
126 (PageGetContents(page) + MAXALIGN(sizeof(ItemPointerData)))
127 #define GinSizeOfItem(page) \
128 (GinPageIsLeaf(page) ? sizeof(ItemPointerData) : sizeof(PostingItem))
129 #define GinDataPageGetItem(page,i) \
130 (GinDataPageGetData(page) + ((i)-1) * GinSizeOfItem(page))
132 #define GinDataPageGetFreeSpace(page) \
133 (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \
134 - MAXALIGN(sizeof(ItemPointerData)) \
135 - GinPageGetOpaque(page)->maxoff * GinSizeOfItem(page) \
136 - MAXALIGN(sizeof(GinPageOpaqueData)))
139 #define GIN_UNLOCK BUFFER_LOCK_UNLOCK
140 #define GIN_SHARE BUFFER_LOCK_SHARE
141 #define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
143 typedef struct GinState
145 FmgrInfo compareFn
[INDEX_MAX_KEYS
];
146 FmgrInfo extractValueFn
[INDEX_MAX_KEYS
];
147 FmgrInfo extractQueryFn
[INDEX_MAX_KEYS
];
148 FmgrInfo consistentFn
[INDEX_MAX_KEYS
];
149 FmgrInfo comparePartialFn
[INDEX_MAX_KEYS
]; /* optional method */
151 bool canPartialMatch
[INDEX_MAX_KEYS
]; /* can opclass perform partial
152 * match (prefix search)? */
154 TupleDesc tupdesc
[INDEX_MAX_KEYS
];
155 TupleDesc origTupdesc
;
161 #define XLOG_GIN_CREATE_INDEX 0x00
163 #define XLOG_GIN_CREATE_PTREE 0x10
165 typedef struct ginxlogCreatePostingTree
170 /* follows list of heap's ItemPointer */
171 } ginxlogCreatePostingTree
;
173 #define XLOG_GIN_INSERT 0x20
175 typedef struct ginxlogInsert
179 BlockNumber updateBlkno
;
187 * follows: tuples or ItemPointerData or PostingItem or list of
192 #define XLOG_GIN_SPLIT 0x30
194 typedef struct ginxlogSplit
198 BlockNumber rootBlkno
;
201 OffsetNumber separator
;
208 BlockNumber leftChildBlkno
;
209 BlockNumber updateBlkno
;
211 ItemPointerData rightbound
; /* used only in posting tree */
212 /* follows: list of tuple or ItemPointerData or PostingItem */
215 #define XLOG_GIN_VACUUM_PAGE 0x40
217 typedef struct ginxlogVacuumPage
222 /* follows content of page */
225 #define XLOG_GIN_DELETE_PAGE 0x50
227 typedef struct ginxlogDeletePage
231 BlockNumber parentBlkno
;
232 OffsetNumber parentOffset
;
233 BlockNumber leftBlkno
;
234 BlockNumber rightLink
;
238 extern Datum
ginoptions(PG_FUNCTION_ARGS
);
239 extern void initGinState(GinState
*state
, Relation index
);
240 extern Buffer
GinNewBuffer(Relation index
);
241 extern void GinInitBuffer(Buffer b
, uint32 f
);
242 extern void GinInitPage(Page page
, uint32 f
, Size pageSize
);
243 extern int compareEntries(GinState
*ginstate
, OffsetNumber attnum
, Datum a
, Datum b
);
244 extern int compareAttEntries(GinState
*ginstate
, OffsetNumber attnum_a
, Datum a
,
245 OffsetNumber attnum_b
, Datum b
);
246 extern Datum
*extractEntriesS(GinState
*ginstate
, OffsetNumber attnum
, Datum value
,
247 int32
*nentries
, bool *needUnique
);
248 extern Datum
*extractEntriesSU(GinState
*ginstate
, OffsetNumber attnum
, Datum value
, int32
*nentries
);
249 extern Page
GinPageGetCopyPage(Page page
);
251 extern Datum
gin_index_getattr(GinState
*ginstate
, IndexTuple tuple
);
252 extern OffsetNumber
gintuple_get_attrnum(GinState
*ginstate
, IndexTuple tuple
);
254 extern Datum
ginbuild(PG_FUNCTION_ARGS
);
255 extern Datum
gininsert(PG_FUNCTION_ARGS
);
258 extern void gin_redo(XLogRecPtr lsn
, XLogRecord
*record
);
259 extern void gin_desc(StringInfo buf
, uint8 xl_info
, char *rec
);
260 extern void gin_xlog_startup(void);
261 extern void gin_xlog_cleanup(void);
262 extern bool gin_safe_restartpoint(void);
266 typedef struct GinBtreeStack
271 /* predictNumber contains prediction number of pages on current level */
272 uint32 predictNumber
;
273 struct GinBtreeStack
*parent
;
276 typedef struct GinBtreeData
*GinBtree
;
278 typedef struct GinBtreeData
281 BlockNumber (*findChildPage
) (GinBtree
, GinBtreeStack
*);
282 bool (*isMoveRight
) (GinBtree
, Page
);
283 bool (*findItem
) (GinBtree
, GinBtreeStack
*);
286 OffsetNumber (*findChildPtr
) (GinBtree
, Page
, BlockNumber
, OffsetNumber
);
287 BlockNumber (*getLeftMostPage
) (GinBtree
, Page
);
288 bool (*isEnoughSpace
) (GinBtree
, Buffer
, OffsetNumber
);
289 void (*placeToPage
) (GinBtree
, Buffer
, OffsetNumber
, XLogRecData
**);
290 Page (*splitPage
) (GinBtree
, Buffer
, Buffer
, OffsetNumber
, XLogRecData
**);
291 void (*fillRoot
) (GinBtree
, Buffer
, Buffer
, Buffer
);
300 BlockNumber rightblkno
;
303 OffsetNumber entryAttnum
;
308 /* Data (posting tree) option */
309 ItemPointerData
*items
;
316 extern GinBtreeStack
*ginPrepareFindLeafPage(GinBtree btree
, BlockNumber blkno
);
317 extern GinBtreeStack
*ginFindLeafPage(GinBtree btree
, GinBtreeStack
*stack
);
318 extern void freeGinBtreeStack(GinBtreeStack
*stack
);
319 extern void ginInsertValue(GinBtree btree
, GinBtreeStack
*stack
);
320 extern void findParents(GinBtree btree
, GinBtreeStack
*stack
, BlockNumber rootBlkno
);
323 extern IndexTuple
GinFormTuple(GinState
*ginstate
, OffsetNumber attnum
, Datum key
,
324 ItemPointerData
*ipd
, uint32 nipd
);
325 extern void prepareEntryScan(GinBtree btree
, Relation index
, OffsetNumber attnum
,
326 Datum value
, GinState
*ginstate
);
327 extern void entryFillRoot(GinBtree btree
, Buffer root
, Buffer lbuf
, Buffer rbuf
);
328 extern IndexTuple
ginPageGetLinkItup(Buffer buf
);
331 extern int compareItemPointers(ItemPointer a
, ItemPointer b
);
334 ItemPointerData
*dst
,
335 ItemPointerData
*a
, uint32 na
,
336 ItemPointerData
*b
, uint32 nb
339 extern void GinDataPageAddItem(Page page
, void *data
, OffsetNumber offset
);
340 extern void PageDeletePostingItem(Page page
, OffsetNumber offset
);
345 GinBtreeStack
*stack
;
346 } GinPostingTreeScan
;
348 extern GinPostingTreeScan
*prepareScanPostingTree(Relation index
,
349 BlockNumber rootBlkno
, bool searchMode
);
350 extern void insertItemPointer(GinPostingTreeScan
*gdi
,
351 ItemPointerData
*items
, uint32 nitem
);
352 extern Buffer
scanBeginPostingTree(GinPostingTreeScan
*gdi
);
353 extern void dataFillRoot(GinBtree btree
, Buffer root
, Buffer lbuf
, Buffer rbuf
);
354 extern void prepareDataScan(GinBtree btree
, Relation index
);
358 typedef struct GinScanEntryData
*GinScanEntry
;
360 typedef struct GinScanEntryData
362 /* link to the equals entry in current scan key */
366 * link to values reported to consistentFn, points to
367 * GinScanKey->entryRes[i]
371 /* entry, got from extractQueryFn */
375 /* Current page in posting tree */
378 /* current ItemPointer to heap */
379 ItemPointerData curItem
;
381 /* partial match support */
383 TIDBitmap
*partialMatch
;
384 TBMIterateResult
*partialMatchResult
;
385 StrategyNumber strategy
;
387 /* used for Posting list and one page in Posting tree */
388 ItemPointerData
*list
;
394 uint32 predictNumberResult
;
397 typedef struct GinScanKeyData
399 /* Number of entries in query (got by extractQueryFn) */
402 /* array of ItemPointer result, reported to consistentFn */
405 /* array of scans per entry */
406 GinScanEntry scanEntry
;
408 /* for calling consistentFn(GinScanKey->entryRes, strategy, query) */
409 StrategyNumber strategy
;
413 ItemPointerData curItem
;
418 typedef GinScanKeyData
*GinScanKey
;
420 typedef struct GinScanOpaqueData
422 MemoryContext tempCtx
;
427 bool isVoidRes
; /* true if ginstate.extractQueryFn guarantees
428 * that nothing will be found */
433 typedef GinScanOpaqueData
*GinScanOpaque
;
435 extern Datum
ginbeginscan(PG_FUNCTION_ARGS
);
436 extern Datum
ginendscan(PG_FUNCTION_ARGS
);
437 extern Datum
ginrescan(PG_FUNCTION_ARGS
);
438 extern Datum
ginmarkpos(PG_FUNCTION_ARGS
);
439 extern Datum
ginrestrpos(PG_FUNCTION_ARGS
);
440 extern void newScanKey(IndexScanDesc scan
);
443 extern PGDLLIMPORT
int GinFuzzySearchLimit
;
445 #define ItemPointerSetMax(p) ItemPointerSet( (p), (BlockNumber)0xffffffff, (OffsetNumber)0xffff )
446 #define ItemPointerIsMax(p) ( ItemPointerGetBlockNumber(p) == (BlockNumber)0xffffffff && ItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff )
447 #define ItemPointerSetMin(p) ItemPointerSet( (p), (BlockNumber)0, (OffsetNumber)0)
448 #define ItemPointerIsMin(p) ( ItemPointerGetBlockNumber(p) == (BlockNumber)0 && ItemPointerGetOffsetNumber(p) == (OffsetNumber)0 )
450 extern Datum
gingetbitmap(PG_FUNCTION_ARGS
);
451 extern Datum
gingettuple(PG_FUNCTION_ARGS
);
452 extern void ginrestartentry(GinScanEntry entry
);
455 extern Datum
ginbulkdelete(PG_FUNCTION_ARGS
);
456 extern Datum
ginvacuumcleanup(PG_FUNCTION_ARGS
);
459 extern Datum
ginarrayextract(PG_FUNCTION_ARGS
);
460 extern Datum
ginqueryarrayextract(PG_FUNCTION_ARGS
);
461 extern Datum
ginarrayconsistent(PG_FUNCTION_ARGS
);
464 typedef struct EntryAccumulator
470 ItemPointerData
*list
;
472 struct EntryAccumulator
*left
;
473 struct EntryAccumulator
*right
;
479 EntryAccumulator
*entries
;
481 EntryAccumulator
**stack
;
483 long allocatedMemory
;
486 EntryAccumulator
*entryallocator
;
489 extern void ginInitBA(BuildAccumulator
*accum
);
490 extern void ginInsertRecordBA(BuildAccumulator
*accum
,
492 OffsetNumber attnum
, Datum
*entries
, int32 nentry
);
493 extern ItemPointerData
*ginGetEntry(BuildAccumulator
*accum
, OffsetNumber
*attnum
, Datum
*entry
, uint32
*n
);