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 "pgstat.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)
 
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 30 of file spgscan.c.

Enumeration Type Documentation

◆ SpGistSpecialOffsetNumbers

Enumerator
SpGistBreakOffsetNumber 
SpGistRedirectOffsetNumber 
SpGistErrorOffsetNumber 

Definition at line 749 of file spgscan.c.

750{
754};
#define InvalidOffsetNumber
Definition: off.h:26
#define MaxOffsetNumber
Definition: off.h:28
@ SpGistErrorOffsetNumber
Definition: spgscan.c:753
@ SpGistBreakOffsetNumber
Definition: spgscan.c:751
@ SpGistRedirectOffsetNumber
Definition: spgscan.c:752

Function Documentation

◆ pairingheap_SpGistSearchItem_cmp()

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

Definition at line 41 of file spgscan.c.

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

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

Referenced by resetSpGistScanOpaque().

◆ resetSpGistScanOpaque()

static void resetSpGistScanOpaque ( SpGistScanOpaque  so)
static

Definition at line 154 of file spgscan.c.

155{
156 MemoryContext oldCtx;
157
159
161
162 /* initialize queue only for distance-ordered scans */
164
165 if (so->searchNulls)
166 /* Add a work item to scan the null index entries */
167 spgAddStartItem(so, true);
168
169 if (so->searchNonNulls)
170 /* Add a work item to scan the non-null index entries */
171 spgAddStartItem(so, false);
172
173 MemoryContextSwitchTo(oldCtx);
174
175 if (so->numberOfOrderBys > 0)
176 {
177 /* Must pfree distances to avoid memory leak */
178 int i;
179
180 for (i = 0; i < so->nPtrs; i++)
181 if (so->distances[i])
182 pfree(so->distances[i]);
183 }
184
185 if (so->want_itup)
186 {
187 /* Must pfree reconstructed tuples to avoid memory leak */
188 int i;
189
190 for (i = 0; i < so->nPtrs; i++)
191 pfree(so->reconTups[i]);
192 }
193 so->iPtr = so->nPtrs = 0;
194}
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
void pfree(void *pointer)
Definition: mcxt.c:1594
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static int pairingheap_SpGistSearchItem_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
Definition: spgscan.c:41
static void spgAddStartItem(SpGistScanOpaque so, bool isnull)
Definition: spgscan.c:130
HeapTuple reconTups[MaxIndexTuplesPerPage]
MemoryContext traversalCxt
pairingheap * scanQueue
IndexOrderByDistance * distances[MaxIndexTuplesPerPage]

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

◆ spgAddSearchItemToQueue()

static void spgAddSearchItemToQueue ( SpGistScanOpaque  so,
SpGistSearchItem item 
)
static

Definition at line 108 of file spgscan.c.

109{
110 pairingheap_add(so->scanQueue, &item->phNode);
111}
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:126
pairingheap_node phNode

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

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

◆ spgAddStartItem()

static void spgAddStartItem ( SpGistScanOpaque  so,
bool  isnull 
)
static

Definition at line 130 of file spgscan.c.

131{
132 SpGistSearchItem *startEntry =
133 spgAllocSearchItem(so, isnull, so->zeroDistances);
134
135 ItemPointerSet(&startEntry->heapPtr,
138 startEntry->isLeaf = false;
139 startEntry->level = 0;
140 startEntry->value = (Datum) 0;
141 startEntry->leafTuple = NULL;
142 startEntry->traversalValue = NULL;
143 startEntry->recheck = false;
144 startEntry->recheckDistances = false;
145
146 spgAddSearchItemToQueue(so, startEntry);
147}
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition: itemptr.h:135
#define FirstOffsetNumber
Definition: off.h:27
uint64_t Datum
Definition: postgres.h:70
#define SPGIST_NULL_BLKNO
#define SPGIST_ROOT_BLKNO
static void spgAddSearchItemToQueue(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:108
static SpGistSearchItem * spgAllocSearchItem(SpGistScanOpaque so, bool isnull, double *distances)
Definition: spgscan.c:114
SpGistLeafTuple leafTuple
ItemPointerData heapPtr

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

◆ spgAllocSearchItem()

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

Definition at line 114 of file spgscan.c.

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

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

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

◆ spgbeginscan()

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

Definition at line 304 of file spgscan.c.

305{
306 IndexScanDesc scan;
308 int i;
309
310 scan = RelationGetIndexScan(rel, keysz, orderbysz);
311
313 if (keysz > 0)
314 so->keyData = palloc_array(ScanKeyData, keysz);
315 else
316 so->keyData = NULL;
318
320 "SP-GiST search temporary context",
323 "SP-GiST traversal-value context",
325
326 /*
327 * Set up reconTupDesc and xs_hitupdesc in case it's an index-only scan,
328 * making sure that the key column is shown as being of type attType.
329 * (It's rather annoying to do this work when it might be wasted, but for
330 * most opclasses we can re-use the index reldesc instead of making one.)
331 */
332 so->reconTupDesc = scan->xs_hitupdesc =
334
335 /* Allocate various arrays needed for order-by scans */
336 if (scan->numberOfOrderBys > 0)
337 {
338 /* This will be filled in spgrescan, but allocate the space here */
341
342 /* These arrays have constant contents, so we can fill them now */
343 so->zeroDistances = palloc_array(double, scan->numberOfOrderBys);
344 so->infDistances = palloc_array(double, scan->numberOfOrderBys);
345
346 for (i = 0; i < scan->numberOfOrderBys; i++)
347 {
348 so->zeroDistances[i] = 0.0;
350 }
351
353 scan->xs_orderbynulls = palloc_array(bool, scan->numberOfOrderBys);
354 memset(scan->xs_orderbynulls, true,
355 sizeof(bool) * scan->numberOfOrderBys);
356 }
357
361
365
366 so->indexCollation = rel->rd_indcollation[0];
367
368 scan->opaque = so;
369
370 return scan;
371}
#define palloc_array(type, count)
Definition: fe_memutils.h:76
#define palloc0_array(type, count)
Definition: fe_memutils.h:77
#define palloc0_object(type)
Definition: fe_memutils.h:75
static float8 get_float8_infinity(void)
Definition: float.h:65
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:581
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:80
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:917
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
unsigned int Oid
Definition: postgres_ext.h:32
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:27
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:26
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:348
TupleDesc getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType)
Definition: spgutils.c:315
bool * xs_orderbynulls
Definition: relscan.h:189
int numberOfOrderBys
Definition: relscan.h:142
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:172
Relation indexRelation
Definition: relscan.h:139
Datum * xs_orderbyvals
Definition: relscan.h:188
Oid * rd_indcollation
Definition: rel.h:217
MemoryContext tempCxt
SpGistTypeDesc attType

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, palloc0_array, palloc0_object, palloc_array, 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().

◆ spgcanreturn()

bool spgcanreturn ( Relation  index,
int  attno 
)

Definition at line 1077 of file spgscan.c.

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

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

Referenced by spghandler().

◆ spgendscan()

void spgendscan ( IndexScanDesc  scan)

Definition at line 423 of file spgscan.c.

424{
426
429
430 if (so->keyData)
431 pfree(so->keyData);
432
433 if (so->state.leafTupDesc &&
436
437 if (so->state.deadTupleStorage)
439
440 if (scan->numberOfOrderBys > 0)
441 {
442 pfree(so->orderByTypes);
444 pfree(so->zeroDistances);
445 pfree(so->infDistances);
446 pfree(scan->xs_orderbyvals);
447 pfree(scan->xs_orderbynulls);
448 }
449
450 pfree(so);
451}
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
#define RelationGetDescr(relation)
Definition: rel.h:541
Relation index
TupleDesc leafTupDesc
char * deadTupleStorage
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:502

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

◆ spgFreeSearchItem()

static void spgFreeSearchItem ( SpGistScanOpaque  so,
SpGistSearchItem item 
)
static

Definition at line 84 of file spgscan.c.

85{
86 /* value is of type attType if isLeaf, else of type attLeafType */
87 /* (no, that is not backwards; yes, it's confusing) */
88 if (!(item->isLeaf ? so->state.attType.attbyval :
90 DatumGetPointer(item->value) != NULL)
92
93 if (item->leafTuple)
94 pfree(item->leafTuple);
95
96 if (item->traversalValue)
97 pfree(item->traversalValue);
98
99 pfree(item);
100}
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
SpGistTypeDesc attLeafType

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

Referenced by spgWalk().

◆ spggetbitmap()

int64 spggetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 936 of file spgscan.c.

937{
939
940 /* Copy want_itup to *so so we don't need to pass it around separately */
941 so->want_itup = false;
942
943 so->tbm = tbm;
944 so->ntids = 0;
945
946 spgWalk(scan->indexRelation, so, true, storeBitmap);
947
948 return so->ntids;
949}
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes)
Definition: spgscan.c:811
static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, SpGistLeafTuple leafTuple, bool recheck, bool recheckDistances, double *distances)
Definition: spgscan.c:925

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

Referenced by spghandler().

◆ spgGetNextQueueItem()

static SpGistSearchItem * spgGetNextQueueItem ( SpGistScanOpaque  so)
static

Definition at line 740 of file spgscan.c.

741{
743 return NULL; /* Done when both heaps are empty */
744
745 /* Return item; caller is responsible to pfree it */
747}
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:159
#define pairingheap_is_empty(h)
Definition: pairingheap.h:99

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

Referenced by spgWalk().

◆ spggettuple()

bool spggettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 1020 of file spgscan.c.

1021{
1023
1024 if (dir != ForwardScanDirection)
1025 elog(ERROR, "SP-GiST only supports forward scan direction");
1026
1027 /* Copy want_itup to *so so we don't need to pass it around separately */
1028 so->want_itup = scan->xs_want_itup;
1029
1030 for (;;)
1031 {
1032 if (so->iPtr < so->nPtrs)
1033 {
1034 /* continuing to return reported tuples */
1035 scan->xs_heaptid = so->heapPtrs[so->iPtr];
1036 scan->xs_recheck = so->recheck[so->iPtr];
1037 scan->xs_hitup = so->reconTups[so->iPtr];
1038
1039 if (so->numberOfOrderBys > 0)
1041 so->distances[so->iPtr],
1042 so->recheckDistances[so->iPtr]);
1043 so->iPtr++;
1044 return true;
1045 }
1046
1047 if (so->numberOfOrderBys > 0)
1048 {
1049 /* Must pfree distances to avoid memory leak */
1050 int i;
1051
1052 for (i = 0; i < so->nPtrs; i++)
1053 if (so->distances[i])
1054 pfree(so->distances[i]);
1055 }
1056
1057 if (so->want_itup)
1058 {
1059 /* Must pfree reconstructed tuples to avoid memory leak */
1060 int i;
1061
1062 for (i = 0; i < so->nPtrs; i++)
1063 pfree(so->reconTups[i]);
1064 }
1065 so->iPtr = so->nPtrs = 0;
1066
1067 spgWalk(scan->indexRelation, so, false, storeGettuple);
1068
1069 if (so->nPtrs == 0)
1070 break; /* must have completed scan */
1071 }
1072
1073 return false;
1074}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:985
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
@ ForwardScanDirection
Definition: sdir.h:28
static void storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, SpGistLeafTuple leafTuple, bool recheck, bool recheckDistances, double *nonNullDistances)
Definition: spgscan.c:953
HeapTuple xs_hitup
Definition: relscan.h:171
ItemPointerData xs_heaptid
Definition: relscan.h:174
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
bool recheckDistances[MaxIndexTuplesPerPage]
bool recheck[MaxIndexTuplesPerPage]

References SpGistScanOpaqueData::distances, elog, ERROR, ForwardScanDirection, SpGistScanOpaqueData::heapPtrs, i, if(), 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, and IndexScanDescData::xs_want_itup.

Referenced by spghandler().

◆ spgInitInnerConsistentIn()

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

Definition at line 600 of file spgscan.c.

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

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

◆ spgInnerTest()

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

Definition at line 661 of file spgscan.c.

663{
666 int nNodes = innerTuple->nNodes;
667 int i;
668
669 memset(&out, 0, sizeof(out));
670
671 if (!isnull)
672 {
674
675 spgInitInnerConsistentIn(&in, so, item, innerTuple);
676
677 /* use user-defined inner consistent method */
679 so->indexCollation,
680 PointerGetDatum(&in),
681 PointerGetDatum(&out));
682 }
683 else
684 {
685 /* force all children to be visited */
686 out.nNodes = nNodes;
687 out.nodeNumbers = palloc_array(int, nNodes);
688 for (i = 0; i < nNodes; i++)
689 out.nodeNumbers[i] = i;
690 }
691
692 /* If allTheSame, they should all or none of them match */
693 if (innerTuple->allTheSame && out.nNodes != 0 && out.nNodes != nNodes)
694 elog(ERROR, "inconsistent inner_consistent results for allTheSame inner tuple");
695
696 if (out.nNodes)
697 {
698 /* collect node pointers */
699 SpGistNodeTuple node;
701
702 SGITITERATE(innerTuple, i, node)
703 {
704 nodes[i] = node;
705 }
706
708
709 for (i = 0; i < out.nNodes; i++)
710 {
711 int nodeN = out.nodeNumbers[i];
712 SpGistSearchItem *innerItem;
713 double *distances;
714
715 Assert(nodeN >= 0 && nodeN < nNodes);
716
717 node = nodes[nodeN];
718
719 if (!ItemPointerIsValid(&node->t_tid))
720 continue;
721
722 /*
723 * Use infinity distances if innerConsistentFn() failed to return
724 * them or if is a NULL item (their distances are really unused).
725 */
726 distances = out.distances ? out.distances[i] : so->infDistances;
727
728 innerItem = spgMakeInnerItem(so, item, node, &out, i, isnull,
729 distances);
730
731 spgAddSearchItemToQueue(so, innerItem);
732 }
733 }
734
735 MemoryContextSwitchTo(oldCxt);
736}
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
#define SGITITERATE(x, i, nt)
static void spgInitInnerConsistentIn(spgInnerConsistentIn *in, SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple)
Definition: spgscan.c:600
static SpGistSearchItem * spgMakeInnerItem(SpGistScanOpaque so, SpGistSearchItem *parentItem, SpGistNodeTuple tuple, spgInnerConsistentOut *out, int i, bool isnull, double *distances)
Definition: spgscan.c:623
ItemPointerData t_tid
Definition: itup.h:37
double ** distances
Definition: spgist.h:161

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_array, PointerGetDatum(), SGITITERATE, spgAddSearchItemToQueue(), spgInitInnerConsistentIn(), spgMakeInnerItem(), IndexTupleData::t_tid, SpGistScanOpaqueData::tempCxt, and SpGistScanOpaqueData::traversalCxt.

Referenced by spgWalk().

◆ spgLeafTest()

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

Definition at line 510 of file spgscan.c.

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

References Assert(), DatumGetBool(), spgLeafConsistentOut::distances, FunctionCall2Coll(), SpGistLeafTupleData::heapPtr, SpGistScanOpaqueData::indexCollation, SpGistSearchItem::isLeaf, SpGistScanOpaqueData::keyData, SpGistScanOpaqueData::leafConsistentFn, spgLeafConsistentIn::leafDatum, spgLeafConsistentOut::leafValue, spgLeafConsistentIn::level, SpGistSearchItem::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, spgLeafConsistentIn::traversalValue, SpGistSearchItem::traversalValue, SpGistSearchItem::value, and SpGistScanOpaqueData::want_itup.

Referenced by spgTestLeafTuple().

◆ spgMakeInnerItem()

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

Definition at line 623 of file spgscan.c.

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

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

◆ spgNewHeapItem()

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

Definition at line 457 of file spgscan.c.

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

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

◆ spgPrepareScanKeys()

static void spgPrepareScanKeys ( IndexScanDesc  scan)
static

Definition at line 208 of file spgscan.c.

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

References i, if(), j, 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().

◆ spgrescan()

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

Definition at line 374 of file spgscan.c.

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

References FmgrInfo::fn_oid, get_func_rettype(), i, if(), IndexScanDescData::indexRelation, IndexScanDescData::instrument, IndexScanDescData::keyData, IndexScanInstrumentation::nsearches, IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, IndexScanDescData::orderByData, SpGistScanOpaqueData::orderByTypes, pgstat_count_index_scan, resetSpGistScanOpaque(), ScanKeyData::sk_func, and spgPrepareScanKeys().

Referenced by spghandler().

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

763{
764 SpGistLeafTuple leafTuple = (SpGistLeafTuple)
765 PageGetItem(page, PageGetItemId(page, offset));
766
767 if (leafTuple->tupstate != SPGIST_LIVE)
768 {
769 if (!isroot) /* all tuples on root should be live */
770 {
771 if (leafTuple->tupstate == SPGIST_REDIRECT)
772 {
773 /* redirection tuple should be first in chain */
774 Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
775 /* transfer attention to redirect point */
776 item->heapPtr = ((SpGistDeadTuple) leafTuple)->pointer;
779 }
780
781 if (leafTuple->tupstate == SPGIST_DEAD)
782 {
783 /* dead tuple should be first in chain */
784 Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
785 /* No live entries on this page */
788 }
789 }
790
791 /* We should not arrive at a placeholder */
792 elog(ERROR, "unexpected SPGiST tuple state: %d", leafTuple->tupstate);
794 }
795
796 Assert(ItemPointerIsValid(&leafTuple->heapPtr));
797
798 spgLeafTest(so, item, leafTuple, isnull, reportedSome, storeRes);
799
800 return SGLT_GET_NEXTOFFSET(leafTuple);
801}
static void * PageGetItem(const PageData *page, const ItemIdData *itemId)
Definition: bufpage.h:353
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:243
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103
SpGistDeadTupleData * SpGistDeadTuple
#define SPGIST_REDIRECT
#define SPGIST_LIVE
#define SGLT_GET_NEXTOFFSET(spgLeafTuple)
#define SPGIST_DEAD
#define SPGIST_METAPAGE_BLKNO
struct SpGistLeafTupleData * SpGistLeafTuple
static bool spgLeafTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistLeafTuple leafTuple, bool isnull, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:510
unsigned int tupstate

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

◆ spgWalk()

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

Definition at line 811 of file spgscan.c.

813{
814 Buffer buffer = InvalidBuffer;
815 bool reportedSome = false;
816
817 while (scanWholeIndex || !reportedSome)
818 {
820
821 if (item == NULL)
822 break; /* No more items in queue -> done */
823
824redirect:
825 /* Check for interrupts, just in case of infinite loop */
827
828 if (item->isLeaf)
829 {
830 /* We store heap items in the queue only in case of ordered search */
832 storeRes(so, &item->heapPtr, item->value, item->isNull,
833 item->leafTuple, item->recheck,
834 item->recheckDistances, item->distances);
835 reportedSome = true;
836 }
837 else
838 {
841 Page page;
842 bool isnull;
843
844 if (buffer == InvalidBuffer)
845 {
846 buffer = ReadBuffer(index, blkno);
848 }
849 else if (blkno != BufferGetBlockNumber(buffer))
850 {
851 UnlockReleaseBuffer(buffer);
852 buffer = ReadBuffer(index, blkno);
854 }
855
856 /* else new pointer points to the same page, no work needed */
857
858 page = BufferGetPage(buffer);
859
860 isnull = SpGistPageStoresNulls(page) ? true : false;
861
862 if (SpGistPageIsLeaf(page))
863 {
864 /* Page is a leaf - that is, all its tuples are heap items */
866
867 if (SpGistBlockIsRoot(blkno))
868 {
869 /* When root is a leaf, examine all its tuples */
870 for (offset = FirstOffsetNumber; offset <= max; offset++)
871 (void) spgTestLeafTuple(so, item, page, offset,
872 isnull, true,
873 &reportedSome, storeRes);
874 }
875 else
876 {
877 /* Normal case: just examine the chain we arrived at */
878 while (offset != InvalidOffsetNumber)
879 {
880 Assert(offset >= FirstOffsetNumber && offset <= max);
881 offset = spgTestLeafTuple(so, item, page, offset,
882 isnull, false,
883 &reportedSome, storeRes);
884 if (offset == SpGistRedirectOffsetNumber)
885 goto redirect;
886 }
887 }
888 }
889 else /* page is inner */
890 {
892 PageGetItem(page, PageGetItemId(page, offset));
893
894 if (innerTuple->tupstate != SPGIST_LIVE)
895 {
896 if (innerTuple->tupstate == SPGIST_REDIRECT)
897 {
898 /* transfer attention to redirect point */
899 item->heapPtr = ((SpGistDeadTuple) innerTuple)->pointer;
902 goto redirect;
903 }
904 elog(ERROR, "unexpected SPGiST tuple state: %d",
905 innerTuple->tupstate);
906 }
907
908 spgInnerTest(so, item, innerTuple, isnull);
909 }
910 }
911
912 /* done with this scan item */
913 spgFreeSearchItem(so, item);
914 /* clear temp context before proceeding to the next one */
916 }
917
918 if (buffer != InvalidBuffer)
919 UnlockReleaseBuffer(buffer);
920}
uint32 BlockNumber
Definition: block.h:31
int Buffer
Definition: buf.h:23
#define InvalidBuffer
Definition: buf.h:25
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:4223
void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition: bufmgr.c:5604
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:5383
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:745
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:436
@ BUFFER_LOCK_SHARE
Definition: bufmgr.h:206
PageData * Page
Definition: bufpage.h:81
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition: bufpage.h:371
return true
Definition: isn.c:130
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
uint16 OffsetNumber
Definition: off.h:24
SpGistInnerTupleData * SpGistInnerTuple
#define SpGistPageStoresNulls(page)
#define SpGistPageIsLeaf(page)
#define SpGistBlockIsRoot(blkno)
static SpGistSearchItem * spgGetNextQueueItem(SpGistScanOpaque so)
Definition: spgscan.c:740
static OffsetNumber spgTestLeafTuple(SpGistScanOpaque so, SpGistSearchItem *item, Page page, OffsetNumber offset, bool isnull, bool isroot, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:757
static void spgFreeSearchItem(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:84
static void spgInnerTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple, bool isnull)
Definition: spgscan.c:661

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, true, SpGistInnerTupleData::tupstate, UnlockReleaseBuffer(), and SpGistSearchItem::value.

Referenced by spggetbitmap(), and spggettuple().

◆ storeBitmap()

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

Definition at line 925 of file spgscan.c.

929{
930 Assert(!recheckDistances && !distances);
931 tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
932 so->ntids++;
933}
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointerData *tids, int ntids, bool recheck)
Definition: tidbitmap.c:367

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

Referenced by spggetbitmap().

◆ storeGettuple()

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

Definition at line 953 of file spgscan.c.

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

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_array, SpGistScanOpaqueData::recheck, SpGistScanOpaqueData::recheckDistances, SpGistScanOpaqueData::reconTupDesc, SpGistScanOpaqueData::reconTups, spgDeformLeafTuple(), spgKeyColumn, SpGistScanOpaqueData::state, IndexOrderByDistance::value, and SpGistScanOpaqueData::want_itup.

Referenced by spggettuple().