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