Header And Logo

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

Data Structures | Typedefs | Functions

spgscan.c File Reference

#include "postgres.h"
#include "access/relscan.h"
#include "access/spgist_private.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "utils/datum.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for spgscan.c:

Go to the source code of this file.

Data Structures

struct  ScanStackEntry

Typedefs

typedef void(* storeRes_func )(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
typedef struct ScanStackEntry ScanStackEntry

Functions

static void freeScanStackEntry (SpGistScanOpaque so, ScanStackEntry *stackEntry)
static void freeScanStack (SpGistScanOpaque so)
static void resetSpGistScanOpaque (SpGistScanOpaque so)
static void spgPrepareScanKeys (IndexScanDesc scan)
Datum spgbeginscan (PG_FUNCTION_ARGS)
Datum spgrescan (PG_FUNCTION_ARGS)
Datum spgendscan (PG_FUNCTION_ARGS)
Datum spgmarkpos (PG_FUNCTION_ARGS)
Datum spgrestrpos (PG_FUNCTION_ARGS)
static bool spgLeafTest (Relation index, SpGistScanOpaque so, SpGistLeafTuple leafTuple, bool isnull, int level, Datum reconstructedValue, Datum *leafValue, bool *recheck)
static void spgWalk (Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes)
static void storeBitmap (SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Datum spggetbitmap (PG_FUNCTION_ARGS)
static void storeGettuple (SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Datum spggettuple (PG_FUNCTION_ARGS)
Datum spgcanreturn (PG_FUNCTION_ARGS)

Typedef Documentation

typedef void(* storeRes_func)(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)

Definition at line 27 of file spgscan.c.


Function Documentation

static void freeScanStack ( SpGistScanOpaque  so  )  [static]

Definition at line 50 of file spgscan.c.

References freeScanStackEntry(), lfirst, list_free(), and SpGistScanOpaqueData::scanStack.

Referenced by resetSpGistScanOpaque().

{
    ListCell   *lc;

    foreach(lc, so->scanStack)
    {
        freeScanStackEntry(so, (ScanStackEntry *) lfirst(lc));
    }
    list_free(so->scanStack);
    so->scanStack = NIL;
}

static void freeScanStackEntry ( SpGistScanOpaque  so,
ScanStackEntry stackEntry 
) [static]
static void resetSpGistScanOpaque ( SpGistScanOpaque  so  )  [static]

Definition at line 67 of file spgscan.c.

References FirstOffsetNumber, freeScanStack(), i, SpGistScanOpaqueData::indexTups, SpGistScanOpaqueData::iPtr, ItemPointerSet, lappend(), SpGistScanOpaqueData::nPtrs, palloc0(), pfree(), ScanStackEntry::ptr, SpGistScanOpaqueData::scanStack, SpGistScanOpaqueData::searchNonNulls, SpGistScanOpaqueData::searchNulls, SPGIST_NULL_BLKNO, SPGIST_ROOT_BLKNO, and SpGistScanOpaqueData::want_itup.

Referenced by spgrescan().

{
    ScanStackEntry *startEntry;

    freeScanStack(so);

    if (so->searchNulls)
    {
        /* Stack a work item to scan the null index entries */
        startEntry = (ScanStackEntry *) palloc0(sizeof(ScanStackEntry));
        ItemPointerSet(&startEntry->ptr, SPGIST_NULL_BLKNO, FirstOffsetNumber);
        so->scanStack = lappend(so->scanStack, startEntry);
    }

    if (so->searchNonNulls)
    {
        /* Stack a work item to scan the non-null index entries */
        startEntry = (ScanStackEntry *) palloc0(sizeof(ScanStackEntry));
        ItemPointerSet(&startEntry->ptr, SPGIST_ROOT_BLKNO, FirstOffsetNumber);
        so->scanStack = lappend(so->scanStack, startEntry);
    }

    if (so->want_itup)
    {
        /* Must pfree IndexTuples to avoid memory leak */
        int         i;

        for (i = 0; i < so->nPtrs; i++)
            pfree(so->indexTups[i]);
    }
    so->iPtr = so->nPtrs = 0;
}

Datum spgbeginscan ( PG_FUNCTION_ARGS   ) 
Datum spgcanreturn ( PG_FUNCTION_ARGS   ) 

Definition at line 658 of file spgscan.c.

References spgConfigOut::canReturnData, SpGistCache::config, PG_GETARG_POINTER, PG_RETURN_BOOL, and spgGetCache().

{
    Relation    index = (Relation) PG_GETARG_POINTER(0);
    SpGistCache *cache;

    /* We can do it if the opclass config function says so */
    cache = spgGetCache(index);

    PG_RETURN_BOOL(cache->config.canReturnData);
}

Datum spgendscan ( PG_FUNCTION_ARGS   ) 
Datum spggetbitmap ( PG_FUNCTION_ARGS   ) 
Datum spggettuple ( PG_FUNCTION_ARGS   ) 

Definition at line 614 of file spgscan.c.

References elog, ERROR, ForwardScanDirection, SpGistScanOpaqueData::heapPtrs, i, IndexScanDescData::indexRelation, SpGistScanOpaqueData::indexTups, SpGistScanOpaqueData::iPtr, SpGistScanOpaqueData::nPtrs, IndexScanDescData::opaque, pfree(), PG_GETARG_INT32, PG_GETARG_POINTER, PG_RETURN_BOOL, SpGistScanOpaqueData::recheck, spgWalk(), storeGettuple(), HeapTupleData::t_self, SpGistScanOpaqueData::want_itup, IndexScanDescData::xs_ctup, IndexScanDescData::xs_itup, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_want_itup.

{
    IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
    ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
    SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;

    if (dir != ForwardScanDirection)
        elog(ERROR, "SP-GiST only supports forward scan direction");

    /* Copy want_itup to *so so we don't need to pass it around separately */
    so->want_itup = scan->xs_want_itup;

    for (;;)
    {
        if (so->iPtr < so->nPtrs)
        {
            /* continuing to return tuples from a leaf page */
            scan->xs_ctup.t_self = so->heapPtrs[so->iPtr];
            scan->xs_recheck = so->recheck[so->iPtr];
            scan->xs_itup = so->indexTups[so->iPtr];
            so->iPtr++;
            PG_RETURN_BOOL(true);
        }

        if (so->want_itup)
        {
            /* Must pfree IndexTuples to avoid memory leak */
            int         i;

            for (i = 0; i < so->nPtrs; i++)
                pfree(so->indexTups[i]);
        }
        so->iPtr = so->nPtrs = 0;

        spgWalk(scan->indexRelation, so, false, storeGettuple);

        if (so->nPtrs == 0)
            break;              /* must have completed scan */
    }

    PG_RETURN_BOOL(false);
}

static bool spgLeafTest ( Relation  index,
SpGistScanOpaque  so,
SpGistLeafTuple  leafTuple,
bool  isnull,
int  level,
Datum  reconstructedValue,
Datum leafValue,
bool recheck 
) [static]

Definition at line 263 of file spgscan.c.

References Assert, DatumGetBool, FunctionCall2Coll(), index_getprocinfo(), SpGistScanOpaqueData::keyData, spgLeafConsistentIn::leafDatum, spgLeafConsistentOut::leafValue, spgLeafConsistentIn::level, MemoryContextSwitchTo(), spgLeafConsistentIn::nkeys, SpGistScanOpaqueData::numberOfKeys, PointerGetDatum, RelationData::rd_indcollation, spgLeafConsistentOut::recheck, spgLeafConsistentIn::reconstructedValue, spgLeafConsistentIn::returnData, spgLeafConsistentIn::scankeys, SpGistScanOpaqueData::searchNulls, SGLTDATUM, SPGIST_LEAF_CONSISTENT_PROC, SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, and SpGistScanOpaqueData::want_itup.

Referenced by spgWalk().

{
    bool        result;
    Datum       leafDatum;
    spgLeafConsistentIn in;
    spgLeafConsistentOut out;
    FmgrInfo   *procinfo;
    MemoryContext oldCtx;

    if (isnull)
    {
        /* Should not have arrived on a nulls page unless nulls are wanted */
        Assert(so->searchNulls);
        *leafValue = (Datum) 0;
        *recheck = false;
        return true;
    }

    leafDatum = SGLTDATUM(leafTuple, &so->state);

    /* use temp context for calling leaf_consistent */
    oldCtx = MemoryContextSwitchTo(so->tempCxt);

    in.scankeys = so->keyData;
    in.nkeys = so->numberOfKeys;
    in.reconstructedValue = reconstructedValue;
    in.level = level;
    in.returnData = so->want_itup;
    in.leafDatum = leafDatum;

    out.leafValue = (Datum) 0;
    out.recheck = false;

    procinfo = index_getprocinfo(index, 1, SPGIST_LEAF_CONSISTENT_PROC);
    result = DatumGetBool(FunctionCall2Coll(procinfo,
                                            index->rd_indcollation[0],
                                            PointerGetDatum(&in),
                                            PointerGetDatum(&out)));

    *leafValue = out.leafValue;
    *recheck = out.recheck;

    MemoryContextSwitchTo(oldCtx);

    return result;
}

Datum spgmarkpos ( PG_FUNCTION_ARGS   ) 

Definition at line 243 of file spgscan.c.

References elog, ERROR, and PG_RETURN_VOID.

{
    elog(ERROR, "SPGiST does not support mark/restore");
    PG_RETURN_VOID();
}

static void spgPrepareScanKeys ( IndexScanDesc  scan  )  [static]

Definition at line 112 of file spgscan.c.

References i, SpGistScanOpaqueData::keyData, IndexScanDescData::keyData, SpGistScanOpaqueData::numberOfKeys, IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, SpGistScanOpaqueData::searchNonNulls, SpGistScanOpaqueData::searchNulls, ScanKeyData::sk_flags, SK_ISNULL, SK_SEARCHNOTNULL, and SK_SEARCHNULL.

Referenced by spgrescan().

{
    SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;
    bool        qual_ok;
    bool        haveIsNull;
    bool        haveNotNull;
    int         nkeys;
    int         i;

    if (scan->numberOfKeys <= 0)
    {
        /* If no quals, whole-index scan is required */
        so->searchNulls = true;
        so->searchNonNulls = true;
        so->numberOfKeys = 0;
        return;
    }

    /* Examine the given quals */
    qual_ok = true;
    haveIsNull = haveNotNull = false;
    nkeys = 0;
    for (i = 0; i < scan->numberOfKeys; i++)
    {
        ScanKey     skey = &scan->keyData[i];

        if (skey->sk_flags & SK_SEARCHNULL)
            haveIsNull = true;
        else if (skey->sk_flags & SK_SEARCHNOTNULL)
            haveNotNull = true;
        else if (skey->sk_flags & SK_ISNULL)
        {
            /* ordinary qual with null argument - unsatisfiable */
            qual_ok = false;
            break;
        }
        else
        {
            /* ordinary qual, propagate into so->keyData */
            so->keyData[nkeys++] = *skey;
            /* this effectively creates a not-null requirement */
            haveNotNull = true;
        }
    }

    /* IS NULL in combination with something else is unsatisfiable */
    if (haveIsNull && haveNotNull)
        qual_ok = false;

    /* Emit results */
    if (qual_ok)
    {
        so->searchNulls = haveIsNull;
        so->searchNonNulls = haveNotNull;
        so->numberOfKeys = nkeys;
    }
    else
    {
        so->searchNulls = false;
        so->searchNonNulls = false;
        so->numberOfKeys = 0;
    }
}

Datum spgrescan ( PG_FUNCTION_ARGS   ) 

Definition at line 209 of file spgscan.c.

References IndexScanDescData::keyData, memmove, IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, PG_GETARG_POINTER, PG_RETURN_VOID, resetSpGistScanOpaque(), and spgPrepareScanKeys().

{
    IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
    SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;
    ScanKey     scankey = (ScanKey) PG_GETARG_POINTER(1);

    /* copy scankeys into local storage */
    if (scankey && scan->numberOfKeys > 0)
    {
        memmove(scan->keyData, scankey,
                scan->numberOfKeys * sizeof(ScanKeyData));
    }

    /* preprocess scankeys, set up the representation in *so */
    spgPrepareScanKeys(scan);

    /* set up starting stack entries */
    resetSpGistScanOpaque(so);

    PG_RETURN_VOID();
}

Datum spgrestrpos ( PG_FUNCTION_ARGS   ) 

Definition at line 250 of file spgscan.c.

References elog, ERROR, and PG_RETURN_VOID.

{
    elog(ERROR, "SPGiST does not support mark/restore");
    PG_RETURN_VOID();
}

static void spgWalk ( Relation  index,
SpGistScanOpaque  so,
bool  scanWholeIndex,
storeRes_func  storeRes 
) [static]

Definition at line 321 of file spgscan.c.

References SpGistInnerTupleData::allTheSame, spgInnerConsistentIn::allTheSame, Assert, SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, SpGistState::attType, BUFFER_LOCK_SHARE, BufferGetBlockNumber(), BufferGetPage, CHECK_FOR_INTERRUPTS, datumCopy(), elog, ERROR, FirstOffsetNumber, freeScanStackEntry(), FunctionCall2Coll(), spgInnerConsistentIn::hasPrefix, SpGistLeafTupleData::heapPtr, i, index_getprocinfo(), InvalidBuffer, InvalidOffsetNumber, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, SpGistScanOpaqueData::keyData, lcons(), spgInnerConsistentIn::level, ScanStackEntry::level, spgInnerConsistentOut::levelAdds, linitial, list_delete_first(), LockBuffer(), MemoryContextReset(), MemoryContextSwitchTo(), SpGistLeafTupleData::nextOffset, NIL, spgInnerConsistentIn::nkeys, spgInnerConsistentOut::nNodes, SpGistInnerTupleData::nNodes, spgInnerConsistentIn::nNodes, spgInnerConsistentIn::nodeLabels, spgInnerConsistentOut::nodeNumbers, SpGistScanOpaqueData::numberOfKeys, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, palloc(), PointerGetDatum, spgInnerConsistentIn::prefixDatum, SpGistInnerTupleData::prefixSize, ScanStackEntry::ptr, RelationData::rd_indcollation, ReadBuffer(), spgInnerConsistentIn::reconstructedValue, ScanStackEntry::reconstructedValue, spgInnerConsistentOut::reconstructedValues, spgInnerConsistentIn::returnData, spgInnerConsistentIn::scankeys, SpGistScanOpaqueData::scanStack, SGITDATUM, SGITITERATE, spgExtractNodeLabels(), SPGIST_DEAD, SPGIST_INNER_CONSISTENT_PROC, SPGIST_LIVE, SPGIST_METAPAGE_BLKNO, SPGIST_REDIRECT, SpGistBlockIsRoot, SpGistPageIsLeaf, SpGistPageStoresNulls, spgLeafTest(), SpGistScanOpaqueData::state, IndexTupleData::t_tid, SpGistScanOpaqueData::tempCxt, SpGistInnerTupleData::tupstate, SpGistLeafTupleData::tupstate, UnlockReleaseBuffer(), and SpGistScanOpaqueData::want_itup.

Referenced by spggetbitmap(), and spggettuple().

{
    Buffer      buffer = InvalidBuffer;
    bool        reportedSome = false;

    while (scanWholeIndex || !reportedSome)
    {
        ScanStackEntry *stackEntry;
        BlockNumber blkno;
        OffsetNumber offset;
        Page        page;
        bool        isnull;

        /* Pull next to-do item from the list */
        if (so->scanStack == NIL)
            break;              /* there are no more pages to scan */

        stackEntry = (ScanStackEntry *) linitial(so->scanStack);
        so->scanStack = list_delete_first(so->scanStack);

redirect:
        /* Check for interrupts, just in case of infinite loop */
        CHECK_FOR_INTERRUPTS();

        blkno = ItemPointerGetBlockNumber(&stackEntry->ptr);
        offset = ItemPointerGetOffsetNumber(&stackEntry->ptr);

        if (buffer == InvalidBuffer)
        {
            buffer = ReadBuffer(index, blkno);
            LockBuffer(buffer, BUFFER_LOCK_SHARE);
        }
        else if (blkno != BufferGetBlockNumber(buffer))
        {
            UnlockReleaseBuffer(buffer);
            buffer = ReadBuffer(index, blkno);
            LockBuffer(buffer, BUFFER_LOCK_SHARE);
        }
        /* else new pointer points to the same page, no work needed */

        page = BufferGetPage(buffer);

        isnull = SpGistPageStoresNulls(page) ? true : false;

        if (SpGistPageIsLeaf(page))
        {
            SpGistLeafTuple leafTuple;
            OffsetNumber max = PageGetMaxOffsetNumber(page);
            Datum       leafValue = (Datum) 0;
            bool        recheck = false;

            if (SpGistBlockIsRoot(blkno))
            {
                /* When root is a leaf, examine all its tuples */
                for (offset = FirstOffsetNumber; offset <= max; offset++)
                {
                    leafTuple = (SpGistLeafTuple)
                        PageGetItem(page, PageGetItemId(page, offset));
                    if (leafTuple->tupstate != SPGIST_LIVE)
                    {
                        /* all tuples on root should be live */
                        elog(ERROR, "unexpected SPGiST tuple state: %d",
                             leafTuple->tupstate);
                    }

                    Assert(ItemPointerIsValid(&leafTuple->heapPtr));
                    if (spgLeafTest(index, so,
                                    leafTuple, isnull,
                                    stackEntry->level,
                                    stackEntry->reconstructedValue,
                                    &leafValue,
                                    &recheck))
                    {
                        storeRes(so, &leafTuple->heapPtr,
                                 leafValue, isnull, recheck);
                        reportedSome = true;
                    }
                }
            }
            else
            {
                /* Normal case: just examine the chain we arrived at */
                while (offset != InvalidOffsetNumber)
                {
                    Assert(offset >= FirstOffsetNumber && offset <= max);
                    leafTuple = (SpGistLeafTuple)
                        PageGetItem(page, PageGetItemId(page, offset));
                    if (leafTuple->tupstate != SPGIST_LIVE)
                    {
                        if (leafTuple->tupstate == SPGIST_REDIRECT)
                        {
                            /* redirection tuple should be first in chain */
                            Assert(offset == ItemPointerGetOffsetNumber(&stackEntry->ptr));
                            /* transfer attention to redirect point */
                            stackEntry->ptr = ((SpGistDeadTuple) leafTuple)->pointer;
                            Assert(ItemPointerGetBlockNumber(&stackEntry->ptr) != SPGIST_METAPAGE_BLKNO);
                            goto redirect;
                        }
                        if (leafTuple->tupstate == SPGIST_DEAD)
                        {
                            /* dead tuple should be first in chain */
                            Assert(offset == ItemPointerGetOffsetNumber(&stackEntry->ptr));
                            /* No live entries on this page */
                            Assert(leafTuple->nextOffset == InvalidOffsetNumber);
                            break;
                        }
                        /* We should not arrive at a placeholder */
                        elog(ERROR, "unexpected SPGiST tuple state: %d",
                             leafTuple->tupstate);
                    }

                    Assert(ItemPointerIsValid(&leafTuple->heapPtr));
                    if (spgLeafTest(index, so,
                                    leafTuple, isnull,
                                    stackEntry->level,
                                    stackEntry->reconstructedValue,
                                    &leafValue,
                                    &recheck))
                    {
                        storeRes(so, &leafTuple->heapPtr,
                                 leafValue, isnull, recheck);
                        reportedSome = true;
                    }

                    offset = leafTuple->nextOffset;
                }
            }
        }
        else    /* page is inner */
        {
            SpGistInnerTuple innerTuple;
            spgInnerConsistentIn in;
            spgInnerConsistentOut out;
            FmgrInfo   *procinfo;
            SpGistNodeTuple *nodes;
            SpGistNodeTuple node;
            int         i;
            MemoryContext oldCtx;

            innerTuple = (SpGistInnerTuple) PageGetItem(page,
                                                PageGetItemId(page, offset));

            if (innerTuple->tupstate != SPGIST_LIVE)
            {
                if (innerTuple->tupstate == SPGIST_REDIRECT)
                {
                    /* transfer attention to redirect point */
                    stackEntry->ptr = ((SpGistDeadTuple) innerTuple)->pointer;
                    Assert(ItemPointerGetBlockNumber(&stackEntry->ptr) != SPGIST_METAPAGE_BLKNO);
                    goto redirect;
                }
                elog(ERROR, "unexpected SPGiST tuple state: %d",
                     innerTuple->tupstate);
            }

            /* use temp context for calling inner_consistent */
            oldCtx = MemoryContextSwitchTo(so->tempCxt);

            in.scankeys = so->keyData;
            in.nkeys = so->numberOfKeys;
            in.reconstructedValue = stackEntry->reconstructedValue;
            in.level = stackEntry->level;
            in.returnData = so->want_itup;
            in.allTheSame = innerTuple->allTheSame;
            in.hasPrefix = (innerTuple->prefixSize > 0);
            in.prefixDatum = SGITDATUM(innerTuple, &so->state);
            in.nNodes = innerTuple->nNodes;
            in.nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);

            /* collect node pointers */
            nodes = (SpGistNodeTuple *) palloc(sizeof(SpGistNodeTuple) * in.nNodes);
            SGITITERATE(innerTuple, i, node)
            {
                nodes[i] = node;
            }

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

            if (!isnull)
            {
                /* use user-defined inner consistent method */
                procinfo = index_getprocinfo(index, 1, SPGIST_INNER_CONSISTENT_PROC);
                FunctionCall2Coll(procinfo,
                                  index->rd_indcollation[0],
                                  PointerGetDatum(&in),
                                  PointerGetDatum(&out));
            }
            else
            {
                /* force all children to be visited */
                out.nNodes = in.nNodes;
                out.nodeNumbers = (int *) palloc(sizeof(int) * in.nNodes);
                for (i = 0; i < in.nNodes; i++)
                    out.nodeNumbers[i] = i;
            }

            MemoryContextSwitchTo(oldCtx);

            /* If allTheSame, they should all or none of 'em match */
            if (innerTuple->allTheSame)
                if (out.nNodes != 0 && out.nNodes != in.nNodes)
                    elog(ERROR, "inconsistent inner_consistent results for allTheSame inner tuple");

            for (i = 0; i < out.nNodes; i++)
            {
                int         nodeN = out.nodeNumbers[i];

                Assert(nodeN >= 0 && nodeN < in.nNodes);
                if (ItemPointerIsValid(&nodes[nodeN]->t_tid))
                {
                    ScanStackEntry *newEntry;

                    /* Create new work item for this node */
                    newEntry = palloc(sizeof(ScanStackEntry));
                    newEntry->ptr = nodes[nodeN]->t_tid;
                    if (out.levelAdds)
                        newEntry->level = stackEntry->level + out.levelAdds[i];
                    else
                        newEntry->level = stackEntry->level;
                    /* Must copy value out of temp context */
                    if (out.reconstructedValues)
                        newEntry->reconstructedValue =
                            datumCopy(out.reconstructedValues[i],
                                      so->state.attType.attbyval,
                                      so->state.attType.attlen);
                    else
                        newEntry->reconstructedValue = (Datum) 0;

                    so->scanStack = lcons(newEntry, so->scanStack);
                }
            }
        }

        /* done with this scan stack entry */
        freeScanStackEntry(so, stackEntry);
        /* clear temp context before proceeding to the next one */
        MemoryContextReset(so->tempCxt);
    }

    if (buffer != InvalidBuffer)
        UnlockReleaseBuffer(buffer);
}

static void storeBitmap ( SpGistScanOpaque  so,
ItemPointer  heapPtr,
Datum  leafValue,
bool  isnull,
bool  recheck 
) [static]

Definition at line 567 of file spgscan.c.

References SpGistScanOpaqueData::ntids, SpGistScanOpaqueData::tbm, and tbm_add_tuples().

Referenced by spggetbitmap().

{
    tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
    so->ntids++;
}

static void storeGettuple ( SpGistScanOpaque  so,
ItemPointer  heapPtr,
Datum  leafValue,
bool  isnull,
bool  recheck 
) [static]

Definition at line 594 of file spgscan.c.

References Assert, SpGistScanOpaqueData::heapPtrs, index_form_tuple(), SpGistScanOpaqueData::indexTupDesc, SpGistScanOpaqueData::indexTups, MaxIndexTuplesPerPage, SpGistScanOpaqueData::nPtrs, SpGistScanOpaqueData::recheck, and SpGistScanOpaqueData::want_itup.

Referenced by spggettuple().

{
    Assert(so->nPtrs < MaxIndexTuplesPerPage);
    so->heapPtrs[so->nPtrs] = *heapPtr;
    so->recheck[so->nPtrs] = recheck;
    if (so->want_itup)
    {
        /*
         * Reconstruct desired IndexTuple.  We have to copy the datum out of
         * the temp context anyway, so we may as well create the tuple here.
         */
        so->indexTups[so->nPtrs] = index_form_tuple(so->indexTupDesc,
                                                    &leafValue,
                                                    &isnull);
    }
    so->nPtrs++;
}