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 *nonNullDistances)
 
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 702 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::numberOfNonNullOrderBys.

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->numberOfNonNullOrderBys; 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 }
IndexOrderByDistance * distances[MaxIndexTuplesPerPage]
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:1056
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::numberOfNonNullOrderBys, 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->numberOfNonNullOrderBys > 0)
115  memcpy(item->distances, distances,
116  sizeof(item->distances[0]) * so->numberOfNonNullOrderBys);
117 
118  return item;
119 }
#define SizeOfSpGistSearchItem(n_distances)
double distances[FLEXIBLE_ARRAY_MEMBER]
void * palloc(Size size)
Definition: mcxt.c:949

◆ spgbeginscan()

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

Definition at line 295 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, SpGistScanOpaqueData::nonNullOrderByOffsets, 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().

296 {
297  IndexScanDesc scan;
298  SpGistScanOpaque so;
299  int i;
300 
301  scan = RelationGetIndexScan(rel, keysz, orderbysz);
302 
304  if (keysz > 0)
305  so->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * keysz);
306  else
307  so->keyData = NULL;
308  initSpGistState(&so->state, scan->indexRelation);
309 
311  "SP-GiST search temporary context",
314  "SP-GiST traversal-value context",
316 
317  /* Set up indexTupDesc and xs_hitupdesc in case it's an index-only scan */
318  so->indexTupDesc = scan->xs_hitupdesc = RelationGetDescr(rel);
319 
320  /* Allocate various arrays needed for order-by scans */
321  if (scan->numberOfOrderBys > 0)
322  {
323  /* This will be filled in spgrescan, but allocate the space here */
324  so->orderByTypes = (Oid *)
325  palloc(sizeof(Oid) * scan->numberOfOrderBys);
326  so->nonNullOrderByOffsets = (int *)
327  palloc(sizeof(int) * scan->numberOfOrderBys);
328 
329  /* These arrays have constant contents, so we can fill them now */
330  so->zeroDistances = (double *)
331  palloc(sizeof(double) * scan->numberOfOrderBys);
332  so->infDistances = (double *)
333  palloc(sizeof(double) * scan->numberOfOrderBys);
334 
335  for (i = 0; i < scan->numberOfOrderBys; i++)
336  {
337  so->zeroDistances[i] = 0.0;
339  }
340 
341  scan->xs_orderbyvals = (Datum *)
342  palloc0(sizeof(Datum) * scan->numberOfOrderBys);
343  scan->xs_orderbynulls = (bool *)
344  palloc(sizeof(bool) * scan->numberOfOrderBys);
345  memset(scan->xs_orderbynulls, true,
346  sizeof(bool) * scan->numberOfOrderBys);
347  }
348 
352 
356 
357  so->indexCollation = rel->rd_indcollation[0];
358 
359  scan->opaque = so;
360 
361  return scan;
362 }
#define AllocSetContextCreate
Definition: memutils.h:170
static float8 get_float8_infinity(void)
Definition: float.h:93
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:27
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:794
#define RelationGetDescr(relation)
Definition: rel.h:454
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:174
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
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:185
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
SpGistScanOpaqueData * SpGistScanOpaque
MemoryContext traversalCxt
void * palloc(Size size)
Definition: mcxt.c:949
int i
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:26
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 1018 of file spgscan.c.

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

Referenced by spghandler().

1019 {
1020  SpGistCache *cache;
1021 
1022  /* We can do it if the opclass config function says so */
1023  cache = spgGetCache(index);
1024 
1025  return cache->config.canReturnData;
1026 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:103
bool canReturnData
Definition: spgist.h:45
spgConfigOut config

◆ spgendscan()

void spgendscan ( IndexScanDesc  scan)

Definition at line 411 of file spgscan.c.

References SpGistState::deadTupleStorage, SpGistScanOpaqueData::infDistances, SpGistScanOpaqueData::keyData, MemoryContextDelete(), SpGistScanOpaqueData::nonNullOrderByOffsets, 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().

412 {
414 
417 
418  if (so->keyData)
419  pfree(so->keyData);
420 
421  if (so->state.deadTupleStorage)
423 
424  if (scan->numberOfOrderBys > 0)
425  {
426  pfree(so->orderByTypes);
428  pfree(so->zeroDistances);
429  pfree(so->infDistances);
430  pfree(scan->xs_orderbyvals);
431  pfree(scan->xs_orderbynulls);
432  }
433 
434  pfree(so);
435 }
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:1056
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:1056
#define DatumGetPointer(X)
Definition: postgres.h:549

◆ spggetbitmap()

int64 spggetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

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

889 {
891 
892  /* Copy want_itup to *so so we don't need to pass it around separately */
893  so->want_itup = false;
894 
895  so->tbm = tbm;
896  so->ntids = 0;
897 
898  spgWalk(scan->indexRelation, so, true, storeBitmap, scan->xs_snapshot);
899 
900  return so->ntids;
901 }
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:764
static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck, bool recheckDistances, double *distances)
Definition: spgscan.c:878

◆ spgGetNextQueueItem()

static SpGistSearchItem* spgGetNextQueueItem ( SpGistScanOpaque  so)
static

Definition at line 693 of file spgscan.c.

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

Referenced by spgWalk().

694 {
696  return NULL; /* Done when both heaps are empty */
697 
698  /* Return item; caller is responsible to pfree it */
700 }
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 960 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().

961 {
963 
964  if (dir != ForwardScanDirection)
965  elog(ERROR, "SP-GiST only supports forward scan direction");
966 
967  /* Copy want_itup to *so so we don't need to pass it around separately */
968  so->want_itup = scan->xs_want_itup;
969 
970  for (;;)
971  {
972  if (so->iPtr < so->nPtrs)
973  {
974  /* continuing to return reported tuples */
975  scan->xs_heaptid = so->heapPtrs[so->iPtr];
976  scan->xs_recheck = so->recheck[so->iPtr];
977  scan->xs_hitup = so->reconTups[so->iPtr];
978 
979  if (so->numberOfOrderBys > 0)
981  so->distances[so->iPtr],
982  so->recheckDistances[so->iPtr]);
983  so->iPtr++;
984  return true;
985  }
986 
987  if (so->numberOfOrderBys > 0)
988  {
989  /* Must pfree distances to avoid memory leak */
990  int i;
991 
992  for (i = 0; i < so->nPtrs; i++)
993  if (so->distances[i])
994  pfree(so->distances[i]);
995  }
996 
997  if (so->want_itup)
998  {
999  /* Must pfree reconstructed tuples to avoid memory leak */
1000  int i;
1001 
1002  for (i = 0; i < so->nPtrs; i++)
1003  pfree(so->reconTups[i]);
1004  }
1005  so->iPtr = so->nPtrs = 0;
1006 
1007  spgWalk(scan->indexRelation, so, false, storeGettuple,
1008  scan->xs_snapshot);
1009 
1010  if (so->nPtrs == 0)
1011  break; /* must have completed scan */
1012  }
1013 
1014  return false;
1015 }
IndexOrderByDistance * distances[MaxIndexTuplesPerPage]
bool recheckDistances[MaxIndexTuplesPerPage]
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
struct SnapshotData * xs_snapshot
Definition: relscan.h:104
HeapTuple reconTups[MaxIndexTuplesPerPage]
Relation indexRelation
Definition: relscan.h:103
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
ItemPointerData xs_heaptid
Definition: relscan.h:132
bool recheck[MaxIndexTuplesPerPage]
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:849
SpGistScanOpaqueData * SpGistScanOpaque
static void storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck, bool recheckDistances, double *nonNullDistances)
Definition: spgscan.c:905
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:764
HeapTuple xs_hitup
Definition: relscan.h:129
#define elog(elevel,...)
Definition: elog.h:228
int i

◆ spgInitInnerConsistentIn()

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

Definition at line 557 of file spgscan.c.

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

Referenced by spgInnerTest().

561 {
562  in->scankeys = so->keyData;
563  in->orderbys = so->orderByData;
564  in->nkeys = so->numberOfKeys;
566  in->reconstructedValue = item->value;
568  in->traversalValue = item->traversalValue;
569  in->level = item->level;
570  in->returnData = so->want_itup;
571  in->allTheSame = innerTuple->allTheSame;
572  in->hasPrefix = (innerTuple->prefixSize > 0);
573  in->prefixDatum = SGITDATUM(innerTuple, &so->state);
574  in->nNodes = innerTuple->nNodes;
575  in->nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);
576 }
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:839
ScanKey orderbys
Definition: spgist.h:134
void * traversalValue
Definition: spgist.h:140
Datum reconstructedValue
Definition: spgist.h:139
#define SGITDATUM(x, s)
unsigned int allTheSame
MemoryContext traversalMemoryContext
Definition: spgist.h:141
unsigned int prefixSize
Datum * nodeLabels
Definition: spgist.h:150
ScanKey scankeys
Definition: spgist.h:133
MemoryContext traversalCxt

◆ spgInnerTest()

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

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

616 {
619  int nNodes = innerTuple->nNodes;
620  int i;
621 
622  memset(&out, 0, sizeof(out));
623 
624  if (!isnull)
625  {
627 
628  spgInitInnerConsistentIn(&in, so, item, innerTuple);
629 
630  /* use user-defined inner consistent method */
632  so->indexCollation,
633  PointerGetDatum(&in),
634  PointerGetDatum(&out));
635  }
636  else
637  {
638  /* force all children to be visited */
639  out.nNodes = nNodes;
640  out.nodeNumbers = (int *) palloc(sizeof(int) * nNodes);
641  for (i = 0; i < nNodes; i++)
642  out.nodeNumbers[i] = i;
643  }
644 
645  /* If allTheSame, they should all or none of them match */
646  if (innerTuple->allTheSame && out.nNodes != 0 && out.nNodes != nNodes)
647  elog(ERROR, "inconsistent inner_consistent results for allTheSame inner tuple");
648 
649  if (out.nNodes)
650  {
651  /* collect node pointers */
652  SpGistNodeTuple node;
653  SpGistNodeTuple *nodes = (SpGistNodeTuple *) palloc(sizeof(SpGistNodeTuple) * nNodes);
654 
655  SGITITERATE(innerTuple, i, node)
656  {
657  nodes[i] = node;
658  }
659 
661 
662  for (i = 0; i < out.nNodes; i++)
663  {
664  int nodeN = out.nodeNumbers[i];
665  SpGistSearchItem *innerItem;
666  double *distances;
667 
668  Assert(nodeN >= 0 && nodeN < nNodes);
669 
670  node = nodes[nodeN];
671 
672  if (!ItemPointerIsValid(&node->t_tid))
673  continue;
674 
675  /*
676  * Use infinity distances if innerConsistentFn() failed to return
677  * them or if is a NULL item (their distances are really unused).
678  */
679  distances = out.distances ? out.distances[i] : so->infDistances;
680 
681  innerItem = spgMakeInnerItem(so, item, node, &out, i, isnull,
682  distances);
683 
684  spgAddSearchItemToQueue(so, innerItem);
685  }
686  }
687 
688  MemoryContextSwitchTo(oldCxt);
689 }
#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:579
static void spgAddSearchItemToQueue(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:100
double ** distances
Definition: spgist.h:160
#define Assert(condition)
Definition: c.h:738
static void spgInitInnerConsistentIn(spgInnerConsistentIn *in, SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple)
Definition: spgscan.c:557
MemoryContext traversalCxt
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
int i

◆ spgLeafTest()

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

Definition at line 468 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::numberOfNonNullOrderBys, 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().

471 {
472  Datum leafValue;
473  double *distances;
474  bool result;
475  bool recheck;
476  bool recheckDistances;
477 
478  if (isnull)
479  {
480  /* Should not have arrived on a nulls page unless nulls are wanted */
481  Assert(so->searchNulls);
482  leafValue = (Datum) 0;
483  distances = NULL;
484  recheck = false;
485  recheckDistances = false;
486  result = true;
487  }
488  else
489  {
492 
493  /* use temp context for calling leaf_consistent */
495 
496  in.scankeys = so->keyData;
497  in.nkeys = so->numberOfKeys;
498  in.orderbys = so->orderByData;
500  in.reconstructedValue = item->value;
501  in.traversalValue = item->traversalValue;
502  in.level = item->level;
503  in.returnData = so->want_itup;
504  in.leafDatum = SGLTDATUM(leafTuple, &so->state);
505 
506  out.leafValue = (Datum) 0;
507  out.recheck = false;
508  out.distances = NULL;
509  out.recheckDistances = false;
510 
512  so->indexCollation,
513  PointerGetDatum(&in),
514  PointerGetDatum(&out)));
515  recheck = out.recheck;
516  recheckDistances = out.recheckDistances;
517  leafValue = out.leafValue;
518  distances = out.distances;
519 
520  MemoryContextSwitchTo(oldCxt);
521  }
522 
523  if (result)
524  {
525  /* item passes the scankeys */
526  if (so->numberOfNonNullOrderBys > 0)
527  {
528  /* the scan is ordered -> add the item to the queue */
530  SpGistSearchItem *heapItem = spgNewHeapItem(so, item->level,
531  &leafTuple->heapPtr,
532  leafValue,
533  recheck,
534  recheckDistances,
535  isnull,
536  distances);
537 
538  spgAddSearchItemToQueue(so, heapItem);
539 
540  MemoryContextSwitchTo(oldCxt);
541  }
542  else
543  {
544  /* non-ordered scan, so report the item right away */
545  Assert(!recheckDistances);
546  storeRes(so, &leafTuple->heapPtr, leafValue, isnull,
547  recheck, false, NULL);
548  *reportedSome = true;
549  }
550  }
551 
552  return result;
553 }
Datum reconstructedValue
Definition: spgist.h:174
#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:169
ScanKey scankeys
Definition: spgist.h:168
double * distances
Definition: spgist.h:187
#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:738
#define SGLTDATUM(x, s)
MemoryContext traversalCxt
void * traversalValue
Definition: spgist.h:175
ItemPointerData heapPtr
static SpGistSearchItem * spgNewHeapItem(SpGistScanOpaque so, int level, ItemPointer heapPtr, Datum leafValue, bool recheck, bool recheckDistances, bool isnull, double *distances)
Definition: spgscan.c:441

◆ spgMakeInnerItem()

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

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

584 {
585  SpGistSearchItem *item = spgAllocSearchItem(so, isnull, distances);
586 
587  item->heapPtr = tuple->t_tid;
588  item->level = out->levelAdds ? parentItem->level + out->levelAdds[i]
589  : parentItem->level;
590 
591  /* Must copy value out of temp context */
592  item->value = out->reconstructedValues
596  : (Datum) 0;
597 
598  /*
599  * Elements of out.traversalValues should be allocated in
600  * in.traversalMemoryContext, which is actually a long lived context of
601  * index scan.
602  */
603  item->traversalValue =
604  out->traversalValues ? out->traversalValues[i] : NULL;
605 
606  item->isLeaf = false;
607  item->recheck = false;
608  item->recheckDistances = false;
609 
610  return item;
611 }
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:159
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:158
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 441 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().

444 {
445  SpGistSearchItem *item = spgAllocSearchItem(so, isnull, distances);
446 
447  item->level = level;
448  item->heapPtr = *heapPtr;
449  /* copy value to queue cxt out of tmp cxt */
450  item->value = isnull ? (Datum) 0 :
451  datumCopy(leafValue, so->state.attLeafType.attbyval,
452  so->state.attLeafType.attlen);
453  item->traversalValue = NULL;
454  item->isLeaf = true;
455  item->recheck = recheck;
456  item->recheckDistances = recheckDistances;
457 
458  return item;
459 }
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, SpGistScanOpaqueData::nonNullOrderByOffsets, IndexScanDescData::numberOfKeys, SpGistScanOpaqueData::numberOfKeys, SpGistScanOpaqueData::numberOfNonNullOrderBys, 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 (so->numberOfOrderBys <= 0)
212  so->numberOfNonNullOrderBys = 0;
213  else
214  {
215  int j = 0;
216 
217  /*
218  * Remove all NULL keys, but remember their offsets in the original
219  * array.
220  */
221  for (i = 0; i < scan->numberOfOrderBys; i++)
222  {
223  ScanKey skey = &so->orderByData[i];
224 
225  if (skey->sk_flags & SK_ISNULL)
226  so->nonNullOrderByOffsets[i] = -1;
227  else
228  {
229  if (i != j)
230  so->orderByData[j] = *skey;
231 
232  so->nonNullOrderByOffsets[i] = j++;
233  }
234  }
235 
236  so->numberOfNonNullOrderBys = j;
237  }
238 
239  if (scan->numberOfKeys <= 0)
240  {
241  /* If no quals, whole-index scan is required */
242  so->searchNulls = true;
243  so->searchNonNulls = true;
244  so->numberOfKeys = 0;
245  return;
246  }
247 
248  /* Examine the given quals */
249  qual_ok = true;
250  haveIsNull = haveNotNull = false;
251  nkeys = 0;
252  for (i = 0; i < scan->numberOfKeys; i++)
253  {
254  ScanKey skey = &scan->keyData[i];
255 
256  if (skey->sk_flags & SK_SEARCHNULL)
257  haveIsNull = true;
258  else if (skey->sk_flags & SK_SEARCHNOTNULL)
259  haveNotNull = true;
260  else if (skey->sk_flags & SK_ISNULL)
261  {
262  /* ordinary qual with null argument - unsatisfiable */
263  qual_ok = false;
264  break;
265  }
266  else
267  {
268  /* ordinary qual, propagate into so->keyData */
269  so->keyData[nkeys++] = *skey;
270  /* this effectively creates a not-null requirement */
271  haveNotNull = true;
272  }
273  }
274 
275  /* IS NULL in combination with something else is unsatisfiable */
276  if (haveIsNull && haveNotNull)
277  qual_ok = false;
278 
279  /* Emit results */
280  if (qual_ok)
281  {
282  so->searchNulls = haveIsNull;
283  so->searchNonNulls = haveNotNull;
284  so->numberOfKeys = nkeys;
285  }
286  else
287  {
288  so->searchNulls = false;
289  so->searchNonNulls = false;
290  so->numberOfKeys = 0;
291  }
292 }
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 365 of file spgscan.c.

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

Referenced by spghandler().

367 {
369 
370  /* copy scankeys into local storage */
371  if (scankey && scan->numberOfKeys > 0)
372  memmove(scan->keyData, scankey,
373  scan->numberOfKeys * sizeof(ScanKeyData));
374 
375  /* initialize order-by data if needed */
376  if (orderbys && scan->numberOfOrderBys > 0)
377  {
378  int i;
379 
380  memmove(scan->orderByData, orderbys,
381  scan->numberOfOrderBys * sizeof(ScanKeyData));
382 
383  for (i = 0; i < scan->numberOfOrderBys; i++)
384  {
385  ScanKey skey = &scan->orderByData[i];
386 
387  /*
388  * Look up the datatype returned by the original ordering
389  * operator. SP-GiST always uses a float8 for the distance
390  * function, but the ordering operator could be anything else.
391  *
392  * XXX: The distance function is only allowed to be lossy if the
393  * ordering operator's result type is float4 or float8. Otherwise
394  * we don't know how to return the distance to the executor. But
395  * we cannot check that here, as we won't know if the distance
396  * function is lossy until it returns *recheck = true for the
397  * first time.
398  */
400  }
401  }
402 
403  /* preprocess scankeys, set up the representation in *so */
404  spgPrepareScanKeys(scan);
405 
406  /* set up starting queue entries */
408 }
struct ScanKeyData * orderByData
Definition: relscan.h:108
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1457
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 710 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().

716 {
717  SpGistLeafTuple leafTuple = (SpGistLeafTuple)
718  PageGetItem(page, PageGetItemId(page, offset));
719 
720  if (leafTuple->tupstate != SPGIST_LIVE)
721  {
722  if (!isroot) /* all tuples on root should be live */
723  {
724  if (leafTuple->tupstate == SPGIST_REDIRECT)
725  {
726  /* redirection tuple should be first in chain */
727  Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
728  /* transfer attention to redirect point */
729  item->heapPtr = ((SpGistDeadTuple) leafTuple)->pointer;
732  }
733 
734  if (leafTuple->tupstate == SPGIST_DEAD)
735  {
736  /* dead tuple should be first in chain */
737  Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
738  /* No live entries on this page */
739  Assert(leafTuple->nextOffset == InvalidOffsetNumber);
741  }
742  }
743 
744  /* We should not arrive at a placeholder */
745  elog(ERROR, "unexpected SPGiST tuple state: %d", leafTuple->tupstate);
747  }
748 
749  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
750 
751  spgLeafTest(so, item, leafTuple, isnull, reportedSome, storeRes);
752 
753  return leafTuple->nextOffset;
754 }
#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:738
#define SPGIST_LIVE
OffsetNumber nextOffset
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define elog(elevel,...)
Definition: elog.h:228
static bool spgLeafTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistLeafTuple leafTuple, bool isnull, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:468
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 764 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::numberOfNonNullOrderBys, 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().

766 {
767  Buffer buffer = InvalidBuffer;
768  bool reportedSome = false;
769 
770  while (scanWholeIndex || !reportedSome)
771  {
773 
774  if (item == NULL)
775  break; /* No more items in queue -> done */
776 
777 redirect:
778  /* Check for interrupts, just in case of infinite loop */
780 
781  if (item->isLeaf)
782  {
783  /* We store heap items in the queue only in case of ordered search */
785  storeRes(so, &item->heapPtr, item->value, item->isNull,
786  item->recheck, item->recheckDistances, item->distances);
787  reportedSome = true;
788  }
789  else
790  {
793  Page page;
794  bool isnull;
795 
796  if (buffer == InvalidBuffer)
797  {
798  buffer = ReadBuffer(index, blkno);
799  LockBuffer(buffer, BUFFER_LOCK_SHARE);
800  }
801  else if (blkno != BufferGetBlockNumber(buffer))
802  {
803  UnlockReleaseBuffer(buffer);
804  buffer = ReadBuffer(index, blkno);
805  LockBuffer(buffer, BUFFER_LOCK_SHARE);
806  }
807 
808  /* else new pointer points to the same page, no work needed */
809 
810  page = BufferGetPage(buffer);
811  TestForOldSnapshot(snapshot, index, page);
812 
813  isnull = SpGistPageStoresNulls(page) ? true : false;
814 
815  if (SpGistPageIsLeaf(page))
816  {
817  /* Page is a leaf - that is, all it's tuples are heap items */
819 
820  if (SpGistBlockIsRoot(blkno))
821  {
822  /* When root is a leaf, examine all its tuples */
823  for (offset = FirstOffsetNumber; offset <= max; offset++)
824  (void) spgTestLeafTuple(so, item, page, offset,
825  isnull, true,
826  &reportedSome, storeRes);
827  }
828  else
829  {
830  /* Normal case: just examine the chain we arrived at */
831  while (offset != InvalidOffsetNumber)
832  {
833  Assert(offset >= FirstOffsetNumber && offset <= max);
834  offset = spgTestLeafTuple(so, item, page, offset,
835  isnull, false,
836  &reportedSome, storeRes);
837  if (offset == SpGistRedirectOffsetNumber)
838  goto redirect;
839  }
840  }
841  }
842  else /* page is inner */
843  {
844  SpGistInnerTuple innerTuple = (SpGistInnerTuple)
845  PageGetItem(page, PageGetItemId(page, offset));
846 
847  if (innerTuple->tupstate != SPGIST_LIVE)
848  {
849  if (innerTuple->tupstate == SPGIST_REDIRECT)
850  {
851  /* transfer attention to redirect point */
852  item->heapPtr = ((SpGistDeadTuple) innerTuple)->pointer;
855  goto redirect;
856  }
857  elog(ERROR, "unexpected SPGiST tuple state: %d",
858  innerTuple->tupstate);
859  }
860 
861  spgInnerTest(so, item, innerTuple, isnull);
862  }
863  }
864 
865  /* done with this scan item */
866  spgFreeSearchItem(so, item);
867  /* clear temp context before proceeding to the next one */
869  }
870 
871  if (buffer != InvalidBuffer)
872  UnlockReleaseBuffer(buffer);
873 }
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:693
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:321
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3398
#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:710
#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:3612
static void spgInnerTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple, bool isnull)
Definition: spgscan.c:614
#define InvalidOffsetNumber
Definition: off.h:26
double distances[FLEXIBLE_ARRAY_MEMBER]
#define SpGistPageStoresNulls(page)
ItemPointerData heapPtr
#define Assert(condition)
Definition: c.h:738
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:2623
#define elog(elevel,...)
Definition: elog.h:228
#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 878 of file spgscan.c.

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

Referenced by spggetbitmap().

881 {
882  Assert(!recheckDistances && !distances);
883  tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
884  so->ntids++;
885 }
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
#define Assert(condition)
Definition: c.h:738

◆ storeGettuple()

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

Definition at line 905 of file spgscan.c.

References Assert, SpGistScanOpaqueData::distances, heap_form_tuple(), SpGistScanOpaqueData::heapPtrs, i, SpGistScanOpaqueData::indexTupDesc, IndexOrderByDistance::isnull, MaxIndexTuplesPerPage, SpGistScanOpaqueData::nonNullOrderByOffsets, SpGistScanOpaqueData::nPtrs, SpGistScanOpaqueData::numberOfNonNullOrderBys, SpGistScanOpaqueData::numberOfOrderBys, palloc(), SpGistScanOpaqueData::recheck, SpGistScanOpaqueData::recheckDistances, SpGistScanOpaqueData::reconTups, IndexOrderByDistance::value, and SpGistScanOpaqueData::want_itup.

Referenced by spggettuple().

908 {
910  so->heapPtrs[so->nPtrs] = *heapPtr;
911  so->recheck[so->nPtrs] = recheck;
912  so->recheckDistances[so->nPtrs] = recheckDistances;
913 
914  if (so->numberOfOrderBys > 0)
915  {
916  if (isnull || so->numberOfNonNullOrderBys <= 0)
917  so->distances[so->nPtrs] = NULL;
918  else
919  {
920  IndexOrderByDistance *distances =
921  palloc(sizeof(distances[0]) * so->numberOfOrderBys);
922  int i;
923 
924  for (i = 0; i < so->numberOfOrderBys; i++)
925  {
926  int offset = so->nonNullOrderByOffsets[i];
927 
928  if (offset >= 0)
929  {
930  /* Copy non-NULL distance value */
931  distances[i].value = nonNullDistances[offset];
932  distances[i].isnull = false;
933  }
934  else
935  {
936  /* Set distance's NULL flag. */
937  distances[i].value = 0.0;
938  distances[i].isnull = true;
939  }
940  }
941 
942  so->distances[so->nPtrs] = distances;
943  }
944  }
945 
946  if (so->want_itup)
947  {
948  /*
949  * Reconstruct index data. We have to copy the datum out of the temp
950  * context anyway, so we may as well create the tuple here.
951  */
953  &leafValue,
954  &isnull);
955  }
956  so->nPtrs++;
957 }
IndexOrderByDistance * distances[MaxIndexTuplesPerPage]
bool recheckDistances[MaxIndexTuplesPerPage]
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTuple reconTups[MaxIndexTuplesPerPage]
bool recheck[MaxIndexTuplesPerPage]
#define Assert(condition)
Definition: c.h:738
#define MaxIndexTuplesPerPage
Definition: itup.h:145
void * palloc(Size size)
Definition: mcxt.c:949
int i