PostgreSQL Source Code  git master
gistget.c File Reference
#include "postgres.h"
#include "access/gist_private.h"
#include "access/relscan.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "lib/pairingheap.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for gistget.c:

Go to the source code of this file.

Functions

static void gistkillitems (IndexScanDesc scan)
 
static bool gistindex_keytest (IndexScanDesc scan, IndexTuple tuple, Page page, OffsetNumber offset, bool *recheck_p, bool *recheck_distances_p)
 
static void gistScanPage (IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances, TIDBitmap *tbm, int64 *ntids)
 
static GISTSearchItemgetNextGISTSearchItem (GISTScanOpaque so)
 
static bool getNextNearest (IndexScanDesc scan)
 
bool gistgettuple (IndexScanDesc scan, ScanDirection dir)
 
int64 gistgetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
bool gistcanreturn (Relation index, int attno)
 

Function Documentation

◆ getNextGISTSearchItem()

static GISTSearchItem* getNextGISTSearchItem ( GISTScanOpaque  so)
static

Definition at line 517 of file gistget.c.

References pairingheap_is_empty, pairingheap_remove_first(), and GISTScanOpaqueData::queue.

Referenced by getNextNearest(), gistgetbitmap(), and gistgettuple().

518 {
519  GISTSearchItem *item;
520 
521  if (!pairingheap_is_empty(so->queue))
522  {
524  }
525  else
526  {
527  /* Done when both heaps are empty */
528  item = NULL;
529  }
530 
531  /* Return item; caller is responsible to pfree it */
532  return item;
533 }
pairingheap * queue
Definition: gist_private.h:155
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145

◆ getNextNearest()

static bool getNextNearest ( IndexScanDesc  scan)
static

Definition at line 539 of file gistget.c.

References CHECK_FOR_INTERRUPTS, GISTSearchItem::data, DatumGetPointer, GISTSearchItem::distances, elog, ERROR, Float4GetDatum(), FLOAT4OID, Float8GetDatum(), FLOAT8OID, getNextGISTSearchItem(), gistScanPage(), GISTSearchItemIsHeap, GISTSearchItem::heap, GISTSearchHeapItem::heapPtr, i, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, GISTScanOpaqueData::orderByTypes, pfree(), GISTSearchHeapItem::recheck, GISTSearchHeapItem::recheckDistances, GISTSearchHeapItem::recontup, HeapTupleData::t_self, IndexScanDescData::xs_ctup, IndexScanDescData::xs_hitup, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, IndexScanDescData::xs_recheck, IndexScanDescData::xs_recheckorderby, and IndexScanDescData::xs_want_itup.

Referenced by gistgettuple().

540 {
541  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
542  bool res = false;
543  int i;
544 
545  if (scan->xs_hitup)
546  {
547  /* free previously returned tuple */
548  pfree(scan->xs_hitup);
549  scan->xs_hitup = NULL;
550  }
551 
552  do
553  {
555 
556  if (!item)
557  break;
558 
559  if (GISTSearchItemIsHeap(*item))
560  {
561  /* found a heap item at currently minimal distance */
562  scan->xs_ctup.t_self = item->data.heap.heapPtr;
563  scan->xs_recheck = item->data.heap.recheck;
565  for (i = 0; i < scan->numberOfOrderBys; i++)
566  {
567  if (so->orderByTypes[i] == FLOAT8OID)
568  {
569 #ifndef USE_FLOAT8_BYVAL
570  /* must free any old value to avoid memory leakage */
571  if (!scan->xs_orderbynulls[i])
573 #endif
574  scan->xs_orderbyvals[i] = Float8GetDatum(item->distances[i]);
575  scan->xs_orderbynulls[i] = false;
576  }
577  else if (so->orderByTypes[i] == FLOAT4OID)
578  {
579  /* convert distance function's result to ORDER BY type */
580 #ifndef USE_FLOAT4_BYVAL
581  /* must free any old value to avoid memory leakage */
582  if (!scan->xs_orderbynulls[i])
584 #endif
585  scan->xs_orderbyvals[i] = Float4GetDatum((float4) item->distances[i]);
586  scan->xs_orderbynulls[i] = false;
587  }
588  else
589  {
590  /*
591  * If the ordering operator's return value is anything
592  * else, we don't know how to convert the float8 bound
593  * calculated by the distance function to that. The
594  * executor won't actually need the order by values we
595  * return here, if there are no lossy results, so only
596  * insist on converting if the *recheck flag is set.
597  */
598  if (scan->xs_recheckorderby)
599  elog(ERROR, "GiST operator family's FOR ORDER BY operator must return float8 or float4 if the distance function is lossy");
600  scan->xs_orderbynulls[i] = true;
601  }
602  }
603 
604  /* in an index-only scan, also return the reconstructed tuple. */
605  if (scan->xs_want_itup)
606  scan->xs_hitup = item->data.heap.recontup;
607  res = true;
608  }
609  else
610  {
611  /* visit an index page, extract its items into queue */
613 
614  gistScanPage(scan, item, item->distances, NULL, NULL);
615  }
616 
617  pfree(item);
618  } while (!res);
619 
620  return res;
621 }
Datum * xs_orderbyvals
Definition: relscan.h:132
bool xs_recheckorderby
Definition: relscan.h:134
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1810
double distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:139
bool * xs_orderbynulls
Definition: relscan.h:133
void pfree(void *pointer)
Definition: mcxt.c:936
#define ERROR
Definition: elog.h:43
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition: gistget.c:322
Datum Float4GetDatum(float4 X)
Definition: fmgr.c:1798
ItemPointerData t_self
Definition: htup.h:65
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:177
#define GISTSearchItemIsHeap(item)
Definition: gist_private.h:143
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition: gistget.c:517
float float4
Definition: c.h:438
GISTSearchHeapItem heap
Definition: gist_private.h:137
#define FLOAT4OID
Definition: pg_type.h:416
union GISTSearchItem::@43 data
bool xs_want_itup
Definition: relscan.h:96
ItemPointerData heapPtr
Definition: gist_private.h:119
HeapTupleData xs_ctup
Definition: relscan.h:120
#define FLOAT8OID
Definition: pg_type.h:419
#define DatumGetPointer(X)
Definition: postgres.h:555
HeapTuple xs_hitup
Definition: relscan.h:116
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
int numberOfOrderBys
Definition: relscan.h:93
#define elog
Definition: elog.h:219

◆ gistcanreturn()

bool gistcanreturn ( Relation  index,
int  attno 
)

Definition at line 807 of file gistget.c.

References GIST_COMPRESS_PROC, GIST_FETCH_PROC, index_getprocid(), and OidIsValid.

Referenced by gisthandler().

808 {
809  if (OidIsValid(index_getprocid(index, attno, GIST_FETCH_PROC)) ||
811  return true;
812  else
813  return false;
814 }
#define GIST_FETCH_PROC
Definition: gist.h:36
#define OidIsValid(objectId)
Definition: c.h:586
#define GIST_COMPRESS_PROC
Definition: gist.h:30
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:821

◆ gistgetbitmap()

int64 gistgetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 758 of file gistget.c.

References CHECK_FOR_INTERRUPTS, GISTScanOpaqueData::curPageData, GISTSearchItem::distances, getNextGISTSearchItem(), GIST_ROOT_BLKNO, gistScanPage(), IndexScanDescData::indexRelation, MemoryContextReset(), GISTScanOpaqueData::nPageData, IndexScanDescData::opaque, GISTScanOpaqueData::pageDataCxt, pfree(), pgstat_count_index_scan, GISTScanOpaqueData::qual_ok, and IndexScanDescData::xs_hitup.

Referenced by gisthandler().

759 {
760  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
761  int64 ntids = 0;
762  GISTSearchItem fakeItem;
763 
764  if (!so->qual_ok)
765  return 0;
766 
768 
769  /* Begin the scan by processing the root page */
770  so->curPageData = so->nPageData = 0;
771  scan->xs_hitup = NULL;
772  if (so->pageDataCxt)
774 
775  fakeItem.blkno = GIST_ROOT_BLKNO;
776  memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
777  gistScanPage(scan, &fakeItem, NULL, tbm, &ntids);
778 
779  /*
780  * While scanning a leaf page, ItemPointers of matching heap tuples will
781  * be stored directly into tbm, so we don't need to deal with them here.
782  */
783  for (;;)
784  {
786 
787  if (!item)
788  break;
789 
791 
792  gistScanPage(scan, item, item->distances, tbm, &ntids);
793 
794  pfree(item);
795  }
796 
797  return ntids;
798 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:134
MemoryContext pageDataCxt
Definition: gist_private.h:173
Relation indexRelation
Definition: relscan.h:90
double distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:139
void pfree(void *pointer)
Definition: mcxt.c:936
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition: gistget.c:322
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:177
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1275
OffsetNumber nPageData
Definition: gist_private.h:171
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition: gistget.c:517
OffsetNumber curPageData
Definition: gist_private.h:172
XLogRecPtr GistNSN
Definition: gist.h:50
HeapTuple xs_hitup
Definition: relscan.h:116
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98

◆ gistgettuple()

bool gistgettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 627 of file gistget.c.

References GISTSearchItem::blkno, CHECK_FOR_INTERRUPTS, GISTScanOpaqueData::curBlkno, GISTScanOpaqueData::curPageData, GISTSearchItem::data, GISTSearchItem::distances, elog, ERROR, GISTScanOpaqueData::firstCall, ForwardScanDirection, getNextGISTSearchItem(), getNextNearest(), GIST_ROOT_BLKNO, gistkillitems(), gistScanPage(), GISTScanOpaqueData::giststate, GISTSearchHeapItem::heapPtr, IndexScanDescData::indexRelation, InvalidBlockNumber, IndexScanDescData::kill_prior_tuple, GISTScanOpaqueData::killedItems, MaxIndexTuplesPerPage, MemoryContextReset(), MemoryContextSwitchTo(), GISTScanOpaqueData::nPageData, IndexScanDescData::numberOfOrderBys, GISTScanOpaqueData::numKilled, GISTSearchHeapItem::offnum, IndexScanDescData::opaque, GISTScanOpaqueData::pageData, GISTScanOpaqueData::pageDataCxt, palloc(), GISTSearchItem::parentlsn, pfree(), pgstat_count_index_scan, GISTScanOpaqueData::qual_ok, GISTSearchHeapItem::recheck, GISTSearchHeapItem::recontup, GISTSTATE::scanCxt, HeapTupleData::t_self, IndexScanDescData::xs_ctup, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_want_itup.

Referenced by gisthandler().

628 {
629  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
630 
631  if (dir != ForwardScanDirection)
632  elog(ERROR, "GiST only supports forward scan direction");
633 
634  if (!so->qual_ok)
635  return false;
636 
637  if (so->firstCall)
638  {
639  /* Begin the scan by processing the root page */
640  GISTSearchItem fakeItem;
641 
643 
644  so->firstCall = false;
645  so->curPageData = so->nPageData = 0;
646  scan->xs_hitup = NULL;
647  if (so->pageDataCxt)
649 
650  fakeItem.blkno = GIST_ROOT_BLKNO;
651  memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
652  gistScanPage(scan, &fakeItem, NULL, NULL, NULL);
653  }
654 
655  if (scan->numberOfOrderBys > 0)
656  {
657  /* Must fetch tuples in strict distance order */
658  return getNextNearest(scan);
659  }
660  else
661  {
662  /* Fetch tuples index-page-at-a-time */
663  for (;;)
664  {
665  if (so->curPageData < so->nPageData)
666  {
667  if (scan->kill_prior_tuple && so->curPageData > 0)
668  {
669 
670  if (so->killedItems == NULL)
671  {
672  MemoryContext oldCxt =
674 
675  so->killedItems =
677  * sizeof(OffsetNumber));
678 
679  MemoryContextSwitchTo(oldCxt);
680  }
682  so->killedItems[so->numKilled++] =
683  so->pageData[so->curPageData - 1].offnum;
684  }
685  /* continuing to return tuples from a leaf page */
686  scan->xs_ctup.t_self = so->pageData[so->curPageData].heapPtr;
687  scan->xs_recheck = so->pageData[so->curPageData].recheck;
688 
689  /* in an index-only scan, also return the reconstructed tuple */
690  if (scan->xs_want_itup)
691  scan->xs_hitup = so->pageData[so->curPageData].recontup;
692 
693  so->curPageData++;
694 
695  return true;
696  }
697 
698  /*
699  * Check the last returned tuple and add it to killitems if
700  * necessary
701  */
702  if (scan->kill_prior_tuple
703  && so->curPageData > 0
704  && so->curPageData == so->nPageData)
705  {
706 
707  if (so->killedItems == NULL)
708  {
709  MemoryContext oldCxt =
711 
712  so->killedItems =
714  * sizeof(OffsetNumber));
715 
716  MemoryContextSwitchTo(oldCxt);
717  }
719  so->killedItems[so->numKilled++] =
720  so->pageData[so->curPageData - 1].offnum;
721  }
722  /* find and process the next index page */
723  do
724  {
725  GISTSearchItem *item;
726 
727  if ((so->curBlkno != InvalidBlockNumber) && (so->numKilled > 0))
728  gistkillitems(scan);
729 
730  item = getNextGISTSearchItem(so);
731 
732  if (!item)
733  return false;
734 
736 
737  /* save current item BlockNumber for next gistkillitems() call */
738  so->curBlkno = item->blkno;
739 
740  /*
741  * While scanning a leaf page, ItemPointers of matching heap
742  * tuples are stored in so->pageData. If there are any on
743  * this page, we fall out of the inner "do" and loop around to
744  * return them.
745  */
746  gistScanPage(scan, item, item->distances, NULL, NULL);
747 
748  pfree(item);
749  } while (so->nPageData == 0);
750  }
751  }
752 }
BlockNumber blkno
Definition: gist_private.h:132
OffsetNumber * killedItems
Definition: gist_private.h:164
BlockNumber curBlkno
Definition: gist_private.h:166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:134
MemoryContext pageDataCxt
Definition: gist_private.h:173
Relation indexRelation
Definition: relscan.h:90
uint16 OffsetNumber
Definition: off.h:24
GISTSTATE * giststate
Definition: gist_private.h:152
double distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:139
void pfree(void *pointer)
Definition: mcxt.c:936
#define ERROR
Definition: elog.h:43
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition: gistget.c:322
ItemPointerData t_self
Definition: htup.h:65
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:177
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1275
OffsetNumber nPageData
Definition: gist_private.h:171
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition: gistget.c:517
union GISTSearchItem::@43 data
bool xs_want_itup
Definition: relscan.h:96
ItemPointerData heapPtr
Definition: gist_private.h:119
static bool getNextNearest(IndexScanDesc scan)
Definition: gistget.c:539
HeapTupleData xs_ctup
Definition: relscan.h:120
GISTSearchHeapItem pageData[BLCKSZ/sizeof(IndexTupleData)]
Definition: gist_private.h:170
#define InvalidBlockNumber
Definition: block.h:33
OffsetNumber curPageData
Definition: gist_private.h:172
XLogRecPtr GistNSN
Definition: gist.h:50
static void gistkillitems(IndexScanDesc scan)
Definition: gistget.c:37
#define MaxIndexTuplesPerPage
Definition: itup.h:137
void * palloc(Size size)
Definition: mcxt.c:835
HeapTuple xs_hitup
Definition: relscan.h:116
OffsetNumber offnum
Definition: gist_private.h:124
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
bool kill_prior_tuple
Definition: relscan.h:100
MemoryContext scanCxt
Definition: gist_private.h:78
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
int numberOfOrderBys
Definition: relscan.h:93
#define elog
Definition: elog.h:219
GistNSN parentlsn
Definition: gist_private.h:135

◆ gistindex_keytest()

static bool gistindex_keytest ( IndexScanDesc  scan,
IndexTuple  tuple,
Page  page,
OffsetNumber  offset,
bool recheck_p,
bool recheck_distances_p 
)
static

Definition at line 124 of file gistget.c.

References Assert, DatumGetBool, DatumGetFloat8, GISTScanOpaqueData::distances, elog, ERROR, FunctionCall5Coll(), get_float8_infinity(), gistdentryinit(), GistPageIsLeaf, GISTScanOpaqueData::giststate, GistTupleIsInvalid, i, index_getattr, IndexScanDescData::indexRelation, Int16GetDatum, IndexScanDescData::keyData, IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, ObjectIdGetDatum, IndexScanDescData::opaque, IndexScanDescData::orderByData, PointerGetDatum, SK_ISNULL, SK_SEARCHNOTNULL, SK_SEARCHNULL, and test().

Referenced by gistScanPage().

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 }
static void test(void)
#define PointerGetDatum(X)
Definition: postgres.h:562
Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5)
Definition: fmgr.c:1116
#define Int16GetDatum(X)
Definition: postgres.h:457
#define GistTupleIsInvalid(itup)
Definition: gist_private.h:275
Relation indexRelation
Definition: relscan.h:90
GISTSTATE * giststate
Definition: gist_private.h:152
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:544
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:177
#define DatumGetBool(X)
Definition: postgres.h:399
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_ISNULL
Definition: skey.h:115
double get_float8_infinity(void)
Definition: float.c:122
#define GistPageIsLeaf(page)
Definition: gist.h:132
#define DatumGetFloat8(X)
Definition: postgres.h:734
ScanKey orderByData
Definition: relscan.h:95
uintptr_t Datum
Definition: postgres.h:372
#define Assert(condition)
Definition: c.h:680
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
ScanKey keyData
Definition: relscan.h:94
int i
int numberOfOrderBys
Definition: relscan.h:93
#define elog
Definition: elog.h:219
#define SK_SEARCHNULL
Definition: skey.h:121

◆ gistkillitems()

static void gistkillitems ( IndexScanDesc  scan)
static

Definition at line 37 of file gistget.c.

References Assert, buffer, BufferGetPage, BufferIsValid, GISTScanOpaqueData::curBlkno, GISTScanOpaqueData::curPageLSN, GIST_SHARE, gistcheckpage(), GistMarkPageHasGarbage, GistPageIsLeaf, i, IndexScanDescData::indexRelation, InvalidBlockNumber, ItemIdMarkDead, GISTScanOpaqueData::killedItems, LockBuffer(), MarkBufferDirtyHint(), GISTScanOpaqueData::numKilled, IndexScanDescData::opaque, PageGetItemId, PageGetLSN, ReadBuffer(), UnlockReleaseBuffer(), and XLogRecPtrIsInvalid.

Referenced by gistgettuple().

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 
52  if (!BufferIsValid(buffer))
53  return;
54 
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  {
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  {
89  }
90 
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 }
#define GistMarkPageHasGarbage(page)
Definition: gist.h:144
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
BlockNumber curBlkno
Definition: gist_private.h:166
Relation indexRelation
Definition: relscan.h:90
uint16 OffsetNumber
Definition: off.h:24
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:177
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GistPageIsLeaf(page)
Definition: gist.h:132
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define Assert(condition)
Definition: c.h:680
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:743
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define GIST_SHARE
Definition: gist_private.h:43
#define PageGetLSN(page)
Definition: bufpage.h:362
int i
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ gistScanPage()

static void gistScanPage ( IndexScanDesc  scan,
GISTSearchItem pageItem,
double *  myDistances,
TIDBitmap tbm,
int64 *  ntids 
)
static

Definition at line 322 of file gistget.c.

References Assert, GISTSearchItem::blkno, buffer, BufferGetLSNAtomic(), BufferGetPage, GISTScanOpaqueData::curPageData, GISTScanOpaqueData::curPageLSN, GISTSearchItem::data, GISTSearchItem::distances, GISTScanOpaqueData::distances, FirstOffsetNumber, GIST_SHARE, gistcheckpage(), gistFetchTuple(), GistFollowRight, gistindex_keytest(), GistPageGetNSN, GistPageGetOpaque, GistPageIsLeaf, GISTSearchItemIsHeap, GISTScanOpaqueData::giststate, GISTSearchItem::heap, GISTSearchHeapItem::heapPtr, i, IndexScanDescData::ignore_killed_tuples, IndexScanDescData::indexRelation, InvalidBlockNumber, ItemIdIsDead, ItemPointerGetBlockNumber, LockBuffer(), MemoryContextReset(), MemoryContextSwitchTo(), GISTScanOpaqueData::nPageData, IndexScanDescData::numberOfOrderBys, GISTSearchHeapItem::offnum, OffsetNumberNext, IndexScanDescData::opaque, GISTScanOpaqueData::pageData, GISTScanOpaqueData::pageDataCxt, PageGetItem, PageGetItemId, PageGetLSN, PageGetMaxOffsetNumber, pairingheap_add(), palloc(), GISTSearchItem::parentlsn, GISTSearchItem::phNode, GISTScanOpaqueData::queue, GISTScanOpaqueData::queueCxt, ReadBuffer(), GISTSearchHeapItem::recheck, GISTSearchHeapItem::recheckDistances, GISTSearchHeapItem::recontup, SizeOfGISTSearchItem, IndexTupleData::t_tid, tbm_add_tuples(), GISTSTATE::tempCxt, TestForOldSnapshot(), UnlockReleaseBuffer(), XLogRecPtrIsInvalid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_snapshot, and IndexScanDescData::xs_want_itup.

Referenced by getNextNearest(), gistgetbitmap(), and gistgettuple().

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);
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  scan->xs_hitup = NULL; /* might point into pageDataCxt */
379  if (so->pageDataCxt)
381 
382  /*
383  * We save the LSN of the page as we read it, so that we know whether it
384  * safe to apply LP_DEAD hints to the page later. This allows us to drop
385  * the pin for MVCC scans, which allows vacuum to avoid blocking.
386  */
387  so->curPageLSN = PageGetLSN(page);
388 
389  /*
390  * check all tuples on page
391  */
392  maxoff = PageGetMaxOffsetNumber(page);
393  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
394  {
395  ItemId iid = PageGetItemId(page, i);
396  IndexTuple it;
397  bool match;
398  bool recheck;
399  bool recheck_distances;
400 
401  /*
402  * If the scan specifies not to return killed tuples, then we treat a
403  * killed tuple as not passing the qual.
404  */
405  if (scan->ignore_killed_tuples && ItemIdIsDead(iid))
406  continue;
407 
408  it = (IndexTuple) PageGetItem(page, iid);
409 
410  /*
411  * Must call gistindex_keytest in tempCxt, and clean up any leftover
412  * junk afterward.
413  */
414  oldcxt = MemoryContextSwitchTo(so->giststate->tempCxt);
415 
416  match = gistindex_keytest(scan, it, page, i,
417  &recheck, &recheck_distances);
418 
419  MemoryContextSwitchTo(oldcxt);
421 
422  /* Ignore tuple if it doesn't match */
423  if (!match)
424  continue;
425 
426  if (tbm && GistPageIsLeaf(page))
427  {
428  /*
429  * getbitmap scan, so just push heap tuple TIDs into the bitmap
430  * without worrying about ordering
431  */
432  tbm_add_tuples(tbm, &it->t_tid, 1, recheck);
433  (*ntids)++;
434  }
435  else if (scan->numberOfOrderBys == 0 && GistPageIsLeaf(page))
436  {
437  /*
438  * Non-ordered scan, so report tuples in so->pageData[]
439  */
440  so->pageData[so->nPageData].heapPtr = it->t_tid;
441  so->pageData[so->nPageData].recheck = recheck;
442  so->pageData[so->nPageData].offnum = i;
443 
444  /*
445  * In an index-only scan, also fetch the data from the tuple. The
446  * reconstructed tuples are stored in pageDataCxt.
447  */
448  if (scan->xs_want_itup)
449  {
450  oldcxt = MemoryContextSwitchTo(so->pageDataCxt);
451  so->pageData[so->nPageData].recontup =
452  gistFetchTuple(giststate, r, it);
453  MemoryContextSwitchTo(oldcxt);
454  }
455  so->nPageData++;
456  }
457  else
458  {
459  /*
460  * Must push item into search queue. We get here for any lower
461  * index page, and also for heap tuples if doing an ordered
462  * search.
463  */
464  GISTSearchItem *item;
465 
466  oldcxt = MemoryContextSwitchTo(so->queueCxt);
467 
468  /* Create new GISTSearchItem for this item */
470 
471  if (GistPageIsLeaf(page))
472  {
473  /* Creating heap-tuple GISTSearchItem */
474  item->blkno = InvalidBlockNumber;
475  item->data.heap.heapPtr = it->t_tid;
476  item->data.heap.recheck = recheck;
477  item->data.heap.recheckDistances = recheck_distances;
478 
479  /*
480  * In an index-only scan, also fetch the data from the tuple.
481  */
482  if (scan->xs_want_itup)
483  item->data.heap.recontup = gistFetchTuple(giststate, r, it);
484  }
485  else
486  {
487  /* Creating index-page GISTSearchItem */
488  item->blkno = ItemPointerGetBlockNumber(&it->t_tid);
489 
490  /*
491  * LSN of current page is lsn of parent page for child. We
492  * only have a shared lock, so we need to get the LSN
493  * atomically.
494  */
496  }
497 
498  /* Insert it into the queue using new distance data */
499  memcpy(item->distances, so->distances,
500  sizeof(double) * scan->numberOfOrderBys);
501 
502  pairingheap_add(so->queue, &item->phNode);
503 
504  MemoryContextSwitchTo(oldcxt);
505  }
506  }
507 
509 }
#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
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
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot xs_snapshot
Definition: relscan.h:91
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:134
MemoryContext pageDataCxt
Definition: gist_private.h:173
#define ItemIdIsDead(itemId)
Definition: itemid.h:112
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
bool ignore_killed_tuples
Definition: relscan.h:101
Relation indexRelation
Definition: relscan.h:90
uint16 OffsetNumber
Definition: off.h:24
GISTSTATE * giststate
Definition: gist_private.h:152
double distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:139
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
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
OffsetNumber nPageData
Definition: gist_private.h:171
#define GISTSearchItemIsHeap(item)
Definition: gist_private.h:143
HeapTuple gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
Definition: gistutil.c:640
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GistPageIsLeaf(page)
Definition: gist.h:132
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
GISTSearchHeapItem heap
Definition: gist_private.h:137
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
union GISTSearchItem::@43 data
bool xs_want_itup
Definition: relscan.h:96
#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:680
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
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 GIST_SHARE
Definition: gist_private.h:43
OffsetNumber curPageData
Definition: gist_private.h:172
#define PageGetLSN(page)
Definition: bufpage.h:362
void * palloc(Size size)
Definition: mcxt.c:835
HeapTuple xs_hitup
Definition: relscan.h:116
OffsetNumber offnum
Definition: gist_private.h:124
int i
#define SizeOfGISTSearchItem(n_distances)
Definition: gist_private.h:145
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
int numberOfOrderBys
Definition: relscan.h:93
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:76
GistNSN parentlsn
Definition: gist_private.h:135
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74