PostgreSQL Source Code  git master
gistget.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * gistget.c
4  * fetch tuples from a GiST scan.
5  *
6  *
7  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/access/gist/gistget.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/genam.h"
18 #include "access/gist_private.h"
19 #include "access/relscan.h"
20 #include "lib/pairingheap.h"
21 #include "miscadmin.h"
22 #include "pgstat.h"
23 #include "storage/predicate.h"
24 #include "utils/float.h"
25 #include "utils/memutils.h"
26 #include "utils/rel.h"
27 
28 /*
29  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
30  * told us were killed.
31  *
32  * We re-read page here, so it's important to check page LSN. If the page
33  * has been modified since the last read (as determined by LSN), we cannot
34  * flag any entries because it is possible that the old entry was vacuumed
35  * away and the TID was re-used by a completely different heap tuple.
36  */
37 static void
39 {
41  Buffer buffer;
42  Page page;
43  OffsetNumber offnum;
44  ItemId iid;
45  int i;
46  bool killedsomething = false;
47 
50  Assert(so->killedItems != NULL);
51 
52  buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
53  if (!BufferIsValid(buffer))
54  return;
55 
56  LockBuffer(buffer, GIST_SHARE);
57  gistcheckpage(scan->indexRelation, buffer);
58  page = BufferGetPage(buffer);
59 
60  /*
61  * If page LSN differs it means that the page was modified since the last
62  * read. killedItems could be not valid so LP_DEAD hints applying is not
63  * safe.
64  */
65  if (BufferGetLSNAtomic(buffer) != so->curPageLSN)
66  {
67  UnlockReleaseBuffer(buffer);
68  so->numKilled = 0; /* reset counter */
69  return;
70  }
71 
72  Assert(GistPageIsLeaf(page));
73 
74  /*
75  * Mark all killedItems as dead. We need no additional recheck, because,
76  * if page was modified, curPageLSN must have changed.
77  */
78  for (i = 0; i < so->numKilled; i++)
79  {
80  offnum = so->killedItems[i];
81  iid = PageGetItemId(page, offnum);
82  ItemIdMarkDead(iid);
83  killedsomething = true;
84  }
85 
86  if (killedsomething)
87  {
89  MarkBufferDirtyHint(buffer, true);
90  }
91 
92  UnlockReleaseBuffer(buffer);
93 
94  /*
95  * Always reset the scan state, so we don't look for same items on other
96  * pages.
97  */
98  so->numKilled = 0;
99 }
100 
101 /*
102  * gistindex_keytest() -- does this index tuple satisfy the scan key(s)?
103  *
104  * The index tuple might represent either a heap tuple or a lower index page,
105  * depending on whether the containing page is a leaf page or not.
106  *
107  * On success return for a heap tuple, *recheck_p is set to indicate whether
108  * the quals need to be rechecked. We recheck if any of the consistent()
109  * functions request it. recheck is not interesting when examining a non-leaf
110  * entry, since we must visit the lower index page if there's any doubt.
111  * Similarly, *recheck_distances_p is set to indicate whether the distances
112  * need to be rechecked, and it is also ignored for non-leaf entries.
113  *
114  * If we are doing an ordered scan, so->distances[] is filled with distance
115  * data from the distance() functions before returning success.
116  *
117  * We must decompress the key in the IndexTuple before passing it to the
118  * sk_funcs (which actually are the opclass Consistent or Distance methods).
119  *
120  * Note that this function is always invoked in a short-lived memory context,
121  * so we don't need to worry about cleaning up allocated memory, either here
122  * or in the implementation of any Consistent or Distance methods.
123  */
124 static bool
126  IndexTuple tuple,
127  Page page,
128  OffsetNumber offset,
129  bool *recheck_p,
130  bool *recheck_distances_p)
131 {
132  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
133  GISTSTATE *giststate = so->giststate;
134  ScanKey key = scan->keyData;
135  int keySize = scan->numberOfKeys;
136  IndexOrderByDistance *distance_p;
137  Relation r = scan->indexRelation;
138 
139  *recheck_p = false;
140  *recheck_distances_p = false;
141 
142  /*
143  * If it's a leftover invalid tuple from pre-9.1, treat it as a match with
144  * minimum possible distances. This means we'll always follow it to the
145  * referenced page.
146  */
147  if (GistTupleIsInvalid(tuple))
148  {
149  int i;
150 
151  if (GistPageIsLeaf(page)) /* shouldn't happen */
152  elog(ERROR, "invalid GiST tuple found on leaf page");
153  for (i = 0; i < scan->numberOfOrderBys; i++)
154  {
156  so->distances[i].isnull = false;
157  }
158  return true;
159  }
160 
161  /* Check whether it matches according to the Consistent functions */
162  while (keySize > 0)
163  {
164  Datum datum;
165  bool isNull;
166 
167  datum = index_getattr(tuple,
168  key->sk_attno,
169  giststate->leafTupdesc,
170  &isNull);
171 
172  if (key->sk_flags & SK_ISNULL)
173  {
174  /*
175  * On non-leaf page we can't conclude that child hasn't NULL
176  * values because of assumption in GiST: union (VAL, NULL) is VAL.
177  * But if on non-leaf page key IS NULL, then all children are
178  * NULL.
179  */
180  if (key->sk_flags & SK_SEARCHNULL)
181  {
182  if (GistPageIsLeaf(page) && !isNull)
183  return false;
184  }
185  else
186  {
187  Assert(key->sk_flags & SK_SEARCHNOTNULL);
188  if (isNull)
189  return false;
190  }
191  }
192  else if (isNull)
193  {
194  return false;
195  }
196  else
197  {
198  Datum test;
199  bool recheck;
200  GISTENTRY de;
201 
202  gistdentryinit(giststate, key->sk_attno - 1, &de,
203  datum, r, page, offset,
204  false, isNull);
205 
206  /*
207  * Call the Consistent function to evaluate the test. The
208  * arguments are the index datum (as a GISTENTRY*), the comparison
209  * datum, the comparison operator's strategy number and subtype
210  * from pg_amop, and the recheck flag.
211  *
212  * (Presently there's no need to pass the subtype since it'll
213  * always be zero, but might as well pass it for possible future
214  * use.)
215  *
216  * We initialize the recheck flag to true (the safest assumption)
217  * in case the Consistent function forgets to set it.
218  */
219  recheck = true;
220 
221  test = FunctionCall5Coll(&key->sk_func,
222  key->sk_collation,
223  PointerGetDatum(&de),
224  key->sk_argument,
225  Int16GetDatum(key->sk_strategy),
226  ObjectIdGetDatum(key->sk_subtype),
227  PointerGetDatum(&recheck));
228 
229  if (!DatumGetBool(test))
230  return false;
231  *recheck_p |= recheck;
232  }
233 
234  key++;
235  keySize--;
236  }
237 
238  /* OK, it passes --- now let's compute the distances */
239  key = scan->orderByData;
240  distance_p = so->distances;
241  keySize = scan->numberOfOrderBys;
242  while (keySize > 0)
243  {
244  Datum datum;
245  bool isNull;
246 
247  datum = index_getattr(tuple,
248  key->sk_attno,
249  giststate->leafTupdesc,
250  &isNull);
251 
252  if ((key->sk_flags & SK_ISNULL) || isNull)
253  {
254  /* Assume distance computes as null */
255  distance_p->value = 0.0;
256  distance_p->isnull = true;
257  }
258  else
259  {
260  Datum dist;
261  bool recheck;
262  GISTENTRY de;
263 
264  gistdentryinit(giststate, key->sk_attno - 1, &de,
265  datum, r, page, offset,
266  false, isNull);
267 
268  /*
269  * Call the Distance function to evaluate the distance. The
270  * arguments are the index datum (as a GISTENTRY*), the comparison
271  * datum, the ordering operator's strategy number and subtype from
272  * pg_amop, and the recheck flag.
273  *
274  * (Presently there's no need to pass the subtype since it'll
275  * always be zero, but might as well pass it for possible future
276  * use.)
277  *
278  * If the function sets the recheck flag, the returned distance is
279  * a lower bound on the true distance and needs to be rechecked.
280  * We initialize the flag to 'false'. This flag was added in
281  * version 9.5; distance functions written before that won't know
282  * about the flag, but are expected to never be lossy.
283  */
284  recheck = false;
285  dist = FunctionCall5Coll(&key->sk_func,
286  key->sk_collation,
287  PointerGetDatum(&de),
288  key->sk_argument,
289  Int16GetDatum(key->sk_strategy),
290  ObjectIdGetDatum(key->sk_subtype),
291  PointerGetDatum(&recheck));
292  *recheck_distances_p |= recheck;
293  distance_p->value = DatumGetFloat8(dist);
294  distance_p->isnull = false;
295  }
296 
297  key++;
298  distance_p++;
299  keySize--;
300  }
301 
302  return true;
303 }
304 
305 /*
306  * Scan all items on the GiST index page identified by *pageItem, and insert
307  * them into the queue (or directly to output areas)
308  *
309  * scan: index scan we are executing
310  * pageItem: search queue item identifying an index page to scan
311  * myDistances: distances array associated with pageItem, or NULL at the root
312  * tbm: if not NULL, gistgetbitmap's output bitmap
313  * ntids: if not NULL, gistgetbitmap's output tuple counter
314  *
315  * If tbm/ntids aren't NULL, we are doing an amgetbitmap scan, and heap
316  * tuples should be reported directly into the bitmap. If they are NULL,
317  * we're doing a plain or ordered indexscan. For a plain indexscan, heap
318  * tuple TIDs are returned into so->pageData[]. For an ordered indexscan,
319  * heap tuple TIDs are pushed into individual search queue items. In an
320  * index-only scan, reconstructed index tuples are returned along with the
321  * TIDs.
322  *
323  * If we detect that the index page has split since we saw its downlink
324  * in the parent, we push its new right sibling onto the queue so the
325  * sibling will be processed next.
326  */
327 static void
329  IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
330 {
331  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
332  GISTSTATE *giststate = so->giststate;
333  Relation r = scan->indexRelation;
334  Buffer buffer;
335  Page page;
336  GISTPageOpaque opaque;
337  OffsetNumber maxoff;
338  OffsetNumber i;
339  MemoryContext oldcxt;
340 
341  Assert(!GISTSearchItemIsHeap(*pageItem));
342 
343  buffer = ReadBuffer(scan->indexRelation, pageItem->blkno);
344  LockBuffer(buffer, GIST_SHARE);
346  gistcheckpage(scan->indexRelation, buffer);
347  page = BufferGetPage(buffer);
348  opaque = GistPageGetOpaque(page);
349 
350  /*
351  * Check if we need to follow the rightlink. We need to follow it if the
352  * page was concurrently split since we visited the parent (in which case
353  * parentlsn < nsn), or if the system crashed after a page split but
354  * before the downlink was inserted into the parent.
355  */
356  if (!XLogRecPtrIsInvalid(pageItem->data.parentlsn) &&
357  (GistFollowRight(page) ||
358  pageItem->data.parentlsn < GistPageGetNSN(page)) &&
359  opaque->rightlink != InvalidBlockNumber /* sanity check */ )
360  {
361  /* There was a page split, follow right link to add pages */
362  GISTSearchItem *item;
363 
364  /* This can't happen when starting at the root */
365  Assert(myDistances != NULL);
366 
367  oldcxt = MemoryContextSwitchTo(so->queueCxt);
368 
369  /* Create new GISTSearchItem for the right sibling index page */
371  item->blkno = opaque->rightlink;
372  item->data.parentlsn = pageItem->data.parentlsn;
373 
374  /* Insert it into the queue using same distances as for this page */
375  memcpy(item->distances, myDistances,
376  sizeof(item->distances[0]) * scan->numberOfOrderBys);
377 
378  pairingheap_add(so->queue, &item->phNode);
379 
380  MemoryContextSwitchTo(oldcxt);
381  }
382 
383  /*
384  * Check if the page was deleted after we saw the downlink. There's
385  * nothing of interest on a deleted page. Note that we must do this after
386  * checking the NSN for concurrent splits! It's possible that the page
387  * originally contained some tuples that are visible to us, but was split
388  * so that all the visible tuples were moved to another page, and then
389  * this page was deleted.
390  */
391  if (GistPageIsDeleted(page))
392  {
393  UnlockReleaseBuffer(buffer);
394  return;
395  }
396 
397  so->nPageData = so->curPageData = 0;
398  scan->xs_hitup = NULL; /* might point into pageDataCxt */
399  if (so->pageDataCxt)
401 
402  /*
403  * We save the LSN of the page as we read it, so that we know whether it
404  * safe to apply LP_DEAD hints to the page later. This allows us to drop
405  * the pin for MVCC scans, which allows vacuum to avoid blocking.
406  */
407  so->curPageLSN = BufferGetLSNAtomic(buffer);
408 
409  /*
410  * check all tuples on page
411  */
412  maxoff = PageGetMaxOffsetNumber(page);
413  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
414  {
415  ItemId iid = PageGetItemId(page, i);
416  IndexTuple it;
417  bool match;
418  bool recheck;
419  bool recheck_distances;
420 
421  /*
422  * If the scan specifies not to return killed tuples, then we treat a
423  * killed tuple as not passing the qual.
424  */
425  if (scan->ignore_killed_tuples && ItemIdIsDead(iid))
426  continue;
427 
428  it = (IndexTuple) PageGetItem(page, iid);
429 
430  /*
431  * Must call gistindex_keytest in tempCxt, and clean up any leftover
432  * junk afterward.
433  */
434  oldcxt = MemoryContextSwitchTo(so->giststate->tempCxt);
435 
436  match = gistindex_keytest(scan, it, page, i,
437  &recheck, &recheck_distances);
438 
439  MemoryContextSwitchTo(oldcxt);
441 
442  /* Ignore tuple if it doesn't match */
443  if (!match)
444  continue;
445 
446  if (tbm && GistPageIsLeaf(page))
447  {
448  /*
449  * getbitmap scan, so just push heap tuple TIDs into the bitmap
450  * without worrying about ordering
451  */
452  tbm_add_tuples(tbm, &it->t_tid, 1, recheck);
453  (*ntids)++;
454  }
455  else if (scan->numberOfOrderBys == 0 && GistPageIsLeaf(page))
456  {
457  /*
458  * Non-ordered scan, so report tuples in so->pageData[]
459  */
460  so->pageData[so->nPageData].heapPtr = it->t_tid;
461  so->pageData[so->nPageData].recheck = recheck;
462  so->pageData[so->nPageData].offnum = i;
463 
464  /*
465  * In an index-only scan, also fetch the data from the tuple. The
466  * reconstructed tuples are stored in pageDataCxt.
467  */
468  if (scan->xs_want_itup)
469  {
470  oldcxt = MemoryContextSwitchTo(so->pageDataCxt);
471  so->pageData[so->nPageData].recontup =
472  gistFetchTuple(giststate, r, it);
473  MemoryContextSwitchTo(oldcxt);
474  }
475  so->nPageData++;
476  }
477  else
478  {
479  /*
480  * Must push item into search queue. We get here for any lower
481  * index page, and also for heap tuples if doing an ordered
482  * search.
483  */
484  GISTSearchItem *item;
485  int nOrderBys = scan->numberOfOrderBys;
486 
487  oldcxt = MemoryContextSwitchTo(so->queueCxt);
488 
489  /* Create new GISTSearchItem for this item */
491 
492  if (GistPageIsLeaf(page))
493  {
494  /* Creating heap-tuple GISTSearchItem */
495  item->blkno = InvalidBlockNumber;
496  item->data.heap.heapPtr = it->t_tid;
497  item->data.heap.recheck = recheck;
498  item->data.heap.recheckDistances = recheck_distances;
499 
500  /*
501  * In an index-only scan, also fetch the data from the tuple.
502  */
503  if (scan->xs_want_itup)
504  item->data.heap.recontup = gistFetchTuple(giststate, r, it);
505  }
506  else
507  {
508  /* Creating index-page GISTSearchItem */
509  item->blkno = ItemPointerGetBlockNumber(&it->t_tid);
510 
511  /*
512  * LSN of current page is lsn of parent page for child. We
513  * only have a shared lock, so we need to get the LSN
514  * atomically.
515  */
516  item->data.parentlsn = BufferGetLSNAtomic(buffer);
517  }
518 
519  /* Insert it into the queue using new distance data */
520  memcpy(item->distances, so->distances,
521  sizeof(item->distances[0]) * nOrderBys);
522 
523  pairingheap_add(so->queue, &item->phNode);
524 
525  MemoryContextSwitchTo(oldcxt);
526  }
527  }
528 
529  UnlockReleaseBuffer(buffer);
530 }
531 
532 /*
533  * Extract next item (in order) from search queue
534  *
535  * Returns a GISTSearchItem or NULL. Caller must pfree item when done with it.
536  */
537 static GISTSearchItem *
539 {
540  GISTSearchItem *item;
541 
542  if (!pairingheap_is_empty(so->queue))
543  {
545  }
546  else
547  {
548  /* Done when both heaps are empty */
549  item = NULL;
550  }
551 
552  /* Return item; caller is responsible to pfree it */
553  return item;
554 }
555 
556 /*
557  * Fetch next heap tuple in an ordered search
558  */
559 static bool
561 {
562  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
563  bool res = false;
564 
565  if (scan->xs_hitup)
566  {
567  /* free previously returned tuple */
568  pfree(scan->xs_hitup);
569  scan->xs_hitup = NULL;
570  }
571 
572  do
573  {
575 
576  if (!item)
577  break;
578 
579  if (GISTSearchItemIsHeap(*item))
580  {
581  /* found a heap item at currently minimal distance */
582  scan->xs_heaptid = item->data.heap.heapPtr;
583  scan->xs_recheck = item->data.heap.recheck;
584 
586  item->distances,
587  item->data.heap.recheckDistances);
588 
589  /* in an index-only scan, also return the reconstructed tuple. */
590  if (scan->xs_want_itup)
591  scan->xs_hitup = item->data.heap.recontup;
592  res = true;
593  }
594  else
595  {
596  /* visit an index page, extract its items into queue */
598 
599  gistScanPage(scan, item, item->distances, NULL, NULL);
600  }
601 
602  pfree(item);
603  } while (!res);
604 
605  return res;
606 }
607 
608 /*
609  * gistgettuple() -- Get the next tuple in the scan
610  */
611 bool
613 {
614  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
615 
616  if (dir != ForwardScanDirection)
617  elog(ERROR, "GiST only supports forward scan direction");
618 
619  if (!so->qual_ok)
620  return false;
621 
622  if (so->firstCall)
623  {
624  /* Begin the scan by processing the root page */
625  GISTSearchItem fakeItem;
626 
628 
629  so->firstCall = false;
630  so->curPageData = so->nPageData = 0;
631  scan->xs_hitup = NULL;
632  if (so->pageDataCxt)
634 
635  fakeItem.blkno = GIST_ROOT_BLKNO;
636  memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
637  gistScanPage(scan, &fakeItem, NULL, NULL, NULL);
638  }
639 
640  if (scan->numberOfOrderBys > 0)
641  {
642  /* Must fetch tuples in strict distance order */
643  return getNextNearest(scan);
644  }
645  else
646  {
647  /* Fetch tuples index-page-at-a-time */
648  for (;;)
649  {
650  if (so->curPageData < so->nPageData)
651  {
652  if (scan->kill_prior_tuple && so->curPageData > 0)
653  {
654 
655  if (so->killedItems == NULL)
656  {
657  MemoryContext oldCxt =
659 
660  so->killedItems =
662  * sizeof(OffsetNumber));
663 
664  MemoryContextSwitchTo(oldCxt);
665  }
667  so->killedItems[so->numKilled++] =
668  so->pageData[so->curPageData - 1].offnum;
669  }
670  /* continuing to return tuples from a leaf page */
671  scan->xs_heaptid = so->pageData[so->curPageData].heapPtr;
672  scan->xs_recheck = so->pageData[so->curPageData].recheck;
673 
674  /* in an index-only scan, also return the reconstructed tuple */
675  if (scan->xs_want_itup)
676  scan->xs_hitup = so->pageData[so->curPageData].recontup;
677 
678  so->curPageData++;
679 
680  return true;
681  }
682 
683  /*
684  * Check the last returned tuple and add it to killedItems if
685  * necessary
686  */
687  if (scan->kill_prior_tuple
688  && so->curPageData > 0
689  && so->curPageData == so->nPageData)
690  {
691 
692  if (so->killedItems == NULL)
693  {
694  MemoryContext oldCxt =
696 
697  so->killedItems =
699  * sizeof(OffsetNumber));
700 
701  MemoryContextSwitchTo(oldCxt);
702  }
704  so->killedItems[so->numKilled++] =
705  so->pageData[so->curPageData - 1].offnum;
706  }
707  /* find and process the next index page */
708  do
709  {
710  GISTSearchItem *item;
711 
712  if ((so->curBlkno != InvalidBlockNumber) && (so->numKilled > 0))
713  gistkillitems(scan);
714 
715  item = getNextGISTSearchItem(so);
716 
717  if (!item)
718  return false;
719 
721 
722  /* save current item BlockNumber for next gistkillitems() call */
723  so->curBlkno = item->blkno;
724 
725  /*
726  * While scanning a leaf page, ItemPointers of matching heap
727  * tuples are stored in so->pageData. If there are any on
728  * this page, we fall out of the inner "do" and loop around to
729  * return them.
730  */
731  gistScanPage(scan, item, item->distances, NULL, NULL);
732 
733  pfree(item);
734  } while (so->nPageData == 0);
735  }
736  }
737 }
738 
739 /*
740  * gistgetbitmap() -- Get a bitmap of all heap tuple locations
741  */
742 int64
744 {
745  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
746  int64 ntids = 0;
747  GISTSearchItem fakeItem;
748 
749  if (!so->qual_ok)
750  return 0;
751 
753 
754  /* Begin the scan by processing the root page */
755  so->curPageData = so->nPageData = 0;
756  scan->xs_hitup = NULL;
757  if (so->pageDataCxt)
759 
760  fakeItem.blkno = GIST_ROOT_BLKNO;
761  memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
762  gistScanPage(scan, &fakeItem, NULL, tbm, &ntids);
763 
764  /*
765  * While scanning a leaf page, ItemPointers of matching heap tuples will
766  * be stored directly into tbm, so we don't need to deal with them here.
767  */
768  for (;;)
769  {
771 
772  if (!item)
773  break;
774 
776 
777  gistScanPage(scan, item, item->distances, tbm, &ntids);
778 
779  pfree(item);
780  }
781 
782  return ntids;
783 }
784 
785 /*
786  * Can we do index-only scans on the given index column?
787  *
788  * Opclasses that implement a fetch function support index-only scans.
789  * Opclasses without compression functions also support index-only scans.
790  * Included attributes always can be fetched for index-only scans.
791  */
792 bool
794 {
798  return true;
799  else
800  return false;
801 }
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3377
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3638
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4577
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4795
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4624
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:734
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:301
Pointer Page
Definition: bufpage.h:78
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:369
#define OidIsValid(objectId)
Definition: c.h:762
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
static float8 get_float8_infinity(void)
Definition: float.h:94
Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5)
Definition: fmgr.c:1223
#define GIST_FETCH_PROC
Definition: gist.h:39
#define GIST_COMPRESS_PROC
Definition: gist.h:33
#define GistPageIsLeaf(page)
Definition: gist.h:169
#define GistFollowRight(page)
Definition: gist.h:182
#define GistPageIsDeleted(page)
Definition: gist.h:172
#define GistPageGetOpaque(page)
Definition: gist.h:167
#define GistMarkPageHasGarbage(page)
Definition: gist.h:179
#define GistPageGetNSN(page)
Definition: gist.h:186
XLogRecPtr GistNSN
Definition: gist.h:62
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:181
#define SizeOfGISTSearchItem(n_distances)
Definition: gist_private.h:147
#define GistTupleIsInvalid(itup)
Definition: gist_private.h:288
#define GIST_SHARE
Definition: gist_private.h:42
#define GISTSearchItemIsHeap(item)
Definition: gist_private.h:145
static bool getNextNearest(IndexScanDesc scan)
Definition: gistget.c:560
static bool gistindex_keytest(IndexScanDesc scan, IndexTuple tuple, Page page, OffsetNumber offset, bool *recheck_p, bool *recheck_distances_p)
Definition: gistget.c:125
bool gistgettuple(IndexScanDesc scan, ScanDirection dir)
Definition: gistget.c:612
int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: gistget.c:743
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition: gistget.c:538
bool gistcanreturn(Relation index, int attno)
Definition: gistget.c:793
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition: gistget.c:328
static void gistkillitems(IndexScanDesc scan)
Definition: gistget.c:38
HeapTuple gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
Definition: gistutil.c:667
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:547
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:785
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:829
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:931
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
#define ItemIdMarkDead(itemId)
Definition: itemid.h:179
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103
IndexTupleData * IndexTuple
Definition: itup.h:53
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: itup.h:117
#define MaxIndexTuplesPerPage
Definition: itup.h:165
Assert(fmt[strlen(fmt) - 1] !='\n')
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:371
void pfree(void *pointer)
Definition: mcxt.c:1508
void * palloc(Size size)
Definition: mcxt.c:1304
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:625
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static float8 DatumGetFloat8(Datum X)
Definition: postgres.h:494
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
Definition: predicate.c:2579
static void test(void)
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
ScanDirection
Definition: sdir.h:25
@ ForwardScanDirection
Definition: sdir.h:28
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_SEARCHNULL
Definition: skey.h:121
#define SK_ISNULL
Definition: skey.h:115
MemoryContext tempCxt
Definition: gist_private.h:78
MemoryContext scanCxt
Definition: gist_private.h:77
OffsetNumber * killedItems
Definition: gist_private.h:168
pairingheap * queue
Definition: gist_private.h:159
OffsetNumber nPageData
Definition: gist_private.h:175
GISTSTATE * giststate
Definition: gist_private.h:156
MemoryContext queueCxt
Definition: gist_private.h:160
OffsetNumber curPageData
Definition: gist_private.h:176
GISTSearchHeapItem pageData[BLCKSZ/sizeof(IndexTupleData)]
Definition: gist_private.h:174
IndexOrderByDistance * distances
Definition: gist_private.h:165
BlockNumber curBlkno
Definition: gist_private.h:170
MemoryContext pageDataCxt
Definition: gist_private.h:177
ItemPointerData heapPtr
Definition: gist_private.h:120
OffsetNumber offnum
Definition: gist_private.h:125
GISTSearchHeapItem heap
Definition: gist_private.h:138
BlockNumber blkno
Definition: gist_private.h:133
IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:142
union GISTSearchItem::@43 data
GistNSN parentlsn
Definition: gist_private.h:136
pairingheap_node phNode
Definition: gist_private.h:132
struct ScanKeyData * keyData
Definition: relscan.h:122
struct ScanKeyData * orderByData
Definition: relscan.h:123
HeapTuple xs_hitup
Definition: relscan.h:144
bool ignore_killed_tuples
Definition: relscan.h:129
int numberOfOrderBys
Definition: relscan.h:121
bool kill_prior_tuple
Definition: relscan.h:128
Relation indexRelation
Definition: relscan.h:118
ItemPointerData xs_heaptid
Definition: relscan.h:147
struct SnapshotData * xs_snapshot
Definition: relscan.h:119
ItemPointerData t_tid
Definition: itup.h:37
Definition: type.h:95
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:377
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29