PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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

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 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
static void freeScanStackEntry ( SpGistScanOpaque  so,
ScanStackEntry stackEntry 
)
static

Definition at line 41 of file spgscan.c.

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

Referenced by freeScanStack(), and spgWalk().

42 {
43  if (!so->state.attType.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 attType
void pfree(void *pointer)
Definition: mcxt.c:950
Datum reconstructedValue
Definition: spgscan.c:32
#define NULL
Definition: c.h:229
#define DatumGetPointer(X)
Definition: postgres.h:555
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:950
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:878
int i
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:104
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, NULL, IndexScanDescData::opaque, palloc(), palloc0(), RelationGetDescr, RelationGetIndexScan(), SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, 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",
197 
198  /* Set up indexTupDesc and xs_hitupdesc in case it's an index-only scan */
199  so->indexTupDesc = scan->xs_hitupdesc = RelationGetDescr(rel);
200 
201  scan->opaque = so;
202 
203  return scan;
204 }
#define RelationGetDescr(relation)
Definition: rel.h:429
MemoryContext tempCxt
TupleDesc xs_hitupdesc
Definition: relscan.h:116
Relation indexRelation
Definition: relscan.h:89
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
ScanKeyData * ScanKey
Definition: skey.h:75
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:158
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
SpGistScanOpaqueData * SpGistScanOpaque
#define NULL
Definition: c.h:229
void * palloc(Size size)
Definition: mcxt.c:849
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:78
bool spgcanreturn ( Relation  index,
int  attno 
)

Definition at line 648 of file spgscan.c.

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

Referenced by spghandler().

649 {
650  SpGistCache *cache;
651 
652  /* We can do it if the opclass config function says so */
653  cache = spgGetCache(index);
654 
655  return cache->config.canReturnData;
656 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
bool canReturnData
Definition: spgist.h:47
spgConfigOut config
void spgendscan ( IndexScanDesc  scan)

Definition at line 227 of file spgscan.c.

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

Referenced by spghandler().

228 {
230 
232 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
MemoryContext tempCxt
SpGistScanOpaqueData * SpGistScanOpaque
int64 spggetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 568 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().

569 {
571 
572  /* Copy want_itup to *so so we don't need to pass it around separately */
573  so->want_itup = false;
574 
575  so->tbm = tbm;
576  so->ntids = 0;
577 
578  spgWalk(scan->indexRelation, so, true, storeBitmap, scan->xs_snapshot);
579 
580  return so->ntids;
581 }
Snapshot xs_snapshot
Definition: relscan.h:90
Relation indexRelation
Definition: relscan.h:89
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:301
static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Definition: spgscan.c:560
bool spggettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 605 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().

606 {
608 
609  if (dir != ForwardScanDirection)
610  elog(ERROR, "SP-GiST only supports forward scan direction");
611 
612  /* Copy want_itup to *so so we don't need to pass it around separately */
613  so->want_itup = scan->xs_want_itup;
614 
615  for (;;)
616  {
617  if (so->iPtr < so->nPtrs)
618  {
619  /* continuing to return tuples from a leaf page */
620  scan->xs_ctup.t_self = so->heapPtrs[so->iPtr];
621  scan->xs_recheck = so->recheck[so->iPtr];
622  scan->xs_hitup = so->reconTups[so->iPtr];
623  so->iPtr++;
624  return true;
625  }
626 
627  if (so->want_itup)
628  {
629  /* Must pfree reconstructed tuples to avoid memory leak */
630  int i;
631 
632  for (i = 0; i < so->nPtrs; i++)
633  pfree(so->reconTups[i]);
634  }
635  so->iPtr = so->nPtrs = 0;
636 
637  spgWalk(scan->indexRelation, so, false, storeGettuple,
638  scan->xs_snapshot);
639 
640  if (so->nPtrs == 0)
641  break; /* must have completed scan */
642  }
643 
644  return false;
645 }
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
Snapshot xs_snapshot
Definition: relscan.h:90
HeapTuple reconTups[MaxIndexTuplesPerPage]
Relation indexRelation
Definition: relscan.h:89
void pfree(void *pointer)
Definition: mcxt.c:950
#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:585
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:301
bool xs_want_itup
Definition: relscan.h:95
HeapTupleData xs_ctup
Definition: relscan.h:119
HeapTuple xs_hitup
Definition: relscan.h:115
int i
#define elog
Definition: elog.h:219
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 241 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, result, spgLeafConsistentIn::returnData, spgLeafConsistentIn::scankeys, SpGistScanOpaqueData::searchNulls, SGLTDATUM, SPGIST_LEAF_CONSISTENT_PROC, SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, spgLeafConsistentIn::traversalValue, and SpGistScanOpaqueData::want_itup.

Referenced by spgWalk().

246 {
247  bool result;
248  Datum leafDatum;
251  FmgrInfo *procinfo;
252  MemoryContext oldCtx;
253 
254  if (isnull)
255  {
256  /* Should not have arrived on a nulls page unless nulls are wanted */
257  Assert(so->searchNulls);
258  *leafValue = (Datum) 0;
259  *recheck = false;
260  return true;
261  }
262 
263  leafDatum = SGLTDATUM(leafTuple, &so->state);
264 
265  /* use temp context for calling leaf_consistent */
266  oldCtx = MemoryContextSwitchTo(so->tempCxt);
267 
268  in.scankeys = so->keyData;
269  in.nkeys = so->numberOfKeys;
270  in.reconstructedValue = reconstructedValue;
271  in.traversalValue = traversalValue;
272  in.level = level;
273  in.returnData = so->want_itup;
274  in.leafDatum = leafDatum;
275 
276  out.leafValue = (Datum) 0;
277  out.recheck = false;
278 
279  procinfo = index_getprocinfo(index, 1, SPGIST_LEAF_CONSISTENT_PROC);
280  result = DatumGetBool(FunctionCall2Coll(procinfo,
281  index->rd_indcollation[0],
282  PointerGetDatum(&in),
283  PointerGetDatum(&out)));
284 
285  *leafValue = out.leafValue;
286  *recheck = out.recheck;
287 
288  MemoryContextSwitchTo(oldCtx);
289 
290  return result;
291 }
Datum reconstructedValue
Definition: spgist.h:170
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:562
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext tempCxt
return result
Definition: formatting.c:1618
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
Oid * rd_indcollation
Definition: rel.h:193
ScanKey scankeys
Definition: spgist.h:167
#define DatumGetBool(X)
Definition: postgres.h:399
uintptr_t Datum
Definition: postgres.h:372
#define Assert(condition)
Definition: c.h:675
#define SGLTDATUM(x, s)
void * traversalValue
Definition: spgist.h:171
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:93
int i
#define SK_SEARCHNULL
Definition: skey.h:121
void spgrescan ( IndexScanDesc  scan,
ScanKey  scankey,
int  nscankeys,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 207 of file spgscan.c.

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

Referenced by spghandler().

209 {
211 
212  /* copy scankeys into local storage */
213  if (scankey && scan->numberOfKeys > 0)
214  {
215  memmove(scan->keyData, scankey,
216  scan->numberOfKeys * sizeof(ScanKeyData));
217  }
218 
219  /* preprocess scankeys, set up the representation in *so */
220  spgPrepareScanKeys(scan);
221 
222  /* set up starting stack entries */
224 }
#define memmove(d, s, c)
Definition: c.h:1058
static void spgPrepareScanKeys(IndexScanDesc scan)
Definition: spgscan.c:116
SpGistScanOpaqueData * SpGistScanOpaque
ScanKey keyData
Definition: relscan.h:93
static void resetSpGistScanOpaque(SpGistScanOpaque so)
Definition: spgscan.c:71
static void spgWalk ( Relation  index,
SpGistScanOpaque  so,
bool  scanWholeIndex,
storeRes_func  storeRes,
Snapshot  snapshot 
)
static

Definition at line 301 of file spgscan.c.

References spgInnerConsistentIn::allTheSame, SpGistInnerTupleData::allTheSame, Assert, SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, SpGistState::attType, 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, NULL, 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(), spgInnerConsistentIn::traversalMemoryContext, ScanStackEntry::traversalValue, spgInnerConsistentIn::traversalValue, spgInnerConsistentOut::traversalValues, SpGistInnerTupleData::tupstate, SpGistLeafTupleData::tupstate, UnlockReleaseBuffer(), and SpGistScanOpaqueData::want_itup.

Referenced by spggetbitmap(), and spggettuple().

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

Definition at line 560 of file spgscan.c.

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

Referenced by spggetbitmap().

562 {
563  tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
564  so->ntids++;
565 }
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:403
static void storeGettuple ( SpGistScanOpaque  so,
ItemPointer  heapPtr,
Datum  leafValue,
bool  isnull,
bool  recheck 
)
static

Definition at line 585 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().

587 {
589  so->heapPtrs[so->nPtrs] = *heapPtr;
590  so->recheck[so->nPtrs] = recheck;
591  if (so->want_itup)
592  {
593  /*
594  * Reconstruct index data. We have to copy the datum out of the temp
595  * context anyway, so we may as well create the tuple here.
596  */
598  &leafValue,
599  &isnull);
600  }
601  so->nPtrs++;
602 }
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
HeapTuple reconTups[MaxIndexTuplesPerPage]
bool recheck[MaxIndexTuplesPerPage]
#define Assert(condition)
Definition: c.h:675
#define MaxIndexTuplesPerPage
Definition: itup.h:137