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, SpGistLeafTuple leafTuple, 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, SpGistLeafTuple leafTuple, 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, SpGistLeafTuple leafTuple, bool recheck, bool recheckDistances, double *distances)
 
int64 spggetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
static void storeGettuple (SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, SpGistLeafTuple leafTuple, 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, SpGistLeafTuple leafTuple, 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 751 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 40 of file spgscan.c.

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

Referenced by resetSpGistScanOpaque().

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

◆ resetSpGistScanOpaque()

static void resetSpGistScanOpaque ( SpGistScanOpaque  so)
static

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

154 {
155  MemoryContext oldCtx;
156 
158 
159  oldCtx = MemoryContextSwitchTo(so->traversalCxt);
160 
161  /* initialize queue only for distance-ordered scans */
163 
164  if (so->searchNulls)
165  /* Add a work item to scan the null index entries */
166  spgAddStartItem(so, true);
167 
168  if (so->searchNonNulls)
169  /* Add a work item to scan the non-null index entries */
170  spgAddStartItem(so, false);
171 
172  MemoryContextSwitchTo(oldCtx);
173 
174  if (so->numberOfOrderBys > 0)
175  {
176  /* Must pfree distances to avoid memory leak */
177  int i;
178 
179  for (i = 0; i < so->nPtrs; i++)
180  if (so->distances[i])
181  pfree(so->distances[i]);
182  }
183 
184  if (so->want_itup)
185  {
186  /* Must pfree reconstructed tuples to avoid memory leak */
187  int i;
188 
189  for (i = 0; i < so->nPtrs; i++)
190  pfree(so->reconTups[i]);
191  }
192  so->iPtr = so->nPtrs = 0;
193 }
IndexOrderByDistance * distances[MaxIndexTuplesPerPage]
static int pairingheap_SpGistSearchItem_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
Definition: spgscan.c:40
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:143
HeapTuple reconTups[MaxIndexTuplesPerPage]
void pfree(void *pointer)
Definition: mcxt.c:1169
static void spgAddStartItem(SpGistScanOpaque so, bool isnull)
Definition: spgscan.c:129
MemoryContext traversalCxt
int i

◆ spgAddSearchItemToQueue()

static void spgAddSearchItemToQueue ( SpGistScanOpaque  so,
SpGistSearchItem item 
)
static

Definition at line 107 of file spgscan.c.

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

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

108 {
109  pairingheap_add(so->scanQueue, &item->phNode);
110 }
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 129 of file spgscan.c.

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

Referenced by resetSpGistScanOpaque().

130 {
131  SpGistSearchItem *startEntry =
132  spgAllocSearchItem(so, isnull, so->zeroDistances);
133 
134  ItemPointerSet(&startEntry->heapPtr,
137  startEntry->isLeaf = false;
138  startEntry->level = 0;
139  startEntry->value = (Datum) 0;
140  startEntry->leafTuple = NULL;
141  startEntry->traversalValue = NULL;
142  startEntry->recheck = false;
143  startEntry->recheckDistances = false;
144 
145  spgAddSearchItemToQueue(so, startEntry);
146 }
#define SPGIST_ROOT_BLKNO
#define SPGIST_NULL_BLKNO
static SpGistSearchItem * spgAllocSearchItem(SpGistScanOpaque so, bool isnull, double *distances)
Definition: spgscan.c:113
SpGistLeafTuple leafTuple
#define FirstOffsetNumber
Definition: off.h:27
static void spgAddSearchItemToQueue(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:107
uintptr_t Datum
Definition: postgres.h:411
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 113 of file spgscan.c.

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

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

114 {
115  /* allocate distance array only for non-NULL items */
116  SpGistSearchItem *item =
118 
119  item->isNull = isnull;
120 
121  if (!isnull && so->numberOfNonNullOrderBys > 0)
122  memcpy(item->distances, distances,
123  sizeof(item->distances[0]) * so->numberOfNonNullOrderBys);
124 
125  return item;
126 }
#define SizeOfSpGistSearchItem(n_distances)
double distances[FLEXIBLE_ARRAY_MEMBER]
void * palloc(Size size)
Definition: mcxt.c:1062

◆ spgbeginscan()

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

Definition at line 303 of file spgscan.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, SpGistState::attType, CurrentMemoryContext, fmgr_info_copy(), get_float8_infinity(), getSpGistTupleDesc(), i, index_getprocinfo(), SpGistScanOpaqueData::indexCollation, IndexScanDescData::indexRelation, SpGistScanOpaqueData::infDistances, initSpGistState(), SpGistScanOpaqueData::innerConsistentFn, SpGistScanOpaqueData::keyData, SpGistScanOpaqueData::leafConsistentFn, SpGistScanOpaqueData::nonNullOrderByOffsets, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, SpGistScanOpaqueData::orderByTypes, palloc(), palloc0(), RelationData::rd_indcollation, SpGistScanOpaqueData::reconTupDesc, 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().

304 {
305  IndexScanDesc scan;
306  SpGistScanOpaque so;
307  int i;
308 
309  scan = RelationGetIndexScan(rel, keysz, orderbysz);
310 
312  if (keysz > 0)
313  so->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * keysz);
314  else
315  so->keyData = NULL;
316  initSpGistState(&so->state, scan->indexRelation);
317 
319  "SP-GiST search temporary context",
322  "SP-GiST traversal-value context",
324 
325  /*
326  * Set up reconTupDesc and xs_hitupdesc in case it's an index-only scan,
327  * making sure that the key column is shown as being of type attType.
328  * (It's rather annoying to do this work when it might be wasted, but for
329  * most opclasses we can re-use the index reldesc instead of making one.)
330  */
331  so->reconTupDesc = scan->xs_hitupdesc =
332  getSpGistTupleDesc(rel, &so->state.attType);
333 
334  /* Allocate various arrays needed for order-by scans */
335  if (scan->numberOfOrderBys > 0)
336  {
337  /* This will be filled in spgrescan, but allocate the space here */
338  so->orderByTypes = (Oid *)
339  palloc(sizeof(Oid) * scan->numberOfOrderBys);
340  so->nonNullOrderByOffsets = (int *)
341  palloc(sizeof(int) * scan->numberOfOrderBys);
342 
343  /* These arrays have constant contents, so we can fill them now */
344  so->zeroDistances = (double *)
345  palloc(sizeof(double) * scan->numberOfOrderBys);
346  so->infDistances = (double *)
347  palloc(sizeof(double) * scan->numberOfOrderBys);
348 
349  for (i = 0; i < scan->numberOfOrderBys; i++)
350  {
351  so->zeroDistances[i] = 0.0;
353  }
354 
355  scan->xs_orderbyvals = (Datum *)
356  palloc0(sizeof(Datum) * scan->numberOfOrderBys);
357  scan->xs_orderbynulls = (bool *)
358  palloc(sizeof(bool) * scan->numberOfOrderBys);
359  memset(scan->xs_orderbynulls, true,
360  sizeof(bool) * scan->numberOfOrderBys);
361  }
362 
366 
370 
371  so->indexCollation = rel->rd_indcollation[0];
372 
373  scan->opaque = so;
374 
375  return scan;
376 }
#define AllocSetContextCreate
Definition: memutils.h:173
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:803
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:145
SpGistTypeDesc attType
MemoryContext tempCxt
Datum * xs_orderbyvals
Definition: relscan.h:161
unsigned int Oid
Definition: postgres_ext.h:31
Relation indexRelation
Definition: relscan.h:118
bool * xs_orderbynulls
Definition: relscan.h:162
Oid * rd_indcollation
Definition: rel.h:215
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:608
ScanKeyData * ScanKey
Definition: skey.h:75
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:318
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void * palloc0(Size size)
Definition: mcxt.c:1093
uintptr_t Datum
Definition: postgres.h:411
SpGistScanOpaqueData * SpGistScanOpaque
MemoryContext traversalCxt
void * palloc(Size size)
Definition: mcxt.c:1062
TupleDesc getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType)
Definition: spgutils.c:287
int i
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:26
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:81
int numberOfOrderBys
Definition: relscan.h:121

◆ spgcanreturn()

bool spgcanreturn ( Relation  index,
int  attno 
)

Definition at line 1081 of file spgscan.c.

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

Referenced by spghandler().

1082 {
1083  SpGistCache *cache;
1084 
1085  /* INCLUDE attributes can always be fetched for index-only scans */
1086  if (attno > 1)
1087  return true;
1088 
1089  /* We can do it if the opclass config function says so */
1090  cache = spgGetCache(index);
1091 
1092  return cache->config.canReturnData;
1093 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:178
bool canReturnData
Definition: spgist.h:46
spgConfigOut config

◆ spgendscan()

void spgendscan ( IndexScanDesc  scan)

Definition at line 425 of file spgscan.c.

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

Referenced by spghandler().

426 {
428 
431 
432  if (so->keyData)
433  pfree(so->keyData);
434 
435  if (so->state.leafTupDesc &&
438 
439  if (so->state.deadTupleStorage)
441 
442  if (scan->numberOfOrderBys > 0)
443  {
444  pfree(so->orderByTypes);
446  pfree(so->zeroDistances);
447  pfree(so->infDistances);
448  pfree(scan->xs_orderbyvals);
449  pfree(scan->xs_orderbynulls);
450  }
451 
452  pfree(so);
453 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
#define RelationGetDescr(relation)
Definition: rel.h:498
MemoryContext tempCxt
Datum * xs_orderbyvals
Definition: relscan.h:161
bool * xs_orderbynulls
Definition: relscan.h:162
void pfree(void *pointer)
Definition: mcxt.c:1169
char * deadTupleStorage
SpGistScanOpaqueData * SpGistScanOpaque
TupleDesc leafTupDesc
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:309
MemoryContext traversalCxt
Relation index
int numberOfOrderBys
Definition: relscan.h:121

◆ spgFreeSearchItem()

static void spgFreeSearchItem ( SpGistScanOpaque  so,
SpGistSearchItem item 
)
static

Definition at line 83 of file spgscan.c.

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

Referenced by spgWalk().

84 {
85  /* value is of type attType if isLeaf, else of type attLeafType */
86  /* (no, that is not backwards; yes, it's confusing) */
87  if (!(item->isLeaf ? so->state.attType.attbyval :
88  so->state.attLeafType.attbyval) &&
89  DatumGetPointer(item->value) != NULL)
90  pfree(DatumGetPointer(item->value));
91 
92  if (item->leafTuple)
93  pfree(item->leafTuple);
94 
95  if (item->traversalValue)
96  pfree(item->traversalValue);
97 
98  pfree(item);
99 }
SpGistTypeDesc attLeafType
SpGistTypeDesc attType
void pfree(void *pointer)
Definition: mcxt.c:1169
SpGistLeafTuple leafTuple
#define DatumGetPointer(X)
Definition: postgres.h:593

◆ spggetbitmap()

int64 spggetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

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

940 {
942 
943  /* Copy want_itup to *so so we don't need to pass it around separately */
944  so->want_itup = false;
945 
946  so->tbm = tbm;
947  so->ntids = 0;
948 
949  spgWalk(scan->indexRelation, so, true, storeBitmap, scan->xs_snapshot);
950 
951  return so->ntids;
952 }
static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, SpGistLeafTuple leafTuple, bool recheck, bool recheckDistances, double *distances)
Definition: spgscan.c:928
struct SnapshotData * xs_snapshot
Definition: relscan.h:119
Relation indexRelation
Definition: relscan.h:118
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:813

◆ spgGetNextQueueItem()

static SpGistSearchItem* spgGetNextQueueItem ( SpGistScanOpaque  so)
static

Definition at line 742 of file spgscan.c.

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

Referenced by spgWalk().

743 {
745  return NULL; /* Done when both heaps are empty */
746 
747  /* Return item; caller is responsible to pfree it */
749 }
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 1023 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().

1024 {
1026 
1027  if (dir != ForwardScanDirection)
1028  elog(ERROR, "SP-GiST only supports forward scan direction");
1029 
1030  /* Copy want_itup to *so so we don't need to pass it around separately */
1031  so->want_itup = scan->xs_want_itup;
1032 
1033  for (;;)
1034  {
1035  if (so->iPtr < so->nPtrs)
1036  {
1037  /* continuing to return reported tuples */
1038  scan->xs_heaptid = so->heapPtrs[so->iPtr];
1039  scan->xs_recheck = so->recheck[so->iPtr];
1040  scan->xs_hitup = so->reconTups[so->iPtr];
1041 
1042  if (so->numberOfOrderBys > 0)
1044  so->distances[so->iPtr],
1045  so->recheckDistances[so->iPtr]);
1046  so->iPtr++;
1047  return true;
1048  }
1049 
1050  if (so->numberOfOrderBys > 0)
1051  {
1052  /* Must pfree distances to avoid memory leak */
1053  int i;
1054 
1055  for (i = 0; i < so->nPtrs; i++)
1056  if (so->distances[i])
1057  pfree(so->distances[i]);
1058  }
1059 
1060  if (so->want_itup)
1061  {
1062  /* Must pfree reconstructed tuples to avoid memory leak */
1063  int i;
1064 
1065  for (i = 0; i < so->nPtrs; i++)
1066  pfree(so->reconTups[i]);
1067  }
1068  so->iPtr = so->nPtrs = 0;
1069 
1070  spgWalk(scan->indexRelation, so, false, storeGettuple,
1071  scan->xs_snapshot);
1072 
1073  if (so->nPtrs == 0)
1074  break; /* must have completed scan */
1075  }
1076 
1077  return false;
1078 }
IndexOrderByDistance * distances[MaxIndexTuplesPerPage]
bool recheckDistances[MaxIndexTuplesPerPage]
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
struct SnapshotData * xs_snapshot
Definition: relscan.h:119
HeapTuple reconTups[MaxIndexTuplesPerPage]
Relation indexRelation
Definition: relscan.h:118
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ERROR
Definition: elog.h:46
ItemPointerData xs_heaptid
Definition: relscan.h:147
bool recheck[MaxIndexTuplesPerPage]
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:871
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:813
HeapTuple xs_hitup
Definition: relscan.h:144
static void storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, SpGistLeafTuple leafTuple, bool recheck, bool recheckDistances, double *nonNullDistances)
Definition: spgscan.c:956
#define elog(elevel,...)
Definition: elog.h:232
int i

◆ spgInitInnerConsistentIn()

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

Definition at line 602 of file spgscan.c.

References spgInnerConsistentIn::allTheSame, SpGistInnerTupleData::allTheSame, Assert, spgInnerConsistentIn::hasPrefix, SpGistSearchItem::isLeaf, 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().

606 {
607  in->scankeys = so->keyData;
608  in->orderbys = so->orderByData;
609  in->nkeys = so->numberOfKeys;
611  Assert(!item->isLeaf); /* else reconstructedValue would be wrong type */
612  in->reconstructedValue = item->value;
614  in->traversalValue = item->traversalValue;
615  in->level = item->level;
616  in->returnData = so->want_itup;
617  in->allTheSame = innerTuple->allTheSame;
618  in->hasPrefix = (innerTuple->prefixSize > 0);
619  in->prefixDatum = SGITDATUM(innerTuple, &so->state);
620  in->nNodes = innerTuple->nNodes;
621  in->nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);
622 }
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:1130
ScanKey orderbys
Definition: spgist.h:135
void * traversalValue
Definition: spgist.h:141
Datum reconstructedValue
Definition: spgist.h:140
#define SGITDATUM(x, s)
unsigned int allTheSame
MemoryContext traversalMemoryContext
Definition: spgist.h:142
unsigned int prefixSize
Datum * nodeLabels
Definition: spgist.h:151
#define Assert(condition)
Definition: c.h:804
ScanKey scankeys
Definition: spgist.h:134
MemoryContext traversalCxt

◆ spgInnerTest()

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

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

665 {
668  int nNodes = innerTuple->nNodes;
669  int i;
670 
671  memset(&out, 0, sizeof(out));
672 
673  if (!isnull)
674  {
676 
677  spgInitInnerConsistentIn(&in, so, item, innerTuple);
678 
679  /* use user-defined inner consistent method */
681  so->indexCollation,
682  PointerGetDatum(&in),
683  PointerGetDatum(&out));
684  }
685  else
686  {
687  /* force all children to be visited */
688  out.nNodes = nNodes;
689  out.nodeNumbers = (int *) palloc(sizeof(int) * nNodes);
690  for (i = 0; i < nNodes; i++)
691  out.nodeNumbers[i] = i;
692  }
693 
694  /* If allTheSame, they should all or none of them match */
695  if (innerTuple->allTheSame && out.nNodes != 0 && out.nNodes != nNodes)
696  elog(ERROR, "inconsistent inner_consistent results for allTheSame inner tuple");
697 
698  if (out.nNodes)
699  {
700  /* collect node pointers */
701  SpGistNodeTuple node;
702  SpGistNodeTuple *nodes = (SpGistNodeTuple *) palloc(sizeof(SpGistNodeTuple) * nNodes);
703 
704  SGITITERATE(innerTuple, i, node)
705  {
706  nodes[i] = node;
707  }
708 
710 
711  for (i = 0; i < out.nNodes; i++)
712  {
713  int nodeN = out.nodeNumbers[i];
714  SpGistSearchItem *innerItem;
715  double *distances;
716 
717  Assert(nodeN >= 0 && nodeN < nNodes);
718 
719  node = nodes[nodeN];
720 
721  if (!ItemPointerIsValid(&node->t_tid))
722  continue;
723 
724  /*
725  * Use infinity distances if innerConsistentFn() failed to return
726  * them or if is a NULL item (their distances are really unused).
727  */
728  distances = out.distances ? out.distances[i] : so->infDistances;
729 
730  innerItem = spgMakeInnerItem(so, item, node, &out, i, isnull,
731  distances);
732 
733  spgAddSearchItemToQueue(so, innerItem);
734  }
735  }
736 
737  MemoryContextSwitchTo(oldCxt);
738 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define PointerGetDatum(X)
Definition: postgres.h:600
#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:1148
unsigned int allTheSame
#define ERROR
Definition: elog.h:46
static SpGistSearchItem * spgMakeInnerItem(SpGistScanOpaque so, SpGistSearchItem *parentItem, SpGistNodeTuple tuple, spgInnerConsistentOut *out, int i, bool isnull, double *distances)
Definition: spgscan.c:625
static void spgAddSearchItemToQueue(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:107
double ** distances
Definition: spgist.h:161
#define Assert(condition)
Definition: c.h:804
static void spgInitInnerConsistentIn(spgInnerConsistentIn *in, SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple)
Definition: spgscan.c:602
MemoryContext traversalCxt
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i

◆ spgLeafTest()

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

Definition at line 512 of file spgscan.c.

References Assert, DatumGetBool, spgLeafConsistentOut::distances, FunctionCall2Coll(), SpGistLeafTupleData::heapPtr, SpGistScanOpaqueData::indexCollation, SpGistSearchItem::isLeaf, 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().

515 {
516  Datum leafValue;
517  double *distances;
518  bool result;
519  bool recheck;
520  bool recheckDistances;
521 
522  if (isnull)
523  {
524  /* Should not have arrived on a nulls page unless nulls are wanted */
525  Assert(so->searchNulls);
526  leafValue = (Datum) 0;
527  distances = NULL;
528  recheck = false;
529  recheckDistances = false;
530  result = true;
531  }
532  else
533  {
536 
537  /* use temp context for calling leaf_consistent */
539 
540  in.scankeys = so->keyData;
541  in.nkeys = so->numberOfKeys;
542  in.orderbys = so->orderByData;
544  Assert(!item->isLeaf); /* else reconstructedValue would be wrong type */
545  in.reconstructedValue = item->value;
546  in.traversalValue = item->traversalValue;
547  in.level = item->level;
548  in.returnData = so->want_itup;
549  in.leafDatum = SGLTDATUM(leafTuple, &so->state);
550 
551  out.leafValue = (Datum) 0;
552  out.recheck = false;
553  out.distances = NULL;
554  out.recheckDistances = false;
555 
557  so->indexCollation,
558  PointerGetDatum(&in),
559  PointerGetDatum(&out)));
560  recheck = out.recheck;
561  recheckDistances = out.recheckDistances;
562  leafValue = out.leafValue;
563  distances = out.distances;
564 
565  MemoryContextSwitchTo(oldCxt);
566  }
567 
568  if (result)
569  {
570  /* item passes the scankeys */
571  if (so->numberOfNonNullOrderBys > 0)
572  {
573  /* the scan is ordered -> add the item to the queue */
575  SpGistSearchItem *heapItem = spgNewHeapItem(so, item->level,
576  leafTuple,
577  leafValue,
578  recheck,
579  recheckDistances,
580  isnull,
581  distances);
582 
583  spgAddSearchItemToQueue(so, heapItem);
584 
585  MemoryContextSwitchTo(oldCxt);
586  }
587  else
588  {
589  /* non-ordered scan, so report the item right away */
590  Assert(!recheckDistances);
591  storeRes(so, &leafTuple->heapPtr, leafValue, isnull,
592  leafTuple, recheck, false, NULL);
593  *reportedSome = true;
594  }
595  }
596 
597  return result;
598 }
Datum reconstructedValue
Definition: spgist.h:175
#define PointerGetDatum(X)
Definition: postgres.h:600
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext tempCxt
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
ScanKey orderbys
Definition: spgist.h:170
ScanKey scankeys
Definition: spgist.h:169
double * distances
Definition: spgist.h:188
#define DatumGetBool(X)
Definition: postgres.h:437
static SpGistSearchItem * spgNewHeapItem(SpGistScanOpaque so, int level, SpGistLeafTuple leafTuple, Datum leafValue, bool recheck, bool recheckDistances, bool isnull, double *distances)
Definition: spgscan.c:459
static void spgAddSearchItemToQueue(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:107
uintptr_t Datum
Definition: postgres.h:411
#define Assert(condition)
Definition: c.h:804
#define SGLTDATUM(x, s)
MemoryContext traversalCxt
void * traversalValue
Definition: spgist.h:176
ItemPointerData heapPtr

◆ spgMakeInnerItem()

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

Definition at line 625 of file spgscan.c.

References SpGistTypeDesc::attbyval, SpGistState::attLeafType, SpGistTypeDesc::attlen, datumCopy(), SpGistSearchItem::heapPtr, i, SpGistSearchItem::isLeaf, SpGistSearchItem::leafTuple, 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().

630 {
631  SpGistSearchItem *item = spgAllocSearchItem(so, isnull, distances);
632 
633  item->heapPtr = tuple->t_tid;
634  item->level = out->levelAdds ? parentItem->level + out->levelAdds[i]
635  : parentItem->level;
636 
637  /* Must copy value out of temp context */
638  /* (recall that reconstructed values are of type leafType) */
639  item->value = out->reconstructedValues
643  : (Datum) 0;
644 
645  item->leafTuple = NULL;
646 
647  /*
648  * Elements of out.traversalValues should be allocated in
649  * in.traversalMemoryContext, which is actually a long lived context of
650  * index scan.
651  */
652  item->traversalValue =
653  out->traversalValues ? out->traversalValues[i] : NULL;
654 
655  item->isLeaf = false;
656  item->recheck = false;
657  item->recheckDistances = false;
658 
659  return item;
660 }
SpGistTypeDesc attLeafType
ItemPointerData t_tid
Definition: itup.h:37
static SpGistSearchItem * spgAllocSearchItem(SpGistScanOpaque so, bool isnull, double *distances)
Definition: spgscan.c:113
SpGistLeafTuple leafTuple
void ** traversalValues
Definition: spgist.h:160
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
uintptr_t Datum
Definition: postgres.h:411
ItemPointerData heapPtr
Datum * reconstructedValues
Definition: spgist.h:159
int i

◆ spgNewHeapItem()

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

Definition at line 459 of file spgscan.c.

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, SpGistState::attType, datumCopy(), SpGistSearchItem::heapPtr, SpGistLeafTupleData::heapPtr, SpGistSearchItem::isLeaf, SpGistState::leafTupDesc, SpGistSearchItem::leafTuple, SpGistSearchItem::level, TupleDescData::natts, palloc(), SpGistSearchItem::recheck, SpGistSearchItem::recheckDistances, SpGistLeafTupleData::size, spgAllocSearchItem(), SpGistScanOpaqueData::state, SpGistSearchItem::traversalValue, SpGistSearchItem::value, and SpGistScanOpaqueData::want_itup.

Referenced by spgLeafTest().

462 {
463  SpGistSearchItem *item = spgAllocSearchItem(so, isnull, distances);
464 
465  item->level = level;
466  item->heapPtr = leafTuple->heapPtr;
467 
468  /*
469  * If we need the reconstructed value, copy it to queue cxt out of tmp
470  * cxt. Caution: the leaf_consistent method may not have supplied a value
471  * if we didn't ask it to, and mildly-broken methods might supply one of
472  * the wrong type. The correct leafValue type is attType not leafType.
473  */
474  if (so->want_itup)
475  {
476  item->value = isnull ? (Datum) 0 :
477  datumCopy(leafValue, so->state.attType.attbyval,
478  so->state.attType.attlen);
479 
480  /*
481  * If we're going to need to reconstruct INCLUDE attributes, store the
482  * whole leaf tuple so we can get the INCLUDE attributes out of it.
483  */
484  if (so->state.leafTupDesc->natts > 1)
485  {
486  item->leafTuple = palloc(leafTuple->size);
487  memcpy(item->leafTuple, leafTuple, leafTuple->size);
488  }
489  else
490  item->leafTuple = NULL;
491  }
492  else
493  {
494  item->value = (Datum) 0;
495  item->leafTuple = NULL;
496  }
497  item->traversalValue = NULL;
498  item->isLeaf = true;
499  item->recheck = recheck;
500  item->recheckDistances = recheckDistances;
501 
502  return item;
503 }
SpGistTypeDesc attType
static SpGistSearchItem * spgAllocSearchItem(SpGistScanOpaque so, bool isnull, double *distances)
Definition: spgscan.c:113
SpGistLeafTuple leafTuple
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
uintptr_t Datum
Definition: postgres.h:411
ItemPointerData heapPtr
TupleDesc leafTupDesc
void * palloc(Size size)
Definition: mcxt.c:1062
ItemPointerData heapPtr

◆ spgPrepareScanKeys()

static void spgPrepareScanKeys ( IndexScanDesc  scan)
static

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

208 {
210  bool qual_ok;
211  bool haveIsNull;
212  bool haveNotNull;
213  int nkeys;
214  int i;
215 
217  so->orderByData = scan->orderByData;
218 
219  if (so->numberOfOrderBys <= 0)
220  so->numberOfNonNullOrderBys = 0;
221  else
222  {
223  int j = 0;
224 
225  /*
226  * Remove all NULL keys, but remember their offsets in the original
227  * array.
228  */
229  for (i = 0; i < scan->numberOfOrderBys; i++)
230  {
231  ScanKey skey = &so->orderByData[i];
232 
233  if (skey->sk_flags & SK_ISNULL)
234  so->nonNullOrderByOffsets[i] = -1;
235  else
236  {
237  if (i != j)
238  so->orderByData[j] = *skey;
239 
240  so->nonNullOrderByOffsets[i] = j++;
241  }
242  }
243 
244  so->numberOfNonNullOrderBys = j;
245  }
246 
247  if (scan->numberOfKeys <= 0)
248  {
249  /* If no quals, whole-index scan is required */
250  so->searchNulls = true;
251  so->searchNonNulls = true;
252  so->numberOfKeys = 0;
253  return;
254  }
255 
256  /* Examine the given quals */
257  qual_ok = true;
258  haveIsNull = haveNotNull = false;
259  nkeys = 0;
260  for (i = 0; i < scan->numberOfKeys; i++)
261  {
262  ScanKey skey = &scan->keyData[i];
263 
264  if (skey->sk_flags & SK_SEARCHNULL)
265  haveIsNull = true;
266  else if (skey->sk_flags & SK_SEARCHNOTNULL)
267  haveNotNull = true;
268  else if (skey->sk_flags & SK_ISNULL)
269  {
270  /* ordinary qual with null argument - unsatisfiable */
271  qual_ok = false;
272  break;
273  }
274  else
275  {
276  /* ordinary qual, propagate into so->keyData */
277  so->keyData[nkeys++] = *skey;
278  /* this effectively creates a not-null requirement */
279  haveNotNull = true;
280  }
281  }
282 
283  /* IS NULL in combination with something else is unsatisfiable */
284  if (haveIsNull && haveNotNull)
285  qual_ok = false;
286 
287  /* Emit results */
288  if (qual_ok)
289  {
290  so->searchNulls = haveIsNull;
291  so->searchNonNulls = haveNotNull;
292  so->numberOfKeys = nkeys;
293  }
294  else
295  {
296  so->searchNulls = false;
297  so->searchNonNulls = false;
298  so->numberOfKeys = 0;
299  }
300 }
struct ScanKeyData * orderByData
Definition: relscan.h:123
#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:122
int i
int numberOfOrderBys
Definition: relscan.h:121
#define SK_SEARCHNULL
Definition: skey.h:121

◆ spgrescan()

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

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

381 {
383 
384  /* copy scankeys into local storage */
385  if (scankey && scan->numberOfKeys > 0)
386  memmove(scan->keyData, scankey,
387  scan->numberOfKeys * sizeof(ScanKeyData));
388 
389  /* initialize order-by data if needed */
390  if (orderbys && scan->numberOfOrderBys > 0)
391  {
392  int i;
393 
394  memmove(scan->orderByData, orderbys,
395  scan->numberOfOrderBys * sizeof(ScanKeyData));
396 
397  for (i = 0; i < scan->numberOfOrderBys; i++)
398  {
399  ScanKey skey = &scan->orderByData[i];
400 
401  /*
402  * Look up the datatype returned by the original ordering
403  * operator. SP-GiST always uses a float8 for the distance
404  * function, but the ordering operator could be anything else.
405  *
406  * XXX: The distance function is only allowed to be lossy if the
407  * ordering operator's result type is float4 or float8. Otherwise
408  * we don't know how to return the distance to the executor. But
409  * we cannot check that here, as we won't know if the distance
410  * function is lossy until it returns *recheck = true for the
411  * first time.
412  */
414  }
415  }
416 
417  /* preprocess scankeys, set up the representation in *so */
418  spgPrepareScanKeys(scan);
419 
420  /* set up starting queue entries */
422 }
struct ScanKeyData * orderByData
Definition: relscan.h:123
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1626
static void spgPrepareScanKeys(IndexScanDesc scan)
Definition: spgscan.c:207
FmgrInfo sk_func
Definition: skey.h:71
SpGistScanOpaqueData * SpGistScanOpaque
Oid fn_oid
Definition: fmgr.h:59
static void resetSpGistScanOpaque(SpGistScanOpaque so)
Definition: spgscan.c:153
struct ScanKeyData * keyData
Definition: relscan.h:122
int i
int numberOfOrderBys
Definition: relscan.h:121

◆ 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 759 of file spgscan.c.

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

Referenced by spgWalk().

765 {
766  SpGistLeafTuple leafTuple = (SpGistLeafTuple)
767  PageGetItem(page, PageGetItemId(page, offset));
768 
769  if (leafTuple->tupstate != SPGIST_LIVE)
770  {
771  if (!isroot) /* all tuples on root should be live */
772  {
773  if (leafTuple->tupstate == SPGIST_REDIRECT)
774  {
775  /* redirection tuple should be first in chain */
776  Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
777  /* transfer attention to redirect point */
778  item->heapPtr = ((SpGistDeadTuple) leafTuple)->pointer;
781  }
782 
783  if (leafTuple->tupstate == SPGIST_DEAD)
784  {
785  /* dead tuple should be first in chain */
786  Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
787  /* No live entries on this page */
790  }
791  }
792 
793  /* We should not arrive at a placeholder */
794  elog(ERROR, "unexpected SPGiST tuple state: %d", leafTuple->tupstate);
796  }
797 
798  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
799 
800  spgLeafTest(so, item, leafTuple, isnull, reportedSome, storeRes);
801 
802  return SGLT_GET_NEXTOFFSET(leafTuple);
803 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define SPGIST_DEAD
#define SPGIST_REDIRECT
#define ERROR
Definition: elog.h:46
struct SpGistLeafTupleData * SpGistLeafTuple
#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:804
#define SPGIST_LIVE
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define SGLT_GET_NEXTOFFSET(spgLeafTuple)
#define elog(elevel,...)
Definition: elog.h:232
static bool spgLeafTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistLeafTuple leafTuple, bool isnull, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:512
ItemPointerData heapPtr
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#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 813 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, SpGistSearchItem::leafTuple, 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().

815 {
816  Buffer buffer = InvalidBuffer;
817  bool reportedSome = false;
818 
819  while (scanWholeIndex || !reportedSome)
820  {
822 
823  if (item == NULL)
824  break; /* No more items in queue -> done */
825 
826 redirect:
827  /* Check for interrupts, just in case of infinite loop */
829 
830  if (item->isLeaf)
831  {
832  /* We store heap items in the queue only in case of ordered search */
834  storeRes(so, &item->heapPtr, item->value, item->isNull,
835  item->leafTuple, item->recheck,
836  item->recheckDistances, item->distances);
837  reportedSome = true;
838  }
839  else
840  {
843  Page page;
844  bool isnull;
845 
846  if (buffer == InvalidBuffer)
847  {
848  buffer = ReadBuffer(index, blkno);
849  LockBuffer(buffer, BUFFER_LOCK_SHARE);
850  }
851  else if (blkno != BufferGetBlockNumber(buffer))
852  {
853  UnlockReleaseBuffer(buffer);
854  buffer = ReadBuffer(index, blkno);
855  LockBuffer(buffer, BUFFER_LOCK_SHARE);
856  }
857 
858  /* else new pointer points to the same page, no work needed */
859 
860  page = BufferGetPage(buffer);
861  TestForOldSnapshot(snapshot, index, page);
862 
863  isnull = SpGistPageStoresNulls(page) ? true : false;
864 
865  if (SpGistPageIsLeaf(page))
866  {
867  /* Page is a leaf - that is, all it's tuples are heap items */
869 
870  if (SpGistBlockIsRoot(blkno))
871  {
872  /* When root is a leaf, examine all its tuples */
873  for (offset = FirstOffsetNumber; offset <= max; offset++)
874  (void) spgTestLeafTuple(so, item, page, offset,
875  isnull, true,
876  &reportedSome, storeRes);
877  }
878  else
879  {
880  /* Normal case: just examine the chain we arrived at */
881  while (offset != InvalidOffsetNumber)
882  {
883  Assert(offset >= FirstOffsetNumber && offset <= max);
884  offset = spgTestLeafTuple(so, item, page, offset,
885  isnull, false,
886  &reportedSome, storeRes);
887  if (offset == SpGistRedirectOffsetNumber)
888  goto redirect;
889  }
890  }
891  }
892  else /* page is inner */
893  {
894  SpGistInnerTuple innerTuple = (SpGistInnerTuple)
895  PageGetItem(page, PageGetItemId(page, offset));
896 
897  if (innerTuple->tupstate != SPGIST_LIVE)
898  {
899  if (innerTuple->tupstate == SPGIST_REDIRECT)
900  {
901  /* transfer attention to redirect point */
902  item->heapPtr = ((SpGistDeadTuple) innerTuple)->pointer;
905  goto redirect;
906  }
907  elog(ERROR, "unexpected SPGiST tuple state: %d",
908  innerTuple->tupstate);
909  }
910 
911  spgInnerTest(so, item, innerTuple, isnull);
912  }
913  }
914 
915  /* done with this scan item */
916  spgFreeSearchItem(so, item);
917  /* clear temp context before proceeding to the next one */
919  }
920 
921  if (buffer != InvalidBuffer)
922  UnlockReleaseBuffer(buffer);
923 }
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:279
SpGistInnerTupleData * SpGistInnerTuple
#define SpGistPageIsLeaf(page)
#define SPGIST_REDIRECT
#define InvalidBuffer
Definition: buf.h:25
static SpGistSearchItem * spgGetNextQueueItem(SpGistScanOpaque so)
Definition: spgscan.c:742
MemoryContext tempCxt
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:143
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define true
Definition: c.h:395
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3807
#define ERROR
Definition: elog.h:46
static OffsetNumber spgTestLeafTuple(SpGistScanOpaque so, SpGistSearchItem *item, Page page, OffsetNumber offset, bool isnull, bool isroot, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:759
SpGistLeafTuple leafTuple
#define FirstOffsetNumber
Definition: off.h:27
#define SPGIST_METAPAGE_BLKNO
SpGistDeadTupleData * SpGistDeadTuple
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4023
static void spgInnerTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple, bool isnull)
Definition: spgscan.c:663
#define InvalidOffsetNumber
Definition: off.h:26
double distances[FLEXIBLE_ARRAY_MEMBER]
#define SpGistPageStoresNulls(page)
ItemPointerData heapPtr
#define Assert(condition)
Definition: c.h:804
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:697
#define SpGistBlockIsRoot(blkno)
#define SPGIST_LIVE
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2758
#define elog(elevel,...)
Definition: elog.h:232
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:102
#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:83

◆ storeBitmap()

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

Definition at line 928 of file spgscan.c.

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

Referenced by spggetbitmap().

932 {
933  Assert(!recheckDistances && !distances);
934  tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
935  so->ntids++;
936 }
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
#define Assert(condition)
Definition: c.h:804

◆ storeGettuple()

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

Definition at line 956 of file spgscan.c.

References Assert, SpGistScanOpaqueData::distances, heap_form_tuple(), SpGistScanOpaqueData::heapPtrs, i, INDEX_MAX_KEYS, IndexOrderByDistance::isnull, SpGistState::leafTupDesc, MaxIndexTuplesPerPage, TupleDescData::natts, SpGistScanOpaqueData::nonNullOrderByOffsets, SpGistScanOpaqueData::nPtrs, SpGistScanOpaqueData::numberOfNonNullOrderBys, SpGistScanOpaqueData::numberOfOrderBys, palloc(), SpGistScanOpaqueData::recheck, SpGistScanOpaqueData::recheckDistances, SpGistScanOpaqueData::reconTupDesc, SpGistScanOpaqueData::reconTups, spgDeformLeafTuple(), spgKeyColumn, SpGistScanOpaqueData::state, IndexOrderByDistance::value, and SpGistScanOpaqueData::want_itup.

Referenced by spggettuple().

960 {
962  so->heapPtrs[so->nPtrs] = *heapPtr;
963  so->recheck[so->nPtrs] = recheck;
964  so->recheckDistances[so->nPtrs] = recheckDistances;
965 
966  if (so->numberOfOrderBys > 0)
967  {
968  if (isnull || so->numberOfNonNullOrderBys <= 0)
969  so->distances[so->nPtrs] = NULL;
970  else
971  {
972  IndexOrderByDistance *distances =
973  palloc(sizeof(distances[0]) * so->numberOfOrderBys);
974  int i;
975 
976  for (i = 0; i < so->numberOfOrderBys; i++)
977  {
978  int offset = so->nonNullOrderByOffsets[i];
979 
980  if (offset >= 0)
981  {
982  /* Copy non-NULL distance value */
983  distances[i].value = nonNullDistances[offset];
984  distances[i].isnull = false;
985  }
986  else
987  {
988  /* Set distance's NULL flag. */
989  distances[i].value = 0.0;
990  distances[i].isnull = true;
991  }
992  }
993 
994  so->distances[so->nPtrs] = distances;
995  }
996  }
997 
998  if (so->want_itup)
999  {
1000  /*
1001  * Reconstruct index data. We have to copy the datum out of the temp
1002  * context anyway, so we may as well create the tuple here.
1003  */
1004  Datum leafDatums[INDEX_MAX_KEYS];
1005  bool leafIsnulls[INDEX_MAX_KEYS];
1006 
1007  /* We only need to deform the old tuple if it has INCLUDE attributes */
1008  if (so->state.leafTupDesc->natts > 1)
1009  spgDeformLeafTuple(leafTuple, so->state.leafTupDesc,
1010  leafDatums, leafIsnulls, isnull);
1011 
1012  leafDatums[spgKeyColumn] = leafValue;
1013  leafIsnulls[spgKeyColumn] = isnull;
1014 
1016  leafDatums,
1017  leafIsnulls);
1018  }
1019  so->nPtrs++;
1020 }
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 spgKeyColumn
uintptr_t Datum
Definition: postgres.h:411
TupleDesc leafTupDesc
#define Assert(condition)
Definition: c.h:804
#define INDEX_MAX_KEYS
#define MaxIndexTuplesPerPage
Definition: itup.h:145
void * palloc(Size size)
Definition: mcxt.c:1062
int i
void spgDeformLeafTuple(SpGistLeafTuple tup, TupleDesc tupleDescriptor, Datum *datums, bool *isnulls, bool keyColumnIsNull)
Definition: spgutils.c:1085