PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 755 of file spgscan.c.

756{
760};
#define InvalidOffsetNumber
Definition: off.h:26
#define MaxOffsetNumber
Definition: off.h:28
@ SpGistErrorOffsetNumber
Definition: spgscan.c:759
@ SpGistBreakOffsetNumber
Definition: spgscan.c:757
@ SpGistRedirectOffsetNumber
Definition: spgscan.c:758

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:71
int a
Definition: isn.c:70
int i
Definition: isn.c:74
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:383
void pfree(void *pointer)
Definition: mcxt.c:1524
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:112
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
uintptr_t Datum
Definition: postgres.h:69
#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:1317
#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 = (ScanKey) palloc(sizeof(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 */
339 so->orderByTypes = (Oid *)
340 palloc(sizeof(Oid) * scan->numberOfOrderBys);
341 so->nonNullOrderByOffsets = (int *)
342 palloc(sizeof(int) * scan->numberOfOrderBys);
343
344 /* These arrays have constant contents, so we can fill them now */
345 so->zeroDistances = (double *)
346 palloc(sizeof(double) * scan->numberOfOrderBys);
347 so->infDistances = (double *)
348 palloc(sizeof(double) * scan->numberOfOrderBys);
349
350 for (i = 0; i < scan->numberOfOrderBys; i++)
351 {
352 so->zeroDistances[i] = 0.0;
354 }
355
356 scan->xs_orderbyvals = (Datum *)
357 palloc0(sizeof(Datum) * scan->numberOfOrderBys);
358 scan->xs_orderbynulls = (bool *)
359 palloc(sizeof(bool) * scan->numberOfOrderBys);
360 memset(scan->xs_orderbynulls, true,
361 sizeof(bool) * scan->numberOfOrderBys);
362 }
363
367
371
372 so->indexCollation = rel->rd_indcollation[0];
373
374 scan->opaque = so;
375
376 return scan;
377}
static float8 get_float8_infinity(void)
Definition: float.h:94
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:580
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:80
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:906
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
unsigned int Oid
Definition: postgres_ext.h:30
ScanKeyData * ScanKey
Definition: skey.h:75
#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:187
int numberOfOrderBys
Definition: relscan.h:140
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:170
Relation indexRelation
Definition: relscan.h:137
Datum * xs_orderbyvals
Definition: relscan.h:186
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, palloc(), palloc0(), RelationData::rd_indcollation, SpGistScanOpaqueData::reconTupDesc, RelationGetIndexScan(), SPGIST_INNER_CONSISTENT_PROC, SPGIST_LEAF_CONSISTENT_PROC, SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, SpGistScanOpaqueData::traversalCxt, IndexScanDescData::xs_hitupdesc, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, and SpGistScanOpaqueData::zeroDistances.

Referenced by spghandler().

◆ spgcanreturn()

bool spgcanreturn ( Relation  index,
int  attno 
)

Definition at line 1083 of file spgscan.c.

1084{
1085 SpGistCache *cache;
1086
1087 /* INCLUDE attributes can always be fetched for index-only scans */
1088 if (attno > 1)
1089 return true;
1090
1091 /* We can do it if the opclass config function says so */
1092 cache = spgGetCache(index);
1093
1094 return cache->config.canReturnData;
1095}
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 429 of file spgscan.c.

430{
432
435
436 if (so->keyData)
437 pfree(so->keyData);
438
439 if (so->state.leafTupDesc &&
442
443 if (so->state.deadTupleStorage)
445
446 if (scan->numberOfOrderBys > 0)
447 {
448 pfree(so->orderByTypes);
450 pfree(so->zeroDistances);
451 pfree(so->infDistances);
452 pfree(scan->xs_orderbyvals);
453 pfree(scan->xs_orderbynulls);
454 }
455
456 pfree(so);
457}
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define RelationGetDescr(relation)
Definition: rel.h:539
Relation index
TupleDesc leafTupDesc
char * deadTupleStorage
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:479

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:317
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 942 of file spgscan.c.

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

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

747{
749 return NULL; /* Done when both heaps are empty */
750
751 /* Return item; caller is responsible to pfree it */
753}
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96

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

Referenced by spgWalk().

◆ spggettuple()

bool spggettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 1026 of file spgscan.c.

1027{
1029
1030 if (dir != ForwardScanDirection)
1031 elog(ERROR, "SP-GiST only supports forward scan direction");
1032
1033 /* Copy want_itup to *so so we don't need to pass it around separately */
1034 so->want_itup = scan->xs_want_itup;
1035
1036 for (;;)
1037 {
1038 if (so->iPtr < so->nPtrs)
1039 {
1040 /* continuing to return reported tuples */
1041 scan->xs_heaptid = so->heapPtrs[so->iPtr];
1042 scan->xs_recheck = so->recheck[so->iPtr];
1043 scan->xs_hitup = so->reconTups[so->iPtr];
1044
1045 if (so->numberOfOrderBys > 0)
1047 so->distances[so->iPtr],
1048 so->recheckDistances[so->iPtr]);
1049 so->iPtr++;
1050 return true;
1051 }
1052
1053 if (so->numberOfOrderBys > 0)
1054 {
1055 /* Must pfree distances to avoid memory leak */
1056 int i;
1057
1058 for (i = 0; i < so->nPtrs; i++)
1059 if (so->distances[i])
1060 pfree(so->distances[i]);
1061 }
1062
1063 if (so->want_itup)
1064 {
1065 /* Must pfree reconstructed tuples to avoid memory leak */
1066 int i;
1067
1068 for (i = 0; i < so->nPtrs; i++)
1069 pfree(so->reconTups[i]);
1070 }
1071 so->iPtr = so->nPtrs = 0;
1072
1073 spgWalk(scan->indexRelation, so, false, storeGettuple);
1074
1075 if (so->nPtrs == 0)
1076 break; /* must have completed scan */
1077 }
1078
1079 return false;
1080}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:974
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:78
@ 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:959
HeapTuple xs_hitup
Definition: relscan.h:169
ItemPointerData xs_heaptid
Definition: relscan.h:172
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 606 of file spgscan.c.

610{
611 in->scankeys = so->keyData;
612 in->orderbys = so->orderByData;
613 in->nkeys = so->numberOfKeys;
615 Assert(!item->isLeaf); /* else reconstructedValue would be wrong type */
616 in->reconstructedValue = item->value;
618 in->traversalValue = item->traversalValue;
619 in->level = item->level;
620 in->returnData = so->want_itup;
621 in->allTheSame = innerTuple->allTheSame;
622 in->hasPrefix = (innerTuple->prefixSize > 0);
623 in->prefixDatum = SGITDATUM(innerTuple, &so->state);
624 in->nNodes = innerTuple->nNodes;
625 in->nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);
626}
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 667 of file spgscan.c.

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

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

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

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

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:75
#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:141
struct ScanKeyData * orderByData
Definition: relscan.h:142
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 380 of file spgscan.c.

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

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

819{
820 Buffer buffer = InvalidBuffer;
821 bool reportedSome = false;
822
823 while (scanWholeIndex || !reportedSome)
824 {
826
827 if (item == NULL)
828 break; /* No more items in queue -> done */
829
830redirect:
831 /* Check for interrupts, just in case of infinite loop */
833
834 if (item->isLeaf)
835 {
836 /* We store heap items in the queue only in case of ordered search */
838 storeRes(so, &item->heapPtr, item->value, item->isNull,
839 item->leafTuple, item->recheck,
840 item->recheckDistances, item->distances);
841 reportedSome = true;
842 }
843 else
844 {
847 Page page;
848 bool isnull;
849
850 if (buffer == InvalidBuffer)
851 {
852 buffer = ReadBuffer(index, blkno);
854 }
855 else if (blkno != BufferGetBlockNumber(buffer))
856 {
857 UnlockReleaseBuffer(buffer);
858 buffer = ReadBuffer(index, blkno);
860 }
861
862 /* else new pointer points to the same page, no work needed */
863
864 page = BufferGetPage(buffer);
865
866 isnull = SpGistPageStoresNulls(page) ? true : false;
867
868 if (SpGistPageIsLeaf(page))
869 {
870 /* Page is a leaf - that is, all its tuples are heap items */
872
873 if (SpGistBlockIsRoot(blkno))
874 {
875 /* When root is a leaf, examine all its tuples */
876 for (offset = FirstOffsetNumber; offset <= max; offset++)
877 (void) spgTestLeafTuple(so, item, page, offset,
878 isnull, true,
879 &reportedSome, storeRes);
880 }
881 else
882 {
883 /* Normal case: just examine the chain we arrived at */
884 while (offset != InvalidOffsetNumber)
885 {
886 Assert(offset >= FirstOffsetNumber && offset <= max);
887 offset = spgTestLeafTuple(so, item, page, offset,
888 isnull, false,
889 &reportedSome, storeRes);
890 if (offset == SpGistRedirectOffsetNumber)
891 goto redirect;
892 }
893 }
894 }
895 else /* page is inner */
896 {
898 PageGetItem(page, PageGetItemId(page, offset));
899
900 if (innerTuple->tupstate != SPGIST_LIVE)
901 {
902 if (innerTuple->tupstate == SPGIST_REDIRECT)
903 {
904 /* transfer attention to redirect point */
905 item->heapPtr = ((SpGistDeadTuple) innerTuple)->pointer;
908 goto redirect;
909 }
910 elog(ERROR, "unexpected SPGiST tuple state: %d",
911 innerTuple->tupstate);
912 }
913
914 spgInnerTest(so, item, innerTuple, isnull);
915 }
916 }
917
918 /* done with this scan item */
919 spgFreeSearchItem(so, item);
920 /* clear temp context before proceeding to the next one */
922 }
923
924 if (buffer != InvalidBuffer)
925 UnlockReleaseBuffer(buffer);
926}
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:3795
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4934
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5151
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:751
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:191
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:401
PageData * Page
Definition: bufpage.h:82
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition: bufpage.h:372
return true
Definition: isn.c:127
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
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:746
static OffsetNumber spgTestLeafTuple(SpGistScanOpaque so, SpGistSearchItem *item, Page page, OffsetNumber offset, bool isnull, bool isroot, bool *reportedSome, storeRes_func storeRes)
Definition: spgscan.c:763
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:667

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

935{
936 Assert(!recheckDistances && !distances);
937 tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
938 so->ntids++;
939}
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:366

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

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

Referenced by spggettuple().