PostgreSQL Source Code  git master
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)
 
IndexScanDesc spgbeginscan (Relation rel, int keysz, int orderbysz)
 
void spgrescan (IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
 
void spgendscan (IndexScanDesc scan)
 
static bool spgLeafTest (Relation index, SpGistScanOpaque so, SpGistLeafTuple leafTuple, bool isnull, int level, Datum reconstructedValue, void *traversalValue, Datum *leafValue, bool *recheck)
 
static void spgWalk (Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
 
static void storeBitmap (SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
 
int64 spggetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
static void storeGettuple (SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
 
bool spggettuple (IndexScanDesc scan, ScanDirection dir)
 
bool spgcanreturn (Relation index, int attno)
 

Typedef Documentation

◆ ScanStackEntry

◆ storeRes_func

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

Definition at line 27 of file spgscan.c.

Function Documentation

◆ freeScanStack()

static void freeScanStack ( SpGistScanOpaque  so)
static

Definition at line 54 of file spgscan.c.

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

Referenced by resetSpGistScanOpaque().

55 {
56  ListCell *lc;
57 
58  foreach(lc, so->scanStack)
59  {
61  }
62  list_free(so->scanStack);
63  so->scanStack = NIL;
64 }
#define NIL
Definition: pg_list.h:69
static void freeScanStackEntry(SpGistScanOpaque so, ScanStackEntry *stackEntry)
Definition: spgscan.c:41
#define lfirst(lc)
Definition: pg_list.h:106
void list_free(List *list)
Definition: list.c:1133

◆ freeScanStackEntry()

static void freeScanStackEntry ( SpGistScanOpaque  so,
ScanStackEntry stackEntry 
)
static

Definition at line 41 of file spgscan.c.

References SpGistTypeDesc::attbyval, SpGistState::attLeafType, DatumGetPointer, pfree(), ScanStackEntry::reconstructedValue, SpGistScanOpaqueData::state, and ScanStackEntry::traversalValue.

Referenced by freeScanStack(), and spgWalk().

42 {
43  if (!so->state.attLeafType.attbyval &&
44  DatumGetPointer(stackEntry->reconstructedValue) != NULL)
46  if (stackEntry->traversalValue)
47  pfree(stackEntry->traversalValue);
48 
49  pfree(stackEntry);
50 }
void * traversalValue
Definition: spgscan.c:33
SpGistTypeDesc attLeafType
void pfree(void *pointer)
Definition: mcxt.c:1031
Datum reconstructedValue
Definition: spgscan.c:32
#define DatumGetPointer(X)
Definition: postgres.h:534

◆ resetSpGistScanOpaque()

static void resetSpGistScanOpaque ( SpGistScanOpaque  so)
static

Definition at line 71 of file spgscan.c.

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

Referenced by spgrescan().

72 {
73  ScanStackEntry *startEntry;
74 
75  freeScanStack(so);
76 
77  if (so->searchNulls)
78  {
79  /* Stack a work item to scan the null index entries */
80  startEntry = (ScanStackEntry *) palloc0(sizeof(ScanStackEntry));
82  so->scanStack = lappend(so->scanStack, startEntry);
83  }
84 
85  if (so->searchNonNulls)
86  {
87  /* Stack a work item to scan the non-null index entries */
88  startEntry = (ScanStackEntry *) palloc0(sizeof(ScanStackEntry));
90  so->scanStack = lappend(so->scanStack, startEntry);
91  }
92 
93  if (so->want_itup)
94  {
95  /* Must pfree reconstructed tuples to avoid memory leak */
96  int i;
97 
98  for (i = 0; i < so->nPtrs; i++)
99  pfree(so->reconTups[i]);
100  }
101  so->iPtr = so->nPtrs = 0;
102 }
#define SPGIST_ROOT_BLKNO
HeapTuple reconTups[MaxIndexTuplesPerPage]
static void freeScanStack(SpGistScanOpaque so)
Definition: spgscan.c:54
void pfree(void *pointer)
Definition: mcxt.c:1031
ItemPointerData ptr
Definition: spgscan.c:35
#define SPGIST_NULL_BLKNO
#define FirstOffsetNumber
Definition: off.h:27
List * lappend(List *list, void *datum)
Definition: list.c:128
void * palloc0(Size size)
Definition: mcxt.c:955
int i
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127

◆ spgbeginscan()

IndexScanDesc spgbeginscan ( Relation  rel,
int  keysz,
int  orderbysz 
)

Definition at line 181 of file spgscan.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CurrentMemoryContext, IndexScanDescData::indexRelation, SpGistScanOpaqueData::indexTupDesc, initSpGistState(), SpGistScanOpaqueData::keyData, IndexScanDescData::opaque, palloc(), palloc0(), RelationGetDescr, RelationGetIndexScan(), SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, SpGistScanOpaqueData::traversalCxt, and IndexScanDescData::xs_hitupdesc.

Referenced by spghandler().

182 {
183  IndexScanDesc scan;
184  SpGistScanOpaque so;
185 
186  scan = RelationGetIndexScan(rel, keysz, 0);
187 
189  if (keysz > 0)
190  so->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * keysz);
191  else
192  so->keyData = NULL;
193  initSpGistState(&so->state, scan->indexRelation);
195  "SP-GiST search temporary context",
198  "SP-GiST traversal-value context",
200 
201  /* Set up indexTupDesc and xs_hitupdesc in case it's an index-only scan */
202  so->indexTupDesc = scan->xs_hitupdesc = RelationGetDescr(rel);
203 
204  scan->opaque = so;
205 
206  return scan;
207 }
#define RelationGetDescr(relation)
Definition: rel.h:433
MemoryContext tempCxt
TupleDesc xs_hitupdesc
Definition: relscan.h:118
Relation indexRelation
Definition: relscan.h:91
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
ScanKeyData * ScanKey
Definition: skey.h:75
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:175
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
void * palloc0(Size size)
Definition: mcxt.c:955
SpGistScanOpaqueData * SpGistScanOpaque
MemoryContext traversalCxt
void * palloc(Size size)
Definition: mcxt.c:924
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:78

◆ spgcanreturn()

bool spgcanreturn ( Relation  index,
int  attno 
)

Definition at line 655 of file spgscan.c.

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

Referenced by spghandler().

656 {
657  SpGistCache *cache;
658 
659  /* We can do it if the opclass config function says so */
660  cache = spgGetCache(index);
661 
662  return cache->config.canReturnData;
663 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:93
bool canReturnData
Definition: spgist.h:50
spgConfigOut config

◆ spgendscan()

void spgendscan ( IndexScanDesc  scan)

Definition at line 233 of file spgscan.c.

References MemoryContextDelete(), IndexScanDescData::opaque, SpGistScanOpaqueData::tempCxt, and SpGistScanOpaqueData::traversalCxt.

Referenced by spghandler().

234 {
236 
239 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
MemoryContext tempCxt
SpGistScanOpaqueData * SpGistScanOpaque
MemoryContext traversalCxt

◆ spggetbitmap()

int64 spggetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 575 of file spgscan.c.

References IndexScanDescData::indexRelation, SpGistScanOpaqueData::ntids, IndexScanDescData::opaque, spgWalk(), storeBitmap(), SpGistScanOpaqueData::tbm, SpGistScanOpaqueData::want_itup, and IndexScanDescData::xs_snapshot.

Referenced by spghandler().

576 {
578 
579  /* Copy want_itup to *so so we don't need to pass it around separately */
580  so->want_itup = false;
581 
582  so->tbm = tbm;
583  so->ntids = 0;
584 
585  spgWalk(scan->indexRelation, so, true, storeBitmap, scan->xs_snapshot);
586 
587  return so->ntids;
588 }
Snapshot xs_snapshot
Definition: relscan.h:92
Relation indexRelation
Definition: relscan.h:91
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:308
static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Definition: spgscan.c:567

◆ spggettuple()

bool spggettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 612 of file spgscan.c.

References elog, ERROR, ForwardScanDirection, SpGistScanOpaqueData::heapPtrs, i, IndexScanDescData::indexRelation, SpGistScanOpaqueData::iPtr, SpGistScanOpaqueData::nPtrs, IndexScanDescData::opaque, pfree(), SpGistScanOpaqueData::recheck, SpGistScanOpaqueData::reconTups, spgWalk(), storeGettuple(), HeapTupleData::t_self, SpGistScanOpaqueData::want_itup, IndexScanDescData::xs_ctup, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, IndexScanDescData::xs_snapshot, and IndexScanDescData::xs_want_itup.

Referenced by spghandler().

613 {
615 
616  if (dir != ForwardScanDirection)
617  elog(ERROR, "SP-GiST only supports forward scan direction");
618 
619  /* Copy want_itup to *so so we don't need to pass it around separately */
620  so->want_itup = scan->xs_want_itup;
621 
622  for (;;)
623  {
624  if (so->iPtr < so->nPtrs)
625  {
626  /* continuing to return tuples from a leaf page */
627  scan->xs_ctup.t_self = so->heapPtrs[so->iPtr];
628  scan->xs_recheck = so->recheck[so->iPtr];
629  scan->xs_hitup = so->reconTups[so->iPtr];
630  so->iPtr++;
631  return true;
632  }
633 
634  if (so->want_itup)
635  {
636  /* Must pfree reconstructed tuples to avoid memory leak */
637  int i;
638 
639  for (i = 0; i < so->nPtrs; i++)
640  pfree(so->reconTups[i]);
641  }
642  so->iPtr = so->nPtrs = 0;
643 
644  spgWalk(scan->indexRelation, so, false, storeGettuple,
645  scan->xs_snapshot);
646 
647  if (so->nPtrs == 0)
648  break; /* must have completed scan */
649  }
650 
651  return false;
652 }
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
Snapshot xs_snapshot
Definition: relscan.h:92
HeapTuple reconTups[MaxIndexTuplesPerPage]
Relation indexRelation
Definition: relscan.h:91
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
bool recheck[MaxIndexTuplesPerPage]
static void storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Definition: spgscan.c:592
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:308
bool xs_want_itup
Definition: relscan.h:97
HeapTupleData xs_ctup
Definition: relscan.h:121
HeapTuple xs_hitup
Definition: relscan.h:117
int i
#define elog
Definition: elog.h:219

◆ spgLeafTest()

static bool spgLeafTest ( Relation  index,
SpGistScanOpaque  so,
SpGistLeafTuple  leafTuple,
bool  isnull,
int  level,
Datum  reconstructedValue,
void *  traversalValue,
Datum leafValue,
bool recheck 
)
static

Definition at line 248 of file spgscan.c.

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

Referenced by spgWalk().

253 {
254  bool result;
255  Datum leafDatum;
258  FmgrInfo *procinfo;
259  MemoryContext oldCtx;
260 
261  if (isnull)
262  {
263  /* Should not have arrived on a nulls page unless nulls are wanted */
264  Assert(so->searchNulls);
265  *leafValue = (Datum) 0;
266  *recheck = false;
267  return true;
268  }
269 
270  leafDatum = SGLTDATUM(leafTuple, &so->state);
271 
272  /* use temp context for calling leaf_consistent */
273  oldCtx = MemoryContextSwitchTo(so->tempCxt);
274 
275  in.scankeys = so->keyData;
276  in.nkeys = so->numberOfKeys;
277  in.reconstructedValue = reconstructedValue;
278  in.traversalValue = traversalValue;
279  in.level = level;
280  in.returnData = so->want_itup;
281  in.leafDatum = leafDatum;
282 
283  out.leafValue = (Datum) 0;
284  out.recheck = false;
285 
286  procinfo = index_getprocinfo(index, 1, SPGIST_LEAF_CONSISTENT_PROC);
287  result = DatumGetBool(FunctionCall2Coll(procinfo,
288  index->rd_indcollation[0],
289  PointerGetDatum(&in),
290  PointerGetDatum(&out)));
291 
292  *leafValue = out.leafValue;
293  *recheck = out.recheck;
294 
295  MemoryContextSwitchTo(oldCtx);
296 
297  return result;
298 }
Datum reconstructedValue
Definition: spgist.h:172
Definition: fmgr.h:56
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:32
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
#define PointerGetDatum(X)
Definition: postgres.h:541
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext tempCxt
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1133
Oid * rd_indcollation
Definition: rel.h:165
ScanKey scankeys
Definition: spgist.h:169
#define DatumGetBool(X)
Definition: postgres.h:378
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:699
#define SGLTDATUM(x, s)
void * traversalValue
Definition: spgist.h:173

◆ spgPrepareScanKeys()

static void spgPrepareScanKeys ( IndexScanDesc  scan)
static

Definition at line 116 of file spgscan.c.

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

Referenced by spgrescan().

117 {
119  bool qual_ok;
120  bool haveIsNull;
121  bool haveNotNull;
122  int nkeys;
123  int i;
124 
125  if (scan->numberOfKeys <= 0)
126  {
127  /* If no quals, whole-index scan is required */
128  so->searchNulls = true;
129  so->searchNonNulls = true;
130  so->numberOfKeys = 0;
131  return;
132  }
133 
134  /* Examine the given quals */
135  qual_ok = true;
136  haveIsNull = haveNotNull = false;
137  nkeys = 0;
138  for (i = 0; i < scan->numberOfKeys; i++)
139  {
140  ScanKey skey = &scan->keyData[i];
141 
142  if (skey->sk_flags & SK_SEARCHNULL)
143  haveIsNull = true;
144  else if (skey->sk_flags & SK_SEARCHNOTNULL)
145  haveNotNull = true;
146  else if (skey->sk_flags & SK_ISNULL)
147  {
148  /* ordinary qual with null argument - unsatisfiable */
149  qual_ok = false;
150  break;
151  }
152  else
153  {
154  /* ordinary qual, propagate into so->keyData */
155  so->keyData[nkeys++] = *skey;
156  /* this effectively creates a not-null requirement */
157  haveNotNull = true;
158  }
159  }
160 
161  /* IS NULL in combination with something else is unsatisfiable */
162  if (haveIsNull && haveNotNull)
163  qual_ok = false;
164 
165  /* Emit results */
166  if (qual_ok)
167  {
168  so->searchNulls = haveIsNull;
169  so->searchNonNulls = haveNotNull;
170  so->numberOfKeys = nkeys;
171  }
172  else
173  {
174  so->searchNulls = false;
175  so->searchNonNulls = false;
176  so->numberOfKeys = 0;
177  }
178 }
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_ISNULL
Definition: skey.h:115
SpGistScanOpaqueData * SpGistScanOpaque
int sk_flags
Definition: skey.h:66
ScanKey keyData
Definition: relscan.h:95
int i
#define SK_SEARCHNULL
Definition: skey.h:121

◆ spgrescan()

void spgrescan ( IndexScanDesc  scan,
ScanKey  scankey,
int  nscankeys,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 210 of file spgscan.c.

References IndexScanDescData::keyData, memmove, MemoryContextReset(), IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, resetSpGistScanOpaque(), spgPrepareScanKeys(), and SpGistScanOpaqueData::traversalCxt.

Referenced by spghandler().

212 {
214 
215  /* clear traversal context before proceeding to the next scan */
217 
218  /* copy scankeys into local storage */
219  if (scankey && scan->numberOfKeys > 0)
220  {
221  memmove(scan->keyData, scankey,
222  scan->numberOfKeys * sizeof(ScanKeyData));
223  }
224 
225  /* preprocess scankeys, set up the representation in *so */
226  spgPrepareScanKeys(scan);
227 
228  /* set up starting stack entries */
230 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
#define memmove(d, s, c)
Definition: c.h:1135
static void spgPrepareScanKeys(IndexScanDesc scan)
Definition: spgscan.c:116
SpGistScanOpaqueData * SpGistScanOpaque
ScanKey keyData
Definition: relscan.h:95
static void resetSpGistScanOpaque(SpGistScanOpaque so)
Definition: spgscan.c:71
MemoryContext traversalCxt

◆ spgWalk()

static void spgWalk ( Relation  index,
SpGistScanOpaque  so,
bool  scanWholeIndex,
storeRes_func  storeRes,
Snapshot  snapshot 
)
static

Definition at line 308 of file spgscan.c.

References spgInnerConsistentIn::allTheSame, SpGistInnerTupleData::allTheSame, Assert, SpGistTypeDesc::attbyval, SpGistState::attLeafType, SpGistTypeDesc::attlen, buffer, 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(), ScanStackEntry::level, spgInnerConsistentIn::level, spgInnerConsistentOut::levelAdds, linitial, list_delete_first(), LockBuffer(), MemoryContextReset(), MemoryContextSwitchTo(), SpGistLeafTupleData::nextOffset, NIL, spgInnerConsistentIn::nkeys, spgInnerConsistentIn::nNodes, spgInnerConsistentOut::nNodes, SpGistInnerTupleData::nNodes, spgInnerConsistentIn::nodeLabels, spgInnerConsistentOut::nodeNumbers, SpGistScanOpaqueData::numberOfKeys, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, palloc(), PointerGetDatum, spgInnerConsistentIn::prefixDatum, SpGistInnerTupleData::prefixSize, ScanStackEntry::ptr, RelationData::rd_indcollation, ReadBuffer(), ScanStackEntry::reconstructedValue, spgInnerConsistentIn::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, TestForOldSnapshot(), SpGistScanOpaqueData::traversalCxt, spgInnerConsistentIn::traversalMemoryContext, ScanStackEntry::traversalValue, spgInnerConsistentIn::traversalValue, spgInnerConsistentOut::traversalValues, true, SpGistInnerTupleData::tupstate, SpGistLeafTupleData::tupstate, UnlockReleaseBuffer(), and SpGistScanOpaqueData::want_itup.

Referenced by spggetbitmap(), and spggettuple().

310 {
312  bool reportedSome = false;
313 
314  while (scanWholeIndex || !reportedSome)
315  {
316  ScanStackEntry *stackEntry;
317  BlockNumber blkno;
318  OffsetNumber offset;
319  Page page;
320  bool isnull;
321 
322  /* Pull next to-do item from the list */
323  if (so->scanStack == NIL)
324  break; /* there are no more pages to scan */
325 
326  stackEntry = (ScanStackEntry *) linitial(so->scanStack);
328 
329 redirect:
330  /* Check for interrupts, just in case of infinite loop */
332 
333  blkno = ItemPointerGetBlockNumber(&stackEntry->ptr);
334  offset = ItemPointerGetOffsetNumber(&stackEntry->ptr);
335 
336  if (buffer == InvalidBuffer)
337  {
338  buffer = ReadBuffer(index, blkno);
339  LockBuffer(buffer, BUFFER_LOCK_SHARE);
340  }
341  else if (blkno != BufferGetBlockNumber(buffer))
342  {
343  UnlockReleaseBuffer(buffer);
344  buffer = ReadBuffer(index, blkno);
345  LockBuffer(buffer, BUFFER_LOCK_SHARE);
346  }
347  /* else new pointer points to the same page, no work needed */
348 
349  page = BufferGetPage(buffer);
350  TestForOldSnapshot(snapshot, index, page);
351 
352  isnull = SpGistPageStoresNulls(page) ? true : false;
353 
354  if (SpGistPageIsLeaf(page))
355  {
356  SpGistLeafTuple leafTuple;
358  Datum leafValue = (Datum) 0;
359  bool recheck = false;
360 
361  if (SpGistBlockIsRoot(blkno))
362  {
363  /* When root is a leaf, examine all its tuples */
364  for (offset = FirstOffsetNumber; offset <= max; offset++)
365  {
366  leafTuple = (SpGistLeafTuple)
367  PageGetItem(page, PageGetItemId(page, offset));
368  if (leafTuple->tupstate != SPGIST_LIVE)
369  {
370  /* all tuples on root should be live */
371  elog(ERROR, "unexpected SPGiST tuple state: %d",
372  leafTuple->tupstate);
373  }
374 
375  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
376  if (spgLeafTest(index, so,
377  leafTuple, isnull,
378  stackEntry->level,
379  stackEntry->reconstructedValue,
380  stackEntry->traversalValue,
381  &leafValue,
382  &recheck))
383  {
384  storeRes(so, &leafTuple->heapPtr,
385  leafValue, isnull, recheck);
386  reportedSome = true;
387  }
388  }
389  }
390  else
391  {
392  /* Normal case: just examine the chain we arrived at */
393  while (offset != InvalidOffsetNumber)
394  {
395  Assert(offset >= FirstOffsetNumber && offset <= max);
396  leafTuple = (SpGistLeafTuple)
397  PageGetItem(page, PageGetItemId(page, offset));
398  if (leafTuple->tupstate != SPGIST_LIVE)
399  {
400  if (leafTuple->tupstate == SPGIST_REDIRECT)
401  {
402  /* redirection tuple should be first in chain */
403  Assert(offset == ItemPointerGetOffsetNumber(&stackEntry->ptr));
404  /* transfer attention to redirect point */
405  stackEntry->ptr = ((SpGistDeadTuple) leafTuple)->pointer;
407  goto redirect;
408  }
409  if (leafTuple->tupstate == SPGIST_DEAD)
410  {
411  /* dead tuple should be first in chain */
412  Assert(offset == ItemPointerGetOffsetNumber(&stackEntry->ptr));
413  /* No live entries on this page */
414  Assert(leafTuple->nextOffset == InvalidOffsetNumber);
415  break;
416  }
417  /* We should not arrive at a placeholder */
418  elog(ERROR, "unexpected SPGiST tuple state: %d",
419  leafTuple->tupstate);
420  }
421 
422  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
423  if (spgLeafTest(index, so,
424  leafTuple, isnull,
425  stackEntry->level,
426  stackEntry->reconstructedValue,
427  stackEntry->traversalValue,
428  &leafValue,
429  &recheck))
430  {
431  storeRes(so, &leafTuple->heapPtr,
432  leafValue, isnull, recheck);
433  reportedSome = true;
434  }
435 
436  offset = leafTuple->nextOffset;
437  }
438  }
439  }
440  else /* page is inner */
441  {
442  SpGistInnerTuple innerTuple;
445  FmgrInfo *procinfo;
446  SpGistNodeTuple *nodes;
447  SpGistNodeTuple node;
448  int i;
449  MemoryContext oldCtx;
450 
451  innerTuple = (SpGistInnerTuple) PageGetItem(page,
452  PageGetItemId(page, offset));
453 
454  if (innerTuple->tupstate != SPGIST_LIVE)
455  {
456  if (innerTuple->tupstate == SPGIST_REDIRECT)
457  {
458  /* transfer attention to redirect point */
459  stackEntry->ptr = ((SpGistDeadTuple) innerTuple)->pointer;
461  goto redirect;
462  }
463  elog(ERROR, "unexpected SPGiST tuple state: %d",
464  innerTuple->tupstate);
465  }
466 
467  /* use temp context for calling inner_consistent */
468  oldCtx = MemoryContextSwitchTo(so->tempCxt);
469 
470  in.scankeys = so->keyData;
471  in.nkeys = so->numberOfKeys;
472  in.reconstructedValue = stackEntry->reconstructedValue;
474  in.traversalValue = stackEntry->traversalValue;
475  in.level = stackEntry->level;
476  in.returnData = so->want_itup;
477  in.allTheSame = innerTuple->allTheSame;
478  in.hasPrefix = (innerTuple->prefixSize > 0);
479  in.prefixDatum = SGITDATUM(innerTuple, &so->state);
480  in.nNodes = innerTuple->nNodes;
481  in.nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);
482 
483  /* collect node pointers */
484  nodes = (SpGistNodeTuple *) palloc(sizeof(SpGistNodeTuple) * in.nNodes);
485  SGITITERATE(innerTuple, i, node)
486  {
487  nodes[i] = node;
488  }
489 
490  memset(&out, 0, sizeof(out));
491 
492  if (!isnull)
493  {
494  /* use user-defined inner consistent method */
495  procinfo = index_getprocinfo(index, 1, SPGIST_INNER_CONSISTENT_PROC);
496  FunctionCall2Coll(procinfo,
497  index->rd_indcollation[0],
498  PointerGetDatum(&in),
499  PointerGetDatum(&out));
500  }
501  else
502  {
503  /* force all children to be visited */
504  out.nNodes = in.nNodes;
505  out.nodeNumbers = (int *) palloc(sizeof(int) * in.nNodes);
506  for (i = 0; i < in.nNodes; i++)
507  out.nodeNumbers[i] = i;
508  }
509 
510  MemoryContextSwitchTo(oldCtx);
511 
512  /* If allTheSame, they should all or none of 'em match */
513  if (innerTuple->allTheSame)
514  if (out.nNodes != 0 && out.nNodes != in.nNodes)
515  elog(ERROR, "inconsistent inner_consistent results for allTheSame inner tuple");
516 
517  for (i = 0; i < out.nNodes; i++)
518  {
519  int nodeN = out.nodeNumbers[i];
520 
521  Assert(nodeN >= 0 && nodeN < in.nNodes);
522  if (ItemPointerIsValid(&nodes[nodeN]->t_tid))
523  {
524  ScanStackEntry *newEntry;
525 
526  /* Create new work item for this node */
527  newEntry = palloc(sizeof(ScanStackEntry));
528  newEntry->ptr = nodes[nodeN]->t_tid;
529  if (out.levelAdds)
530  newEntry->level = stackEntry->level + out.levelAdds[i];
531  else
532  newEntry->level = stackEntry->level;
533  /* Must copy value out of temp context */
534  if (out.reconstructedValues)
535  newEntry->reconstructedValue =
538  so->state.attLeafType.attlen);
539  else
540  newEntry->reconstructedValue = (Datum) 0;
541 
542  /*
543  * Elements of out.traversalValues should be allocated in
544  * in.traversalMemoryContext, which is actually a long
545  * lived context of index scan.
546  */
547  newEntry->traversalValue = (out.traversalValues) ?
548  out.traversalValues[i] : NULL;
549 
550  so->scanStack = lcons(newEntry, so->scanStack);
551  }
552  }
553  }
554 
555  /* done with this scan stack entry */
556  freeScanStackEntry(so, stackEntry);
557  /* clear temp context before proceeding to the next one */
559  }
560 
561  if (buffer != InvalidBuffer)
562  UnlockReleaseBuffer(buffer);
563 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define SPGIST_DEAD
#define NIL
Definition: pg_list.h:69
Definition: fmgr.h:56
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:822
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
SpGistInnerTupleData * SpGistInnerTuple
void * traversalValue
Definition: spgscan.c:33
#define SpGistPageIsLeaf(page)
static bool spgLeafTest(Relation index, SpGistScanOpaque so, SpGistLeafTuple leafTuple, bool isnull, int level, Datum reconstructedValue, void *traversalValue, Datum *leafValue, bool *recheck)
Definition: spgscan.c:248
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
#define SPGIST_REDIRECT
#define PointerGetDatum(X)
Definition: postgres.h:541
#define SGITITERATE(x, i, nt)
SpGistTypeDesc attLeafType
ItemPointerData t_tid
Definition: itup.h:37
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void * traversalValue
Definition: spgist.h:142
#define InvalidBuffer
Definition: buf.h:25
MemoryContext tempCxt
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 BlockNumber
Definition: block.h:31
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1133
static void freeScanStackEntry(SpGistScanOpaque so, ScanStackEntry *stackEntry)
Definition: spgscan.c:41
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
Datum reconstructedValue
Definition: spgist.h:141
uint16 OffsetNumber
Definition: off.h:24
#define SGITDATUM(x, s)
#define true
Definition: c.h:279
unsigned int allTheSame
#define linitial(l)
Definition: pg_list.h:111
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
Oid * rd_indcollation
Definition: rel.h:165
MemoryContext traversalMemoryContext
Definition: spgist.h:143
#define ERROR
Definition: elog.h:43
ItemPointerData ptr
Definition: spgscan.c:35
unsigned int prefixSize
Datum reconstructedValue
Definition: spgscan.c:32
#define FirstOffsetNumber
Definition: off.h:27
#define SPGIST_METAPAGE_BLKNO
SpGistDeadTupleData * SpGistDeadTuple
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void ** traversalValues
Definition: spgist.h:161
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
unsigned int tupstate
uintptr_t Datum
Definition: postgres.h:367
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
Datum * nodeLabels
Definition: spgist.h:152
#define InvalidOffsetNumber
Definition: off.h:26
#define SpGistPageStoresNulls(page)
List * lcons(void *datum, List *list)
Definition: list.c:259
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define SpGistBlockIsRoot(blkno)
#define SPGIST_LIVE
Datum * reconstructedValues
Definition: spgist.h:160
OffsetNumber nextOffset
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
ScanKey scankeys
Definition: spgist.h:138
MemoryContext traversalCxt
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
void * palloc(Size size)
Definition: mcxt.c:924
int i
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:31
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
ItemPointerData heapPtr
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
SpGistLeafTupleData * SpGistLeafTuple
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74
List * list_delete_first(List *list)
Definition: list.c:666

◆ storeBitmap()

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().

569 {
570  tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
571  so->ntids++;
572 }
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376

◆ storeGettuple()

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

Definition at line 592 of file spgscan.c.

References Assert, heap_form_tuple(), SpGistScanOpaqueData::heapPtrs, SpGistScanOpaqueData::indexTupDesc, MaxIndexTuplesPerPage, SpGistScanOpaqueData::nPtrs, SpGistScanOpaqueData::recheck, SpGistScanOpaqueData::reconTups, and SpGistScanOpaqueData::want_itup.

Referenced by spggettuple().

594 {
596  so->heapPtrs[so->nPtrs] = *heapPtr;
597  so->recheck[so->nPtrs] = recheck;
598  if (so->want_itup)
599  {
600  /*
601  * Reconstruct index data. We have to copy the datum out of the temp
602  * context anyway, so we may as well create the tuple here.
603  */
605  &leafValue,
606  &isnull);
607  }
608  so->nPtrs++;
609 }
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
HeapTuple reconTups[MaxIndexTuplesPerPage]
bool recheck[MaxIndexTuplesPerPage]
#define Assert(condition)
Definition: c.h:699
#define MaxIndexTuplesPerPage
Definition: itup.h:145