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 539 of file gistget.c.

540{
541 GISTSearchItem *item;
542
543 if (!pairingheap_is_empty(so->queue))
544 {
545 item = (GISTSearchItem *) pairingheap_remove_first(so->queue);
546 }
547 else
548 {
549 /* Done when both heaps are empty */
550 item = NULL;
551 }
552
553 /* Return item; caller is responsible to pfree it */
554 return item;
555}
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 561 of file gistget.c.

562{
564 bool res = false;
565
566 if (scan->xs_hitup)
567 {
568 /* free previously returned tuple */
569 pfree(scan->xs_hitup);
570 scan->xs_hitup = NULL;
571 }
572
573 do
574 {
576
577 if (!item)
578 break;
579
580 if (GISTSearchItemIsHeap(*item))
581 {
582 /* found a heap item at currently minimal distance */
583 scan->xs_heaptid = item->data.heap.heapPtr;
584 scan->xs_recheck = item->data.heap.recheck;
585
586 index_store_float8_orderby_distances(scan, so->orderByTypes,
587 item->distances,
589
590 /* in an index-only scan, also return the reconstructed tuple. */
591 if (scan->xs_want_itup)
592 scan->xs_hitup = item->data.heap.recontup;
593 res = true;
594 }
595 else
596 {
597 /* visit an index page, extract its items into queue */
599
600 gistScanPage(scan, item, item->distances, NULL, NULL);
601 }
602
603 pfree(item);
604 } while (!res);
605
606 return res;
607}
GISTScanOpaqueData * GISTScanOpaque
#define GISTSearchItemIsHeap(item)
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition gistget.c:539
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition gistget.c:329
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition indexam.c:985
void pfree(void *pointer)
Definition mcxt.c:1616
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
ItemPointerData heapPtr
GISTSearchHeapItem heap
IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]
union GISTSearchItem::@47 data
HeapTuple xs_hitup
Definition relscan.h:170
ItemPointerData xs_heaptid
Definition relscan.h:173

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 798 of file gistget.c.

799{
803 return true;
804 else
805 return false;
806}
#define OidIsValid(objectId)
Definition c.h:788
#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:883
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition rel.h:533
Definition type.h:96

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

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

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 613 of file gistget.c.

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

References GISTSearchItem::blkno, 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 126 of file gistget.c.

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

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 {
68 UnlockReleaseBuffer(buffer);
69 so->numKilled = 0; /* reset counter */
70 return;
71 }
72
74
75 /*
76 * Mark all killedItems as dead. We need no additional recheck, because,
77 * if page was modified, curPageLSN must have changed.
78 */
79 for (i = 0; i < so->numKilled; i++)
80 {
81 offnum = so->killedItems[i];
82 iid = PageGetItemId(page, offnum);
84 killedsomething = true;
85 }
86
88 {
90 MarkBufferDirtyHint(buffer, true);
91 }
92
93 UnlockReleaseBuffer(buffer);
94
95 /*
96 * Always reset the scan state, so we don't look for same items on other
97 * pages.
98 */
99 so->numKilled = 0;
100}
int Buffer
Definition buf.h:23
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition bufmgr.c:4634
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5518
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition bufmgr.c:5565
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:864
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:466
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:328
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:417
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:243
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, BufferGetLSNAtomic(), BufferGetPage(), BufferIsValid(), fb(), GIST_SHARE, gistcheckpage(), GistMarkPageHasGarbage, GistPageIsLeaf, i, IndexScanDescData::indexRelation, InvalidBlockNumber, ItemIdMarkDead, LockBuffer(), MarkBufferDirtyHint(), 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 329 of file gistget.c.

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