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