PostgreSQL Source Code  git master
spgscan.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/relscan.h"
#include "access/spgist_private.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "utils/datum.h"
#include "utils/float.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for spgscan.c:

Go to the source code of this file.

Typedefs

typedef void(* storeRes_func) (SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isNull, bool recheck, bool recheckDistances, double *distances)
 

Enumerations

enum  SpGistSpecialOffsetNumbers { SpGistBreakOffsetNumber = InvalidOffsetNumber, SpGistRedirectOffsetNumber = MaxOffsetNumber + 1, SpGistErrorOffsetNumber = MaxOffsetNumber + 2 }
 

Functions

static int pairingheap_SpGistSearchItem_cmp (const pairingheap_node *a, const pairingheap_node *b, void *arg)
 
static void spgFreeSearchItem (SpGistScanOpaque so, SpGistSearchItem *item)
 
static void spgAddSearchItemToQueue (SpGistScanOpaque so, SpGistSearchItem *item)
 
static SpGistSearchItemspgAllocSearchItem (SpGistScanOpaque so, bool isnull, double *distances)
 
static void spgAddStartItem (SpGistScanOpaque so, bool isnull)
 
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 SpGistSearchItemspgNewHeapItem (SpGistScanOpaque so, int level, ItemPointer heapPtr, Datum leafValue, bool recheck, bool recheckDistances, bool isnull, double *distances)
 
static bool spgLeafTest (SpGistScanOpaque so, SpGistSearchItem *item, SpGistLeafTuple leafTuple, bool isnull, bool *reportedSome, storeRes_func storeRes)
 
static void spgInitInnerConsistentIn (spgInnerConsistentIn *in, SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple)
 
static SpGistSearchItemspgMakeInnerItem (SpGistScanOpaque so, SpGistSearchItem *parentItem, SpGistNodeTuple tuple, spgInnerConsistentOut *out, int i, bool isnull, double *distances)
 
static void spgInnerTest (SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple, bool isnull)
 
static SpGistSearchItemspgGetNextQueueItem (SpGistScanOpaque so)
 
static OffsetNumber spgTestLeafTuple (SpGistScanOpaque so, SpGistSearchItem *item, Page page, OffsetNumber offset, bool isnull, bool isroot, bool *reportedSome, storeRes_func storeRes)
 
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, bool recheckDistances, double *distances)
 
int64 spggetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
static void storeGettuple (SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck, bool recheckDistances, double *distances)
 
bool spggettuple (IndexScanDesc scan, ScanDirection dir)
 
bool spgcanreturn (Relation index, int attno)
 

Typedef Documentation

◆ storeRes_func

typedef void(* storeRes_func) (SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isNull, bool recheck, bool recheckDistances, double *distances)

Definition at line 29 of file spgscan.c.

Enumeration Type Documentation

◆ SpGistSpecialOffsetNumbers

Enumerator
SpGistBreakOffsetNumber 
SpGistRedirectOffsetNumber 
SpGistErrorOffsetNumber 

Definition at line 672 of file spgscan.c.

Function Documentation

◆ pairingheap_SpGistSearchItem_cmp()

static int pairingheap_SpGistSearchItem_cmp ( const pairingheap_node a,
const pairingheap_node b,
void *  arg 
)
static

Definition at line 39 of file spgscan.c.

References SpGistSearchItem::distances, i, SpGistSearchItem::isLeaf, SpGistSearchItem::isNull, and SpGistScanOpaqueData::numberOfOrderBys.

Referenced by resetSpGistScanOpaque().

41 {
42  const SpGistSearchItem *sa = (const SpGistSearchItem *) a;
43  const SpGistSearchItem *sb = (const SpGistSearchItem *) b;
45  int i;
46 
47  if (sa->isNull)
48  {
49  if (!sb->isNull)
50  return -1;
51  }
52  else if (sb->isNull)
53  {
54  return 1;
55  }
56  else
57  {
58  /* Order according to distance comparison */
59  for (i = 0; i < so->numberOfOrderBys; i++)
60  {
61  if (isnan(sa->distances[i]) && isnan(sb->distances[i]))
62  continue; /* NaN == NaN */
63  if (isnan(sa->distances[i]))
64  return -1; /* NaN > number */
65  if (isnan(sb->distances[i]))
66  return 1; /* number < NaN */
67  if (sa->distances[i] != sb->distances[i])
68  return (sa->distances[i] < sb->distances[i]) ? 1 : -1;
69  }
70  }
71 
72  /* Leaf items go before inner pages, to ensure a depth-first search */
73  if (sa->isLeaf && !sb->isLeaf)
74  return 1;
75  if (!sa->isLeaf && sb->isLeaf)
76  return -1;
77 
78  return 0;
79 }
SpGistScanOpaqueData * SpGistScanOpaque
double distances[FLEXIBLE_ARRAY_MEMBER]
int i
void * arg

◆ resetSpGistScanOpaque()

static void resetSpGistScanOpaque ( SpGistScanOpaque  so)
static

Definition at line 145 of file spgscan.c.

References SpGistScanOpaqueData::distances, i, SpGistScanOpaqueData::iPtr, MemoryContextReset(), MemoryContextSwitchTo(), SpGistScanOpaqueData::nPtrs, SpGistScanOpaqueData::numberOfOrderBys, pairingheap_allocate(), pairingheap_SpGistSearchItem_cmp(), pfree(), SpGistScanOpaqueData::reconTups, SpGistScanOpaqueData::scanQueue, SpGistScanOpaqueData::searchNonNulls, SpGistScanOpaqueData::searchNulls, spgAddStartItem(), SpGistScanOpaqueData::traversalCxt, and SpGistScanOpaqueData::want_itup.

Referenced by spgrescan().

146 {
147  MemoryContext oldCtx;
148 
150 
151  oldCtx = MemoryContextSwitchTo(so->traversalCxt);
152 
153  /* initialize queue only for distance-ordered scans */
155 
156  if (so->searchNulls)
157  /* Add a work item to scan the null index entries */
158  spgAddStartItem(so, true);
159 
160  if (so->searchNonNulls)
161  /* Add a work item to scan the non-null index entries */
162  spgAddStartItem(so, false);
163 
164  MemoryContextSwitchTo(oldCtx);
165 
166  if (so->numberOfOrderBys > 0)
167  {
168  /* Must pfree distances to avoid memory leak */
169  int i;
170 
171  for (i = 0; i < so->nPtrs; i++)
172  if (so->distances[i])
173  pfree(so->distances[i]);
174  }
175 
176  if (so->want_itup)
177  {
178  /* Must pfree reconstructed tuples to avoid memory leak */
179  int i;
180 
181  for (i = 0; i < so->nPtrs; i++)
182  pfree(so->reconTups[i]);
183  }
184  so->iPtr = so->nPtrs = 0;
185 }
static int pairingheap_SpGistSearchItem_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
Definition: spgscan.c:39
pairingheap * scanQueue
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
HeapTuple reconTups[MaxIndexTuplesPerPage]
void pfree(void *pointer)
Definition: mcxt.c:1031
double * distances[MaxIndexTuplesPerPage]
static void spgAddStartItem(SpGistScanOpaque so, bool isnull)
Definition: spgscan.c:122
MemoryContext traversalCxt
int i

◆ spgAddSearchItemToQueue()

static void spgAddSearchItemToQueue ( SpGistScanOpaque  so,
SpGistSearchItem item 
)
static

Definition at line 100 of file spgscan.c.

References pairingheap_add(), SpGistSearchItem::phNode, and SpGistScanOpaqueData::scanQueue.

Referenced by spgAddStartItem(), spgInnerTest(), and spgLeafTest().

101 {
102  pairingheap_add(so->scanQueue, &item->phNode);
103 }
pairingheap * scanQueue
pairingheap_node phNode
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112

◆ spgAddStartItem()

static void spgAddStartItem ( SpGistScanOpaque  so,
bool  isnull 
)
static

Definition at line 122 of file spgscan.c.

References FirstOffsetNumber, SpGistSearchItem::heapPtr, SpGistSearchItem::isLeaf, ItemPointerSet, SpGistSearchItem::level, SpGistSearchItem::recheck, SpGistSearchItem::recheckDistances, spgAddSearchItemToQueue(), spgAllocSearchItem(), SPGIST_NULL_BLKNO, SPGIST_ROOT_BLKNO, SpGistSearchItem::traversalValue, SpGistSearchItem::value, and SpGistScanOpaqueData::zeroDistances.

Referenced by resetSpGistScanOpaque().

123 {
124  SpGistSearchItem *startEntry =
125  spgAllocSearchItem(so, isnull, so->zeroDistances);
126 
127  ItemPointerSet(&startEntry->heapPtr,
130  startEntry->isLeaf = false;
131  startEntry->level = 0;
132  startEntry->value = (Datum) 0;
133  startEntry->traversalValue = NULL;
134  startEntry->recheck = false;
135  startEntry->recheckDistances = false;
136 
137  spgAddSearchItemToQueue(so, startEntry);
138 }
#define SPGIST_ROOT_BLKNO
#define SPGIST_NULL_BLKNO
static SpGistSearchItem * spgAllocSearchItem(SpGistScanOpaque so, bool isnull, double *distances)
Definition: spgscan.c:106
#define FirstOffsetNumber
Definition: off.h:27
static void spgAddSearchItemToQueue(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:100
uintptr_t Datum
Definition: postgres.h:367
ItemPointerData heapPtr
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127

◆ spgAllocSearchItem()

static SpGistSearchItem* spgAllocSearchItem ( SpGistScanOpaque  so,
bool  isnull,
double *  distances 
)
static

Definition at line 106 of file spgscan.c.

References SpGistSearchItem::distances, SpGistSearchItem::isNull, SpGistScanOpaqueData::numberOfOrderBys, palloc(), and SizeOfSpGistSearchItem.

Referenced by spgAddStartItem(), spgMakeInnerItem(), and spgNewHeapItem().

107 {
108  /* allocate distance array only for non-NULL items */
109  SpGistSearchItem *item =
111 
112  item->isNull = isnull;
113 
114  if (!isnull && so->numberOfOrderBys > 0)
115  memcpy(item->distances, distances,
116  so->numberOfOrderBys * sizeof(double));
117 
118  return item;
119 }
#define SizeOfSpGistSearchItem(n_distances)
double distances[FLEXIBLE_ARRAY_MEMBER]
void * palloc(Size size)
Definition: mcxt.c:924

◆ spgbeginscan()

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

Definition at line 267 of file spgscan.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CurrentMemoryContext, fmgr_info_copy(), get_float8_infinity(), i, index_getprocinfo(), SpGistScanOpaqueData::indexCollation, IndexScanDescData::indexRelation, SpGistScanOpaqueData::indexTupDesc, SpGistScanOpaqueData::infDistances, initSpGistState(), SpGistScanOpaqueData::innerConsistentFn, SpGistScanOpaqueData::keyData, SpGistScanOpaqueData::leafConsistentFn, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, SpGistScanOpaqueData::orderByTypes, palloc(), palloc0(), RelationData::rd_indcollation, RelationGetDescr, RelationGetIndexScan(), SPGIST_INNER_CONSISTENT_PROC, SPGIST_LEAF_CONSISTENT_PROC, SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, SpGistScanOpaqueData::traversalCxt, IndexScanDescData::xs_hitupdesc, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, and SpGistScanOpaqueData::zeroDistances.

Referenced by spghandler().

268 {
269  IndexScanDesc scan;
270  SpGistScanOpaque so;
271  int i;
272 
273  scan = RelationGetIndexScan(rel, keysz, orderbysz);
274 
276  if (keysz > 0)
277  so->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * keysz);
278  else
279  so->keyData = NULL;
280  initSpGistState(&so->state, scan->indexRelation);
281 
283  "SP-GiST search temporary context",
286  "SP-GiST traversal-value context",
288 
289  /* Set up indexTupDesc and xs_hitupdesc in case it's an index-only scan */
290  so->indexTupDesc = scan->xs_hitupdesc = RelationGetDescr(rel);
291 
292  /* Allocate various arrays needed for order-by scans */
293  if (scan->numberOfOrderBys > 0)
294  {
295  /* This will be filled in spgrescan, but allocate the space here */
296  so->orderByTypes = (Oid *)
297  palloc(sizeof(Oid) * scan->numberOfOrderBys);
298 
299  /* These arrays have constant contents, so we can fill them now */
300  so->zeroDistances = (double *)
301  palloc(sizeof(double) * scan->numberOfOrderBys);
302  so->infDistances = (double *)
303  palloc(sizeof(double) * scan->numberOfOrderBys);
304 
305  for (i = 0; i < scan->numberOfOrderBys; i++)
306  {
307  so->zeroDistances[i] = 0.0;
309  }
310 
311  scan->xs_orderbyvals = (Datum *)
312  palloc0(sizeof(Datum) * scan->numberOfOrderBys);
313  scan->xs_orderbynulls = (bool *)
314  palloc(sizeof(bool) * scan->numberOfOrderBys);
315  memset(scan->xs_orderbynulls, true,
316  sizeof(bool) * scan->numberOfOrderBys);
317  }
318 
322 
326 
327  so->indexCollation = rel->rd_indcollation[0];
328 
329  scan->opaque = so;
330 
331  return scan;
332 }
#define AllocSetContextCreate
Definition: memutils.h:169
static float8 get_float8_infinity(void)
Definition: float.h:90
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:31
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:794
#define RelationGetDescr(relation)
Definition: rel.h:442
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:130
MemoryContext tempCxt
Datum * xs_orderbyvals
Definition: relscan.h:146
unsigned int Oid
Definition: postgres_ext.h:31
Relation indexRelation
Definition: relscan.h:103
bool * xs_orderbynulls
Definition: relscan.h:147
Oid * rd_indcollation
Definition: rel.h:168
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:191
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:610
ScanKeyData * ScanKey
Definition: skey.h:75
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:181
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:367
SpGistScanOpaqueData * SpGistScanOpaque
MemoryContext traversalCxt
void * palloc(Size size)
Definition: mcxt.c:924
int i
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:30
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:80
int numberOfOrderBys
Definition: relscan.h:106

◆ spgcanreturn()

bool spgcanreturn ( Relation  index,
int  attno 
)

Definition at line 968 of file spgscan.c.

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

Referenced by spghandler().

969 {
970  SpGistCache *cache;
971 
972  /* We can do it if the opclass config function says so */
973  cache = spgGetCache(index);
974 
975  return cache->config.canReturnData;
976 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:99
bool canReturnData
Definition: spgist.h:49
spgConfigOut config

◆ spgendscan()

void spgendscan ( IndexScanDesc  scan)

Definition at line 381 of file spgscan.c.

References SpGistState::deadTupleStorage, SpGistScanOpaqueData::infDistances, SpGistScanOpaqueData::keyData, MemoryContextDelete(), IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, SpGistScanOpaqueData::orderByTypes, pfree(), SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, SpGistScanOpaqueData::traversalCxt, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, and SpGistScanOpaqueData::zeroDistances.

Referenced by spghandler().

382 {
384 
387 
388  if (so->keyData)
389  pfree(so->keyData);
390 
391  if (so->state.deadTupleStorage)
393 
394  if (scan->numberOfOrderBys > 0)
395  {
396  pfree(so->orderByTypes);
397  pfree(so->zeroDistances);
398  pfree(so->infDistances);
399  pfree(scan->xs_orderbyvals);
400  pfree(scan->xs_orderbynulls);
401  }
402 
403  pfree(so);
404 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
MemoryContext tempCxt
Datum * xs_orderbyvals
Definition: relscan.h:146
bool * xs_orderbynulls
Definition: relscan.h:147
void pfree(void *pointer)
Definition: mcxt.c:1031
char * deadTupleStorage
SpGistScanOpaqueData * SpGistScanOpaque
MemoryContext traversalCxt
int numberOfOrderBys
Definition: relscan.h:106

◆ spgFreeSearchItem()

static void spgFreeSearchItem ( SpGistScanOpaque  so,
SpGistSearchItem item 
)
static

Definition at line 82 of file spgscan.c.

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

Referenced by spgWalk().

83 {
84  if (!so->state.attLeafType.attbyval &&
85  DatumGetPointer(item->value) != NULL)
86  pfree(DatumGetPointer(item->value));
87 
88  if (item->traversalValue)
89  pfree(item->traversalValue);
90 
91  pfree(item);
92 }
SpGistTypeDesc attLeafType
void pfree(void *pointer)
Definition: mcxt.c:1031
#define DatumGetPointer(X)
Definition: postgres.h:549

◆ spggetbitmap()

int64 spggetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

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

859 {
861 
862  /* Copy want_itup to *so so we don't need to pass it around separately */
863  so->want_itup = false;
864 
865  so->tbm = tbm;
866  so->ntids = 0;
867 
868  spgWalk(scan->indexRelation, so, true, storeBitmap, scan->xs_snapshot);
869 
870  return so->ntids;
871 }
struct SnapshotData * xs_snapshot
Definition: relscan.h:104
Relation indexRelation
Definition: relscan.h:103
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:734
static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck, bool recheckDistances, double *distances)
Definition: spgscan.c:848

◆ spgGetNextQueueItem()

static SpGistSearchItem* spgGetNextQueueItem ( SpGistScanOpaque  so)
static

Definition at line 663 of file spgscan.c.

References pairingheap_is_empty, pairingheap_remove_first(), and SpGistScanOpaqueData::scanQueue.

Referenced by spgWalk().

664 {
666  return NULL; /* Done when both heaps are empty */
667 
668  /* Return item; caller is responsible to pfree it */
670 }
pairingheap * scanQueue
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145

◆ spggettuple()

bool spggettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 910 of file spgscan.c.

References SpGistScanOpaqueData::distances, elog, ERROR, ForwardScanDirection, SpGistScanOpaqueData::heapPtrs, i, index_store_float8_orderby_distances(), IndexScanDescData::indexRelation, SpGistScanOpaqueData::iPtr, SpGistScanOpaqueData::nPtrs, SpGistScanOpaqueData::numberOfOrderBys, IndexScanDescData::opaque, SpGistScanOpaqueData::orderByTypes, pfree(), SpGistScanOpaqueData::recheck, SpGistScanOpaqueData::recheckDistances, SpGistScanOpaqueData::reconTups, spgWalk(), storeGettuple(), SpGistScanOpaqueData::want_itup, IndexScanDescData::xs_heaptid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, IndexScanDescData::xs_snapshot, and IndexScanDescData::xs_want_itup.

Referenced by spghandler().

911 {
913 
914  if (dir != ForwardScanDirection)
915  elog(ERROR, "SP-GiST only supports forward scan direction");
916 
917  /* Copy want_itup to *so so we don't need to pass it around separately */
918  so->want_itup = scan->xs_want_itup;
919 
920  for (;;)
921  {
922  if (so->iPtr < so->nPtrs)
923  {
924  /* continuing to return reported tuples */
925  scan->xs_heaptid = so->heapPtrs[so->iPtr];
926  scan->xs_recheck = so->recheck[so->iPtr];
927  scan->xs_hitup = so->reconTups[so->iPtr];
928 
929  if (so->numberOfOrderBys > 0)
931  so->distances[so->iPtr],
932  so->recheckDistances[so->iPtr]);
933  so->iPtr++;
934  return true;
935  }
936 
937  if (so->numberOfOrderBys > 0)
938  {
939  /* Must pfree distances to avoid memory leak */
940  int i;
941 
942  for (i = 0; i < so->nPtrs; i++)
943  if (so->distances[i])
944  pfree(so->distances[i]);
945  }
946 
947  if (so->want_itup)
948  {
949  /* Must pfree reconstructed tuples to avoid memory leak */
950  int i;
951 
952  for (i = 0; i < so->nPtrs; i++)
953  pfree(so->reconTups[i]);
954  }
955  so->iPtr = so->nPtrs = 0;
956 
957  spgWalk(scan->indexRelation, so, false, storeGettuple,
958  scan->xs_snapshot);
959 
960  if (so->nPtrs == 0)
961  break; /* must have completed scan */
962  }
963 
964  return false;
965 }
static void storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck, bool recheckDistances, double *distances)
Definition: spgscan.c:875
bool recheckDistances[MaxIndexTuplesPerPage]
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
struct SnapshotData * xs_snapshot
Definition: relscan.h:104
HeapTuple reconTups[MaxIndexTuplesPerPage]
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, double *distances, bool recheckOrderBy)
Definition: indexam.c:849
Relation indexRelation
Definition: relscan.h:103
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
ItemPointerData xs_heaptid
Definition: relscan.h:132
double * distances[MaxIndexTuplesPerPage]
bool recheck[MaxIndexTuplesPerPage]
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:734
HeapTuple xs_hitup
Definition: relscan.h:129
#define elog(elevel,...)
Definition: elog.h:226
int i

◆ spgInitInnerConsistentIn()

static void spgInitInnerConsistentIn ( spgInnerConsistentIn in,
SpGistScanOpaque  so,
SpGistSearchItem item,
SpGistInnerTuple  innerTuple 
)
static

Definition at line 526 of file spgscan.c.

References spgInnerConsistentIn::allTheSame, SpGistInnerTupleData::allTheSame, spgInnerConsistentIn::hasPrefix, SpGistScanOpaqueData::keyData, SpGistSearchItem::level, spgInnerConsistentIn::level, spgInnerConsistentIn::nkeys, spgInnerConsistentIn::nNodes, SpGistInnerTupleData::nNodes, spgInnerConsistentIn::nodeLabels, spgInnerConsistentIn::norderbys, SpGistScanOpaqueData::numberOfKeys, SpGistScanOpaqueData::numberOfOrderBys, SpGistScanOpaqueData::orderByData, spgInnerConsistentIn::orderbys, spgInnerConsistentIn::prefixDatum, SpGistInnerTupleData::prefixSize, spgInnerConsistentIn::reconstructedValue, spgInnerConsistentIn::returnData, spgInnerConsistentIn::scankeys, SGITDATUM, spgExtractNodeLabels(), SpGistScanOpaqueData::state, SpGistScanOpaqueData::traversalCxt, spgInnerConsistentIn::traversalMemoryContext, SpGistSearchItem::traversalValue, spgInnerConsistentIn::traversalValue, SpGistSearchItem::value, and SpGistScanOpaqueData::want_itup.

Referenced by spgInnerTest().

530 {
531  in->scankeys = so->keyData;
532  in->orderbys = so->orderByData;
533  in->nkeys = so->numberOfKeys;
534  in->norderbys = so->numberOfOrderBys;
535  in->reconstructedValue = item->value;
537  in->traversalValue = item->traversalValue;
538  in->level = item->level;
539  in->returnData = so->want_itup;
540  in->allTheSame = innerTuple->allTheSame;
541  in->hasPrefix = (innerTuple->prefixSize > 0);
542  in->prefixDatum = SGITDATUM(innerTuple, &so->state);
543  in->nNodes = innerTuple->nNodes;
544  in->nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);
545 }
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:828
ScanKey orderbys
Definition: spgist.h:138
void * traversalValue
Definition: spgist.h:144
Datum reconstructedValue
Definition: spgist.h:143
#define SGITDATUM(x, s)
unsigned int allTheSame
MemoryContext traversalMemoryContext
Definition: spgist.h:145
unsigned int prefixSize
Datum * nodeLabels
Definition: spgist.h:154
ScanKey scankeys
Definition: spgist.h:137
MemoryContext traversalCxt

◆ spgInnerTest()

static void spgInnerTest ( SpGistScanOpaque  so,
SpGistSearchItem item,
SpGistInnerTuple  innerTuple,
bool  isnull 
)
static

Definition at line 583 of file spgscan.c.

References SpGistInnerTupleData::allTheSame, Assert, spgInnerConsistentOut::distances, elog, ERROR, FunctionCall2Coll(), i, SpGistScanOpaqueData::indexCollation, SpGistScanOpaqueData::infDistances, SpGistScanOpaqueData::innerConsistentFn, ItemPointerIsValid, MemoryContextSwitchTo(), spgInnerConsistentOut::nNodes, SpGistInnerTupleData::nNodes, spgInnerConsistentOut::nodeNumbers, palloc(), PointerGetDatum, SGITITERATE, spgAddSearchItemToQueue(), spgInitInnerConsistentIn(), spgMakeInnerItem(), IndexTupleData::t_tid, SpGistScanOpaqueData::tempCxt, and SpGistScanOpaqueData::traversalCxt.

Referenced by spgWalk().

585 {
588  int nNodes = innerTuple->nNodes;
589  int i;
590 
591  memset(&out, 0, sizeof(out));
592 
593  if (!isnull)
594  {
596 
597  spgInitInnerConsistentIn(&in, so, item, innerTuple);
598 
599  /* use user-defined inner consistent method */
601  so->indexCollation,
602  PointerGetDatum(&in),
603  PointerGetDatum(&out));
604  }
605  else
606  {
607  /* force all children to be visited */
608  out.nNodes = nNodes;
609  out.nodeNumbers = (int *) palloc(sizeof(int) * nNodes);
610  for (i = 0; i < nNodes; i++)
611  out.nodeNumbers[i] = i;
612  }
613 
614  /* If allTheSame, they should all or none of them match */
615  if (innerTuple->allTheSame && out.nNodes != 0 && out.nNodes != nNodes)
616  elog(ERROR, "inconsistent inner_consistent results for allTheSame inner tuple");
617 
618  if (out.nNodes)
619  {
620  /* collect node pointers */
621  SpGistNodeTuple node;
623  sizeof(SpGistNodeTuple) * nNodes);
624 
625  SGITITERATE(innerTuple, i, node)
626  {
627  nodes[i] = node;
628  }
629 
631 
632  for (i = 0; i < out.nNodes; i++)
633  {
634  int nodeN = out.nodeNumbers[i];
635  SpGistSearchItem *innerItem;
636  double *distances;
637 
638  Assert(nodeN >= 0 && nodeN < nNodes);
639 
640  node = nodes[nodeN];
641 
642  if (!ItemPointerIsValid(&node->t_tid))
643  continue;
644 
645  /*
646  * Use infinity distances if innerConsistentFn() failed to return
647  * them or if is a NULL item (their distances are really unused).
648  */
649  distances = out.distances ? out.distances[i] : so->infDistances;
650 
651  innerItem = spgMakeInnerItem(so, item, node, &out, i, isnull,
652  distances);
653 
654  spgAddSearchItemToQueue(so, innerItem);
655  }
656  }
657 
658  MemoryContextSwitchTo(oldCxt);
659 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define PointerGetDatum(X)
Definition: postgres.h:556
#define SGITITERATE(x, i, nt)
ItemPointerData t_tid
Definition: itup.h:37
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext tempCxt
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
unsigned int allTheSame
#define ERROR
Definition: elog.h:43
static SpGistSearchItem * spgMakeInnerItem(SpGistScanOpaque so, SpGistSearchItem *parentItem, SpGistNodeTuple tuple, spgInnerConsistentOut *out, int i, bool isnull, double *distances)
Definition: spgscan.c:548
static void spgAddSearchItemToQueue(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:100
double ** distances
Definition: spgist.h:164
#define Assert(condition)
Definition: c.h:732
static void spgInitInnerConsistentIn(spgInnerConsistentIn *in, SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple)
Definition: spgscan.c:526
MemoryContext traversalCxt
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
int i

◆ spgLeafTest()

static bool spgLeafTest ( SpGistScanOpaque  so,
SpGistSearchItem item,
SpGistLeafTuple  leafTuple,
bool  isnull,
bool reportedSome,
storeRes_func  storeRes 
)
static

Definition at line 437 of file spgscan.c.

References Assert, DatumGetBool, spgLeafConsistentOut::distances, FunctionCall2Coll(), SpGistLeafTupleData::heapPtr, SpGistScanOpaqueData::indexCollation, SpGistScanOpaqueData::keyData, SpGistScanOpaqueData::leafConsistentFn, spgLeafConsistentIn::leafDatum, spgLeafConsistentOut::leafValue, SpGistSearchItem::level, spgLeafConsistentIn::level, MemoryContextSwitchTo(), spgLeafConsistentIn::nkeys, spgLeafConsistentIn::norderbys, SpGistScanOpaqueData::numberOfKeys, SpGistScanOpaqueData::numberOfOrderBys, SpGistScanOpaqueData::orderByData, spgLeafConsistentIn::orderbys, PointerGetDatum, spgLeafConsistentOut::recheck, spgLeafConsistentOut::recheckDistances, spgLeafConsistentIn::reconstructedValue, spgLeafConsistentIn::returnData, spgLeafConsistentIn::scankeys, SpGistScanOpaqueData::searchNulls, SGLTDATUM, spgAddSearchItemToQueue(), spgNewHeapItem(), SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, SpGistScanOpaqueData::traversalCxt, SpGistSearchItem::traversalValue, spgLeafConsistentIn::traversalValue, SpGistSearchItem::value, and SpGistScanOpaqueData::want_itup.

Referenced by spgTestLeafTuple().

440 {
441  Datum leafValue;
442  double *distances;
443  bool result;
444  bool recheck;
445  bool recheckDistances;
446 
447  if (isnull)
448  {
449  /* Should not have arrived on a nulls page unless nulls are wanted */
450  Assert(so->searchNulls);
451  leafValue = (Datum) 0;
452  distances = NULL;
453  recheck = false;
454  recheckDistances = false;
455  result = true;
456  }
457  else
458  {
461 
462  /* use temp context for calling leaf_consistent */
464 
465  in.scankeys = so->keyData;
466  in.nkeys = so->numberOfKeys;
467  in.orderbys = so->orderByData;
468  in.norderbys = so->numberOfOrderBys;
469  in.reconstructedValue = item->value;
470  in.traversalValue = item->traversalValue;
471  in.level = item->level;
472  in.returnData = so->want_itup;
473  in.leafDatum = SGLTDATUM(leafTuple, &so->state);
474 
475  out.leafValue = (Datum) 0;
476  out.recheck = false;
477  out.distances = NULL;
478  out.recheckDistances = false;
479 
481  so->indexCollation,
482  PointerGetDatum(&in),
483  PointerGetDatum(&out)));
484  recheck = out.recheck;
485  recheckDistances = out.recheckDistances;
486  leafValue = out.leafValue;
487  distances = out.distances;
488 
489  MemoryContextSwitchTo(oldCxt);
490  }
491 
492  if (result)
493  {
494  /* item passes the scankeys */
495  if (so->numberOfOrderBys > 0)
496  {
497  /* the scan is ordered -> add the item to the queue */
499  SpGistSearchItem *heapItem = spgNewHeapItem(so, item->level,
500  &leafTuple->heapPtr,
501  leafValue,
502  recheck,
503  recheckDistances,
504  isnull,
505  distances);
506 
507  spgAddSearchItemToQueue(so, heapItem);
508 
509  MemoryContextSwitchTo(oldCxt);
510  }
511  else
512  {
513  /* non-ordered scan, so report the item right away */
514  Assert(!recheckDistances);
515  storeRes(so, &leafTuple->heapPtr, leafValue, isnull,
516  recheck, false, NULL);
517  *reportedSome = true;
518  }
519  }
520 
521  return result;
522 }
Datum reconstructedValue
Definition: spgist.h:178
#define PointerGetDatum(X)
Definition: postgres.h:556
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext tempCxt
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
ScanKey orderbys
Definition: spgist.h:173
ScanKey scankeys
Definition: spgist.h:172
double * distances
Definition: spgist.h:191
#define DatumGetBool(X)
Definition: postgres.h:393
static void spgAddSearchItemToQueue(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:100
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:732
#define SGLTDATUM(x, s)
MemoryContext traversalCxt
void * traversalValue
Definition: spgist.h:179
ItemPointerData heapPtr
static SpGistSearchItem * spgNewHeapItem(SpGistScanOpaque so, int level, ItemPointer heapPtr, Datum leafValue, bool recheck, bool recheckDistances, bool isnull, double *distances)
Definition: spgscan.c:410

◆ spgMakeInnerItem()

static SpGistSearchItem* spgMakeInnerItem ( SpGistScanOpaque  so,
SpGistSearchItem parentItem,
SpGistNodeTuple  tuple,
spgInnerConsistentOut out,
int  i,
bool  isnull,
double *  distances 
)
static

Definition at line 548 of file spgscan.c.

References SpGistTypeDesc::attbyval, SpGistState::attLeafType, SpGistTypeDesc::attlen, datumCopy(), SpGistSearchItem::heapPtr, i, SpGistSearchItem::isLeaf, SpGistSearchItem::level, spgInnerConsistentOut::levelAdds, SpGistSearchItem::recheck, SpGistSearchItem::recheckDistances, spgInnerConsistentOut::reconstructedValues, spgAllocSearchItem(), SpGistScanOpaqueData::state, IndexTupleData::t_tid, SpGistSearchItem::traversalValue, spgInnerConsistentOut::traversalValues, and SpGistSearchItem::value.

Referenced by spgInnerTest().

553 {
554  SpGistSearchItem *item = spgAllocSearchItem(so, isnull, distances);
555 
556  item->heapPtr = tuple->t_tid;
557  item->level = out->levelAdds ? parentItem->level + out->levelAdds[i]
558  : parentItem->level;
559 
560  /* Must copy value out of temp context */
561  item->value = out->reconstructedValues
565  : (Datum) 0;
566 
567  /*
568  * Elements of out.traversalValues should be allocated in
569  * in.traversalMemoryContext, which is actually a long lived context of
570  * index scan.
571  */
572  item->traversalValue =
573  out->traversalValues ? out->traversalValues[i] : NULL;
574 
575  item->isLeaf = false;
576  item->recheck = false;
577  item->recheckDistances = false;
578 
579  return item;
580 }
SpGistTypeDesc attLeafType
ItemPointerData t_tid
Definition: itup.h:37
static SpGistSearchItem * spgAllocSearchItem(SpGistScanOpaque so, bool isnull, double *distances)
Definition: spgscan.c:106
void ** traversalValues
Definition: spgist.h:163
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
uintptr_t Datum
Definition: postgres.h:367
ItemPointerData heapPtr
Datum * reconstructedValues
Definition: spgist.h:162
int i

◆ spgNewHeapItem()

static SpGistSearchItem* spgNewHeapItem ( SpGistScanOpaque  so,
int  level,
ItemPointer  heapPtr,
Datum  leafValue,
bool  recheck,
bool  recheckDistances,
bool  isnull,
double *  distances 
)
static

Definition at line 410 of file spgscan.c.

References SpGistTypeDesc::attbyval, SpGistState::attLeafType, SpGistTypeDesc::attlen, datumCopy(), SpGistSearchItem::heapPtr, SpGistSearchItem::isLeaf, SpGistSearchItem::level, SpGistSearchItem::recheck, SpGistSearchItem::recheckDistances, spgAllocSearchItem(), SpGistScanOpaqueData::state, SpGistSearchItem::traversalValue, and SpGistSearchItem::value.

Referenced by spgLeafTest().

413 {
414  SpGistSearchItem *item = spgAllocSearchItem(so, isnull, distances);
415 
416  item->level = level;
417  item->heapPtr = *heapPtr;
418  /* copy value to queue cxt out of tmp cxt */
419  item->value = isnull ? (Datum) 0 :
420  datumCopy(leafValue, so->state.attLeafType.attbyval,
421  so->state.attLeafType.attlen);
422  item->traversalValue = NULL;
423  item->isLeaf = true;
424  item->recheck = recheck;
425  item->recheckDistances = recheckDistances;
426 
427  return item;
428 }
SpGistTypeDesc attLeafType
static SpGistSearchItem * spgAllocSearchItem(SpGistScanOpaque so, bool isnull, double *distances)
Definition: spgscan.c:106
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
uintptr_t Datum
Definition: postgres.h:367
ItemPointerData heapPtr

◆ spgPrepareScanKeys()

static void spgPrepareScanKeys ( IndexScanDesc  scan)
static

Definition at line 199 of file spgscan.c.

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

Referenced by spgrescan().

200 {
202  bool qual_ok;
203  bool haveIsNull;
204  bool haveNotNull;
205  int nkeys;
206  int i;
207 
209  so->orderByData = scan->orderByData;
210 
211  if (scan->numberOfKeys <= 0)
212  {
213  /* If no quals, whole-index scan is required */
214  so->searchNulls = true;
215  so->searchNonNulls = true;
216  so->numberOfKeys = 0;
217  return;
218  }
219 
220  /* Examine the given quals */
221  qual_ok = true;
222  haveIsNull = haveNotNull = false;
223  nkeys = 0;
224  for (i = 0; i < scan->numberOfKeys; i++)
225  {
226  ScanKey skey = &scan->keyData[i];
227 
228  if (skey->sk_flags & SK_SEARCHNULL)
229  haveIsNull = true;
230  else if (skey->sk_flags & SK_SEARCHNOTNULL)
231  haveNotNull = true;
232  else if (skey->sk_flags & SK_ISNULL)
233  {
234  /* ordinary qual with null argument - unsatisfiable */
235  qual_ok = false;
236  break;
237  }
238  else
239  {
240  /* ordinary qual, propagate into so->keyData */
241  so->keyData[nkeys++] = *skey;
242  /* this effectively creates a not-null requirement */
243  haveNotNull = true;
244  }
245  }
246 
247  /* IS NULL in combination with something else is unsatisfiable */
248  if (haveIsNull && haveNotNull)
249  qual_ok = false;
250 
251  /* Emit results */
252  if (qual_ok)
253  {
254  so->searchNulls = haveIsNull;
255  so->searchNonNulls = haveNotNull;
256  so->numberOfKeys = nkeys;
257  }
258  else
259  {
260  so->searchNulls = false;
261  so->searchNonNulls = false;
262  so->numberOfKeys = 0;
263  }
264 }
struct ScanKeyData * orderByData
Definition: relscan.h:108
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_ISNULL
Definition: skey.h:115
SpGistScanOpaqueData * SpGistScanOpaque
int sk_flags
Definition: skey.h:66
struct ScanKeyData * keyData
Definition: relscan.h:107
int i
int numberOfOrderBys
Definition: relscan.h:106
#define SK_SEARCHNULL
Definition: skey.h:121

◆ spgrescan()

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

Definition at line 335 of file spgscan.c.

References FmgrInfo::fn_oid, get_func_rettype(), i, IndexScanDescData::keyData, memmove, IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, IndexScanDescData::orderByData, SpGistScanOpaqueData::orderByTypes, resetSpGistScanOpaque(), ScanKeyData::sk_func, and spgPrepareScanKeys().

Referenced by spghandler().

337 {
339 
340  /* copy scankeys into local storage */
341  if (scankey && scan->numberOfKeys > 0)
342  memmove(scan->keyData, scankey,
343  scan->numberOfKeys * sizeof(ScanKeyData));
344 
345  /* initialize order-by data if needed */
346  if (orderbys && scan->numberOfOrderBys > 0)
347  {
348  int i;
349 
350  memmove(scan->orderByData, orderbys,
351  scan->numberOfOrderBys * sizeof(ScanKeyData));
352 
353  for (i = 0; i < scan->numberOfOrderBys; i++)
354  {
355  ScanKey skey = &scan->orderByData[i];
356 
357  /*
358  * Look up the datatype returned by the original ordering
359  * operator. SP-GiST always uses a float8 for the distance
360  * function, but the ordering operator could be anything else.
361  *
362  * XXX: The distance function is only allowed to be lossy if the
363  * ordering operator's result type is float4 or float8. Otherwise
364  * we don't know how to return the distance to the executor. But
365  * we cannot check that here, as we won't know if the distance
366  * function is lossy until it returns *recheck = true for the
367  * first time.
368  */
370  }
371  }
372 
373  /* preprocess scankeys, set up the representation in *so */
374  spgPrepareScanKeys(scan);
375 
376  /* set up starting queue entries */
378 }
struct ScanKeyData * orderByData
Definition: relscan.h:108
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1457
#define memmove(d, s, c)
Definition: c.h:1238
static void spgPrepareScanKeys(IndexScanDesc scan)
Definition: spgscan.c:199
FmgrInfo sk_func
Definition: skey.h:71
SpGistScanOpaqueData * SpGistScanOpaque
Oid fn_oid
Definition: fmgr.h:59
static void resetSpGistScanOpaque(SpGistScanOpaque so)
Definition: spgscan.c:145
struct ScanKeyData * keyData
Definition: relscan.h:107
int i
int numberOfOrderBys
Definition: relscan.h:106

◆ spgTestLeafTuple()

static OffsetNumber spgTestLeafTuple ( SpGistScanOpaque  so,
SpGistSearchItem item,
Page  page,
OffsetNumber  offset,
bool  isnull,
bool  isroot,
bool reportedSome,
storeRes_func  storeRes 
)
static

Definition at line 680 of file spgscan.c.

References Assert, elog, ERROR, SpGistSearchItem::heapPtr, SpGistLeafTupleData::heapPtr, InvalidOffsetNumber, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, SpGistLeafTupleData::nextOffset, PageGetItem, PageGetItemId, SPGIST_DEAD, SPGIST_LIVE, SPGIST_METAPAGE_BLKNO, SPGIST_REDIRECT, SpGistBreakOffsetNumber, SpGistErrorOffsetNumber, SpGistRedirectOffsetNumber, spgLeafTest(), and SpGistLeafTupleData::tupstate.

Referenced by spgWalk().

686 {
687  SpGistLeafTuple leafTuple = (SpGistLeafTuple)
688  PageGetItem(page, PageGetItemId(page, offset));
689 
690  if (leafTuple->tupstate != SPGIST_LIVE)
691  {
692  if (!isroot) /* all tuples on root should be live */
693  {
694  if (leafTuple->tupstate == SPGIST_REDIRECT)
695  {
696  /* redirection tuple should be first in chain */
697  Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
698  /* transfer attention to redirect point */
699  item->heapPtr = ((SpGistDeadTuple) leafTuple)->pointer;
702  }
703 
704  if (leafTuple->tupstate == SPGIST_DEAD)
705  {
706  /* dead tuple should be first in chain */
707  Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
708  /* No live entries on this page */
709  Assert(leafTuple->nextOffset == InvalidOffsetNumber);
711  }
712  }
713 
714  /* We should not arrive at a placeholder */
715  elog(ERROR, "unexpected SPGiST tuple state: %d", leafTuple->tupstate);
717  }
718 
719  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
720 
721  spgLeafTest(so, item, leafTuple, isnull, reportedSome, storeRes);
722 
723  return leafTuple->nextOffset;
724 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define SPGIST_DEAD
#define SPGIST_REDIRECT
#define ERROR
Definition: elog.h:43
#define SPGIST_METAPAGE_BLKNO
SpGistDeadTupleData * SpGistDeadTuple
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
unsigned int tupstate
#define InvalidOffsetNumber
Definition: off.h:26
ItemPointerData heapPtr
#define Assert(condition)
Definition: c.h:732
#define SPGIST_LIVE
OffsetNumber nextOffset
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define elog(elevel,...)
Definition: elog.h:226
static bool spgLeafTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistLeafTuple leafTuple, bool isnull, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:437
ItemPointerData heapPtr
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
SpGistLeafTupleData * SpGistLeafTuple
#define PageGetItem(page, itemId)
Definition: bufpage.h:340

◆ spgWalk()

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

Definition at line 734 of file spgscan.c.

References Assert, BUFFER_LOCK_SHARE, BufferGetBlockNumber(), BufferGetPage, CHECK_FOR_INTERRUPTS, SpGistSearchItem::distances, elog, ERROR, FirstOffsetNumber, SpGistSearchItem::heapPtr, InvalidBuffer, InvalidOffsetNumber, SpGistSearchItem::isLeaf, SpGistSearchItem::isNull, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, LockBuffer(), MemoryContextReset(), SpGistScanOpaqueData::numberOfOrderBys, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, ReadBuffer(), SpGistSearchItem::recheck, SpGistSearchItem::recheckDistances, spgFreeSearchItem(), spgGetNextQueueItem(), spgInnerTest(), SPGIST_LIVE, SPGIST_METAPAGE_BLKNO, SPGIST_REDIRECT, SpGistBlockIsRoot, SpGistPageIsLeaf, SpGistPageStoresNulls, SpGistRedirectOffsetNumber, spgTestLeafTuple(), SpGistScanOpaqueData::tempCxt, TestForOldSnapshot(), true, SpGistInnerTupleData::tupstate, UnlockReleaseBuffer(), and SpGistSearchItem::value.

Referenced by spggetbitmap(), and spggettuple().

736 {
737  Buffer buffer = InvalidBuffer;
738  bool reportedSome = false;
739 
740  while (scanWholeIndex || !reportedSome)
741  {
743 
744  if (item == NULL)
745  break; /* No more items in queue -> done */
746 
747 redirect:
748  /* Check for interrupts, just in case of infinite loop */
750 
751  if (item->isLeaf)
752  {
753  /* We store heap items in the queue only in case of ordered search */
754  Assert(so->numberOfOrderBys > 0);
755  storeRes(so, &item->heapPtr, item->value, item->isNull,
756  item->recheck, item->recheckDistances, item->distances);
757  reportedSome = true;
758  }
759  else
760  {
763  Page page;
764  bool isnull;
765 
766  if (buffer == InvalidBuffer)
767  {
768  buffer = ReadBuffer(index, blkno);
769  LockBuffer(buffer, BUFFER_LOCK_SHARE);
770  }
771  else if (blkno != BufferGetBlockNumber(buffer))
772  {
773  UnlockReleaseBuffer(buffer);
774  buffer = ReadBuffer(index, blkno);
775  LockBuffer(buffer, BUFFER_LOCK_SHARE);
776  }
777 
778  /* else new pointer points to the same page, no work needed */
779 
780  page = BufferGetPage(buffer);
781  TestForOldSnapshot(snapshot, index, page);
782 
783  isnull = SpGistPageStoresNulls(page) ? true : false;
784 
785  if (SpGistPageIsLeaf(page))
786  {
787  /* Page is a leaf - that is, all it's tuples are heap items */
789 
790  if (SpGistBlockIsRoot(blkno))
791  {
792  /* When root is a leaf, examine all its tuples */
793  for (offset = FirstOffsetNumber; offset <= max; offset++)
794  (void) spgTestLeafTuple(so, item, page, offset,
795  isnull, true,
796  &reportedSome, storeRes);
797  }
798  else
799  {
800  /* Normal case: just examine the chain we arrived at */
801  while (offset != InvalidOffsetNumber)
802  {
803  Assert(offset >= FirstOffsetNumber && offset <= max);
804  offset = spgTestLeafTuple(so, item, page, offset,
805  isnull, false,
806  &reportedSome, storeRes);
807  if (offset == SpGistRedirectOffsetNumber)
808  goto redirect;
809  }
810  }
811  }
812  else /* page is inner */
813  {
814  SpGistInnerTuple innerTuple = (SpGistInnerTuple)
815  PageGetItem(page, PageGetItemId(page, offset));
816 
817  if (innerTuple->tupstate != SPGIST_LIVE)
818  {
819  if (innerTuple->tupstate == SPGIST_REDIRECT)
820  {
821  /* transfer attention to redirect point */
822  item->heapPtr = ((SpGistDeadTuple) innerTuple)->pointer;
825  goto redirect;
826  }
827  elog(ERROR, "unexpected SPGiST tuple state: %d",
828  innerTuple->tupstate);
829  }
830 
831  spgInnerTest(so, item, innerTuple, isnull);
832  }
833  }
834 
835  /* done with this scan item */
836  spgFreeSearchItem(so, item);
837  /* clear temp context before proceeding to the next one */
839  }
840 
841  if (buffer != InvalidBuffer)
842  UnlockReleaseBuffer(buffer);
843 }
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:264
SpGistInnerTupleData * SpGistInnerTuple
#define SpGistPageIsLeaf(page)
#define SPGIST_REDIRECT
#define InvalidBuffer
Definition: buf.h:25
static SpGistSearchItem * spgGetNextQueueItem(SpGistScanOpaque so)
Definition: spgscan.c:663
MemoryContext tempCxt
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define true
Definition: c.h:312
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3376
#define ERROR
Definition: elog.h:43
static OffsetNumber spgTestLeafTuple(SpGistScanOpaque so, SpGistSearchItem *item, Page page, OffsetNumber offset, bool isnull, bool isroot, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:680
#define FirstOffsetNumber
Definition: off.h:27
#define SPGIST_METAPAGE_BLKNO
SpGistDeadTupleData * SpGistDeadTuple
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3590
static void spgInnerTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple, bool isnull)
Definition: spgscan.c:583
#define InvalidOffsetNumber
Definition: off.h:26
double distances[FLEXIBLE_ARRAY_MEMBER]
#define SpGistPageStoresNulls(page)
ItemPointerData heapPtr
#define Assert(condition)
Definition: c.h:732
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define SpGistBlockIsRoot(blkno)
#define SPGIST_LIVE
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
#define elog(elevel,...)
Definition: elog.h:226
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:87
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
static void spgFreeSearchItem(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:82

◆ storeBitmap()

static void storeBitmap ( SpGistScanOpaque  so,
ItemPointer  heapPtr,
Datum  leafValue,
bool  isnull,
bool  recheck,
bool  recheckDistances,
double *  distances 
)
static

Definition at line 848 of file spgscan.c.

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

Referenced by spggetbitmap().

851 {
852  Assert(!recheckDistances && !distances);
853  tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
854  so->ntids++;
855 }
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
#define Assert(condition)
Definition: c.h:732

◆ storeGettuple()

static void storeGettuple ( SpGistScanOpaque  so,
ItemPointer  heapPtr,
Datum  leafValue,
bool  isnull,
bool  recheck,
bool  recheckDistances,
double *  distances 
)
static

Definition at line 875 of file spgscan.c.

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

Referenced by spggettuple().

878 {
880  so->heapPtrs[so->nPtrs] = *heapPtr;
881  so->recheck[so->nPtrs] = recheck;
882  so->recheckDistances[so->nPtrs] = recheckDistances;
883 
884  if (so->numberOfOrderBys > 0)
885  {
886  if (isnull)
887  so->distances[so->nPtrs] = NULL;
888  else
889  {
890  Size size = sizeof(double) * so->numberOfOrderBys;
891 
892  so->distances[so->nPtrs] = memcpy(palloc(size), distances, size);
893  }
894  }
895 
896  if (so->want_itup)
897  {
898  /*
899  * Reconstruct index data. We have to copy the datum out of the temp
900  * context anyway, so we may as well create the tuple here.
901  */
903  &leafValue,
904  &isnull);
905  }
906  so->nPtrs++;
907 }
bool recheckDistances[MaxIndexTuplesPerPage]
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTuple reconTups[MaxIndexTuplesPerPage]
double * distances[MaxIndexTuplesPerPage]
bool recheck[MaxIndexTuplesPerPage]
#define Assert(condition)
Definition: c.h:732
size_t Size
Definition: c.h:466
#define MaxIndexTuplesPerPage
Definition: itup.h:145
void * palloc(Size size)
Definition: mcxt.c:924