#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"
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 struct ScanStackEntry ScanStackEntry |
| typedef void(* storeRes_func)(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck) |
| 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] |
Definition at line 40 of file spgscan.c.
References SpGistTypeDesc::attbyval, SpGistState::attType, DatumGetPointer, NULL, pfree(), ScanStackEntry::reconstructedValue, and SpGistScanOpaqueData::state.
Referenced by freeScanStack(), and spgWalk().
{
if (!so->state.attType.attbyval &&
DatumGetPointer(stackEntry->reconstructedValue) != NULL)
pfree(DatumGetPointer(stackEntry->reconstructedValue));
pfree(stackEntry);
}
| 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 | ) |
Definition at line 177 of file spgscan.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), CurrentMemoryContext, IndexScanDescData::indexRelation, SpGistScanOpaqueData::indexTupDesc, initSpGistState(), SpGistScanOpaqueData::keyData, IndexScanDescData::opaque, palloc(), palloc0(), PG_GETARG_INT32, PG_GETARG_POINTER, PG_RETURN_POINTER, RelationGetDescr, RelationGetIndexScan(), SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, and IndexScanDescData::xs_itupdesc.
{
Relation rel = (Relation) PG_GETARG_POINTER(0);
int keysz = PG_GETARG_INT32(1);
/* ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2); */
IndexScanDesc scan;
SpGistScanOpaque so;
scan = RelationGetIndexScan(rel, keysz, 0);
so = (SpGistScanOpaque) palloc0(sizeof(SpGistScanOpaqueData));
if (keysz > 0)
so->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * keysz);
else
so->keyData = NULL;
initSpGistState(&so->state, scan->indexRelation);
so->tempCxt = AllocSetContextCreate(CurrentMemoryContext,
"SP-GiST search temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* Set up indexTupDesc and xs_itupdesc in case it's an index-only scan */
so->indexTupDesc = scan->xs_itupdesc = RelationGetDescr(rel);
scan->opaque = so;
PG_RETURN_POINTER(scan);
}
| 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 | ) |
Definition at line 232 of file spgscan.c.
References MemoryContextDelete(), IndexScanDescData::opaque, PG_GETARG_POINTER, PG_RETURN_VOID, and SpGistScanOpaqueData::tempCxt.
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;
MemoryContextDelete(so->tempCxt);
PG_RETURN_VOID();
}
| Datum spggetbitmap | ( | PG_FUNCTION_ARGS | ) |
Definition at line 575 of file spgscan.c.
References IndexScanDescData::indexRelation, SpGistScanOpaqueData::ntids, IndexScanDescData::opaque, PG_GETARG_POINTER, PG_RETURN_INT64, spgWalk(), storeBitmap(), SpGistScanOpaqueData::tbm, and SpGistScanOpaqueData::want_itup.
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;
/* Copy want_itup to *so so we don't need to pass it around separately */
so->want_itup = false;
so->tbm = tbm;
so->ntids = 0;
spgWalk(scan->indexRelation, so, true, storeBitmap);
PG_RETURN_INT64(so->ntids);
}
| 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++;
}
1.7.1