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