Header And Logo

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

Functions

ginentrypage.c File Reference

#include "postgres.h"
#include "access/gin_private.h"
#include "utils/rel.h"
Include dependency graph for ginentrypage.c:

Go to the source code of this file.

Functions

IndexTuple GinFormTuple (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *ipd, uint32 nipd, bool errorTooBig)
void GinShortenTuple (IndexTuple itup, uint32 nipd)
static IndexTuple GinFormInteriorTuple (IndexTuple itup, Page page, BlockNumber childblk)
static IndexTuple getRightMostTuple (Page page)
static bool entryIsMoveRight (GinBtree btree, Page page)
static BlockNumber entryLocateEntry (GinBtree btree, GinBtreeStack *stack)
static bool entryLocateLeafEntry (GinBtree btree, GinBtreeStack *stack)
static OffsetNumber entryFindChildPtr (GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
static BlockNumber entryGetLeftMostPage (GinBtree btree, Page page)
static bool entryIsEnoughSpace (GinBtree btree, Buffer buf, OffsetNumber off)
static BlockNumber entryPreparePage (GinBtree btree, Page page, OffsetNumber off)
static void entryPlaceToPage (GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata)
static Page entrySplitPage (GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata)
IndexTuple ginPageGetLinkItup (Buffer buf)
void ginEntryFillRoot (GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
void ginPrepareEntryScan (GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)

Function Documentation

static OffsetNumber entryFindChildPtr ( GinBtree  btree,
Page  page,
BlockNumber  blkno,
OffsetNumber  storedOff 
) [static]

Definition at line 374 of file ginentrypage.c.

References Assert, FirstOffsetNumber, GinGetDownlink, GinPageIsData, GinPageIsLeaf, i, PageGetItem, PageGetItemId, and PageGetMaxOffsetNumber.

{
    OffsetNumber i,
                maxoff = PageGetMaxOffsetNumber(page);
    IndexTuple  itup;

    Assert(!GinPageIsLeaf(page));
    Assert(!GinPageIsData(page));

    /* if page isn't changed, we returns storedOff */
    if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
    {
        itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, storedOff));
        if (GinGetDownlink(itup) == blkno)
            return storedOff;

        /*
         * we hope, that needed pointer goes to right. It's true if there
         * wasn't a deletion
         */
        for (i = storedOff + 1; i <= maxoff; i++)
        {
            itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
            if (GinGetDownlink(itup) == blkno)
                return i;
        }
        maxoff = storedOff - 1;
    }

    /* last chance */
    for (i = FirstOffsetNumber; i <= maxoff; i++)
    {
        itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
        if (GinGetDownlink(itup) == blkno)
            return i;
    }

    return InvalidOffsetNumber;
}

static BlockNumber entryGetLeftMostPage ( GinBtree  btree,
Page  page 
) [static]
static bool entryIsEnoughSpace ( GinBtree  btree,
Buffer  buf,
OffsetNumber  off 
) [static]

Definition at line 428 of file ginentrypage.c.

References Assert, BufferGetPage, GinBtreeData::entry, GinPageIsData, IndexTupleSize, GinBtreeData::isDelete, MAXALIGN, PageGetFreeSpace(), PageGetItem, and PageGetItemId.

{
    Size        itupsz = 0;
    Page        page = BufferGetPage(buf);

    Assert(btree->entry);
    Assert(!GinPageIsData(page));

    if (btree->isDelete)
    {
        IndexTuple  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));

        itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
    }

    if (PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
        return true;

    return false;
}

static bool entryIsMoveRight ( GinBtree  btree,
Page  page 
) [static]

Definition at line 212 of file ginentrypage.c.

References GinBtreeData::entryAttnum, GinBtreeData::entryCategory, GinBtreeData::entryKey, getRightMostTuple(), ginCompareAttEntries(), GinPageRightMost, GinBtreeData::ginstate, gintuple_get_attrnum(), and gintuple_get_key().

{
    IndexTuple  itup;
    OffsetNumber attnum;
    Datum       key;
    GinNullCategory category;

    if (GinPageRightMost(page))
        return FALSE;

    itup = getRightMostTuple(page);
    attnum = gintuple_get_attrnum(btree->ginstate, itup);
    key = gintuple_get_key(btree->ginstate, itup, &category);

    if (ginCompareAttEntries(btree->ginstate,
                   btree->entryAttnum, btree->entryKey, btree->entryCategory,
                             attnum, key, category) > 0)
        return TRUE;

    return FALSE;
}

static BlockNumber entryLocateEntry ( GinBtree  btree,
GinBtreeStack stack 
) [static]

Definition at line 239 of file ginentrypage.c.

References Assert, GinBtreeStack::buffer, BufferGetPage, GinBtreeData::entryAttnum, GinBtreeData::entryCategory, GinBtreeData::entryKey, FirstOffsetNumber, GinBtreeData::fullScan, GinBtreeData::getLeftMostPage, GIN_ROOT_BLKNO, ginCompareAttEntries(), GinGetDownlink, GinPageIsData, GinPageIsLeaf, GinPageRightMost, GinBtreeData::ginstate, gintuple_get_attrnum(), gintuple_get_key(), GinBtreeStack::off, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, and GinBtreeStack::predictNumber.

{
    OffsetNumber low,
                high,
                maxoff;
    IndexTuple  itup = NULL;
    int         result;
    Page        page = BufferGetPage(stack->buffer);

    Assert(!GinPageIsLeaf(page));
    Assert(!GinPageIsData(page));

    if (btree->fullScan)
    {
        stack->off = FirstOffsetNumber;
        stack->predictNumber *= PageGetMaxOffsetNumber(page);
        return btree->getLeftMostPage(btree, page);
    }

    low = FirstOffsetNumber;
    maxoff = high = PageGetMaxOffsetNumber(page);
    Assert(high >= low);

    high++;

    while (high > low)
    {
        OffsetNumber mid = low + ((high - low) / 2);

        if (mid == maxoff && GinPageRightMost(page))
        {
            /* Right infinity */
            result = -1;
        }
        else
        {
            OffsetNumber attnum;
            Datum       key;
            GinNullCategory category;

            itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
            attnum = gintuple_get_attrnum(btree->ginstate, itup);
            key = gintuple_get_key(btree->ginstate, itup, &category);
            result = ginCompareAttEntries(btree->ginstate,
                                          btree->entryAttnum,
                                          btree->entryKey,
                                          btree->entryCategory,
                                          attnum, key, category);
        }

        if (result == 0)
        {
            stack->off = mid;
            Assert(GinGetDownlink(itup) != GIN_ROOT_BLKNO);
            return GinGetDownlink(itup);
        }
        else if (result > 0)
            low = mid + 1;
        else
            high = mid;
    }

    Assert(high >= FirstOffsetNumber && high <= maxoff);

    stack->off = high;
    itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, high));
    Assert(GinGetDownlink(itup) != GIN_ROOT_BLKNO);
    return GinGetDownlink(itup);
}

static bool entryLocateLeafEntry ( GinBtree  btree,
GinBtreeStack stack 
) [static]

Definition at line 315 of file ginentrypage.c.

References Assert, GinBtreeStack::buffer, BufferGetPage, GinBtreeData::entryAttnum, GinBtreeData::entryCategory, GinBtreeData::entryKey, GinBtreeData::fullScan, ginCompareAttEntries(), GinPageIsData, GinPageIsLeaf, GinBtreeData::ginstate, gintuple_get_attrnum(), gintuple_get_key(), GinBtreeStack::off, PageGetItem, PageGetItemId, and PageGetMaxOffsetNumber.

{
    Page        page = BufferGetPage(stack->buffer);
    OffsetNumber low,
                high;

    Assert(GinPageIsLeaf(page));
    Assert(!GinPageIsData(page));

    if (btree->fullScan)
    {
        stack->off = FirstOffsetNumber;
        return TRUE;
    }

    low = FirstOffsetNumber;
    high = PageGetMaxOffsetNumber(page);

    if (high < low)
    {
        stack->off = FirstOffsetNumber;
        return false;
    }

    high++;

    while (high > low)
    {
        OffsetNumber mid = low + ((high - low) / 2);
        IndexTuple  itup;
        OffsetNumber attnum;
        Datum       key;
        GinNullCategory category;
        int         result;

        itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
        attnum = gintuple_get_attrnum(btree->ginstate, itup);
        key = gintuple_get_key(btree->ginstate, itup, &category);
        result = ginCompareAttEntries(btree->ginstate,
                                      btree->entryAttnum,
                                      btree->entryKey,
                                      btree->entryCategory,
                                      attnum, key, category);
        if (result == 0)
        {
            stack->off = mid;
            return true;
        }
        else if (result > 0)
            low = mid + 1;
        else
            high = mid;
    }

    stack->off = high;
    return false;
}

static void entryPlaceToPage ( GinBtree  btree,
Buffer  buf,
OffsetNumber  off,
XLogRecData **  prdata 
) [static]

Definition at line 485 of file ginentrypage.c.

References ginxlogInsert::blkno, XLogRecData::buffer, XLogRecData::buffer_std, BufferGetBlockNumber(), BufferGetPage, XLogRecData::data, elog, GinBtreeData::entry, entryPreparePage(), ERROR, GinPageIsLeaf, GinBtreeData::index, IndexTupleSize, InvalidBlockNumber, ginxlogInsert::isData, GinBtreeData::isDelete, ginxlogInsert::isDelete, ginxlogInsert::isLeaf, XLogRecData::len, XLogRecData::next, ginxlogInsert::nitem, ginxlogInsert::node, ginxlogInsert::offset, PageAddItem(), RelationData::rd_node, RelationGetRelationName, TRUE, and ginxlogInsert::updateBlkno.

{
    Page        page = BufferGetPage(buf);
    OffsetNumber placed;
    int         cnt = 0;

    /* these must be static so they can be returned to caller */
    static XLogRecData rdata[3];
    static ginxlogInsert data;

    *prdata = rdata;
    data.updateBlkno = entryPreparePage(btree, page, off);

    placed = PageAddItem(page, (Item) btree->entry, IndexTupleSize(btree->entry), off, false, false);
    if (placed != off)
        elog(ERROR, "failed to add item to index page in \"%s\"",
             RelationGetRelationName(btree->index));

    data.node = btree->index->rd_node;
    data.blkno = BufferGetBlockNumber(buf);
    data.offset = off;
    data.nitem = 1;
    data.isDelete = btree->isDelete;
    data.isData = false;
    data.isLeaf = GinPageIsLeaf(page) ? TRUE : FALSE;

    /*
     * Prevent full page write if child's split occurs. That is needed to
     * remove incomplete splits while replaying WAL
     *
     * data.updateBlkno contains new block number (of newly created right
     * page) for recently splited page.
     */
    if (data.updateBlkno == InvalidBlockNumber)
    {
        rdata[0].buffer = buf;
        rdata[0].buffer_std = TRUE;
        rdata[0].data = NULL;
        rdata[0].len = 0;
        rdata[0].next = &rdata[1];
        cnt++;
    }

    rdata[cnt].buffer = InvalidBuffer;
    rdata[cnt].data = (char *) &data;
    rdata[cnt].len = sizeof(ginxlogInsert);
    rdata[cnt].next = &rdata[cnt + 1];
    cnt++;

    rdata[cnt].buffer = InvalidBuffer;
    rdata[cnt].data = (char *) btree->entry;
    rdata[cnt].len = IndexTupleSize(btree->entry);
    rdata[cnt].next = NULL;

    btree->entry = NULL;
}

static BlockNumber entryPreparePage ( GinBtree  btree,
Page  page,
OffsetNumber  off 
) [static]

Definition at line 455 of file ginentrypage.c.

References Assert, GinBtreeData::entry, GinPageIsData, GinPageIsLeaf, GinSetDownlink, InvalidBlockNumber, GinBtreeData::isDelete, PageGetItem, PageGetItemId, PageIndexTupleDelete(), and GinBtreeData::rightblkno.

Referenced by entryPlaceToPage(), and entrySplitPage().

{
    BlockNumber ret = InvalidBlockNumber;

    Assert(btree->entry);
    Assert(!GinPageIsData(page));

    if (btree->isDelete)
    {
        Assert(GinPageIsLeaf(page));
        PageIndexTupleDelete(page, off);
    }

    if (!GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber)
    {
        IndexTuple  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));

        GinSetDownlink(itup, btree->rightblkno);
        ret = btree->rightblkno;
    }

    btree->rightblkno = InvalidBlockNumber;

    return ret;
}

static Page entrySplitPage ( GinBtree  btree,
Buffer  lbuf,
Buffer  rbuf,
OffsetNumber  off,
XLogRecData **  prdata 
) [static]

Definition at line 549 of file ginentrypage.c.

References XLogRecData::buffer, BufferGetBlockNumber(), BufferGetPage, XLogRecData::data, elog, GinBtreeData::entry, entryPreparePage(), ERROR, FirstOffsetNumber, GinFormInteriorTuple(), GinGetDownlink, GinInitPage(), GinPageGetOpaque, GinPageIsLeaf, i, GinBtreeData::index, IndexTupleSize, InvalidOffsetNumber, ginxlogSplit::isData, ginxlogSplit::isLeaf, ginxlogSplit::isRootSplit, ginxlogSplit::lblkno, ginxlogSplit::leftChildBlkno, XLogRecData::len, MAXALIGN, XLogRecData::next, ginxlogSplit::nitem, ginxlogSplit::node, PageAddItem(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetPageSize, PageGetTempPageCopy(), ginxlogSplit::rblkno, RelationData::rd_node, RelationGetRelationName, GinBtreeData::rightblkno, ginxlogSplit::rootBlkno, ginxlogSplit::separator, totalsize, TRUE, and ginxlogSplit::updateBlkno.

{
    OffsetNumber i,
                maxoff,
                separator = InvalidOffsetNumber;
    Size        totalsize = 0;
    Size        lsize = 0,
                size;
    char       *ptr;
    IndexTuple  itup,
                leftrightmost = NULL;
    Page        page;
    Page        lpage = PageGetTempPageCopy(BufferGetPage(lbuf));
    Page        rpage = BufferGetPage(rbuf);
    Size        pageSize = PageGetPageSize(lpage);

    /* these must be static so they can be returned to caller */
    static XLogRecData rdata[2];
    static ginxlogSplit data;
    static char tupstore[2 * BLCKSZ];

    *prdata = rdata;
    data.leftChildBlkno = (GinPageIsLeaf(lpage)) ?
        InvalidOffsetNumber : GinGetDownlink(btree->entry);
    data.updateBlkno = entryPreparePage(btree, lpage, off);

    maxoff = PageGetMaxOffsetNumber(lpage);
    ptr = tupstore;

    for (i = FirstOffsetNumber; i <= maxoff; i++)
    {
        if (i == off)
        {
            size = MAXALIGN(IndexTupleSize(btree->entry));
            memcpy(ptr, btree->entry, size);
            ptr += size;
            totalsize += size + sizeof(ItemIdData);
        }

        itup = (IndexTuple) PageGetItem(lpage, PageGetItemId(lpage, i));
        size = MAXALIGN(IndexTupleSize(itup));
        memcpy(ptr, itup, size);
        ptr += size;
        totalsize += size + sizeof(ItemIdData);
    }

    if (off == maxoff + 1)
    {
        size = MAXALIGN(IndexTupleSize(btree->entry));
        memcpy(ptr, btree->entry, size);
        ptr += size;
        totalsize += size + sizeof(ItemIdData);
    }

    GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
    GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);

    ptr = tupstore;
    maxoff++;
    lsize = 0;

    page = lpage;
    for (i = FirstOffsetNumber; i <= maxoff; i++)
    {
        itup = (IndexTuple) ptr;

        if (lsize > totalsize / 2)
        {
            if (separator == InvalidOffsetNumber)
                separator = i - 1;
            page = rpage;
        }
        else
        {
            leftrightmost = itup;
            lsize += MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
        }

        if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
            elog(ERROR, "failed to add item to index page in \"%s\"",
                 RelationGetRelationName(btree->index));
        ptr += MAXALIGN(IndexTupleSize(itup));
    }

    btree->entry = GinFormInteriorTuple(leftrightmost, lpage,
                                        BufferGetBlockNumber(lbuf));

    btree->rightblkno = BufferGetBlockNumber(rbuf);

    data.node = btree->index->rd_node;
    data.rootBlkno = InvalidBlockNumber;
    data.lblkno = BufferGetBlockNumber(lbuf);
    data.rblkno = BufferGetBlockNumber(rbuf);
    data.separator = separator;
    data.nitem = maxoff;
    data.isData = FALSE;
    data.isLeaf = GinPageIsLeaf(lpage) ? TRUE : FALSE;
    data.isRootSplit = FALSE;

    rdata[0].buffer = InvalidBuffer;
    rdata[0].data = (char *) &data;
    rdata[0].len = sizeof(ginxlogSplit);
    rdata[0].next = &rdata[1];

    rdata[1].buffer = InvalidBuffer;
    rdata[1].data = tupstore;
    rdata[1].len = MAXALIGN(totalsize);
    rdata[1].next = NULL;

    return lpage;
}

static IndexTuple getRightMostTuple ( Page  page  )  [static]

Definition at line 204 of file ginentrypage.c.

References PageGetItem, PageGetItemId, and PageGetMaxOffsetNumber.

Referenced by entryIsMoveRight(), and ginPageGetLinkItup().

{
    OffsetNumber maxoff = PageGetMaxOffsetNumber(page);

    return (IndexTuple) PageGetItem(page, PageGetItemId(page, maxoff));
}

void ginEntryFillRoot ( GinBtree  btree,
Buffer  root,
Buffer  lbuf,
Buffer  rbuf 
)

Definition at line 682 of file ginentrypage.c.

References BufferGetPage, elog, ERROR, ginPageGetLinkItup(), IndexTupleSize, InvalidOffsetNumber, PageAddItem(), and pfree().

Referenced by ginRedoSplit().

{
    Page        page;
    IndexTuple  itup;

    page = BufferGetPage(root);

    itup = ginPageGetLinkItup(lbuf);
    if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
        elog(ERROR, "failed to add item to index root page");
    pfree(itup);

    itup = ginPageGetLinkItup(rbuf);
    if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
        elog(ERROR, "failed to add item to index root page");
    pfree(itup);
}

static IndexTuple GinFormInteriorTuple ( IndexTuple  itup,
Page  page,
BlockNumber  childblk 
) [static]

Definition at line 170 of file ginentrypage.c.

References GinGetPostingOffset, GinIsPostingTree, GinPageIsLeaf, GinSetDownlink, IndexTupleSize, MAXALIGN, palloc(), and IndexTupleData::t_info.

Referenced by entrySplitPage(), and ginPageGetLinkItup().

{
    IndexTuple  nitup;

    if (GinPageIsLeaf(page) && !GinIsPostingTree(itup))
    {
        /* Tuple contains a posting list, just copy stuff before that */
        uint32      origsize = GinGetPostingOffset(itup);

        origsize = MAXALIGN(origsize);
        nitup = (IndexTuple) palloc(origsize);
        memcpy(nitup, itup, origsize);
        /* ... be sure to fix the size header field ... */
        nitup->t_info &= ~INDEX_SIZE_MASK;
        nitup->t_info |= origsize;
    }
    else
    {
        /* Copy the tuple as-is */
        nitup = (IndexTuple) palloc(IndexTupleSize(itup));
        memcpy(nitup, itup, IndexTupleSize(itup));
    }

    /* Now insert the correct downlink */
    GinSetDownlink(nitup, childblk);

    return nitup;
}

IndexTuple GinFormTuple ( GinState ginstate,
OffsetNumber  attnum,
Datum  key,
GinNullCategory  category,
ItemPointerData ipd,
uint32  nipd,
bool  errorTooBig 
)

Definition at line 36 of file ginentrypage.c.

References Assert, ereport, errcode(), errmsg(), ERROR, GIN_CAT_NORM_KEY, GinCategoryOffset, GinGetPosting, GinMaxItemSize, GinSetNPosting, GinSetNullCategory, GinSetPostingOffset, GinState::index, index_form_tuple(), INDEX_SIZE_MASK, IndexTupleHasNulls, IndexTupleSize, Max, MAXALIGN, Min, GinState::oneCol, pfree(), RelationGetRelationName, repalloc(), SHORTALIGN, IndexTupleData::t_info, GinState::tupdesc, and UInt16GetDatum.

Referenced by addItemPointersToLeafTuple(), buildFreshLeafTuple(), ginHeapTupleFastCollect(), and ginVacuumEntryPage().

{
    Datum       datums[2];
    bool        isnull[2];
    IndexTuple  itup;
    uint32      newsize;

    /* Build the basic tuple: optional column number, plus key datum */
    if (ginstate->oneCol)
    {
        datums[0] = key;
        isnull[0] = (category != GIN_CAT_NORM_KEY);
    }
    else
    {
        datums[0] = UInt16GetDatum(attnum);
        isnull[0] = false;
        datums[1] = key;
        isnull[1] = (category != GIN_CAT_NORM_KEY);
    }

    itup = index_form_tuple(ginstate->tupdesc[attnum - 1], datums, isnull);

    /*
     * Determine and store offset to the posting list, making sure there is
     * room for the category byte if needed.
     *
     * Note: because index_form_tuple MAXALIGNs the tuple size, there may well
     * be some wasted pad space.  Is it worth recomputing the data length to
     * prevent that?  That would also allow us to Assert that the real data
     * doesn't overlap the GinNullCategory byte, which this code currently
     * takes on faith.
     */
    newsize = IndexTupleSize(itup);

    if (IndexTupleHasNulls(itup))
    {
        uint32      minsize;

        Assert(category != GIN_CAT_NORM_KEY);
        minsize = GinCategoryOffset(itup, ginstate) + sizeof(GinNullCategory);
        newsize = Max(newsize, minsize);
    }

    newsize = SHORTALIGN(newsize);

    GinSetPostingOffset(itup, newsize);

    GinSetNPosting(itup, nipd);

    /*
     * Add space needed for posting list, if any.  Then check that the tuple
     * won't be too big to store.
     */
    newsize += sizeof(ItemPointerData) * nipd;
    newsize = MAXALIGN(newsize);
    if (newsize > Min(INDEX_SIZE_MASK, GinMaxItemSize))
    {
        if (errorTooBig)
            ereport(ERROR,
                    (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
            errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
                   (unsigned long) newsize,
                   (unsigned long) Min(INDEX_SIZE_MASK,
                                       GinMaxItemSize),
                   RelationGetRelationName(ginstate->index))));
        pfree(itup);
        return NULL;
    }

    /*
     * Resize tuple if needed
     */
    if (newsize != IndexTupleSize(itup))
    {
        itup = repalloc(itup, newsize);

        /* set new size in tuple header */
        itup->t_info &= ~INDEX_SIZE_MASK;
        itup->t_info |= newsize;
    }

    /*
     * Insert category byte, if needed
     */
    if (category != GIN_CAT_NORM_KEY)
    {
        Assert(IndexTupleHasNulls(itup));
        GinSetNullCategory(itup, ginstate, category);
    }

    /*
     * Copy in the posting list, if provided
     */
    if (ipd)
        memcpy(GinGetPosting(itup), ipd, sizeof(ItemPointerData) * nipd);

    return itup;
}

IndexTuple ginPageGetLinkItup ( Buffer  buf  ) 

Definition at line 665 of file ginentrypage.c.

References BufferGetBlockNumber(), BufferGetPage, getRightMostTuple(), and GinFormInteriorTuple().

Referenced by ginContinueSplit(), and ginEntryFillRoot().

{
    IndexTuple  itup,
                nitup;
    Page        page = BufferGetPage(buf);

    itup = getRightMostTuple(page);
    nitup = GinFormInteriorTuple(itup, page, BufferGetBlockNumber(buf));

    return nitup;
}

void ginPrepareEntryScan ( GinBtree  btree,
OffsetNumber  attnum,
Datum  key,
GinNullCategory  category,
GinState ginstate 
)

Definition at line 707 of file ginentrypage.c.

References GinBtreeData::entryAttnum, GinBtreeData::entryCategory, GinBtreeData::entryKey, GinBtreeData::fillRoot, GinBtreeData::findChildPage, GinBtreeData::findChildPtr, GinBtreeData::findItem, GinBtreeData::fullScan, GinBtreeData::getLeftMostPage, GinBtreeData::ginstate, GinState::index, GinBtreeData::index, GinBtreeData::isBuild, GinBtreeData::isData, GinBtreeData::isDelete, GinBtreeData::isEnoughSpace, GinBtreeData::isMoveRight, GinBtreeData::placeToPage, GinBtreeData::searchMode, and GinBtreeData::splitPage.

Referenced by ginContinueSplit(), ginEntryInsert(), and startScanEntry().

{
    memset(btree, 0, sizeof(GinBtreeData));

    btree->index = ginstate->index;
    btree->ginstate = ginstate;

    btree->findChildPage = entryLocateEntry;
    btree->isMoveRight = entryIsMoveRight;
    btree->findItem = entryLocateLeafEntry;
    btree->findChildPtr = entryFindChildPtr;
    btree->getLeftMostPage = entryGetLeftMostPage;
    btree->isEnoughSpace = entryIsEnoughSpace;
    btree->placeToPage = entryPlaceToPage;
    btree->splitPage = entrySplitPage;
    btree->fillRoot = ginEntryFillRoot;

    btree->isData = FALSE;
    btree->searchMode = FALSE;
    btree->fullScan = FALSE;
    btree->isBuild = FALSE;

    btree->entryAttnum = attnum;
    btree->entryKey = key;
    btree->entryCategory = category;
    btree->isDelete = FALSE;
}

void GinShortenTuple ( IndexTuple  itup,
uint32  nipd 
)

Definition at line 145 of file ginentrypage.c.

References Assert, GinGetNPosting, GinGetPostingOffset, GinSetNPosting, INDEX_SIZE_MASK, MAXALIGN, and IndexTupleData::t_info.

Referenced by addItemPointersToLeafTuple().

{
    uint32      newsize;

    Assert(nipd <= GinGetNPosting(itup));

    newsize = GinGetPostingOffset(itup) + sizeof(ItemPointerData) * nipd;
    newsize = MAXALIGN(newsize);

    Assert(newsize <= (itup->t_info & INDEX_SIZE_MASK));

    itup->t_info &= ~INDEX_SIZE_MASK;
    itup->t_info |= newsize;

    GinSetNPosting(itup, nipd);
}