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 "executor/instrument_node.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 31 of file spgscan.c.

Enumeration Type Documentation

◆ SpGistSpecialOffsetNumbers

Enumerator
SpGistBreakOffsetNumber 
SpGistRedirectOffsetNumber 
SpGistErrorOffsetNumber 

Definition at line 750 of file spgscan.c.

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

Function Documentation

◆ pairingheap_SpGistSearchItem_cmp()

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

Definition at line 42 of file spgscan.c.

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

156{
157 MemoryContext oldCtx;
158
160
162
163 /* initialize queue only for distance-ordered scans */
165
166 if (so->searchNulls)
167 /* Add a work item to scan the null index entries */
168 spgAddStartItem(so, true);
169
170 if (so->searchNonNulls)
171 /* Add a work item to scan the non-null index entries */
172 spgAddStartItem(so, false);
173
174 MemoryContextSwitchTo(oldCtx);
175
176 if (so->numberOfOrderBys > 0)
177 {
178 /* Must pfree distances to avoid memory leak */
179 int i;
180
181 for (i = 0; i < so->nPtrs; i++)
182 if (so->distances[i])
183 pfree(so->distances[i]);
184 }
185
186 if (so->want_itup)
187 {
188 /* Must pfree reconstructed tuples to avoid memory leak */
189 int i;
190
191 for (i = 0; i < so->nPtrs; i++)
192 pfree(so->reconTups[i]);
193 }
194 so->iPtr = so->nPtrs = 0;
195}
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:403
void pfree(void *pointer)
Definition: mcxt.c:1616
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:42
static void spgAddStartItem(SpGistScanOpaque so, bool isnull)
Definition: spgscan.c:131
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 109 of file spgscan.c.

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

132{
133 SpGistSearchItem *startEntry =
134 spgAllocSearchItem(so, isnull, so->zeroDistances);
135
136 ItemPointerSet(&startEntry->heapPtr,
139 startEntry->isLeaf = false;
140 startEntry->level = 0;
141 startEntry->value = (Datum) 0;
142 startEntry->leafTuple = NULL;
143 startEntry->traversalValue = NULL;
144 startEntry->recheck = false;
145 startEntry->recheckDistances = false;
146
147 spgAddSearchItemToQueue(so, startEntry);
148}
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:109
static SpGistSearchItem * spgAllocSearchItem(SpGistScanOpaque so, bool isnull, double *distances)
Definition: spgscan.c:115
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 115 of file spgscan.c.

116{
117 /* allocate distance array only for non-NULL items */
118 SpGistSearchItem *item =
120
121 item->isNull = isnull;
122
123 if (!isnull && so->numberOfNonNullOrderBys > 0)
124 memcpy(item->distances, distances,
125 sizeof(item->distances[0]) * so->numberOfNonNullOrderBys);
126
127 return item;
128}
void * palloc(Size size)
Definition: mcxt.c:1387
#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 305 of file spgscan.c.

306{
307 IndexScanDesc scan;
309 int i;
310
311 scan = RelationGetIndexScan(rel, keysz, orderbysz);
312
314 if (keysz > 0)
315 so->keyData = palloc_array(ScanKeyData, keysz);
316 else
317 so->keyData = NULL;
319
321 "SP-GiST search temporary context",
324 "SP-GiST traversal-value context",
326
327 /*
328 * Set up reconTupDesc and xs_hitupdesc in case it's an index-only scan,
329 * making sure that the key column is shown as being of type attType.
330 * (It's rather annoying to do this work when it might be wasted, but for
331 * most opclasses we can re-use the index reldesc instead of making one.)
332 */
333 so->reconTupDesc = scan->xs_hitupdesc =
335
336 /* Allocate various arrays needed for order-by scans */
337 if (scan->numberOfOrderBys > 0)
338 {
339 /* This will be filled in spgrescan, but allocate the space here */
342
343 /* These arrays have constant contents, so we can fill them now */
344 so->zeroDistances = palloc_array(double, scan->numberOfOrderBys);
345 so->infDistances = palloc_array(double, scan->numberOfOrderBys);
346
347 for (i = 0; i < scan->numberOfOrderBys; i++)
348 {
349 so->zeroDistances[i] = 0.0;
351 }
352
354 scan->xs_orderbynulls = palloc_array(bool, scan->numberOfOrderBys);
355 memset(scan->xs_orderbynulls, true,
356 sizeof(bool) * scan->numberOfOrderBys);
357 }
358
362
366
367 so->indexCollation = rel->rd_indcollation[0];
368
369 scan->opaque = so;
370
371 return scan;
372}
#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:349
TupleDesc getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType)
Definition: spgutils.c:316
bool * xs_orderbynulls
Definition: relscan.h:188
int numberOfOrderBys
Definition: relscan.h:141
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:171
Relation indexRelation
Definition: relscan.h:138
Datum * xs_orderbyvals
Definition: relscan.h:187
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 1078 of file spgscan.c.

1079{
1080 SpGistCache *cache;
1081
1082 /* INCLUDE attributes can always be fetched for index-only scans */
1083 if (attno > 1)
1084 return true;
1085
1086 /* We can do it if the opclass config function says so */
1087 cache = spgGetCache(index);
1088
1089 return cache->config.canReturnData;
1090}
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:189
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 424 of file spgscan.c.

425{
427
430
431 if (so->keyData)
432 pfree(so->keyData);
433
434 if (so->state.leafTupDesc &&
437
438 if (so->state.deadTupleStorage)
440
441 if (scan->numberOfOrderBys > 0)
442 {
443 pfree(so->orderByTypes);
445 pfree(so->zeroDistances);
446 pfree(so->infDistances);
447 pfree(scan->xs_orderbyvals);
448 pfree(scan->xs_orderbynulls);
449 }
450
451 pfree(so);
452}
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:472
#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 85 of file spgscan.c.

86{
87 /* value is of type attType if isLeaf, else of type attLeafType */
88 /* (no, that is not backwards; yes, it's confusing) */
89 if (!(item->isLeaf ? so->state.attType.attbyval :
91 DatumGetPointer(item->value) != NULL)
93
94 if (item->leafTuple)
95 pfree(item->leafTuple);
96
97 if (item->traversalValue)
98 pfree(item->traversalValue);
99
100 pfree(item);
101}
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:342
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 937 of file spgscan.c.

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

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

742{
744 return NULL; /* Done when both heaps are empty */
745
746 /* Return item; caller is responsible to pfree it */
748}
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 1021 of file spgscan.c.

1022{
1024
1025 if (dir != ForwardScanDirection)
1026 elog(ERROR, "SP-GiST only supports forward scan direction");
1027
1028 /* Copy want_itup to *so so we don't need to pass it around separately */
1029 so->want_itup = scan->xs_want_itup;
1030
1031 for (;;)
1032 {
1033 if (so->iPtr < so->nPtrs)
1034 {
1035 /* continuing to return reported tuples */
1036 scan->xs_heaptid = so->heapPtrs[so->iPtr];
1037 scan->xs_recheck = so->recheck[so->iPtr];
1038 scan->xs_hitup = so->reconTups[so->iPtr];
1039
1040 if (so->numberOfOrderBys > 0)
1042 so->distances[so->iPtr],
1043 so->recheckDistances[so->iPtr]);
1044 so->iPtr++;
1045 return true;
1046 }
1047
1048 if (so->numberOfOrderBys > 0)
1049 {
1050 /* Must pfree distances to avoid memory leak */
1051 int i;
1052
1053 for (i = 0; i < so->nPtrs; i++)
1054 if (so->distances[i])
1055 pfree(so->distances[i]);
1056 }
1057
1058 if (so->want_itup)
1059 {
1060 /* Must pfree reconstructed tuples to avoid memory leak */
1061 int i;
1062
1063 for (i = 0; i < so->nPtrs; i++)
1064 pfree(so->reconTups[i]);
1065 }
1066 so->iPtr = so->nPtrs = 0;
1067
1068 spgWalk(scan->indexRelation, so, false, storeGettuple);
1069
1070 if (so->nPtrs == 0)
1071 break; /* must have completed scan */
1072 }
1073
1074 return false;
1075}
#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:954
HeapTuple xs_hitup
Definition: relscan.h:170
ItemPointerData xs_heaptid
Definition: relscan.h:173
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 601 of file spgscan.c.

605{
606 in->scankeys = so->keyData;
607 in->orderbys = so->orderByData;
608 in->nkeys = so->numberOfKeys;
610 Assert(!item->isLeaf); /* else reconstructedValue would be wrong type */
611 in->reconstructedValue = item->value;
613 in->traversalValue = item->traversalValue;
614 in->level = item->level;
615 in->returnData = so->want_itup;
616 in->allTheSame = innerTuple->allTheSame;
617 in->hasPrefix = (innerTuple->prefixSize > 0);
618 in->prefixDatum = SGITDATUM(innerTuple, &so->state);
619 in->nNodes = innerTuple->nNodes;
620 in->nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);
621}
Assert(PointerIsAligned(start, uint64))
#define SGITDATUM(x, s)
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:1161
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 662 of file spgscan.c.

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

514{
515 Datum leafValue;
516 double *distances;
517 bool result;
518 bool recheck;
519 bool recheckDistances;
520
521 if (isnull)
522 {
523 /* Should not have arrived on a nulls page unless nulls are wanted */
524 Assert(so->searchNulls);
525 leafValue = (Datum) 0;
526 distances = NULL;
527 recheck = false;
528 recheckDistances = false;
529 result = true;
530 }
531 else
532 {
535
536 /* use temp context for calling leaf_consistent */
538
539 in.scankeys = so->keyData;
540 in.nkeys = so->numberOfKeys;
541 in.orderbys = so->orderByData;
543 Assert(!item->isLeaf); /* else reconstructedValue would be wrong type */
544 in.reconstructedValue = item->value;
546 in.level = item->level;
547 in.returnData = so->want_itup;
548 in.leafDatum = SGLTDATUM(leafTuple, &so->state);
549
550 out.leafValue = (Datum) 0;
551 out.recheck = false;
552 out.distances = NULL;
553 out.recheckDistances = false;
554
556 so->indexCollation,
557 PointerGetDatum(&in),
558 PointerGetDatum(&out)));
559 recheck = out.recheck;
560 recheckDistances = out.recheckDistances;
561 leafValue = out.leafValue;
562 distances = out.distances;
563
564 MemoryContextSwitchTo(oldCxt);
565 }
566
567 if (result)
568 {
569 /* item passes the scankeys */
570 if (so->numberOfNonNullOrderBys > 0)
571 {
572 /* the scan is ordered -> add the item to the queue */
574 SpGistSearchItem *heapItem = spgNewHeapItem(so, item->level,
575 leafTuple,
576 leafValue,
577 recheck,
578 recheckDistances,
579 isnull,
580 distances);
581
582 spgAddSearchItemToQueue(so, heapItem);
583
584 MemoryContextSwitchTo(oldCxt);
585 }
586 else
587 {
588 /* non-ordered scan, so report the item right away */
589 Assert(!recheckDistances);
590 storeRes(so, &leafTuple->heapPtr, leafValue, isnull,
591 leafTuple, recheck, false, NULL);
592 *reportedSome = true;
593 }
594 }
595
596 return result;
597}
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:458
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 624 of file spgscan.c.

629{
630 SpGistSearchItem *item = spgAllocSearchItem(so, isnull, distances);
631
632 item->heapPtr = tuple->t_tid;
633 item->level = out->levelAdds ? parentItem->level + out->levelAdds[i]
634 : parentItem->level;
635
636 /* Must copy value out of temp context */
637 /* (recall that reconstructed values are of type leafType) */
638 item->value = out->reconstructedValues
642 : (Datum) 0;
643
644 item->leafTuple = NULL;
645
646 /*
647 * Elements of out.traversalValues should be allocated in
648 * in.traversalMemoryContext, which is actually a long lived context of
649 * index scan.
650 */
651 item->traversalValue =
652 out->traversalValues ? out->traversalValues[i] : NULL;
653
654 item->isLeaf = false;
655 item->recheck = false;
656 item->recheckDistances = false;
657
658 return item;
659}
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 458 of file spgscan.c.

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

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

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

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

764{
765 SpGistLeafTuple leafTuple = (SpGistLeafTuple)
766 PageGetItem(page, PageGetItemId(page, offset));
767
768 if (leafTuple->tupstate != SPGIST_LIVE)
769 {
770 if (!isroot) /* all tuples on root should be live */
771 {
772 if (leafTuple->tupstate == SPGIST_REDIRECT)
773 {
774 /* redirection tuple should be first in chain */
775 Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
776 /* transfer attention to redirect point */
777 item->heapPtr = ((SpGistDeadTuple) leafTuple)->pointer;
780 }
781
782 if (leafTuple->tupstate == SPGIST_DEAD)
783 {
784 /* dead tuple should be first in chain */
785 Assert(offset == ItemPointerGetOffsetNumber(&item->heapPtr));
786 /* No live entries on this page */
789 }
790 }
791
792 /* We should not arrive at a placeholder */
793 elog(ERROR, "unexpected SPGiST tuple state: %d", leafTuple->tupstate);
795 }
796
797 Assert(ItemPointerIsValid(&leafTuple->heapPtr));
798
799 spgLeafTest(so, item, leafTuple, isnull, reportedSome, storeRes);
800
801 return SGLT_GET_NEXTOFFSET(leafTuple);
802}
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:243
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition: bufpage.h:353
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:511
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 812 of file spgscan.c.

814{
815 Buffer buffer = InvalidBuffer;
816 bool reportedSome = false;
817
818 while (scanWholeIndex || !reportedSome)
819 {
821
822 if (item == NULL)
823 break; /* No more items in queue -> done */
824
825redirect:
826 /* Check for interrupts, just in case of infinite loop */
828
829 if (item->isLeaf)
830 {
831 /* We store heap items in the queue only in case of ordered search */
833 storeRes(so, &item->heapPtr, item->value, item->isNull,
834 item->leafTuple, item->recheck,
835 item->recheckDistances, item->distances);
836 reportedSome = true;
837 }
838 else
839 {
842 Page page;
843 bool isnull;
844
845 if (buffer == InvalidBuffer)
846 {
847 buffer = ReadBuffer(index, blkno);
849 }
850 else if (blkno != BufferGetBlockNumber(buffer))
851 {
852 UnlockReleaseBuffer(buffer);
853 buffer = ReadBuffer(index, blkno);
855 }
856
857 /* else new pointer points to the same page, no work needed */
858
859 page = BufferGetPage(buffer);
860
861 isnull = SpGistPageStoresNulls(page) ? true : false;
862
863 if (SpGistPageIsLeaf(page))
864 {
865 /* Page is a leaf - that is, all its tuples are heap items */
867
868 if (SpGistBlockIsRoot(blkno))
869 {
870 /* When root is a leaf, examine all its tuples */
871 for (offset = FirstOffsetNumber; offset <= max; offset++)
872 (void) spgTestLeafTuple(so, item, page, offset,
873 isnull, true,
874 &reportedSome, storeRes);
875 }
876 else
877 {
878 /* Normal case: just examine the chain we arrived at */
879 while (offset != InvalidOffsetNumber)
880 {
881 Assert(offset >= FirstOffsetNumber && offset <= max);
882 offset = spgTestLeafTuple(so, item, page, offset,
883 isnull, false,
884 &reportedSome, storeRes);
885 if (offset == SpGistRedirectOffsetNumber)
886 goto redirect;
887 }
888 }
889 }
890 else /* page is inner */
891 {
893 PageGetItem(page, PageGetItemId(page, offset));
894
895 if (innerTuple->tupstate != SPGIST_LIVE)
896 {
897 if (innerTuple->tupstate == SPGIST_REDIRECT)
898 {
899 /* transfer attention to redirect point */
900 item->heapPtr = ((SpGistDeadTuple) innerTuple)->pointer;
903 goto redirect;
904 }
905 elog(ERROR, "unexpected SPGiST tuple state: %d",
906 innerTuple->tupstate);
907 }
908
909 spgInnerTest(so, item, innerTuple, isnull);
910 }
911 }
912
913 /* done with this scan item */
914 spgFreeSearchItem(so, item);
915 /* clear temp context before proceeding to the next one */
917 }
918
919 if (buffer != InvalidBuffer)
920 UnlockReleaseBuffer(buffer);
921}
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:4356
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:5518
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:864
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:466
@ BUFFER_LOCK_SHARE
Definition: bufmgr.h:210
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition: bufmgr.h:328
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:741
static OffsetNumber spgTestLeafTuple(SpGistScanOpaque so, SpGistSearchItem *item, Page page, OffsetNumber offset, bool isnull, bool isroot, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:758
static void spgFreeSearchItem(SpGistScanOpaque so, SpGistSearchItem *item)
Definition: spgscan.c:85
static void spgInnerTest(SpGistScanOpaque so, SpGistSearchItem *item, SpGistInnerTuple innerTuple, bool isnull)
Definition: spgscan.c:662

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

930{
931 Assert(!recheckDistances && !distances);
932 tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
933 so->ntids++;
934}
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 954 of file spgscan.c.

958{
960 so->heapPtrs[so->nPtrs] = *heapPtr;
961 so->recheck[so->nPtrs] = recheck;
962 so->recheckDistances[so->nPtrs] = recheckDistances;
963
964 if (so->numberOfOrderBys > 0)
965 {
966 if (isnull || so->numberOfNonNullOrderBys <= 0)
967 so->distances[so->nPtrs] = NULL;
968 else
969 {
971 so->numberOfOrderBys);
972 int i;
973
974 for (i = 0; i < so->numberOfOrderBys; i++)
975 {
976 int offset = so->nonNullOrderByOffsets[i];
977
978 if (offset >= 0)
979 {
980 /* Copy non-NULL distance value */
981 distances[i].value = nonNullDistances[offset];
982 distances[i].isnull = false;
983 }
984 else
985 {
986 /* Set distance's NULL flag. */
987 distances[i].value = 0.0;
988 distances[i].isnull = true;
989 }
990 }
991
992 so->distances[so->nPtrs] = distances;
993 }
994 }
995
996 if (so->want_itup)
997 {
998 /*
999 * Reconstruct index data. We have to copy the datum out of the temp
1000 * context anyway, so we may as well create the tuple here.
1001 */
1002 Datum leafDatums[INDEX_MAX_KEYS];
1003 bool leafIsnulls[INDEX_MAX_KEYS];
1004
1005 /* We only need to deform the old tuple if it has INCLUDE attributes */
1006 if (so->state.leafTupDesc->natts > 1)
1007 spgDeformLeafTuple(leafTuple, so->state.leafTupDesc,
1008 leafDatums, leafIsnulls, isnull);
1009
1010 leafDatums[spgKeyColumn] = leafValue;
1011 leafIsnulls[spgKeyColumn] = isnull;
1012
1014 leafDatums,
1015 leafIsnulls);
1016 }
1017 so->nPtrs++;
1018}
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:1116

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