postgresql/src/include/access/gin.h

650 lines
19 KiB
C
Raw Normal View History

/*--------------------------------------------------------------------------
* gin.h
2006-10-04 02:30:14 +02:00
* header file for postgres inverted index access method implementation.
*
2010-01-02 17:58:17 +01:00
* Copyright (c) 2006-2010, PostgreSQL Global Development Group
*
2010-09-20 22:08:53 +02:00
* src/include/access/gin.h
*--------------------------------------------------------------------------
*/
#ifndef GIN_H
#define GIN_H
#include "access/genam.h"
#include "access/itup.h"
#include "access/xlog.h"
#include "utils/rbtree.h"
#include "fmgr.h"
/*
* amproc indexes for inverted indexes.
*/
2006-10-04 02:30:14 +02:00
#define GIN_COMPARE_PROC 1
#define GIN_EXTRACTVALUE_PROC 2
#define GIN_EXTRACTQUERY_PROC 3
#define GIN_CONSISTENT_PROC 4
#define GIN_COMPARE_PARTIAL_PROC 5
#define GINNProcs 5
/*
* Page opaque data in a inverted index page.
*
* Note: GIN does not include a page ID word as do the other index types.
* This is OK because the opaque data is only 8 bytes and so can be reliably
* distinguished by size. Revisit this if the size ever increases.
*/
2006-10-04 02:30:14 +02:00
typedef struct GinPageOpaqueData
{
BlockNumber rightlink; /* next page if any */
OffsetNumber maxoff; /* number entries on GIN_DATA page; number of
2006-10-04 02:30:14 +02:00
* heap ItemPointer on GIN_DATA|GIN_LEAF page
* and number of records on GIN_DATA &
* ~GIN_LEAF page. On GIN_LIST page, number of
* heap tuples. */
uint16 flags; /* see bit definitions below */
} GinPageOpaqueData;
typedef GinPageOpaqueData *GinPageOpaque;
2006-10-04 02:30:14 +02:00
#define GIN_DATA (1 << 0)
#define GIN_LEAF (1 << 1)
#define GIN_DELETED (1 << 2)
#define GIN_META (1 << 3)
#define GIN_LIST (1 << 4)
#define GIN_LIST_FULLROW (1 << 5) /* makes sense only on GIN_LIST page */
/* Page numbers of fixed-location pages */
#define GIN_METAPAGE_BLKNO (0)
#define GIN_ROOT_BLKNO (1)
typedef struct GinMetaPageData
{
/*
* Pointers to head and tail of pending list, which consists of GIN_LIST
* pages. These store fast-inserted entries that haven't yet been moved
* into the regular GIN structure.
*/
BlockNumber head;
BlockNumber tail;
/*
* Free space in bytes in the pending list's tail page.
*/
uint32 tailFreeSize;
/*
* We store both number of pages and number of heap tuples that are in the
* pending list.
*/
BlockNumber nPendingPages;
int64 nPendingHeapTuples;
/*
* Statistics for planner use (accurate as of last VACUUM)
*/
BlockNumber nTotalPages;
BlockNumber nEntryPages;
BlockNumber nDataPages;
int64 nEntries;
} GinMetaPageData;
#define GinPageGetMeta(p) \
((GinMetaPageData *) PageGetContents(p))
/*
2006-10-04 02:30:14 +02:00
* Works on page
*/
#define GinPageGetOpaque(page) ( (GinPageOpaque) PageGetSpecialPointer(page) )
#define GinPageIsLeaf(page) ( GinPageGetOpaque(page)->flags & GIN_LEAF )
#define GinPageSetLeaf(page) ( GinPageGetOpaque(page)->flags |= GIN_LEAF )
#define GinPageSetNonLeaf(page) ( GinPageGetOpaque(page)->flags &= ~GIN_LEAF )
#define GinPageIsData(page) ( GinPageGetOpaque(page)->flags & GIN_DATA )
#define GinPageSetData(page) ( GinPageGetOpaque(page)->flags |= GIN_DATA )
#define GinPageIsList(page) ( GinPageGetOpaque(page)->flags & GIN_LIST )
#define GinPageSetList(page) ( GinPageGetOpaque(page)->flags |= GIN_LIST )
#define GinPageHasFullRow(page) ( GinPageGetOpaque(page)->flags & GIN_LIST_FULLROW )
#define GinPageSetFullRow(page) ( GinPageGetOpaque(page)->flags |= GIN_LIST_FULLROW )
#define GinPageIsDeleted(page) ( GinPageGetOpaque(page)->flags & GIN_DELETED)
#define GinPageSetDeleted(page) ( GinPageGetOpaque(page)->flags |= GIN_DELETED)
#define GinPageSetNonDeleted(page) ( GinPageGetOpaque(page)->flags &= ~GIN_DELETED)
#define GinPageRightMost(page) ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber)
/*
* We use our own ItemPointerGet(BlockNumber|GetOffsetNumber)
* to avoid Asserts, since sometimes the ip_posid isn't "valid"
*/
#define GinItemPointerGetBlockNumber(pointer) \
BlockIdGetBlockNumber(&(pointer)->ip_blkid)
#define GinItemPointerGetOffsetNumber(pointer) \
((pointer)->ip_posid)
/*
* Special-case item pointer values needed by the GIN search logic.
* MIN: sorts less than any valid item pointer
* MAX: sorts greater than any valid item pointer
* LOSSY PAGE: indicates a whole heap page, sorts after normal item
* pointers for that page
* Note that these are all distinguishable from an "invalid" item pointer
* (which is InvalidBlockNumber/0) as well as from all normal item
* pointers (which have item numbers in the range 1..MaxHeapTuplesPerPage).
*/
#define ItemPointerSetMin(p) \
ItemPointerSet((p), (BlockNumber)0, (OffsetNumber)0)
#define ItemPointerIsMin(p) \
(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0 && \
GinItemPointerGetBlockNumber(p) == (BlockNumber)0)
#define ItemPointerSetMax(p) \
ItemPointerSet((p), InvalidBlockNumber, (OffsetNumber)0xffff)
#define ItemPointerIsMax(p) \
(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff && \
GinItemPointerGetBlockNumber(p) == InvalidBlockNumber)
#define ItemPointerSetLossyPage(p, b) \
ItemPointerSet((p), (b), (OffsetNumber)0xffff)
#define ItemPointerIsLossyPage(p) \
(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff && \
GinItemPointerGetBlockNumber(p) != InvalidBlockNumber)
typedef struct
{
BlockIdData child_blkno; /* use it instead of BlockNumber to save space
* on page */
ItemPointerData key;
} PostingItem;
#define PostingItemGetBlockNumber(pointer) \
BlockIdGetBlockNumber(&(pointer)->child_blkno)
#define PostingItemSetBlockNumber(pointer, blockNumber) \
BlockIdSet(&((pointer)->child_blkno), (blockNumber))
/*
* Support work on IndexTuple on leaf pages
*/
#define GinGetNPosting(itup) GinItemPointerGetOffsetNumber(&(itup)->t_tid)
#define GinSetNPosting(itup,n) ItemPointerSetOffsetNumber(&(itup)->t_tid,(n))
#define GIN_TREE_POSTING ((OffsetNumber)0xffff)
#define GinIsPostingTree(itup) ( GinGetNPosting(itup)==GIN_TREE_POSTING )
2006-10-04 02:30:14 +02:00
#define GinSetPostingTree(itup, blkno) ( GinSetNPosting((itup),GIN_TREE_POSTING ), ItemPointerSetBlockNumber(&(itup)->t_tid, blkno) )
#define GinGetPostingTree(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid)
2006-10-04 02:30:14 +02:00
#define GinGetOrigSizePosting(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid)
#define GinSetOrigSizePosting(itup,n) ItemPointerSetBlockNumber(&(itup)->t_tid,(n))
#define GinGetPosting(itup) ( (ItemPointer)(( ((char*)(itup)) + SHORTALIGN(GinGetOrigSizePosting(itup)) )) )
#define GinMaxItemSize \
MAXALIGN_DOWN(((BLCKSZ - SizeOfPageHeaderData - \
MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData)))
/*
* Data (posting tree) pages
*/
#define GinDataPageGetRightBound(page) ((ItemPointer) PageGetContents(page))
#define GinDataPageGetData(page) \
(PageGetContents(page) + MAXALIGN(sizeof(ItemPointerData)))
#define GinSizeOfItem(page) \
(GinPageIsLeaf(page) ? sizeof(ItemPointerData) : sizeof(PostingItem))
#define GinDataPageGetItem(page,i) \
(GinDataPageGetData(page) + ((i)-1) * GinSizeOfItem(page))
#define GinDataPageGetFreeSpace(page) \
(BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \
- MAXALIGN(sizeof(ItemPointerData)) \
- GinPageGetOpaque(page)->maxoff * GinSizeOfItem(page) \
- MAXALIGN(sizeof(GinPageOpaqueData)))
/*
* List pages
*/
#define GinListPageSize \
( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GinPageOpaqueData)) )
/*
* Storage type for GIN's reloptions
*/
typedef struct GinOptions
{
int32 vl_len_; /* varlena header (do not touch directly!) */
bool useFastUpdate; /* use fast updates? */
} GinOptions;
#define GIN_DEFAULT_USE_FASTUPDATE true
#define GinGetUseFastUpdate(relation) \
((relation)->rd_options ? \
((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
2006-10-04 02:30:14 +02:00
#define GIN_UNLOCK BUFFER_LOCK_UNLOCK
#define GIN_SHARE BUFFER_LOCK_SHARE
#define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
2006-10-04 02:30:14 +02:00
typedef struct GinState
{
FmgrInfo compareFn[INDEX_MAX_KEYS];
FmgrInfo extractValueFn[INDEX_MAX_KEYS];
FmgrInfo extractQueryFn[INDEX_MAX_KEYS];
FmgrInfo consistentFn[INDEX_MAX_KEYS];
FmgrInfo comparePartialFn[INDEX_MAX_KEYS]; /* optional method */
bool canPartialMatch[INDEX_MAX_KEYS]; /* can opclass perform
* partial match (prefix
* search)? */
TupleDesc tupdesc[INDEX_MAX_KEYS];
TupleDesc origTupdesc;
bool oneCol;
} GinState;
/* XLog stuff */
#define XLOG_GIN_CREATE_INDEX 0x00
#define XLOG_GIN_CREATE_PTREE 0x10
2006-10-04 02:30:14 +02:00
typedef struct ginxlogCreatePostingTree
{
RelFileNode node;
BlockNumber blkno;
uint32 nitem;
/* follows list of heap's ItemPointer */
} ginxlogCreatePostingTree;
#define XLOG_GIN_INSERT 0x20
2006-10-04 02:30:14 +02:00
typedef struct ginxlogInsert
{
RelFileNode node;
BlockNumber blkno;
BlockNumber updateBlkno;
OffsetNumber offset;
bool isDelete;
bool isData;
bool isLeaf;
OffsetNumber nitem;
/*
* follows: tuples or ItemPointerData or PostingItem or list of
* ItemPointerData
*/
} ginxlogInsert;
2006-10-04 02:30:14 +02:00
#define XLOG_GIN_SPLIT 0x30
2006-10-04 02:30:14 +02:00
typedef struct ginxlogSplit
{
RelFileNode node;
BlockNumber lblkno;
BlockNumber rootBlkno;
BlockNumber rblkno;
BlockNumber rrlink;
OffsetNumber separator;
OffsetNumber nitem;
2006-10-04 02:30:14 +02:00
bool isData;
bool isLeaf;
bool isRootSplit;
2006-10-04 02:30:14 +02:00
BlockNumber leftChildBlkno;
BlockNumber updateBlkno;
2006-10-04 02:30:14 +02:00
ItemPointerData rightbound; /* used only in posting tree */
/* follows: list of tuple or ItemPointerData or PostingItem */
} ginxlogSplit;
2006-10-04 02:30:14 +02:00
#define XLOG_GIN_VACUUM_PAGE 0x40
2006-10-04 02:30:14 +02:00
typedef struct ginxlogVacuumPage
{
RelFileNode node;
BlockNumber blkno;
OffsetNumber nitem;
/* follows content of page */
} ginxlogVacuumPage;
2006-10-04 02:30:14 +02:00
#define XLOG_GIN_DELETE_PAGE 0x50
2006-10-04 02:30:14 +02:00
typedef struct ginxlogDeletePage
{
RelFileNode node;
BlockNumber blkno;
BlockNumber parentBlkno;
OffsetNumber parentOffset;
BlockNumber leftBlkno;
BlockNumber rightLink;
} ginxlogDeletePage;
#define XLOG_GIN_UPDATE_META_PAGE 0x60
typedef struct ginxlogUpdateMeta
{
RelFileNode node;
GinMetaPageData metadata;
BlockNumber prevTail;
BlockNumber newRightlink;
int32 ntuples; /* if ntuples > 0 then metadata.tail was
* updated with that many tuples; else new sub
* list was inserted */
/* array of inserted tuples follows */
} ginxlogUpdateMeta;
#define XLOG_GIN_INSERT_LISTPAGE 0x70
typedef struct ginxlogInsertListPage
{
RelFileNode node;
BlockNumber blkno;
BlockNumber rightlink;
int32 ntuples;
/* array of inserted tuples follows */
} ginxlogInsertListPage;
#define XLOG_GIN_DELETE_LISTPAGE 0x80
#define GIN_NDELETE_AT_ONCE 16
typedef struct ginxlogDeleteListPages
{
RelFileNode node;
GinMetaPageData metadata;
int32 ndeleted;
BlockNumber toDelete[GIN_NDELETE_AT_ONCE];
} ginxlogDeleteListPages;
/* ginutil.c */
extern Datum ginoptions(PG_FUNCTION_ARGS);
2006-10-04 02:30:14 +02:00
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, Datum b);
extern int ginCompareAttEntries(GinState *ginstate, OffsetNumber attnum_a, Datum a,
OffsetNumber attnum_b, Datum b);
extern Datum *ginExtractEntriesS(GinState *ginstate, OffsetNumber attnum, Datum value,
2007-11-15 22:14:46 +01:00
int32 *nentries, bool *needUnique);
extern Datum *ginExtractEntriesSU(GinState *ginstate, OffsetNumber attnum, Datum value, int32 *nentries);
extern Datum gin_index_getattr(GinState *ginstate, IndexTuple tuple);
extern OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple);
/*
* GinStatsData represents stats data for planner use
*/
typedef struct GinStatsData
{
BlockNumber nPendingPages;
BlockNumber nTotalPages;
BlockNumber nEntryPages;
BlockNumber nDataPages;
int64 nEntries;
} GinStatsData;
extern void ginGetStats(Relation index, GinStatsData *stats);
extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* gininsert.c */
extern Datum ginbuild(PG_FUNCTION_ARGS);
extern Datum ginbuildempty(PG_FUNCTION_ARGS);
extern Datum gininsert(PG_FUNCTION_ARGS);
extern void ginEntryInsert(Relation index, GinState *ginstate,
OffsetNumber attnum, Datum value,
ItemPointerData *items, uint32 nitem,
GinStatsData *buildStats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, uint8 xl_info, char *rec);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
extern bool gin_safe_restartpoint(void);
/* ginbtree.c */
2006-10-04 02:30:14 +02:00
typedef struct GinBtreeStack
{
BlockNumber blkno;
Buffer buffer;
OffsetNumber off;
/* predictNumber contains prediction number of pages on current level */
uint32 predictNumber;
struct GinBtreeStack *parent;
} GinBtreeStack;
typedef struct GinBtreeData *GinBtree;
2006-10-04 02:30:14 +02:00
typedef struct GinBtreeData
{
/* search methods */
2006-10-04 02:30:14 +02:00
BlockNumber (*findChildPage) (GinBtree, GinBtreeStack *);
bool (*isMoveRight) (GinBtree, Page);
bool (*findItem) (GinBtree, GinBtreeStack *);
/* insert methods */
2006-10-04 02:30:14 +02:00
OffsetNumber (*findChildPtr) (GinBtree, Page, BlockNumber, OffsetNumber);
BlockNumber (*getLeftMostPage) (GinBtree, Page);
bool (*isEnoughSpace) (GinBtree, Buffer, OffsetNumber);
void (*placeToPage) (GinBtree, Buffer, OffsetNumber, XLogRecData **);
Page (*splitPage) (GinBtree, Buffer, Buffer, OffsetNumber, XLogRecData **);
void (*fillRoot) (GinBtree, Buffer, Buffer, Buffer);
bool isData;
2006-10-04 02:30:14 +02:00
bool searchMode;
2006-10-04 02:30:14 +02:00
Relation index;
GinState *ginstate;
bool fullScan;
bool isBuild;
2006-10-04 02:30:14 +02:00
BlockNumber rightblkno;
/* Entry options */
OffsetNumber entryAttnum;
2006-10-04 02:30:14 +02:00
Datum entryValue;
IndexTuple entry;
bool isDelete;
/* Data (posting tree) option */
2006-10-04 02:30:14 +02:00
ItemPointerData *items;
uint32 nitem;
uint32 curitem;
2006-10-04 02:30:14 +02:00
PostingItem pitem;
} GinBtreeData;
2006-10-04 02:30:14 +02:00
extern GinBtreeStack *ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno);
extern GinBtreeStack *ginFindLeafPage(GinBtree btree, GinBtreeStack *stack);
extern void freeGinBtreeStack(GinBtreeStack *stack);
extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack,
GinStatsData *buildStats);
extern void ginFindParents(GinBtree btree, GinBtreeStack *stack, BlockNumber rootBlkno);
/* ginentrypage.c */
extern IndexTuple GinFormTuple(Relation index, GinState *ginstate,
OffsetNumber attnum, Datum key,
ItemPointerData *ipd, uint32 nipd, bool errorTooBig);
extern void GinShortenTuple(IndexTuple itup, uint32 nipd);
extern void ginPrepareEntryScan(GinBtree btree, Relation index, OffsetNumber attnum,
Datum value, GinState *ginstate);
extern void ginEntryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
extern IndexTuple ginPageGetLinkItup(Buffer buf);
/* gindatapage.c */
extern int ginCompareItemPointers(ItemPointer a, ItemPointer b);
extern uint32 ginMergeItemPointers(ItemPointerData *dst,
2006-10-04 02:30:14 +02:00
ItemPointerData *a, uint32 na,
ItemPointerData *b, uint32 nb);
2006-10-04 02:30:14 +02:00
extern void GinDataPageAddItem(Page page, void *data, OffsetNumber offset);
extern void GinPageDeletePostingItem(Page page, OffsetNumber offset);
2006-10-04 02:30:14 +02:00
typedef struct
{
GinBtreeData btree;
GinBtreeStack *stack;
} GinPostingTreeScan;
extern GinPostingTreeScan *ginPrepareScanPostingTree(Relation index,
2006-10-04 02:30:14 +02:00
BlockNumber rootBlkno, bool searchMode);
extern void ginInsertItemPointer(GinPostingTreeScan *gdi,
ItemPointerData *items, uint32 nitem,
GinStatsData *buildStats);
extern Buffer ginScanBeginPostingTree(GinPostingTreeScan *gdi);
extern void ginDataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
extern void ginPrepareDataScan(GinBtree btree, Relation index);
2006-10-04 02:30:14 +02:00
/* ginscan.c */
typedef struct GinScanEntryData *GinScanEntry;
2006-10-04 02:30:14 +02:00
typedef struct GinScanEntryData
{
/* link to the equals entry in current scan key */
2006-10-04 02:30:14 +02:00
GinScanEntry master;
2006-10-04 02:30:14 +02:00
/*
* link to values reported to consistentFn, points to
* GinScanKey->entryRes[i]
*/
bool *pval;
2006-10-04 02:30:14 +02:00
/* entry, got from extractQueryFn */
Datum entry;
OffsetNumber attnum;
Pointer extra_data;
/* Current page in posting tree */
2006-10-04 02:30:14 +02:00
Buffer buffer;
/* current ItemPointer to heap */
ItemPointerData curItem;
/* partial match support */
bool isPartialMatch;
TIDBitmap *partialMatch;
TBMIterator *partialMatchIterator;
TBMIterateResult *partialMatchResult;
StrategyNumber strategy;
/* used for Posting list and one page in Posting tree */
2006-10-04 02:30:14 +02:00
ItemPointerData *list;
uint32 nlist;
OffsetNumber offset;
2006-10-04 02:30:14 +02:00
bool isFinished;
bool reduceResult;
uint32 predictNumberResult;
} GinScanEntryData;
2006-10-04 02:30:14 +02:00
typedef struct GinScanKeyData
{
/* Number of entries in query (got by extractQueryFn) */
uint32 nentries;
/* array of ItemPointer result, reported to consistentFn */
2006-10-04 02:30:14 +02:00
bool *entryRes;
2006-10-04 02:30:14 +02:00
/* array of scans per entry */
GinScanEntry scanEntry;
Pointer *extra_data;
/* for calling consistentFn(GinScanKey->entryRes, strategy, query) */
2006-10-04 02:30:14 +02:00
StrategyNumber strategy;
Datum query;
OffsetNumber attnum;
2006-10-04 02:30:14 +02:00
ItemPointerData curItem;
Rewrite the key-combination logic in GIN's keyGetItem() and scanGetItem() routines to make them behave better in the presence of "lossy" index pointers. The previous coding was outright incorrect for some cases, as recently reported by Artur Dabrowski: scanGetItem would fail to return index entries in cases where one index key had multiple exact pointers on the same page as another key had a lossy pointer. Also, keyGetItem was extremely inefficient for cases where a single index key generates multiple "entry" streams, such as an @@ operator with a multiple-clause tsquery. The presence of a lossy page pointer in any one stream defeated its ability to use the opclass consistentFn, resulting in probing many heap pages that didn't really need to be visited. In Artur's example case, a query like WHERE tsvector @@ to_tsquery('a & b') was about 50X slower than the theoretically equivalent WHERE tsvector @@ to_tsquery('a') AND tsvector @@ to_tsquery('b') The way that I chose to fix this was to have GIN call the consistentFn twice with both TRUE and FALSE values for the in-doubt entry stream, returning a hit if either call produces TRUE, but not if they both return FALSE. The code handles this for the case of a single in-doubt entry stream, but punts (falling back to the stupid behavior) if there's more than one lossy reference to the same page. The idea could be scaled up to deal with multiple lossy references, but I think that would probably be wasted complexity. At least to judge by Artur's example, such cases don't occur often enough to be worth trying to optimize. Back-patch to 8.4. 8.3 did not have lossy GIN index pointers, so not subject to these problems.
2010-07-31 02:30:54 +02:00
bool recheckCurItem;
2006-10-04 02:30:14 +02:00
bool firstCall;
bool isFinished;
} GinScanKeyData;
2006-10-04 02:30:14 +02:00
typedef GinScanKeyData *GinScanKey;
2006-10-04 02:30:14 +02:00
typedef struct GinScanOpaqueData
{
MemoryContext tempCtx;
GinState ginstate;
2006-10-04 02:30:14 +02:00
GinScanKey keys;
uint32 nkeys;
2007-11-15 22:14:46 +01:00
bool isVoidRes; /* true if ginstate.extractQueryFn guarantees
* that nothing will be found */
} GinScanOpaqueData;
typedef GinScanOpaqueData *GinScanOpaque;
extern Datum ginbeginscan(PG_FUNCTION_ARGS);
extern Datum ginendscan(PG_FUNCTION_ARGS);
extern Datum ginrescan(PG_FUNCTION_ARGS);
extern Datum ginmarkpos(PG_FUNCTION_ARGS);
extern Datum ginrestrpos(PG_FUNCTION_ARGS);
extern void ginNewScanKey(IndexScanDesc scan);
/* ginget.c */
extern PGDLLIMPORT int GinFuzzySearchLimit;
extern Datum gingetbitmap(PG_FUNCTION_ARGS);
/* ginvacuum.c */
extern Datum ginbulkdelete(PG_FUNCTION_ARGS);
extern Datum ginvacuumcleanup(PG_FUNCTION_ARGS);
/* ginarrayproc.c */
extern Datum ginarrayextract(PG_FUNCTION_ARGS);
extern Datum ginqueryarrayextract(PG_FUNCTION_ARGS);
extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);
/* ginbulk.c */
2006-10-04 02:30:14 +02:00
typedef struct EntryAccumulator
{
RBNode rbnode;
Datum value;
uint32 length;
uint32 number;
OffsetNumber attnum;
bool shouldSort;
ItemPointerData *list;
} EntryAccumulator;
2006-10-04 02:30:14 +02:00
typedef struct
{
GinState *ginstate;
long allocatedMemory;
2006-10-04 02:30:14 +02:00
uint32 length;
2010-02-26 03:01:40 +01:00
EntryAccumulator *entryallocator;
RBTree *tree;
} BuildAccumulator;
extern void ginInitBA(BuildAccumulator *accum);
2006-10-04 02:30:14 +02:00
extern void ginInsertRecordBA(BuildAccumulator *accum,
ItemPointer heapptr,
OffsetNumber attnum, Datum *entries, int32 nentry);
extern void ginBeginBAScan(BuildAccumulator *accum);
extern ItemPointerData *ginGetEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *entry, uint32 *n);
/* ginfast.c */
typedef struct GinTupleCollector
{
IndexTuple *tuples;
uint32 ntuples;
uint32 lentuples;
uint32 sumsize;
} GinTupleCollector;
extern void ginHeapTupleFastInsert(Relation index, GinState *ginstate,
GinTupleCollector *collector);
extern uint32 ginHeapTupleFastCollect(Relation index, GinState *ginstate,
GinTupleCollector *collector,
OffsetNumber attnum, Datum value, ItemPointer item);
extern void ginInsertCleanup(Relation index, GinState *ginstate,
bool vac_delay, IndexBulkDeleteResult *stats);
#endif /* GIN_H */