Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions

spgist_private.h File Reference

#include "access/itup.h"
#include "access/spgist.h"
#include "nodes/tidbitmap.h"
#include "storage/relfilenode.h"
#include "utils/relcache.h"
Include dependency graph for spgist_private.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  SpGistPageOpaqueData
struct  SpGistLastUsedPage
struct  SpGistLUPCache
struct  SpGistMetaPageData
struct  SpGistTypeDesc
struct  SpGistState
struct  SpGistScanOpaqueData
struct  SpGistCache
struct  SpGistInnerTupleData
struct  SpGistLeafTupleData
struct  SpGistDeadTupleData
struct  spgxlogState
struct  spgxlogAddLeaf
struct  spgxlogMoveLeafs
struct  spgxlogAddNode
struct  spgxlogSplitTuple
struct  spgxlogPickSplit
struct  spgxlogVacuumLeaf
struct  spgxlogVacuumRoot
struct  spgxlogVacuumRedirect

Defines

#define SPGIST_METAPAGE_BLKNO   (0)
#define SPGIST_ROOT_BLKNO   (1)
#define SPGIST_NULL_BLKNO   (2)
#define SPGIST_LAST_FIXED_BLKNO   SPGIST_NULL_BLKNO
#define SpGistBlockIsRoot(blkno)   ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO)
#define SpGistBlockIsFixed(blkno)   ((BlockNumber) (blkno) <= (BlockNumber) SPGIST_LAST_FIXED_BLKNO)
#define SPGIST_META   (1<<0)
#define SPGIST_DELETED   (1<<1)
#define SPGIST_LEAF   (1<<2)
#define SPGIST_NULLS   (1<<3)
#define SpGistPageGetOpaque(page)   ((SpGistPageOpaque) PageGetSpecialPointer(page))
#define SpGistPageIsMeta(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_META)
#define SpGistPageIsDeleted(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED)
#define SpGistPageSetDeleted(page)   (SpGistPageGetOpaque(page)->flags |= SPGIST_DELETED)
#define SpGistPageIsLeaf(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF)
#define SpGistPageStoresNulls(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS)
#define SPGIST_PAGE_ID   0xFF82
#define SPGIST_CACHED_PAGES   8
#define SPGIST_MAGIC_NUMBER   (0xBA0BABEE)
#define SpGistPageGetMeta(p)   ((SpGistMetaPageData *) PageGetContents(p))
#define SPGIST_LIVE   0
#define SPGIST_REDIRECT   1
#define SPGIST_DEAD   2
#define SPGIST_PLACEHOLDER   3
#define SGITMAXNNODES   0x1FFF
#define SGITMAXPREFIXSIZE   0xFFFF
#define SGITMAXSIZE   0xFFFF
#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))
#define _SGITDATA(x)   (((char *) (x)) + SGITHDRSZ)
#define SGITDATAPTR(x)   ((x)->prefixSize ? _SGITDATA(x) : NULL)
#define SGITDATUM(x, s)
#define SGITNODEPTR(x)   ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize))
#define SGITITERATE(x, i, nt)
#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))
#define SGNTDATAPTR(x)   (((char *) (x)) + SGNTHDRSZ)
#define SGNTDATUM(x, s)
#define SGLTHDRSZ   MAXALIGN(sizeof(SpGistLeafTupleData))
#define SGLTDATAPTR(x)   (((char *) (x)) + SGLTHDRSZ)
#define SGLTDATUM(x, s)
#define SGDTSIZE   MAXALIGN(sizeof(SpGistDeadTupleData))
#define SPGIST_PAGE_CAPACITY
#define SpGistPageGetFreeSpace(p, n)
#define ACCEPT_RDATA_DATA(p, s, i)
#define ACCEPT_RDATA_BUFFER(b, i)
#define XLOG_SPGIST_CREATE_INDEX   0x00
#define XLOG_SPGIST_ADD_LEAF   0x10
#define XLOG_SPGIST_MOVE_LEAFS   0x20
#define XLOG_SPGIST_ADD_NODE   0x30
#define XLOG_SPGIST_SPLIT_TUPLE   0x40
#define XLOG_SPGIST_PICKSPLIT   0x50
#define XLOG_SPGIST_VACUUM_LEAF   0x60
#define XLOG_SPGIST_VACUUM_ROOT   0x70
#define XLOG_SPGIST_VACUUM_REDIRECT   0x80
#define STORE_STATE(s, d)
#define GBUF_LEAF   0x03
#define GBUF_INNER_PARITY(x)   ((x) % 3)
#define GBUF_NULLS   0x04
#define GBUF_PARITY_MASK   0x03
#define GBUF_REQ_LEAF(flags)   (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF)
#define GBUF_REQ_NULLS(flags)   ((flags) & GBUF_NULLS)

Typedefs

typedef struct SpGistPageOpaqueData SpGistPageOpaqueData
typedef SpGistPageOpaqueDataSpGistPageOpaque
typedef struct SpGistLastUsedPage SpGistLastUsedPage
typedef struct SpGistLUPCache SpGistLUPCache
typedef struct SpGistMetaPageData SpGistMetaPageData
typedef struct SpGistTypeDesc SpGistTypeDesc
typedef struct SpGistState SpGistState
typedef struct SpGistScanOpaqueData SpGistScanOpaqueData
typedef SpGistScanOpaqueDataSpGistScanOpaque
typedef struct SpGistCache SpGistCache
typedef struct SpGistInnerTupleData SpGistInnerTupleData
typedef SpGistInnerTupleDataSpGistInnerTuple
typedef IndexTupleData SpGistNodeTupleData
typedef SpGistNodeTupleDataSpGistNodeTuple
typedef struct SpGistLeafTupleData SpGistLeafTupleData
typedef SpGistLeafTupleDataSpGistLeafTuple
typedef struct SpGistDeadTupleData SpGistDeadTupleData
typedef SpGistDeadTupleDataSpGistDeadTuple
typedef struct spgxlogState spgxlogState
typedef struct spgxlogAddLeaf spgxlogAddLeaf
typedef struct spgxlogMoveLeafs spgxlogMoveLeafs
typedef struct spgxlogAddNode spgxlogAddNode
typedef struct spgxlogSplitTuple spgxlogSplitTuple
typedef struct spgxlogPickSplit spgxlogPickSplit
typedef struct spgxlogVacuumLeaf spgxlogVacuumLeaf
typedef struct spgxlogVacuumRoot spgxlogVacuumRoot
typedef struct
spgxlogVacuumRedirect 
spgxlogVacuumRedirect

Functions

SpGistCachespgGetCache (Relation index)
void initSpGistState (SpGistState *state, Relation index)
Buffer SpGistNewBuffer (Relation index)
void SpGistUpdateMetaPage (Relation index)
Buffer SpGistGetBuffer (Relation index, int flags, int needSpace, bool *isNew)
void SpGistSetLastUsedPage (Relation index, Buffer buffer)
void SpGistInitPage (Page page, uint16 f)
void SpGistInitBuffer (Buffer b, uint16 f)
void SpGistInitMetapage (Page page)
unsigned int SpGistGetTypeSize (SpGistTypeDesc *att, Datum datum)
SpGistLeafTuple spgFormLeafTuple (SpGistState *state, ItemPointer heapPtr, Datum datum, bool isnull)
SpGistNodeTuple spgFormNodeTuple (SpGistState *state, Datum label, bool isnull)
SpGistInnerTuple spgFormInnerTuple (SpGistState *state, bool hasPrefix, Datum prefix, int nNodes, SpGistNodeTuple *nodes)
SpGistDeadTuple spgFormDeadTuple (SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
DatumspgExtractNodeLabels (SpGistState *state, SpGistInnerTuple innerTuple)
OffsetNumber SpGistPageAddNewItem (SpGistState *state, Page page, Item item, Size size, OffsetNumber *startOffset, bool errorOK)
void spgUpdateNodeLink (SpGistInnerTuple tup, int nodeN, BlockNumber blkno, OffsetNumber offset)
void spgPageIndexMultiDelete (SpGistState *state, Page page, OffsetNumber *itemnos, int nitems, int firststate, int reststate, BlockNumber blkno, OffsetNumber offnum)
void spgdoinsert (Relation index, SpGistState *state, ItemPointer heapPtr, Datum datum, bool isnull)

Define Documentation

#define _SGITDATA (   x  )     (((char *) (x)) + SGITHDRSZ)

Definition at line 227 of file spgist_private.h.

#define ACCEPT_RDATA_BUFFER (   b,
  i 
)
Value:
do { \
        Assert((i) < lengthof(rdata)); \
        rdata[i].data = NULL; \
        rdata[i].len = 0; \
        rdata[i].buffer = (b); \
        rdata[i].buffer_std = true; \
        rdata[i].next = NULL; \
        if ((i) > 0) \
            rdata[(i) - 1].next = rdata + (i); \
    } while(0)

Definition at line 369 of file spgist_private.h.

Referenced by addLeafTuple(), doPickSplit(), moveLeafs(), spgAddNodeAction(), spgSplitNodeAction(), vacuumLeafPage(), vacuumLeafRoot(), and vacuumRedirectAndPlaceholder().

#define ACCEPT_RDATA_DATA (   p,
  s,
  i 
)
Value:
do { \
        Assert((i) < lengthof(rdata)); \
        rdata[i].data = (char *) (p); \
        rdata[i].len = (s); \
        rdata[i].buffer = InvalidBuffer; \
        rdata[i].buffer_std = true; \
        rdata[i].next = NULL; \
        if ((i) > 0) \
            rdata[(i) - 1].next = rdata + (i); \
    } while(0)

Definition at line 357 of file spgist_private.h.

Referenced by addLeafTuple(), doPickSplit(), moveLeafs(), spgAddNodeAction(), spgSplitNodeAction(), vacuumLeafPage(), vacuumLeafRoot(), and vacuumRedirectAndPlaceholder().

#define GBUF_INNER_PARITY (   x  )     ((x) % 3)
#define GBUF_LEAF   0x03

Definition at line 611 of file spgist_private.h.

Referenced by doPickSplit(), moveLeafs(), and spgdoinsert().

#define GBUF_NULLS   0x04

Definition at line 613 of file spgist_private.h.

Referenced by doPickSplit(), moveLeafs(), and spgdoinsert().

#define GBUF_PARITY_MASK   0x03

Definition at line 615 of file spgist_private.h.

Referenced by allocNewBuffer().

#define GBUF_REQ_LEAF (   flags  )     (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF)

Definition at line 616 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

#define GBUF_REQ_NULLS (   flags  )     ((flags) & GBUF_NULLS)

Definition at line 617 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

#define SGDTSIZE   MAXALIGN(sizeof(SpGistDeadTupleData))
#define SGITDATAPTR (   x  )     ((x)->prefixSize ? _SGITDATA(x) : NULL)

Definition at line 228 of file spgist_private.h.

Referenced by spgFormInnerTuple().

#define SGITDATUM (   x,
  s 
)
Value:
((x)->prefixSize ? \
                             ((s)->attPrefixType.attbyval ? \
                              *(Datum *) _SGITDATA(x) : \
                              PointerGetDatum(_SGITDATA(x))) \
                             : (Datum) 0)

Definition at line 229 of file spgist_private.h.

Referenced by addNode(), spgdoinsert(), and spgWalk().

#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))

Definition at line 226 of file spgist_private.h.

Referenced by spgFormInnerTuple().

#define SGITITERATE (   x,
  i,
  nt 
)
Value:
for ((i) = 0, (nt) = SGITNODEPTR(x); \
         (i) < (x)->nNodes; \
         (i)++, (nt) = (SpGistNodeTuple) (((char *) (nt)) + IndexTupleSize(nt)))

Definition at line 237 of file spgist_private.h.

Referenced by addNode(), doPickSplit(), spgExtractNodeLabels(), spgMatchNodeAction(), spgprocesspending(), spgSplitNodeAction(), spgUpdateNodeLink(), and spgWalk().

#define SGITMAXNNODES   0x1FFF

Definition at line 222 of file spgist_private.h.

Referenced by spgFormInnerTuple().

#define SGITMAXPREFIXSIZE   0xFFFF

Definition at line 223 of file spgist_private.h.

Referenced by spgFormInnerTuple().

#define SGITMAXSIZE   0xFFFF

Definition at line 224 of file spgist_private.h.

Referenced by spgFormInnerTuple().

#define SGITNODEPTR (   x  )     ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize))

Definition at line 234 of file spgist_private.h.

Referenced by spgExtractNodeLabels(), and spgFormInnerTuple().

#define SGLTDATAPTR (   x  )     (((char *) (x)) + SGLTHDRSZ)

Definition at line 300 of file spgist_private.h.

Referenced by spgFormLeafTuple().

#define SGLTDATUM (   x,
  s 
)
Value:
((s)->attType.attbyval ? \
                             *(Datum *) SGLTDATAPTR(x) : \
                             PointerGetDatum(SGLTDATAPTR(x)))

Definition at line 301 of file spgist_private.h.

Referenced by doPickSplit(), and spgLeafTest().

#define SGLTHDRSZ   MAXALIGN(sizeof(SpGistLeafTupleData))

Definition at line 299 of file spgist_private.h.

Referenced by spgdoinsert().

#define SGNTDATAPTR (   x  )     (((char *) (x)) + SGNTHDRSZ)

Definition at line 257 of file spgist_private.h.

Referenced by spgFormNodeTuple().

#define SGNTDATUM (   x,
  s 
)
Value:
((s)->attLabelType.attbyval ? \
                             *(Datum *) SGNTDATAPTR(x) : \
                             PointerGetDatum(SGNTDATAPTR(x)))

Definition at line 258 of file spgist_private.h.

Referenced by spgExtractNodeLabels().

#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))

Definition at line 256 of file spgist_private.h.

#define SPGIST_CACHED_PAGES   8

Definition at line 82 of file spgist_private.h.

#define SPGIST_DEAD   2
#define SPGIST_DELETED   (1<<1)

Definition at line 51 of file spgist_private.h.

#define SPGIST_LAST_FIXED_BLKNO   SPGIST_NULL_BLKNO

Definition at line 28 of file spgist_private.h.

#define SPGIST_LEAF   (1<<2)
#define SPGIST_LIVE   0
#define SPGIST_MAGIC_NUMBER   (0xBA0BABEE)

Definition at line 98 of file spgist_private.h.

Referenced by spgGetCache().

#define SPGIST_META   (1<<0)

Definition at line 50 of file spgist_private.h.

Referenced by SpGistInitMetapage().

#define SPGIST_METAPAGE_BLKNO   (0)
#define SPGIST_NULL_BLKNO   (2)
#define SPGIST_NULLS   (1<<3)
#define SPGIST_PAGE_CAPACITY
#define SPGIST_PAGE_ID   0xFF82

Definition at line 68 of file spgist_private.h.

#define SPGIST_PLACEHOLDER   3
#define SPGIST_REDIRECT   1
#define SPGIST_ROOT_BLKNO   (1)
#define SpGistBlockIsFixed (   blkno  )     ((BlockNumber) (blkno) <= (BlockNumber) SPGIST_LAST_FIXED_BLKNO)

Definition at line 32 of file spgist_private.h.

Referenced by SpGistGetBuffer(), SpGistNewBuffer(), and SpGistSetLastUsedPage().

#define SpGistBlockIsRoot (   blkno  )     ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO)
#define SpGistPageGetFreeSpace (   p,
  n 
)
Value:
(PageGetExactFreeSpace(p) + \
     Min(SpGistPageGetOpaque(p)->nPlaceholder, n) * \
     (SGDTSIZE + sizeof(ItemIdData)))

Definition at line 346 of file spgist_private.h.

Referenced by doPickSplit(), spgdoinsert(), and spgSplitNodeAction().

#define SpGistPageGetMeta (   p  )     ((SpGistMetaPageData *) PageGetContents(p))

Definition at line 100 of file spgist_private.h.

Referenced by spgGetCache(), SpGistInitMetapage(), and SpGistUpdateMetaPage().

#define SpGistPageGetOpaque (   page  )     ((SpGistPageOpaque) PageGetSpecialPointer(page))
#define SpGistPageIsDeleted (   page  )     (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED)
#define SpGistPageIsLeaf (   page  )     (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF)
#define SpGistPageIsMeta (   page  )     (SpGistPageGetOpaque(page)->flags & SPGIST_META)

Definition at line 56 of file spgist_private.h.

#define SpGistPageSetDeleted (   page  )     (SpGistPageGetOpaque(page)->flags |= SPGIST_DELETED)

Definition at line 58 of file spgist_private.h.

Referenced by spgvacuumpage().

#define SpGistPageStoresNulls (   page  )     (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS)
#define STORE_STATE (   s,
  d 
)
Value:
do { \
        (d).myXid = (s)->myXid; \
        (d).isBuild = (s)->isBuild; \
    } while(0)

Definition at line 404 of file spgist_private.h.

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), vacuumLeafPage(), and vacuumLeafRoot().

#define XLOG_SPGIST_ADD_LEAF   0x10

Definition at line 384 of file spgist_private.h.

Referenced by addLeafTuple(), spg_desc(), and spg_redo().

#define XLOG_SPGIST_ADD_NODE   0x30

Definition at line 386 of file spgist_private.h.

Referenced by spg_desc(), spg_redo(), and spgAddNodeAction().

#define XLOG_SPGIST_CREATE_INDEX   0x00

Definition at line 383 of file spgist_private.h.

Referenced by spg_desc(), spg_redo(), and spgbuild().

#define XLOG_SPGIST_MOVE_LEAFS   0x20

Definition at line 385 of file spgist_private.h.

Referenced by moveLeafs(), spg_desc(), and spg_redo().

#define XLOG_SPGIST_PICKSPLIT   0x50

Definition at line 388 of file spgist_private.h.

Referenced by doPickSplit(), spg_desc(), and spg_redo().

#define XLOG_SPGIST_SPLIT_TUPLE   0x40

Definition at line 387 of file spgist_private.h.

Referenced by spg_desc(), spg_redo(), and spgSplitNodeAction().

#define XLOG_SPGIST_VACUUM_LEAF   0x60

Definition at line 389 of file spgist_private.h.

Referenced by spg_desc(), spg_redo(), and vacuumLeafPage().

#define XLOG_SPGIST_VACUUM_REDIRECT   0x80

Definition at line 391 of file spgist_private.h.

Referenced by spg_desc(), spg_redo(), and vacuumRedirectAndPlaceholder().

#define XLOG_SPGIST_VACUUM_ROOT   0x70

Definition at line 390 of file spgist_private.h.

Referenced by spg_desc(), spg_redo(), and vacuumLeafRoot().


Typedef Documentation

typedef struct SpGistCache SpGistCache

Definition at line 325 of file spgist_private.h.

Definition at line 219 of file spgist_private.h.

Definition at line 297 of file spgist_private.h.

Definition at line 254 of file spgist_private.h.

Definition at line 252 of file spgist_private.h.

Definition at line 47 of file spgist_private.h.

Definition at line 169 of file spgist_private.h.

typedef struct SpGistState SpGistState
typedef struct spgxlogState spgxlogState

Function Documentation

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 108 of file spgutils.c.

References SpGistCache::attLabelType, SpGistState::attLabelType, SpGistCache::attPrefixType, SpGistState::attPrefixType, SpGistCache::attType, SpGistState::attType, SpGistCache::config, SpGistState::config, SpGistState::deadTupleStorage, GetTopTransactionIdIfAny(), SpGistState::isBuild, SpGistState::myXid, palloc0(), SGDTSIZE, and spgGetCache().

Referenced by spgbeginscan(), spgbuild(), spginsert(), and spgvacuumscan().

{
    SpGistCache *cache;

    /* Get cached static information about index */
    cache = spgGetCache(index);

    state->config = cache->config;
    state->attType = cache->attType;
    state->attPrefixType = cache->attPrefixType;
    state->attLabelType = cache->attLabelType;

    /* Make workspace for constructing dead tuples */
    state->deadTupleStorage = palloc0(SGDTSIZE);

    /* Set XID to use in redirection tuples */
    state->myXid = GetTopTransactionIdIfAny();

    /* Assume we're not in an index build (spgbuild will override) */
    state->isBuild = false;
}

void spgdoinsert ( Relation  index,
SpGistState state,
ItemPointer  heapPtr,
Datum  datum,
bool  isnull 
)

Definition at line 1842 of file spgdoinsert.c.

References addLeafTuple(), spgChooseOut::addNode, SpGistInnerTupleData::allTheSame, spgChooseIn::allTheSame, Assert, SpGistTypeDesc::attlen, SpGistState::attType, SPPageDesc::blkno, SPPageDesc::buffer, BUFFER_LOCK_EXCLUSIVE, BufferGetBlockNumber(), BufferGetPage, CHECK_FOR_INTERRUPTS, checkSplitConditions(), SpGistState::config, spgChooseIn::datum, doPickSplit(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, FunctionCall2Coll(), GBUF_LEAF, GBUF_NULLS, spgChooseIn::hasPrefix, index_getprocinfo(), InvalidBlockNumber, InvalidBuffer, spgChooseIn::leafDatum, spgChooseIn::level, LockBuffer(), spgConfigOut::longValuesOK, spgChooseOut::matchNode, Min, moveLeafs(), SpGistInnerTupleData::nNodes, spgChooseIn::nNodes, SPPageDesc::node, spgChooseIn::nodeLabels, NULL, SPPageDesc::offnum, SPPageDesc::page, PageGetItem, PageGetItemId, pfree(), PG_DETOAST_DATUM, PointerGetDatum, spgChooseIn::prefixDatum, SpGistInnerTupleData::prefixSize, random(), RelationData::rd_indcollation, ReadBuffer(), RelationGetRelationName, spgChooseOut::result, spgChooseOut::resultType, SGDTSIZE, SGITDATUM, SGLTHDRSZ, SpGistLeafTupleData::size, spgAddNode, spgAddNodeAction(), spgExtractNodeLabels(), spgFormLeafTuple(), SPGIST_CHOOSE_PROC, SPGIST_NULL_BLKNO, SPGIST_PAGE_CAPACITY, SpGistGetBuffer(), SpGistGetTypeSize(), SpGistPageGetFreeSpace, SpGistPageIsLeaf, SpGistPageStoresNulls, SpGistSetLastUsedPage(), spgMatchNode, spgMatchNodeAction(), spgSplitNodeAction(), spgSplitTuple, and UnlockReleaseBuffer().

Referenced by spginsert(), and spgistBuildCallback().

{
    int         level = 0;
    Datum       leafDatum;
    int         leafSize;
    SPPageDesc  current,
                parent;
    FmgrInfo   *procinfo = NULL;

    /*
     * Look up FmgrInfo of the user-defined choose function once, to save
     * cycles in the loop below.
     */
    if (!isnull)
        procinfo = index_getprocinfo(index, 1, SPGIST_CHOOSE_PROC);

    /*
     * Since we don't use index_form_tuple in this AM, we have to make sure
     * value to be inserted is not toasted; FormIndexDatum doesn't guarantee
     * that.
     */
    if (!isnull && state->attType.attlen == -1)
        datum = PointerGetDatum(PG_DETOAST_DATUM(datum));

    leafDatum = datum;

    /*
     * Compute space needed for a leaf tuple containing the given datum.
     *
     * If it isn't gonna fit, and the opclass can't reduce the datum size by
     * suffixing, bail out now rather than getting into an endless loop.
     */
    if (!isnull)
        leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
            SpGistGetTypeSize(&state->attType, leafDatum);
    else
        leafSize = SGDTSIZE + sizeof(ItemIdData);

    if (leafSize > SPGIST_PAGE_CAPACITY && !state->config.longValuesOK)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
            errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
                   (unsigned long) (leafSize - sizeof(ItemIdData)),
                 (unsigned long) (SPGIST_PAGE_CAPACITY - sizeof(ItemIdData)),
                   RelationGetRelationName(index)),
            errhint("Values larger than a buffer page cannot be indexed.")));

    /* Initialize "current" to the appropriate root page */
    current.blkno = isnull ? SPGIST_NULL_BLKNO : SPGIST_ROOT_BLKNO;
    current.buffer = InvalidBuffer;
    current.page = NULL;
    current.offnum = FirstOffsetNumber;
    current.node = -1;

    /* "parent" is invalid for the moment */
    parent.blkno = InvalidBlockNumber;
    parent.buffer = InvalidBuffer;
    parent.page = NULL;
    parent.offnum = InvalidOffsetNumber;
    parent.node = -1;

    for (;;)
    {
        bool        isNew = false;

        /*
         * Bail out if query cancel is pending.  We must have this somewhere
         * in the loop since a broken opclass could produce an infinite
         * picksplit loop.
         */
        CHECK_FOR_INTERRUPTS();

        if (current.blkno == InvalidBlockNumber)
        {
            /*
             * Create a leaf page.  If leafSize is too large to fit on a page,
             * we won't actually use the page yet, but it simplifies the API
             * for doPickSplit to always have a leaf page at hand; so just
             * quietly limit our request to a page size.
             */
            current.buffer =
                SpGistGetBuffer(index,
                                GBUF_LEAF | (isnull ? GBUF_NULLS : 0),
                                Min(leafSize, SPGIST_PAGE_CAPACITY),
                                &isNew);
            current.blkno = BufferGetBlockNumber(current.buffer);
        }
        else if (parent.buffer == InvalidBuffer ||
                 current.blkno != parent.blkno)
        {
            current.buffer = ReadBuffer(index, current.blkno);
            LockBuffer(current.buffer, BUFFER_LOCK_EXCLUSIVE);
        }
        else
        {
            /* inner tuple can be stored on the same page as parent one */
            current.buffer = parent.buffer;
        }
        current.page = BufferGetPage(current.buffer);

        /* should not arrive at a page of the wrong type */
        if (isnull ? !SpGistPageStoresNulls(current.page) :
            SpGistPageStoresNulls(current.page))
            elog(ERROR, "SPGiST index page %u has wrong nulls flag",
                 current.blkno);

        if (SpGistPageIsLeaf(current.page))
        {
            SpGistLeafTuple leafTuple;
            int         nToSplit,
                        sizeToSplit;

            leafTuple = spgFormLeafTuple(state, heapPtr, leafDatum, isnull);
            if (leafTuple->size + sizeof(ItemIdData) <=
                SpGistPageGetFreeSpace(current.page, 1))
            {
                /* it fits on page, so insert it and we're done */
                addLeafTuple(index, state, leafTuple,
                             &current, &parent, isnull, isNew);
                break;
            }
            else if ((sizeToSplit =
                      checkSplitConditions(index, state, &current,
                                    &nToSplit)) < SPGIST_PAGE_CAPACITY / 2 &&
                     nToSplit < 64 &&
                     leafTuple->size + sizeof(ItemIdData) + sizeToSplit <= SPGIST_PAGE_CAPACITY)
            {
                /*
                 * the amount of data is pretty small, so just move the whole
                 * chain to another leaf page rather than splitting it.
                 */
                Assert(!isNew);
                moveLeafs(index, state, &current, &parent, leafTuple, isnull);
                break;          /* we're done */
            }
            else
            {
                /* picksplit */
                if (doPickSplit(index, state, &current, &parent,
                                leafTuple, level, isnull, isNew))
                    break;      /* doPickSplit installed new tuples */

                /* leaf tuple will not be inserted yet */
                pfree(leafTuple);

                /*
                 * current now describes new inner tuple, go insert into it
                 */
                Assert(!SpGistPageIsLeaf(current.page));
                goto process_inner_tuple;
            }
        }
        else    /* non-leaf page */
        {
            /*
             * Apply the opclass choose function to figure out how to insert
             * the given datum into the current inner tuple.
             */
            SpGistInnerTuple innerTuple;
            spgChooseIn in;
            spgChooseOut out;

            /*
             * spgAddNode and spgSplitTuple cases will loop back to here to
             * complete the insertion operation.  Just in case the choose
             * function is broken and produces add or split requests
             * repeatedly, check for query cancel.
             */
    process_inner_tuple:
            CHECK_FOR_INTERRUPTS();

            innerTuple = (SpGistInnerTuple) PageGetItem(current.page,
                                PageGetItemId(current.page, current.offnum));

            in.datum = datum;
            in.leafDatum = leafDatum;
            in.level = level;
            in.allTheSame = innerTuple->allTheSame;
            in.hasPrefix = (innerTuple->prefixSize > 0);
            in.prefixDatum = SGITDATUM(innerTuple, state);
            in.nNodes = innerTuple->nNodes;
            in.nodeLabels = spgExtractNodeLabels(state, innerTuple);

            memset(&out, 0, sizeof(out));

            if (!isnull)
            {
                /* use user-defined choose method */
                FunctionCall2Coll(procinfo,
                                  index->rd_indcollation[0],
                                  PointerGetDatum(&in),
                                  PointerGetDatum(&out));
            }
            else
            {
                /* force "match" action (to insert to random subnode) */
                out.resultType = spgMatchNode;
            }

            if (innerTuple->allTheSame)
            {
                /*
                 * It's not allowed to do an AddNode at an allTheSame tuple.
                 * Opclass must say "match", in which case we choose a random
                 * one of the nodes to descend into, or "split".
                 */
                if (out.resultType == spgAddNode)
                    elog(ERROR, "cannot add a node to an allTheSame inner tuple");
                else if (out.resultType == spgMatchNode)
                    out.result.matchNode.nodeN = random() % innerTuple->nNodes;
            }

            switch (out.resultType)
            {
                case spgMatchNode:
                    /* Descend to N'th child node */
                    spgMatchNodeAction(index, state, innerTuple,
                                       &current, &parent,
                                       out.result.matchNode.nodeN);
                    /* Adjust level as per opclass request */
                    level += out.result.matchNode.levelAdd;
                    /* Replace leafDatum and recompute leafSize */
                    if (!isnull)
                    {
                        leafDatum = out.result.matchNode.restDatum;
                        leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
                            SpGistGetTypeSize(&state->attType, leafDatum);
                    }

                    /*
                     * Loop around and attempt to insert the new leafDatum at
                     * "current" (which might reference an existing child
                     * tuple, or might be invalid to force us to find a new
                     * page for the tuple).
                     *
                     * Note: if the opclass sets longValuesOK, we rely on the
                     * choose function to eventually shorten the leafDatum
                     * enough to fit on a page.  We could add a test here to
                     * complain if the datum doesn't get visibly shorter each
                     * time, but that could get in the way of opclasses that
                     * "simplify" datums in a way that doesn't necessarily
                     * lead to physical shortening on every cycle.
                     */
                    break;
                case spgAddNode:
                    /* AddNode is not sensible if nodes don't have labels */
                    if (in.nodeLabels == NULL)
                        elog(ERROR, "cannot add a node to an inner tuple without node labels");
                    /* Add node to inner tuple, per request */
                    spgAddNodeAction(index, state, innerTuple,
                                     &current, &parent,
                                     out.result.addNode.nodeN,
                                     out.result.addNode.nodeLabel);

                    /*
                     * Retry insertion into the enlarged node.  We assume that
                     * we'll get a MatchNode result this time.
                     */
                    goto process_inner_tuple;
                    break;
                case spgSplitTuple:
                    /* Split inner tuple, per request */
                    spgSplitNodeAction(index, state, innerTuple,
                                       &current, &out);

                    /* Retry insertion into the split node */
                    goto process_inner_tuple;
                    break;
                default:
                    elog(ERROR, "unrecognized SPGiST choose result: %d",
                         (int) out.resultType);
                    break;
            }
        }
    }                           /* end loop */

    /*
     * Release any buffers we're still holding.  Beware of possibility that
     * current and parent reference same buffer.
     */
    if (current.buffer != InvalidBuffer)
    {
        SpGistSetLastUsedPage(index, current.buffer);
        UnlockReleaseBuffer(current.buffer);
    }
    if (parent.buffer != InvalidBuffer &&
        parent.buffer != current.buffer)
    {
        SpGistSetLastUsedPage(index, parent.buffer);
        UnlockReleaseBuffer(parent.buffer);
    }
}

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 743 of file spgutils.c.

References elog, ERROR, i, IndexTupleHasNulls, SpGistInnerTupleData::nNodes, palloc(), SGITITERATE, SGITNODEPTR, and SGNTDATUM.

Referenced by spgdoinsert(), and spgWalk().

{
    Datum      *nodeLabels;
    int         i;
    SpGistNodeTuple node;

    /* Either all the labels must be NULL, or none. */
    node = SGITNODEPTR(innerTuple);
    if (IndexTupleHasNulls(node))
    {
        SGITITERATE(innerTuple, i, node)
        {
            if (!IndexTupleHasNulls(node))
                elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
        }
        /* They're all null, so just return NULL */
        return NULL;
    }
    else
    {
        nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
        SGITITERATE(innerTuple, i, node)
        {
            if (IndexTupleHasNulls(node))
                elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
            nodeLabels[i] = SGNTDATUM(node, state);
        }
        return nodeLabels;
    }
}

SpGistDeadTuple spgFormDeadTuple ( SpGistState state,
int  tupstate,
BlockNumber  blkno,
OffsetNumber  offnum 
)
SpGistInnerTuple spgFormInnerTuple ( SpGistState state,
bool  hasPrefix,
Datum  prefix,
int  nNodes,
SpGistNodeTuple nodes 
)

Definition at line 630 of file spgutils.c.

References SpGistState::attPrefixType, elog, ereport, errcode(), errhint(), errmsg(), ERROR, i, IndexTupleSize, memcpyDatum(), SpGistInnerTupleData::nNodes, palloc0(), SpGistInnerTupleData::prefixSize, SGDTSIZE, SGITDATAPTR, SGITHDRSZ, SGITMAXNNODES, SGITMAXPREFIXSIZE, SGITMAXSIZE, SGITNODEPTR, SpGistInnerTupleData::size, SPGIST_PAGE_CAPACITY, and SpGistGetTypeSize().

Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().

{
    SpGistInnerTuple tup;
    unsigned int size;
    unsigned int prefixSize;
    int         i;
    char       *ptr;

    /* Compute size needed */
    if (hasPrefix)
        prefixSize = SpGistGetTypeSize(&state->attPrefixType, prefix);
    else
        prefixSize = 0;

    size = SGITHDRSZ + prefixSize;

    /* Note: we rely on node tuple sizes to be maxaligned already */
    for (i = 0; i < nNodes; i++)
        size += IndexTupleSize(nodes[i]);

    /*
     * Ensure that we can replace the tuple with a dead tuple later.  This
     * test is unnecessary given current tuple layouts, but let's be safe.
     */
    if (size < SGDTSIZE)
        size = SGDTSIZE;

    /*
     * Inner tuple should be small enough to fit on a page
     */
    if (size > SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("SP-GiST inner tuple size %lu exceeds maximum %lu",
                        (unsigned long) size,
                (unsigned long) (SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))),
            errhint("Values larger than a buffer page cannot be indexed.")));

    /*
     * Check for overflow of header fields --- probably can't fail if the
     * above succeeded, but let's be paranoid
     */
    if (size > SGITMAXSIZE ||
        prefixSize > SGITMAXPREFIXSIZE ||
        nNodes > SGITMAXNNODES)
        elog(ERROR, "SPGiST inner tuple header field is too small");

    /* OK, form the tuple */
    tup = (SpGistInnerTuple) palloc0(size);

    tup->nNodes = nNodes;
    tup->prefixSize = prefixSize;
    tup->size = size;

    if (hasPrefix)
        memcpyDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);

    ptr = (char *) SGITNODEPTR(tup);

    for (i = 0; i < nNodes; i++)
    {
        SpGistNodeTuple node = nodes[i];

        memcpy(ptr, node, IndexTupleSize(node));
        ptr += IndexTupleSize(node);
    }

    return tup;
}

SpGistLeafTuple spgFormLeafTuple ( SpGistState state,
ItemPointer  heapPtr,
Datum  datum,
bool  isnull 
)

Definition at line 550 of file spgutils.c.

References SpGistState::attType, SpGistLeafTupleData::heapPtr, memcpyDatum(), SpGistLeafTupleData::nextOffset, palloc0(), SGDTSIZE, SGLTDATAPTR, SpGistLeafTupleData::size, and SpGistGetTypeSize().

Referenced by doPickSplit(), and spgdoinsert().

{
    SpGistLeafTuple tup;
    unsigned int size;

    /* compute space needed (note result is already maxaligned) */
    size = SGLTHDRSZ;
    if (!isnull)
        size += SpGistGetTypeSize(&state->attType, datum);

    /*
     * Ensure that we can replace the tuple with a dead tuple later.  This
     * test is unnecessary when !isnull, but let's be safe.
     */
    if (size < SGDTSIZE)
        size = SGDTSIZE;

    /* OK, form the tuple */
    tup = (SpGistLeafTuple) palloc0(size);

    tup->size = size;
    tup->nextOffset = InvalidOffsetNumber;
    tup->heapPtr = *heapPtr;
    if (!isnull)
        memcpyDatum(SGLTDATAPTR(tup), &state->attType, datum);

    return tup;
}

SpGistNodeTuple spgFormNodeTuple ( SpGistState state,
Datum  label,
bool  isnull 
)

Definition at line 587 of file spgutils.c.

References SpGistState::attLabelType, ereport, errcode(), errmsg(), ERROR, INDEX_SIZE_MASK, ItemPointerSetInvalid, memcpyDatum(), palloc0(), SGNTDATAPTR, SpGistGetTypeSize(), IndexTupleData::t_info, and IndexTupleData::t_tid.

Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().

{
    SpGistNodeTuple tup;
    unsigned int size;
    unsigned short infomask = 0;

    /* compute space needed (note result is already maxaligned) */
    size = SGNTHDRSZ;
    if (!isnull)
        size += SpGistGetTypeSize(&state->attLabelType, label);

    /*
     * Here we make sure that the size will fit in the field reserved for it
     * in t_info.
     */
    if ((size & INDEX_SIZE_MASK) != size)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("index row requires %lu bytes, maximum size is %lu",
                        (unsigned long) size,
                        (unsigned long) INDEX_SIZE_MASK)));

    tup = (SpGistNodeTuple) palloc0(size);

    if (isnull)
        infomask |= INDEX_NULL_MASK;
    /* we don't bother setting the INDEX_VAR_MASK bit */
    infomask |= size;
    tup->t_info = infomask;

    /* The TID field will be filled in later */
    ItemPointerSetInvalid(&tup->t_tid);

    if (!isnull)
        memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);

    return tup;
}

SpGistCache* spgGetCache ( Relation  index  ) 

Definition at line 42 of file spgutils.c.

References Assert, SpGistCache::attLabelType, SpGistCache::attPrefixType, tupleDesc::attrs, SpGistCache::attType, spgConfigIn::attType, BUFFER_LOCK_SHARE, BufferGetPage, SpGistCache::config, elog, ERROR, fillTypeDesc(), FunctionCall2Coll(), index_getprocinfo(), spgConfigOut::labelType, SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, LockBuffer(), SpGistMetaPageData::magicNumber, MemoryContextAllocZero(), tupleDesc::natts, NULL, PointerGetDatum, spgConfigOut::prefixType, RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_indcollation, RelationData::rd_indexcxt, ReadBuffer(), RelationGetRelationName, SPGIST_CONFIG_PROC, SPGIST_MAGIC_NUMBER, SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, and UnlockReleaseBuffer().

Referenced by allocNewBuffer(), initSpGistState(), spgcanreturn(), SpGistGetBuffer(), and SpGistSetLastUsedPage().

{
    SpGistCache *cache;

    if (index->rd_amcache == NULL)
    {
        Oid         atttype;
        spgConfigIn in;
        FmgrInfo   *procinfo;
        Buffer      metabuffer;
        SpGistMetaPageData *metadata;

        cache = MemoryContextAllocZero(index->rd_indexcxt,
                                       sizeof(SpGistCache));

        /* SPGiST doesn't support multi-column indexes */
        Assert(index->rd_att->natts == 1);

        /*
         * Get the actual data type of the indexed column from the index
         * tupdesc.  We pass this to the opclass config function so that
         * polymorphic opclasses are possible.
         */
        atttype = index->rd_att->attrs[0]->atttypid;

        /* Call the config function to get config info for the opclass */
        in.attType = atttype;

        procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC);
        FunctionCall2Coll(procinfo,
                          index->rd_indcollation[0],
                          PointerGetDatum(&in),
                          PointerGetDatum(&cache->config));

        /* Get the information we need about each relevant datatype */
        fillTypeDesc(&cache->attType, atttype);
        fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
        fillTypeDesc(&cache->attLabelType, cache->config.labelType);

        /* Last, get the lastUsedPages data from the metapage */
        metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
        LockBuffer(metabuffer, BUFFER_LOCK_SHARE);

        metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));

        if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
            elog(ERROR, "index \"%s\" is not an SP-GiST index",
                 RelationGetRelationName(index));

        cache->lastUsedPages = metadata->lastUsedPages;

        UnlockReleaseBuffer(metabuffer);

        index->rd_amcache = (void *) cache;
    }
    else
    {
        /* assume it's up to date */
        cache = (SpGistCache *) index->rd_amcache;
    }

    return cache;
}

Buffer SpGistGetBuffer ( Relation  index,
int  flags,
int  needSpace,
bool isNew 
)

Definition at line 309 of file spgutils.c.

References allocNewBuffer(), Assert, SpGistLastUsedPage::blkno, BufferGetPage, ConditionalLockBuffer(), elog, ERROR, SpGistLastUsedPage::freeSpace, GBUF_REQ_LEAF, GBUF_REQ_NULLS, GET_LUP, InvalidBlockNumber, Min, PageGetExactFreeSpace(), PageIsEmpty, PageIsNew, ReadBuffer(), RelationGetTargetPageFreeSpace, ReleaseBuffer(), spgGetCache(), SPGIST_DEFAULT_FILLFACTOR, SPGIST_PAGE_CAPACITY, SpGistBlockIsFixed, SpGistInitBuffer(), SpGistPageIsDeleted, SpGistPageIsLeaf, SpGistPageStoresNulls, and UnlockReleaseBuffer().

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), spgdoinsert(), and spgSplitNodeAction().

{
    SpGistCache *cache = spgGetCache(index);
    SpGistLastUsedPage *lup;

    /* Bail out if even an empty page wouldn't meet the demand */
    if (needSpace > SPGIST_PAGE_CAPACITY)
        elog(ERROR, "desired SPGiST tuple size is too big");

    /*
     * If possible, increase the space request to include relation's
     * fillfactor.  This ensures that when we add unrelated tuples to a page,
     * we try to keep 100-fillfactor% available for adding tuples that are
     * related to the ones already on it.  But fillfactor mustn't cause an
     * error for requests that would otherwise be legal.
     */
    needSpace += RelationGetTargetPageFreeSpace(index,
                                                SPGIST_DEFAULT_FILLFACTOR);
    needSpace = Min(needSpace, SPGIST_PAGE_CAPACITY);

    /* Get the cache entry for this flags setting */
    lup = GET_LUP(cache, flags);

    /* If we have nothing cached, just turn it over to allocNewBuffer */
    if (lup->blkno == InvalidBlockNumber)
    {
        *isNew = true;
        return allocNewBuffer(index, flags);
    }

    /* fixed pages should never be in cache */
    Assert(!SpGistBlockIsFixed(lup->blkno));

    /* If cached freeSpace isn't enough, don't bother looking at the page */
    if (lup->freeSpace >= needSpace)
    {
        Buffer      buffer;
        Page        page;

        buffer = ReadBuffer(index, lup->blkno);

        if (!ConditionalLockBuffer(buffer))
        {
            /*
             * buffer is locked by another process, so return a new buffer
             */
            ReleaseBuffer(buffer);
            *isNew = true;
            return allocNewBuffer(index, flags);
        }

        page = BufferGetPage(buffer);

        if (PageIsNew(page) || SpGistPageIsDeleted(page) || PageIsEmpty(page))
        {
            /* OK to initialize the page */
            uint16      pageflags = 0;

            if (GBUF_REQ_LEAF(flags))
                pageflags |= SPGIST_LEAF;
            if (GBUF_REQ_NULLS(flags))
                pageflags |= SPGIST_NULLS;
            SpGistInitBuffer(buffer, pageflags);
            lup->freeSpace = PageGetExactFreeSpace(page) - needSpace;
            *isNew = true;
            return buffer;
        }

        /*
         * Check that page is of right type and has enough space.  We must
         * recheck this since our cache isn't necessarily up to date.
         */
        if ((GBUF_REQ_LEAF(flags) ? SpGistPageIsLeaf(page) : !SpGistPageIsLeaf(page)) &&
            (GBUF_REQ_NULLS(flags) ? SpGistPageStoresNulls(page) : !SpGistPageStoresNulls(page)))
        {
            int         freeSpace = PageGetExactFreeSpace(page);

            if (freeSpace >= needSpace)
            {
                /* Success, update freespace info and return the buffer */
                lup->freeSpace = freeSpace - needSpace;
                *isNew = false;
                return buffer;
            }
        }

        /*
         * fallback to allocation of new buffer
         */
        UnlockReleaseBuffer(buffer);
    }

    /* No success with cache, so return a new buffer */
    *isNew = true;
    return allocNewBuffer(index, flags);
}

unsigned int SpGistGetTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 513 of file spgutils.c.

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, MAXALIGN, and VARSIZE_ANY.

Referenced by spgdoinsert(), spgFormInnerTuple(), spgFormLeafTuple(), and spgFormNodeTuple().

{
    unsigned int size;

    if (att->attbyval)
        size = sizeof(Datum);
    else if (att->attlen > 0)
        size = att->attlen;
    else
        size = VARSIZE_ANY(datum);

    return MAXALIGN(size);
}

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)
void SpGistInitMetapage ( Page  page  ) 

Definition at line 474 of file spgutils.c.

References SpGistLastUsedPage::blkno, SpGistLUPCache::cachedPage, i, InvalidBlockNumber, SpGistMetaPageData::lastUsedPages, SpGistMetaPageData::magicNumber, SPGIST_META, SpGistInitPage(), and SpGistPageGetMeta.

Referenced by spgbuild(), spgbuildempty(), and spgRedoCreateIndex().

{
    SpGistMetaPageData *metadata;
    int         i;

    SpGistInitPage(page, SPGIST_META);
    metadata = SpGistPageGetMeta(page);
    memset(metadata, 0, sizeof(SpGistMetaPageData));
    metadata->magicNumber = SPGIST_MAGIC_NUMBER;

    /* initialize last-used-page cache to empty */
    for (i = 0; i < SPGIST_CACHED_PAGES; i++)
        metadata->lastUsedPages.cachedPage[i].blkno = InvalidBlockNumber;
}

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 449 of file spgutils.c.

References SpGistPageOpaqueData::flags, MAXALIGN, PageInit(), SpGistPageOpaqueData::spgist_page_id, and SpGistPageGetOpaque.

Referenced by spgbuildempty(), SpGistInitBuffer(), and SpGistInitMetapage().

{
    SpGistPageOpaque opaque;

    PageInit(page, BLCKSZ, MAXALIGN(sizeof(SpGistPageOpaqueData)));
    opaque = SpGistPageGetOpaque(page);
    memset(opaque, 0, sizeof(SpGistPageOpaqueData));
    opaque->flags = f;
    opaque->spgist_page_id = SPGIST_PAGE_ID;
}

Buffer SpGistNewBuffer ( Relation  index  ) 

Definition at line 137 of file spgutils.c.

References BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsEmpty, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, ReleaseBuffer(), SpGistBlockIsFixed, SpGistPageIsDeleted, and UnlockRelationForExtension().

Referenced by allocNewBuffer(), and spgbuild().

{
    Buffer      buffer;
    bool        needLock;

    /* First, try to get a page from FSM */
    for (;;)
    {
        BlockNumber blkno = GetFreeIndexPage(index);

        if (blkno == InvalidBlockNumber)
            break;              /* nothing known to FSM */

        /*
         * The fixed pages shouldn't ever be listed in FSM, but just in case
         * one is, ignore it.
         */
        if (SpGistBlockIsFixed(blkno))
            continue;

        buffer = ReadBuffer(index, blkno);

        /*
         * We have to guard against the possibility that someone else already
         * recycled this page; the buffer may be locked if so.
         */
        if (ConditionalLockBuffer(buffer))
        {
            Page        page = BufferGetPage(buffer);

            if (PageIsNew(page))
                return buffer;  /* OK to use, if never initialized */

            if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
                return buffer;  /* OK to use */

            LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
        }

        /* Can't use it, so release buffer and try again */
        ReleaseBuffer(buffer);
    }

    /* Must extend the file */
    needLock = !RELATION_IS_LOCAL(index);
    if (needLock)
        LockRelationForExtension(index, ExclusiveLock);

    buffer = ReadBuffer(index, P_NEW);
    LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);

    if (needLock)
        UnlockRelationForExtension(index, ExclusiveLock);

    return buffer;
}

OffsetNumber SpGistPageAddNewItem ( SpGistState state,
Page  page,
Item  item,
Size  size,
OffsetNumber startOffset,
bool  errorOK 
)

Definition at line 786 of file spgutils.c.

References Assert, elog, ERROR, i, InvalidOffsetNumber, MAXALIGN, SpGistPageOpaqueData::nPlaceholder, PageAddItem(), PageGetExactFreeSpace(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageIndexTupleDelete(), PANIC, SGDTSIZE, SPGIST_PLACEHOLDER, SpGistPageGetOpaque, and SpGistDeadTupleData::tupstate.

Referenced by addLeafTuple(), doPickSplit(), moveLeafs(), spgAddNodeAction(), and spgSplitNodeAction().

{
    SpGistPageOpaque opaque = SpGistPageGetOpaque(page);
    OffsetNumber i,
                maxoff,
                offnum;

    if (opaque->nPlaceholder > 0 &&
        PageGetExactFreeSpace(page) + SGDTSIZE >= MAXALIGN(size))
    {
        /* Try to replace a placeholder */
        maxoff = PageGetMaxOffsetNumber(page);
        offnum = InvalidOffsetNumber;

        for (;;)
        {
            if (startOffset && *startOffset != InvalidOffsetNumber)
                i = *startOffset;
            else
                i = FirstOffsetNumber;
            for (; i <= maxoff; i++)
            {
                SpGistDeadTuple it = (SpGistDeadTuple) PageGetItem(page,
                                                     PageGetItemId(page, i));

                if (it->tupstate == SPGIST_PLACEHOLDER)
                {
                    offnum = i;
                    break;
                }
            }

            /* Done if we found a placeholder */
            if (offnum != InvalidOffsetNumber)
                break;

            if (startOffset && *startOffset != InvalidOffsetNumber)
            {
                /* Hint was no good, re-search from beginning */
                *startOffset = InvalidOffsetNumber;
                continue;
            }

            /* Hmm, no placeholder found? */
            opaque->nPlaceholder = 0;
            break;
        }

        if (offnum != InvalidOffsetNumber)
        {
            /* Replace the placeholder tuple */
            PageIndexTupleDelete(page, offnum);

            offnum = PageAddItem(page, item, size, offnum, false, false);

            /*
             * We should not have failed given the size check at the top of
             * the function, but test anyway.  If we did fail, we must PANIC
             * because we've already deleted the placeholder tuple, and
             * there's no other way to keep the damage from getting to disk.
             */
            if (offnum != InvalidOffsetNumber)
            {
                Assert(opaque->nPlaceholder > 0);
                opaque->nPlaceholder--;
                if (startOffset)
                    *startOffset = offnum + 1;
            }
            else
                elog(PANIC, "failed to add item of size %u to SPGiST index page",
                     (int) size);

            return offnum;
        }
    }

    /* No luck in replacing a placeholder, so just add it to the page */
    offnum = PageAddItem(page, item, size,
                         InvalidOffsetNumber, false, false);

    if (offnum == InvalidOffsetNumber && !errorOK)
        elog(ERROR, "failed to add item of size %u to SPGiST index page",
             (int) size);

    return offnum;
}

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 414 of file spgutils.c.

References SpGistLastUsedPage::blkno, BufferGetBlockNumber(), BufferGetPage, SpGistLastUsedPage::freeSpace, GBUF_INNER_PARITY, GET_LUP, InvalidBlockNumber, PageGetExactFreeSpace(), spgGetCache(), SpGistBlockIsFixed, SpGistPageIsLeaf, and SpGistPageStoresNulls.

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), spgdoinsert(), spgMatchNodeAction(), spgprocesspending(), spgSplitNodeAction(), and spgvacuumpage().

{
    SpGistCache *cache = spgGetCache(index);
    SpGistLastUsedPage *lup;
    int         freeSpace;
    Page        page = BufferGetPage(buffer);
    BlockNumber blkno = BufferGetBlockNumber(buffer);
    int         flags;

    /* Never enter fixed pages (root pages) in cache, though */
    if (SpGistBlockIsFixed(blkno))
        return;

    if (SpGistPageIsLeaf(page))
        flags = GBUF_LEAF;
    else
        flags = GBUF_INNER_PARITY(blkno);
    if (SpGistPageStoresNulls(page))
        flags |= GBUF_NULLS;

    lup = GET_LUP(cache, flags);

    freeSpace = PageGetExactFreeSpace(page);
    if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
        lup->freeSpace < freeSpace)
    {
        lup->blkno = blkno;
        lup->freeSpace = freeSpace;
    }
}

void SpGistUpdateMetaPage ( Relation  index  ) 
void spgPageIndexMultiDelete ( SpGistState state,
Page  page,
OffsetNumber itemnos,
int  nitems,
int  firststate,
int  reststate,
BlockNumber  blkno,
OffsetNumber  offnum 
)

Definition at line 128 of file spgdoinsert.c.

References cmpOffsetNumbers(), elog, ERROR, i, NULL, PageAddItem(), PageIndexMultiDelete(), palloc(), pfree(), qsort, SpGistDeadTupleData::size, spgFormDeadTuple(), SPGIST_PLACEHOLDER, SPGIST_REDIRECT, SpGistPageGetOpaque, and SpGistDeadTupleData::tupstate.

Referenced by doPickSplit(), moveLeafs(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoVacuumLeaf(), and vacuumLeafPage().

{
    OffsetNumber firstItem;
    OffsetNumber *sortednos;
    SpGistDeadTuple tuple = NULL;
    int         i;

    if (nitems == 0)
        return;                 /* nothing to do */

    /*
     * For efficiency we want to use PageIndexMultiDelete, which requires the
     * targets to be listed in sorted order, so we have to sort the itemnos
     * array.  (This also greatly simplifies the math for reinserting the
     * replacement tuples.)  However, we must not scribble on the caller's
     * array, so we have to make a copy.
     */
    sortednos = (OffsetNumber *) palloc(sizeof(OffsetNumber) * nitems);
    memcpy(sortednos, itemnos, sizeof(OffsetNumber) * nitems);
    if (nitems > 1)
        qsort(sortednos, nitems, sizeof(OffsetNumber), cmpOffsetNumbers);

    PageIndexMultiDelete(page, sortednos, nitems);

    firstItem = itemnos[0];

    for (i = 0; i < nitems; i++)
    {
        OffsetNumber itemno = sortednos[i];
        int         tupstate;

        tupstate = (itemno == firstItem) ? firststate : reststate;
        if (tuple == NULL || tuple->tupstate != tupstate)
            tuple = spgFormDeadTuple(state, tupstate, blkno, offnum);

        if (PageAddItem(page, (Item) tuple, tuple->size,
                        itemno, false, false) != itemno)
            elog(ERROR, "failed to add item of size %u to SPGiST index page",
                 tuple->size);

        if (tupstate == SPGIST_REDIRECT)
            SpGistPageGetOpaque(page)->nRedirection++;
        else if (tupstate == SPGIST_PLACEHOLDER)
            SpGistPageGetOpaque(page)->nPlaceholder++;
    }

    pfree(sortednos);
}

void spgUpdateNodeLink ( SpGistInnerTuple  tup,
int  nodeN,
BlockNumber  blkno,
OffsetNumber  offset 
)

Definition at line 48 of file spgdoinsert.c.

References elog, ERROR, i, ItemPointerSet, SGITITERATE, and IndexTupleData::t_tid.

Referenced by saveNodeLink(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), and spgSplitNodeAction().

{
    int         i;
    SpGistNodeTuple node;

    SGITITERATE(tup, i, node)
    {
        if (i == nodeN)
        {
            ItemPointerSet(&node->t_tid, blkno, offset);
            return;
        }
    }

    elog(ERROR, "failed to find requested node %d in SPGiST inner tuple",
         nodeN);
}