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