PostgreSQL Source Code git master
Loading...
Searching...
No Matches
gistget.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/gist_private.h"
#include "access/relscan.h"
#include "executor/instrument_node.h"
#include "lib/pairingheap.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/predicate.h"
#include "utils/float.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for gistget.c:

Go to the source code of this file.

Functions

static void gistkillitems (IndexScanDesc scan)
 
static bool gistindex_keytest (IndexScanDesc scan, IndexTuple tuple, Page page, OffsetNumber offset, bool *recheck_p, bool *recheck_distances_p)
 
static void gistScanPage (IndexScanDesc scan, GISTSearchItem *pageItem, IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
 
static GISTSearchItemgetNextGISTSearchItem (GISTScanOpaque so)
 
static bool getNextNearest (IndexScanDesc scan)
 
bool gistgettuple (IndexScanDesc scan, ScanDirection dir)
 
int64 gistgetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
bool gistcanreturn (Relation index, int attno)
 

Function Documentation

◆ getNextGISTSearchItem()

static GISTSearchItem * getNextGISTSearchItem ( GISTScanOpaque  so)
static

Definition at line 549 of file gistget.c.

550{
551 GISTSearchItem *item;
552
553 if (!pairingheap_is_empty(so->queue))
554 {
555 item = (GISTSearchItem *) pairingheap_remove_first(so->queue);
556 }
557 else
558 {
559 /* Done when both heaps are empty */
560 item = NULL;
561 }
562
563 /* Return item; caller is responsible to pfree it */
564 return item;
565}
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
#define pairingheap_is_empty(h)
Definition pairingheap.h:99
static int fb(int x)

References fb(), pairingheap_is_empty, and pairingheap_remove_first().

Referenced by getNextNearest(), gistgetbitmap(), and gistgettuple().

◆ getNextNearest()

static bool getNextNearest ( IndexScanDesc  scan)
static

Definition at line 571 of file gistget.c.

572{
574 bool res = false;
575
576 if (scan->xs_hitup)
577 {
578 /* free previously returned tuple */
579 pfree(scan->xs_hitup);
580 scan->xs_hitup = NULL;
581 }
582
583 do
584 {
586
587 if (!item)
588 break;
589
590 if (GISTSearchItemIsHeap(*item))
591 {
592 /* found a heap item at currently minimal distance */
593 scan->xs_heaptid = item->data.heap.heapPtr;
594 scan->xs_recheck = item->data.heap.recheck;
595
596 index_store_float8_orderby_distances(scan, so->orderByTypes,
597 item->distances,
599
600 /* in an index-only scan, also return the reconstructed tuple. */
601 if (scan->xs_want_itup)
602 scan->xs_hitup = item->data.heap.recontup;
603 res = true;
604 }
605 else
606 {
607 /* visit an index page, extract its items into queue */
609
610 gistScanPage(scan, item, item->distances, NULL, NULL);
611 }
612
613 pfree(item);
614 } while (!res);
615
616 return res;
617}
GISTScanOpaqueData * GISTScanOpaque
#define GISTSearchItemIsHeap(item)
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition gistget.c:549
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition gistget.c:337
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition indexam.c:953
void pfree(void *pointer)
Definition mcxt.c:1619
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
ItemPointerData heapPtr
GISTSearchHeapItem heap
union GISTSearchItem::@50 data
IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]
HeapTuple xs_hitup
Definition relscan.h:182
ItemPointerData xs_heaptid
Definition relscan.h:185

References CHECK_FOR_INTERRUPTS, GISTSearchItem::data, GISTSearchItem::distances, fb(), getNextGISTSearchItem(), gistScanPage(), GISTSearchItemIsHeap, GISTSearchItem::heap, GISTSearchHeapItem::heapPtr, index_store_float8_orderby_distances(), IndexScanDescData::opaque, pfree(), GISTSearchHeapItem::recheck, GISTSearchHeapItem::recheckDistances, GISTSearchHeapItem::recontup, IndexScanDescData::xs_heaptid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_want_itup.

Referenced by gistgettuple().

◆ gistcanreturn()

bool gistcanreturn ( Relation  index,
int  attno 
)

Definition at line 805 of file gistget.c.

806{
810 return true;
811 else
812 return false;
813}
#define OidIsValid(objectId)
Definition c.h:917
#define GIST_FETCH_PROC
Definition gist.h:40
#define GIST_COMPRESS_PROC
Definition gist.h:34
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:851
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition rel.h:535
Definition type.h:97

References GIST_COMPRESS_PROC, GIST_FETCH_PROC, index_getprocid(), IndexRelationGetNumberOfKeyAttributes, and OidIsValid.

Referenced by gisthandler().

◆ gistgetbitmap()

int64 gistgetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 753 of file gistget.c.

754{
756 int64 ntids = 0;
758
759 if (!so->qual_ok)
760 return 0;
761
763 if (scan->instrument)
764 scan->instrument->nsearches++;
765
766 /* Begin the scan by processing the root page */
767 so->curPageData = so->nPageData = 0;
768 scan->xs_hitup = NULL;
769 if (so->pageDataCxt)
770 MemoryContextReset(so->pageDataCxt);
771
773 memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
774 gistScanPage(scan, &fakeItem, NULL, tbm, &ntids);
775
776 /*
777 * While scanning a leaf page, ItemPointers of matching heap tuples will
778 * be stored directly into tbm, so we don't need to deal with them here.
779 */
780 for (;;)
781 {
783
784 if (!item)
785 break;
786
788
789 gistScanPage(scan, item, item->distances, tbm, &ntids);
790
791 pfree(item);
792 }
793
794 return ntids;
795}
int64_t int64
Definition c.h:680
XLogRecPtr GistNSN
Definition gist.h:63
#define GIST_ROOT_BLKNO
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:406
#define pgstat_count_index_scan(rel)
Definition pgstat.h:745
struct IndexScanInstrumentation * instrument
Definition relscan.h:172
Relation indexRelation
Definition relscan.h:150

References CHECK_FOR_INTERRUPTS, GISTSearchItem::distances, fb(), getNextGISTSearchItem(), GIST_ROOT_BLKNO, gistScanPage(), IndexScanDescData::indexRelation, IndexScanDescData::instrument, MemoryContextReset(), IndexScanInstrumentation::nsearches, IndexScanDescData::opaque, pfree(), pgstat_count_index_scan, and IndexScanDescData::xs_hitup.

Referenced by gisthandler().

◆ gistgettuple()

bool gistgettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 623 of file gistget.c.

624{
626
627 if (dir != ForwardScanDirection)
628 elog(ERROR, "GiST only supports forward scan direction");
629
630 if (!so->qual_ok)
631 return false;
632
633 if (so->firstCall)
634 {
635 /* Begin the scan by processing the root page */
637
639 if (scan->instrument)
640 scan->instrument->nsearches++;
641
642 so->firstCall = false;
643 so->curPageData = so->nPageData = 0;
644 scan->xs_hitup = NULL;
645 if (so->pageDataCxt)
646 MemoryContextReset(so->pageDataCxt);
647
649 memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
651 }
652
653 if (scan->numberOfOrderBys > 0)
654 {
655 /* Must fetch tuples in strict distance order */
656 return getNextNearest(scan);
657 }
658 else
659 {
660 /* Fetch tuples index-page-at-a-time */
661 for (;;)
662 {
663 if (so->curPageData < so->nPageData)
664 {
665 if (scan->kill_prior_tuple && so->curPageData > 0)
666 {
667
668 if (so->killedItems == NULL)
669 {
671 MemoryContextSwitchTo(so->giststate->scanCxt);
672
673 so->killedItems =
675 * sizeof(OffsetNumber));
676
678 }
679 if (so->numKilled < MaxIndexTuplesPerPage)
680 so->killedItems[so->numKilled++] =
681 so->pageData[so->curPageData - 1].offnum;
682 }
683 /* continuing to return tuples from a leaf page */
684 scan->xs_heaptid = so->pageData[so->curPageData].heapPtr;
685 scan->xs_recheck = so->pageData[so->curPageData].recheck;
686
687 /* in an index-only scan, also return the reconstructed tuple */
688 if (scan->xs_want_itup)
689 scan->xs_hitup = so->pageData[so->curPageData].recontup;
690
691 so->curPageData++;
692
693 return true;
694 }
695
696 /*
697 * Check the last returned tuple and add it to killedItems if
698 * necessary
699 */
700 if (scan->kill_prior_tuple
701 && so->curPageData > 0
702 && so->curPageData == so->nPageData)
703 {
704
705 if (so->killedItems == NULL)
706 {
708 MemoryContextSwitchTo(so->giststate->scanCxt);
709
710 so->killedItems =
712 * sizeof(OffsetNumber));
713
715 }
716 if (so->numKilled < MaxIndexTuplesPerPage)
717 so->killedItems[so->numKilled++] =
718 so->pageData[so->curPageData - 1].offnum;
719 }
720 /* find and process the next index page */
721 do
722 {
723 GISTSearchItem *item;
724
725 if ((so->curBlkno != InvalidBlockNumber) && (so->numKilled > 0))
726 gistkillitems(scan);
727
729
730 if (!item)
731 return false;
732
734
735 /*
736 * While scanning a leaf page, ItemPointers of matching heap
737 * tuples are stored in so->pageData. If there are any on
738 * this page, we fall out of the inner "do" and loop around to
739 * return them.
740 */
741 gistScanPage(scan, item, item->distances, NULL, NULL);
742
743 pfree(item);
744 } while (so->nPageData == 0);
745 }
746 }
747}
#define InvalidBlockNumber
Definition block.h:33
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
static bool getNextNearest(IndexScanDesc scan)
Definition gistget.c:571
static void gistkillitems(IndexScanDesc scan)
Definition gistget.c:39
#define MaxIndexTuplesPerPage
Definition itup.h:181
void * palloc(Size size)
Definition mcxt.c:1390
uint16 OffsetNumber
Definition off.h:24
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
@ ForwardScanDirection
Definition sdir.h:28
bool kill_prior_tuple
Definition relscan.h:160

References CHECK_FOR_INTERRUPTS, GISTSearchItem::distances, elog, ERROR, fb(), ForwardScanDirection, getNextGISTSearchItem(), getNextNearest(), GIST_ROOT_BLKNO, gistkillitems(), gistScanPage(), IndexScanDescData::indexRelation, IndexScanDescData::instrument, InvalidBlockNumber, IndexScanDescData::kill_prior_tuple, MaxIndexTuplesPerPage, MemoryContextReset(), MemoryContextSwitchTo(), IndexScanInstrumentation::nsearches, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, palloc(), pfree(), pgstat_count_index_scan, IndexScanDescData::xs_heaptid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_want_itup.

Referenced by gisthandler().

◆ gistindex_keytest()

static bool gistindex_keytest ( IndexScanDesc  scan,
IndexTuple  tuple,
Page  page,
OffsetNumber  offset,
bool recheck_p,
bool recheck_distances_p 
)
static

Definition at line 134 of file gistget.c.

140{
142 GISTSTATE *giststate = so->giststate;
143 ScanKey key = scan->keyData;
144 int keySize = scan->numberOfKeys;
146 Relation r = scan->indexRelation;
147
148 *recheck_p = false;
149 *recheck_distances_p = false;
150
151 /*
152 * If it's a leftover invalid tuple from pre-9.1, treat it as a match with
153 * minimum possible distances. This means we'll always follow it to the
154 * referenced page.
155 */
156 if (GistTupleIsInvalid(tuple))
157 {
158 int i;
159
160 if (GistPageIsLeaf(page)) /* shouldn't happen */
161 elog(ERROR, "invalid GiST tuple found on leaf page");
162 for (i = 0; i < scan->numberOfOrderBys; i++)
163 {
164 so->distances[i].value = -get_float8_infinity();
165 so->distances[i].isnull = false;
166 }
167 return true;
168 }
169
170 /* Check whether it matches according to the Consistent functions */
171 while (keySize > 0)
172 {
173 Datum datum;
174 bool isNull;
175
176 datum = index_getattr(tuple,
177 key->sk_attno,
178 giststate->leafTupdesc,
179 &isNull);
180
181 if (key->sk_flags & SK_ISNULL)
182 {
183 /*
184 * On non-leaf page we can't conclude that child hasn't NULL
185 * values because of assumption in GiST: union (VAL, NULL) is VAL.
186 * But if on non-leaf page key IS NULL, then all children are
187 * NULL.
188 */
189 if (key->sk_flags & SK_SEARCHNULL)
190 {
191 if (GistPageIsLeaf(page) && !isNull)
192 return false;
193 }
194 else
195 {
196 Assert(key->sk_flags & SK_SEARCHNOTNULL);
197 if (isNull)
198 return false;
199 }
200 }
201 else if (isNull)
202 {
203 return false;
204 }
205 else
206 {
207 Datum test;
208 bool recheck;
210
211 gistdentryinit(giststate, key->sk_attno - 1, &de,
212 datum, r, page, offset,
213 false, isNull);
214
215 /*
216 * Call the Consistent function to evaluate the test. The
217 * arguments are the index datum (as a GISTENTRY*), the comparison
218 * datum, the comparison operator's strategy number and subtype
219 * from pg_amop, and the recheck flag.
220 *
221 * (Presently there's no need to pass the subtype since it'll
222 * always be zero, but might as well pass it for possible future
223 * use.)
224 *
225 * We initialize the recheck flag to true (the safest assumption)
226 * in case the Consistent function forgets to set it.
227 */
228 recheck = true;
229
230 test = FunctionCall5Coll(&key->sk_func,
231 key->sk_collation,
233 key->sk_argument,
234 UInt16GetDatum(key->sk_strategy),
235 ObjectIdGetDatum(key->sk_subtype),
236 PointerGetDatum(&recheck));
237
238 if (!DatumGetBool(test))
239 return false;
240 *recheck_p |= recheck;
241 }
242
243 key++;
244 keySize--;
245 }
246
247 /* OK, it passes --- now let's compute the distances */
248 key = scan->orderByData;
249 distance_p = so->distances;
251 while (keySize > 0)
252 {
253 Datum datum;
254 bool isNull;
255
256 datum = index_getattr(tuple,
257 key->sk_attno,
258 giststate->leafTupdesc,
259 &isNull);
260
261 if ((key->sk_flags & SK_ISNULL) || isNull)
262 {
263 /* Assume distance computes as null */
264 distance_p->value = 0.0;
265 distance_p->isnull = true;
266 }
267 else
268 {
269 Datum dist;
270 bool recheck;
272
273 gistdentryinit(giststate, key->sk_attno - 1, &de,
274 datum, r, page, offset,
275 false, isNull);
276
277 /*
278 * Call the Distance function to evaluate the distance. The
279 * arguments are the index datum (as a GISTENTRY*), the comparison
280 * datum, the ordering operator's strategy number and subtype from
281 * pg_amop, and the recheck flag.
282 *
283 * (Presently there's no need to pass the subtype since it'll
284 * always be zero, but might as well pass it for possible future
285 * use.)
286 *
287 * If the function sets the recheck flag, the returned distance is
288 * a lower bound on the true distance and needs to be rechecked.
289 * We initialize the flag to 'false'. This flag was added in
290 * version 9.5; distance functions written before that won't know
291 * about the flag, but are expected to never be lossy.
292 */
293 recheck = false;
294 dist = FunctionCall5Coll(&key->sk_func,
295 key->sk_collation,
297 key->sk_argument,
298 UInt16GetDatum(key->sk_strategy),
299 ObjectIdGetDatum(key->sk_subtype),
300 PointerGetDatum(&recheck));
301 *recheck_distances_p |= recheck;
303 distance_p->isnull = false;
304 }
305
306 key++;
307 distance_p++;
308 keySize--;
309 }
310
311 return true;
312}
#define Assert(condition)
Definition c.h:1002
static float8 get_float8_infinity(void)
Definition float.h:68
Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5)
Definition fmgr.c:1225
#define GistPageIsLeaf(page)
Definition gist.h:170
#define GistTupleIsInvalid(itup)
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition gistutil.c:547
int i
Definition isn.c:77
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition itup.h:131
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static Datum UInt16GetDatum(uint16 X)
Definition postgres.h:192
static float8 DatumGetFloat8(Datum X)
Definition postgres.h:498
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
static void test(void)
#define SK_SEARCHNOTNULL
Definition skey.h:122
#define SK_SEARCHNULL
Definition skey.h:121
#define SK_ISNULL
Definition skey.h:115
TupleDesc leafTupdesc
struct ScanKeyData * keyData
Definition relscan.h:154
struct ScanKeyData * orderByData
Definition relscan.h:155

References Assert, DatumGetBool(), DatumGetFloat8(), elog, ERROR, fb(), FunctionCall5Coll(), get_float8_infinity(), gistdentryinit(), GistPageIsLeaf, GistTupleIsInvalid, i, index_getattr(), IndexScanDescData::indexRelation, IndexScanDescData::keyData, GISTSTATE::leafTupdesc, IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, ObjectIdGetDatum(), IndexScanDescData::opaque, IndexScanDescData::orderByData, PointerGetDatum, SK_ISNULL, SK_SEARCHNOTNULL, SK_SEARCHNULL, test(), and UInt16GetDatum().

Referenced by gistScanPage().

◆ gistkillitems()

static void gistkillitems ( IndexScanDesc  scan)
static

Definition at line 39 of file gistget.c.

40{
42 Buffer buffer;
43 Page page;
44 OffsetNumber offnum;
45 ItemId iid;
46 int i;
47 bool killedsomething = false;
48
49 Assert(so->curBlkno != InvalidBlockNumber);
50 Assert(XLogRecPtrIsValid(so->curPageLSN));
51 Assert(so->killedItems != NULL);
52
53 buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
54 if (!BufferIsValid(buffer))
55 return;
56
57 LockBuffer(buffer, GIST_SHARE);
58 gistcheckpage(scan->indexRelation, buffer);
59 page = BufferGetPage(buffer);
60
61 /*
62 * If page LSN differs it means that the page was modified since the last
63 * read. killedItems could be not valid so LP_DEAD hints applying is not
64 * safe.
65 */
66 if (BufferGetLSNAtomic(buffer) != so->curPageLSN)
67 goto unlock;
68
70
71 /*
72 * Mark all killedItems as dead. We need no additional recheck, because,
73 * if page was modified, curPageLSN must have changed.
74 */
75 for (i = 0; i < so->numKilled; i++)
76 {
77 if (!killedsomething)
78 {
79 /*
80 * Use the hint bit infrastructure to check if we can update the
81 * page while just holding a share lock. If we are not allowed,
82 * there's no point continuing.
83 */
84 if (!BufferBeginSetHintBits(buffer))
85 goto unlock;
86 }
87
88 offnum = so->killedItems[i];
89 iid = PageGetItemId(page, offnum);
91 killedsomething = true;
92 }
93
95 {
97 BufferFinishSetHintBits(buffer, true, true);
98 }
99
100unlock:
101 UnlockReleaseBuffer(buffer);
102
103 /*
104 * Always reset the scan state, so we don't look for same items on other
105 * pages.
106 */
107 so->numKilled = 0;
108}
int Buffer
Definition buf.h:23
void BufferFinishSetHintBits(Buffer buffer, bool mark_dirty, bool buffer_std)
Definition bufmgr.c:7119
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition bufmgr.c:4736
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5626
bool BufferBeginSetHintBits(Buffer buffer)
Definition bufmgr.c:7091
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:879
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:468
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:334
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:419
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:268
PageData * Page
Definition bufpage.h:81
#define GistMarkPageHasGarbage(page)
Definition gist.h:180
#define GIST_SHARE
void gistcheckpage(Relation rel, Buffer buf)
Definition gistutil.c:785
#define ItemIdMarkDead(itemId)
Definition itemid.h:179
#define XLogRecPtrIsValid(r)
Definition xlogdefs.h:29

References Assert, BufferBeginSetHintBits(), BufferFinishSetHintBits(), BufferGetLSNAtomic(), BufferGetPage(), BufferIsValid(), fb(), GIST_SHARE, gistcheckpage(), GistMarkPageHasGarbage, GistPageIsLeaf, i, IndexScanDescData::indexRelation, InvalidBlockNumber, ItemIdMarkDead, LockBuffer(), IndexScanDescData::opaque, PageGetItemId(), ReadBuffer(), UnlockReleaseBuffer(), and XLogRecPtrIsValid.

Referenced by gistgettuple().

◆ gistScanPage()

static void gistScanPage ( IndexScanDesc  scan,
GISTSearchItem pageItem,
IndexOrderByDistance myDistances,
TIDBitmap tbm,
int64 ntids 
)
static

Definition at line 337 of file gistget.c.

339{
341 GISTSTATE *giststate = so->giststate;
342 Relation r = scan->indexRelation;
343 Buffer buffer;
344 Page page;
345 GISTPageOpaque opaque;
346 OffsetNumber maxoff;
349
351
352 buffer = ReadBuffer(scan->indexRelation, pageItem->blkno);
353 LockBuffer(buffer, GIST_SHARE);
355 gistcheckpage(scan->indexRelation, buffer);
356 page = BufferGetPage(buffer);
357 opaque = GistPageGetOpaque(page);
358
359 /*
360 * Check if we need to follow the rightlink. We need to follow it if the
361 * page was concurrently split since we visited the parent (in which case
362 * parentlsn < nsn), or if the system crashed after a page split but
363 * before the downlink was inserted into the parent.
364 */
365 if (XLogRecPtrIsValid(pageItem->data.parentlsn) &&
366 (GistFollowRight(page) ||
367 pageItem->data.parentlsn < GistPageGetNSN(page)) &&
368 opaque->rightlink != InvalidBlockNumber /* sanity check */ )
369 {
370 /* There was a page split, follow right link to add pages */
371 GISTSearchItem *item;
372
373 /* This can't happen when starting at the root */
375
376 oldcxt = MemoryContextSwitchTo(so->queueCxt);
377
378 /* Create new GISTSearchItem for the right sibling index page */
380 item->blkno = opaque->rightlink;
381 item->data.parentlsn = pageItem->data.parentlsn;
382
383 /* Insert it into the queue using same distances as for this page */
385 sizeof(item->distances[0]) * scan->numberOfOrderBys);
386
387 pairingheap_add(so->queue, &item->phNode);
388
390 }
391
392 /*
393 * Check if the page was deleted after we saw the downlink. There's
394 * nothing of interest on a deleted page. Note that we must do this after
395 * checking the NSN for concurrent splits! It's possible that the page
396 * originally contained some tuples that are visible to us, but was split
397 * so that all the visible tuples were moved to another page, and then
398 * this page was deleted.
399 */
400 if (GistPageIsDeleted(page))
401 {
402 UnlockReleaseBuffer(buffer);
403 return;
404 }
405
406 so->nPageData = so->curPageData = 0;
407 scan->xs_hitup = NULL; /* might point into pageDataCxt */
408 if (so->pageDataCxt)
409 MemoryContextReset(so->pageDataCxt);
410
411 /*
412 * Save the current page's block number for a possible gistkillitems()
413 * call later. We also save its LSN, so that we know whether it is safe
414 * to apply the LP_DEAD hints to the page later. This allows us to drop
415 * the pin for MVCC scans, which allows vacuum to avoid blocking.
416 */
417 so->curBlkno = pageItem->blkno;
418 so->curPageLSN = BufferGetLSNAtomic(buffer);
419
420 /*
421 * check all tuples on page
422 */
423 maxoff = PageGetMaxOffsetNumber(page);
424 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
425 {
426 ItemId iid = PageGetItemId(page, i);
428 bool match;
429 bool recheck;
431
432 /*
433 * If the scan specifies not to return killed tuples, then we treat a
434 * killed tuple as not passing the qual.
435 */
437 continue;
438
439 it = (IndexTuple) PageGetItem(page, iid);
440
441 /*
442 * Must call gistindex_keytest in tempCxt, and clean up any leftover
443 * junk afterward.
444 */
445 oldcxt = MemoryContextSwitchTo(so->giststate->tempCxt);
446
447 match = gistindex_keytest(scan, it, page, i,
448 &recheck, &recheck_distances);
449
451 MemoryContextReset(so->giststate->tempCxt);
452
453 /* Ignore tuple if it doesn't match */
454 if (!match)
455 continue;
456
457 if (tbm && GistPageIsLeaf(page))
458 {
459 /*
460 * getbitmap scan, so just push heap tuple TIDs into the bitmap
461 * without worrying about ordering
462 */
463 tbm_add_tuples(tbm, &it->t_tid, 1, recheck);
464 (*ntids)++;
465 }
466 else if (scan->numberOfOrderBys == 0 && GistPageIsLeaf(page))
467 {
468 /*
469 * Non-ordered scan, so report tuples in so->pageData[]
470 */
471 so->pageData[so->nPageData].heapPtr = it->t_tid;
472 so->pageData[so->nPageData].recheck = recheck;
473 so->pageData[so->nPageData].offnum = i;
474
475 /*
476 * In an index-only scan, also fetch the data from the tuple. The
477 * reconstructed tuples are stored in pageDataCxt.
478 */
479 if (scan->xs_want_itup)
480 {
481 oldcxt = MemoryContextSwitchTo(so->pageDataCxt);
482 so->pageData[so->nPageData].recontup =
483 gistFetchTuple(giststate, r, it);
485 }
486 so->nPageData++;
487 }
488 else
489 {
490 /*
491 * Must push item into search queue. We get here for any lower
492 * index page, and also for heap tuples if doing an ordered
493 * search.
494 */
495 GISTSearchItem *item;
496 int nOrderBys = scan->numberOfOrderBys;
497
498 oldcxt = MemoryContextSwitchTo(so->queueCxt);
499
500 /* Create new GISTSearchItem for this item */
502
503 if (GistPageIsLeaf(page))
504 {
505 /* Creating heap-tuple GISTSearchItem */
507 item->data.heap.heapPtr = it->t_tid;
508 item->data.heap.recheck = recheck;
510
511 /*
512 * In an index-only scan, also fetch the data from the tuple.
513 */
514 if (scan->xs_want_itup)
515 item->data.heap.recontup = gistFetchTuple(giststate, r, it);
516 }
517 else
518 {
519 /* Creating index-page GISTSearchItem */
520 item->blkno = ItemPointerGetBlockNumber(&it->t_tid);
521
522 /*
523 * LSN of current page is lsn of parent page for child. We
524 * only have a shared lock, so we need to get the LSN
525 * atomically.
526 */
527 item->data.parentlsn = BufferGetLSNAtomic(buffer);
528 }
529
530 /* Insert it into the queue using new distance data */
531 memcpy(item->distances, so->distances,
532 sizeof(item->distances[0]) * nOrderBys);
533
534 pairingheap_add(so->queue, &item->phNode);
535
537 }
538 }
539
540 UnlockReleaseBuffer(buffer);
541}
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4469
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:378
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:396
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
#define GistFollowRight(page)
Definition gist.h:183
#define GistPageIsDeleted(page)
Definition gist.h:173
#define GistPageGetOpaque(page)
Definition gist.h:168
#define GistPageGetNSN(page)
Definition gist.h:187
#define SizeOfGISTSearchItem(n_distances)
static bool gistindex_keytest(IndexScanDesc scan, IndexTuple tuple, Page page, OffsetNumber offset, bool *recheck_p, bool *recheck_distances_p)
Definition gistget.c:134
HeapTuple gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
Definition gistutil.c:667
#define ItemIdIsDead(itemId)
Definition itemid.h:113
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition itemptr.h:103
IndexTupleData * IndexTuple
Definition itup.h:53
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
#define FirstOffsetNumber
Definition off.h:27
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
Definition predicate.c:2528
BlockNumber rightlink
Definition gist.h:81
BlockNumber blkno
pairingheap_node phNode
bool ignore_killed_tuples
Definition relscan.h:161
struct SnapshotData * xs_snapshot
Definition relscan.h:151
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointerData *tids, int ntids, bool recheck)
Definition tidbitmap.c:367

References Assert, GISTSearchItem::blkno, BufferGetBlockNumber(), BufferGetLSNAtomic(), BufferGetPage(), GISTSearchItem::data, GISTSearchItem::distances, fb(), FirstOffsetNumber, GIST_SHARE, gistcheckpage(), gistFetchTuple(), GistFollowRight, gistindex_keytest(), GistPageGetNSN, GistPageGetOpaque, GistPageIsDeleted, GistPageIsLeaf, GISTSearchItemIsHeap, GISTSearchItem::heap, GISTSearchHeapItem::heapPtr, i, IndexScanDescData::ignore_killed_tuples, IndexScanDescData::indexRelation, InvalidBlockNumber, ItemIdIsDead, ItemPointerGetBlockNumber(), LockBuffer(), memcpy(), MemoryContextReset(), MemoryContextSwitchTo(), IndexScanDescData::numberOfOrderBys, OffsetNumberNext, IndexScanDescData::opaque, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), pairingheap_add(), palloc(), GISTSearchItem::parentlsn, GISTSearchItem::phNode, PredicateLockPage(), ReadBuffer(), GISTSearchHeapItem::recheck, GISTSearchHeapItem::recheckDistances, GISTSearchHeapItem::recontup, GISTPageOpaqueData::rightlink, SizeOfGISTSearchItem, tbm_add_tuples(), UnlockReleaseBuffer(), XLogRecPtrIsValid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_snapshot, and IndexScanDescData::xs_want_itup.

Referenced by getNextNearest(), gistgetbitmap(), and gistgettuple().