PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
spgscan.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * spgscan.c
4  * routines for scanning SP-GiST indexes
5  *
6  *
7  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/access/spgist/spgscan.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "access/relscan.h"
19 #include "access/spgist_private.h"
20 #include "miscadmin.h"
21 #include "storage/bufmgr.h"
22 #include "utils/datum.h"
23 #include "utils/memutils.h"
24 #include "utils/rel.h"
25 
26 
27 typedef void (*storeRes_func) (SpGistScanOpaque so, ItemPointer heapPtr,
28  Datum leafValue, bool isnull, bool recheck);
29 
30 typedef struct ScanStackEntry
31 {
32  Datum reconstructedValue; /* value reconstructed from parent */
33  void *traversalValue; /* opclass-specific traverse value */
34  int level; /* level of items on this page */
35  ItemPointerData ptr; /* block and offset to scan from */
37 
38 
39 /* Free a ScanStackEntry */
40 static void
42 {
43  if (!so->state.attType.attbyval &&
44  DatumGetPointer(stackEntry->reconstructedValue) != NULL)
46  if (stackEntry->traversalValue)
47  pfree(stackEntry->traversalValue);
48 
49  pfree(stackEntry);
50 }
51 
52 /* Free the entire stack */
53 static void
55 {
56  ListCell *lc;
57 
58  foreach(lc, so->scanStack)
59  {
61  }
62  list_free(so->scanStack);
63  so->scanStack = NIL;
64 }
65 
66 /*
67  * Initialize scanStack to search the root page, resetting
68  * any previously active scan
69  */
70 static void
72 {
73  ScanStackEntry *startEntry;
74 
75  freeScanStack(so);
76 
77  if (so->searchNulls)
78  {
79  /* Stack a work item to scan the null index entries */
80  startEntry = (ScanStackEntry *) palloc0(sizeof(ScanStackEntry));
82  so->scanStack = lappend(so->scanStack, startEntry);
83  }
84 
85  if (so->searchNonNulls)
86  {
87  /* Stack a work item to scan the non-null index entries */
88  startEntry = (ScanStackEntry *) palloc0(sizeof(ScanStackEntry));
90  so->scanStack = lappend(so->scanStack, startEntry);
91  }
92 
93  if (so->want_itup)
94  {
95  /* Must pfree reconstructed tuples to avoid memory leak */
96  int i;
97 
98  for (i = 0; i < so->nPtrs; i++)
99  pfree(so->reconTups[i]);
100  }
101  so->iPtr = so->nPtrs = 0;
102 }
103 
104 /*
105  * Prepare scan keys in SpGistScanOpaque from caller-given scan keys
106  *
107  * Sets searchNulls, searchNonNulls, numberOfKeys, keyData fields of *so.
108  *
109  * The point here is to eliminate null-related considerations from what the
110  * opclass consistent functions need to deal with. We assume all SPGiST-
111  * indexable operators are strict, so any null RHS value makes the scan
112  * condition unsatisfiable. We also pull out any IS NULL/IS NOT NULL
113  * conditions; their effect is reflected into searchNulls/searchNonNulls.
114  */
115 static void
117 {
119  bool qual_ok;
120  bool haveIsNull;
121  bool haveNotNull;
122  int nkeys;
123  int i;
124 
125  if (scan->numberOfKeys <= 0)
126  {
127  /* If no quals, whole-index scan is required */
128  so->searchNulls = true;
129  so->searchNonNulls = true;
130  so->numberOfKeys = 0;
131  return;
132  }
133 
134  /* Examine the given quals */
135  qual_ok = true;
136  haveIsNull = haveNotNull = false;
137  nkeys = 0;
138  for (i = 0; i < scan->numberOfKeys; i++)
139  {
140  ScanKey skey = &scan->keyData[i];
141 
142  if (skey->sk_flags & SK_SEARCHNULL)
143  haveIsNull = true;
144  else if (skey->sk_flags & SK_SEARCHNOTNULL)
145  haveNotNull = true;
146  else if (skey->sk_flags & SK_ISNULL)
147  {
148  /* ordinary qual with null argument - unsatisfiable */
149  qual_ok = false;
150  break;
151  }
152  else
153  {
154  /* ordinary qual, propagate into so->keyData */
155  so->keyData[nkeys++] = *skey;
156  /* this effectively creates a not-null requirement */
157  haveNotNull = true;
158  }
159  }
160 
161  /* IS NULL in combination with something else is unsatisfiable */
162  if (haveIsNull && haveNotNull)
163  qual_ok = false;
164 
165  /* Emit results */
166  if (qual_ok)
167  {
168  so->searchNulls = haveIsNull;
169  so->searchNonNulls = haveNotNull;
170  so->numberOfKeys = nkeys;
171  }
172  else
173  {
174  so->searchNulls = false;
175  so->searchNonNulls = false;
176  so->numberOfKeys = 0;
177  }
178 }
179 
181 spgbeginscan(Relation rel, int keysz, int orderbysz)
182 {
183  IndexScanDesc scan;
184  SpGistScanOpaque so;
185 
186  scan = RelationGetIndexScan(rel, keysz, 0);
187 
189  if (keysz > 0)
190  so->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * keysz);
191  else
192  so->keyData = NULL;
193  initSpGistState(&so->state, scan->indexRelation);
195  "SP-GiST search temporary context",
197 
198  /* Set up indexTupDesc and xs_hitupdesc in case it's an index-only scan */
199  so->indexTupDesc = scan->xs_hitupdesc = RelationGetDescr(rel);
200 
201  scan->opaque = so;
202 
203  return scan;
204 }
205 
206 void
207 spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
208  ScanKey orderbys, int norderbys)
209 {
211 
212  /* copy scankeys into local storage */
213  if (scankey && scan->numberOfKeys > 0)
214  {
215  memmove(scan->keyData, scankey,
216  scan->numberOfKeys * sizeof(ScanKeyData));
217  }
218 
219  /* preprocess scankeys, set up the representation in *so */
220  spgPrepareScanKeys(scan);
221 
222  /* set up starting stack entries */
224 }
225 
226 void
228 {
230 
232 }
233 
234 /*
235  * Test whether a leaf tuple satisfies all the scan keys
236  *
237  * *leafValue is set to the reconstructed datum, if provided
238  * *recheck is set true if any of the operators are lossy
239  */
240 static bool
242  SpGistLeafTuple leafTuple, bool isnull,
243  int level, Datum reconstructedValue,
244  void *traversalValue,
245  Datum *leafValue, bool *recheck)
246 {
247  bool result;
248  Datum leafDatum;
251  FmgrInfo *procinfo;
252  MemoryContext oldCtx;
253 
254  if (isnull)
255  {
256  /* Should not have arrived on a nulls page unless nulls are wanted */
257  Assert(so->searchNulls);
258  *leafValue = (Datum) 0;
259  *recheck = false;
260  return true;
261  }
262 
263  leafDatum = SGLTDATUM(leafTuple, &so->state);
264 
265  /* use temp context for calling leaf_consistent */
266  oldCtx = MemoryContextSwitchTo(so->tempCxt);
267 
268  in.scankeys = so->keyData;
269  in.nkeys = so->numberOfKeys;
270  in.reconstructedValue = reconstructedValue;
271  in.traversalValue = traversalValue;
272  in.level = level;
273  in.returnData = so->want_itup;
274  in.leafDatum = leafDatum;
275 
276  out.leafValue = (Datum) 0;
277  out.recheck = false;
278 
279  procinfo = index_getprocinfo(index, 1, SPGIST_LEAF_CONSISTENT_PROC);
280  result = DatumGetBool(FunctionCall2Coll(procinfo,
281  index->rd_indcollation[0],
282  PointerGetDatum(&in),
283  PointerGetDatum(&out)));
284 
285  *leafValue = out.leafValue;
286  *recheck = out.recheck;
287 
288  MemoryContextSwitchTo(oldCtx);
289 
290  return result;
291 }
292 
293 /*
294  * Walk the tree and report all tuples passing the scan quals to the storeRes
295  * subroutine.
296  *
297  * If scanWholeIndex is true, we'll do just that. If not, we'll stop at the
298  * next page boundary once we have reported at least one tuple.
299  */
300 static void
301 spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex,
302  storeRes_func storeRes, Snapshot snapshot)
303 {
305  bool reportedSome = false;
306 
307  while (scanWholeIndex || !reportedSome)
308  {
309  ScanStackEntry *stackEntry;
310  BlockNumber blkno;
311  OffsetNumber offset;
312  Page page;
313  bool isnull;
314 
315  /* Pull next to-do item from the list */
316  if (so->scanStack == NIL)
317  break; /* there are no more pages to scan */
318 
319  stackEntry = (ScanStackEntry *) linitial(so->scanStack);
321 
322 redirect:
323  /* Check for interrupts, just in case of infinite loop */
325 
326  blkno = ItemPointerGetBlockNumber(&stackEntry->ptr);
327  offset = ItemPointerGetOffsetNumber(&stackEntry->ptr);
328 
329  if (buffer == InvalidBuffer)
330  {
331  buffer = ReadBuffer(index, blkno);
332  LockBuffer(buffer, BUFFER_LOCK_SHARE);
333  }
334  else if (blkno != BufferGetBlockNumber(buffer))
335  {
336  UnlockReleaseBuffer(buffer);
337  buffer = ReadBuffer(index, blkno);
338  LockBuffer(buffer, BUFFER_LOCK_SHARE);
339  }
340  /* else new pointer points to the same page, no work needed */
341 
342  page = BufferGetPage(buffer);
343  TestForOldSnapshot(snapshot, index, page);
344 
345  isnull = SpGistPageStoresNulls(page) ? true : false;
346 
347  if (SpGistPageIsLeaf(page))
348  {
349  SpGistLeafTuple leafTuple;
351  Datum leafValue = (Datum) 0;
352  bool recheck = false;
353 
354  if (SpGistBlockIsRoot(blkno))
355  {
356  /* When root is a leaf, examine all its tuples */
357  for (offset = FirstOffsetNumber; offset <= max; offset++)
358  {
359  leafTuple = (SpGistLeafTuple)
360  PageGetItem(page, PageGetItemId(page, offset));
361  if (leafTuple->tupstate != SPGIST_LIVE)
362  {
363  /* all tuples on root should be live */
364  elog(ERROR, "unexpected SPGiST tuple state: %d",
365  leafTuple->tupstate);
366  }
367 
368  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
369  if (spgLeafTest(index, so,
370  leafTuple, isnull,
371  stackEntry->level,
372  stackEntry->reconstructedValue,
373  stackEntry->traversalValue,
374  &leafValue,
375  &recheck))
376  {
377  storeRes(so, &leafTuple->heapPtr,
378  leafValue, isnull, recheck);
379  reportedSome = true;
380  }
381  }
382  }
383  else
384  {
385  /* Normal case: just examine the chain we arrived at */
386  while (offset != InvalidOffsetNumber)
387  {
388  Assert(offset >= FirstOffsetNumber && offset <= max);
389  leafTuple = (SpGistLeafTuple)
390  PageGetItem(page, PageGetItemId(page, offset));
391  if (leafTuple->tupstate != SPGIST_LIVE)
392  {
393  if (leafTuple->tupstate == SPGIST_REDIRECT)
394  {
395  /* redirection tuple should be first in chain */
396  Assert(offset == ItemPointerGetOffsetNumber(&stackEntry->ptr));
397  /* transfer attention to redirect point */
398  stackEntry->ptr = ((SpGistDeadTuple) leafTuple)->pointer;
400  goto redirect;
401  }
402  if (leafTuple->tupstate == SPGIST_DEAD)
403  {
404  /* dead tuple should be first in chain */
405  Assert(offset == ItemPointerGetOffsetNumber(&stackEntry->ptr));
406  /* No live entries on this page */
407  Assert(leafTuple->nextOffset == InvalidOffsetNumber);
408  break;
409  }
410  /* We should not arrive at a placeholder */
411  elog(ERROR, "unexpected SPGiST tuple state: %d",
412  leafTuple->tupstate);
413  }
414 
415  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
416  if (spgLeafTest(index, so,
417  leafTuple, isnull,
418  stackEntry->level,
419  stackEntry->reconstructedValue,
420  stackEntry->traversalValue,
421  &leafValue,
422  &recheck))
423  {
424  storeRes(so, &leafTuple->heapPtr,
425  leafValue, isnull, recheck);
426  reportedSome = true;
427  }
428 
429  offset = leafTuple->nextOffset;
430  }
431  }
432  }
433  else /* page is inner */
434  {
435  SpGistInnerTuple innerTuple;
438  FmgrInfo *procinfo;
439  SpGistNodeTuple *nodes;
440  SpGistNodeTuple node;
441  int i;
442  MemoryContext oldCtx;
443 
444  innerTuple = (SpGistInnerTuple) PageGetItem(page,
445  PageGetItemId(page, offset));
446 
447  if (innerTuple->tupstate != SPGIST_LIVE)
448  {
449  if (innerTuple->tupstate == SPGIST_REDIRECT)
450  {
451  /* transfer attention to redirect point */
452  stackEntry->ptr = ((SpGistDeadTuple) innerTuple)->pointer;
454  goto redirect;
455  }
456  elog(ERROR, "unexpected SPGiST tuple state: %d",
457  innerTuple->tupstate);
458  }
459 
460  /* use temp context for calling inner_consistent */
461  oldCtx = MemoryContextSwitchTo(so->tempCxt);
462 
463  in.scankeys = so->keyData;
464  in.nkeys = so->numberOfKeys;
465  in.reconstructedValue = stackEntry->reconstructedValue;
466  in.traversalMemoryContext = oldCtx;
467  in.traversalValue = stackEntry->traversalValue;
468  in.level = stackEntry->level;
469  in.returnData = so->want_itup;
470  in.allTheSame = innerTuple->allTheSame;
471  in.hasPrefix = (innerTuple->prefixSize > 0);
472  in.prefixDatum = SGITDATUM(innerTuple, &so->state);
473  in.nNodes = innerTuple->nNodes;
474  in.nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);
475 
476  /* collect node pointers */
477  nodes = (SpGistNodeTuple *) palloc(sizeof(SpGistNodeTuple) * in.nNodes);
478  SGITITERATE(innerTuple, i, node)
479  {
480  nodes[i] = node;
481  }
482 
483  memset(&out, 0, sizeof(out));
484 
485  if (!isnull)
486  {
487  /* use user-defined inner consistent method */
488  procinfo = index_getprocinfo(index, 1, SPGIST_INNER_CONSISTENT_PROC);
489  FunctionCall2Coll(procinfo,
490  index->rd_indcollation[0],
491  PointerGetDatum(&in),
492  PointerGetDatum(&out));
493  }
494  else
495  {
496  /* force all children to be visited */
497  out.nNodes = in.nNodes;
498  out.nodeNumbers = (int *) palloc(sizeof(int) * in.nNodes);
499  for (i = 0; i < in.nNodes; i++)
500  out.nodeNumbers[i] = i;
501  }
502 
503  MemoryContextSwitchTo(oldCtx);
504 
505  /* If allTheSame, they should all or none of 'em match */
506  if (innerTuple->allTheSame)
507  if (out.nNodes != 0 && out.nNodes != in.nNodes)
508  elog(ERROR, "inconsistent inner_consistent results for allTheSame inner tuple");
509 
510  for (i = 0; i < out.nNodes; i++)
511  {
512  int nodeN = out.nodeNumbers[i];
513 
514  Assert(nodeN >= 0 && nodeN < in.nNodes);
515  if (ItemPointerIsValid(&nodes[nodeN]->t_tid))
516  {
517  ScanStackEntry *newEntry;
518 
519  /* Create new work item for this node */
520  newEntry = palloc(sizeof(ScanStackEntry));
521  newEntry->ptr = nodes[nodeN]->t_tid;
522  if (out.levelAdds)
523  newEntry->level = stackEntry->level + out.levelAdds[i];
524  else
525  newEntry->level = stackEntry->level;
526  /* Must copy value out of temp context */
527  if (out.reconstructedValues)
528  newEntry->reconstructedValue =
530  so->state.attType.attbyval,
531  so->state.attType.attlen);
532  else
533  newEntry->reconstructedValue = (Datum) 0;
534 
535  /*
536  * Elements of out.traversalValues should be allocated in
537  * in.traversalMemoryContext, which is actually a long
538  * lived context of index scan.
539  */
540  newEntry->traversalValue = (out.traversalValues) ?
541  out.traversalValues[i] : NULL;
542 
543  so->scanStack = lcons(newEntry, so->scanStack);
544  }
545  }
546  }
547 
548  /* done with this scan stack entry */
549  freeScanStackEntry(so, stackEntry);
550  /* clear temp context before proceeding to the next one */
552  }
553 
554  if (buffer != InvalidBuffer)
555  UnlockReleaseBuffer(buffer);
556 }
557 
558 /* storeRes subroutine for getbitmap case */
559 static void
561  Datum leafValue, bool isnull, bool recheck)
562 {
563  tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
564  so->ntids++;
565 }
566 
567 int64
569 {
571 
572  /* Copy want_itup to *so so we don't need to pass it around separately */
573  so->want_itup = false;
574 
575  so->tbm = tbm;
576  so->ntids = 0;
577 
578  spgWalk(scan->indexRelation, so, true, storeBitmap, scan->xs_snapshot);
579 
580  return so->ntids;
581 }
582 
583 /* storeRes subroutine for gettuple case */
584 static void
586  Datum leafValue, bool isnull, bool recheck)
587 {
589  so->heapPtrs[so->nPtrs] = *heapPtr;
590  so->recheck[so->nPtrs] = recheck;
591  if (so->want_itup)
592  {
593  /*
594  * Reconstruct index data. We have to copy the datum out of the temp
595  * context anyway, so we may as well create the tuple here.
596  */
598  &leafValue,
599  &isnull);
600  }
601  so->nPtrs++;
602 }
603 
604 bool
606 {
608 
609  if (dir != ForwardScanDirection)
610  elog(ERROR, "SP-GiST only supports forward scan direction");
611 
612  /* Copy want_itup to *so so we don't need to pass it around separately */
613  so->want_itup = scan->xs_want_itup;
614 
615  for (;;)
616  {
617  if (so->iPtr < so->nPtrs)
618  {
619  /* continuing to return tuples from a leaf page */
620  scan->xs_ctup.t_self = so->heapPtrs[so->iPtr];
621  scan->xs_recheck = so->recheck[so->iPtr];
622  scan->xs_hitup = so->reconTups[so->iPtr];
623  so->iPtr++;
624  return true;
625  }
626 
627  if (so->want_itup)
628  {
629  /* Must pfree reconstructed tuples to avoid memory leak */
630  int i;
631 
632  for (i = 0; i < so->nPtrs; i++)
633  pfree(so->reconTups[i]);
634  }
635  so->iPtr = so->nPtrs = 0;
636 
637  spgWalk(scan->indexRelation, so, false, storeGettuple,
638  scan->xs_snapshot);
639 
640  if (so->nPtrs == 0)
641  break; /* must have completed scan */
642  }
643 
644  return false;
645 }
646 
647 bool
649 {
650  SpGistCache *cache;
651 
652  /* We can do it if the opclass config function says so */
653  cache = spgGetCache(index);
654 
655  return cache->config.canReturnData;
656 }
Datum reconstructedValue
Definition: spgist.h:169
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define SPGIST_DEAD
#define NIL
Definition: pg_list.h:69
Definition: fmgr.h:56
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:784
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
SpGistInnerTupleData * SpGistInnerTuple
void * traversalValue
Definition: spgscan.c:33
#define SpGistPageIsLeaf(page)
static bool spgLeafTest(Relation index, SpGistScanOpaque so, SpGistLeafTuple leafTuple, bool isnull, int level, Datum reconstructedValue, void *traversalValue, Datum *leafValue, bool *recheck)
Definition: spgscan.c:241
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:32
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
bool canReturnData
Definition: spgist.h:47
#define RelationGetDescr(relation)
Definition: rel.h:428
#define SPGIST_REDIRECT
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
#define PointerGetDatum(X)
Definition: postgres.h:562
#define SGITITERATE(x, i, nt)
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:403
ItemPointerData t_tid
Definition: itup.h:37
SpGistTypeDesc attType
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void * traversalValue
Definition: spgist.h:139
Snapshot xs_snapshot
Definition: relscan.h:91
#define InvalidBuffer
Definition: buf.h:25
MemoryContext tempCxt
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: spgscan.c:207
return result
Definition: formatting.c:1633
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
uint32 BlockNumber
Definition: block.h:31
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
static void freeScanStackEntry(SpGistScanOpaque so, ScanStackEntry *stackEntry)
Definition: spgscan.c:41
#define SPGIST_ROOT_BLKNO
void spgendscan(IndexScanDesc scan)
Definition: spgscan.c:227
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
Datum reconstructedValue
Definition: spgist.h:138
TupleDesc xs_hitupdesc
Definition: relscan.h:117
HeapTuple reconTups[MaxIndexTuplesPerPage]
bool spgcanreturn(Relation index, int attno)
Definition: spgscan.c:648
static void freeScanStack(SpGistScanOpaque so)
Definition: spgscan.c:54
Relation indexRelation
Definition: relscan.h:90
uint16 OffsetNumber
Definition: off.h:24
#define SGITDATUM(x, s)
Definition: type.h:89
void pfree(void *pointer)
Definition: mcxt.c:949
unsigned int allTheSame
#define linitial(l)
Definition: pg_list.h:111
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
Oid * rd_indcollation
Definition: rel.h:193
MemoryContext traversalMemoryContext
Definition: spgist.h:140
#define ERROR
Definition: elog.h:43
struct ScanStackEntry ScanStackEntry
ItemPointerData ptr
Definition: spgscan.c:35
ItemPointerData t_self
Definition: htup.h:65
ScanKey scankeys
Definition: spgist.h:166
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
unsigned int prefixSize
Datum reconstructedValue
Definition: spgscan.c:32
#define SPGIST_NULL_BLKNO
#define memmove(d, s, c)
Definition: c.h:1047
ScanKeyData * ScanKey
Definition: skey.h:75
bool recheck[MaxIndexTuplesPerPage]
static void storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Definition: spgscan.c:585
#define FirstOffsetNumber
Definition: off.h:27
static void spgPrepareScanKeys(IndexScanDesc scan)
Definition: spgscan.c:116
#define SPGIST_METAPAGE_BLKNO
ScanDirection
Definition: sdir.h:22
#define DatumGetBool(X)
Definition: postgres.h:399
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:158
SpGistDeadTupleData * SpGistDeadTuple
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: spgscan.c:568
#define SK_SEARCHNOTNULL
Definition: skey.h:122
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define SK_ISNULL
Definition: skey.h:115
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void ** traversalValues
Definition: spgist.h:158
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
List * lappend(List *list, void *datum)
Definition: list.c:128
spgConfigOut config
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
unsigned int tupstate
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:877
void(* storeRes_func)(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Definition: spgscan.c:27
uintptr_t Datum
Definition: postgres.h:372
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
SpGistScanOpaqueData * SpGistScanOpaque
Datum * nodeLabels
Definition: spgist.h:149
#define InvalidOffsetNumber
Definition: off.h:26
#define SpGistPageStoresNulls(page)
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:301
bool xs_want_itup
Definition: relscan.h:96
List * lcons(void *datum, List *list)
Definition: list.c:259
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:664
#define lfirst(lc)
Definition: pg_list.h:106
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
HeapTupleData xs_ctup
Definition: relscan.h:120
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define SpGistBlockIsRoot(blkno)
#define SPGIST_LIVE
#define SGLTDATUM(x, s)
Datum * reconstructedValues
Definition: spgist.h:157
OffsetNumber nextOffset
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:95
ScanKey keyData
Definition: relscan.h:94
ScanKey scankeys
Definition: spgist.h:135
static void resetSpGistScanOpaque(SpGistScanOpaque so)
Definition: spgscan.c:71
#define DatumGetPointer(X)
Definition: postgres.h:555
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define MaxIndexTuplesPerPage
Definition: itup.h:137
void * palloc(Size size)
Definition: mcxt.c:848
HeapTuple xs_hitup
Definition: relscan.h:116
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition: spgscan.c:605
void list_free(List *list)
Definition: list.c:1133
int i
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:31
void * traversalValue
Definition: spgist.h:170
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:78
IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz)
Definition: spgscan.c:181
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
ItemPointerData heapPtr
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:76
SpGistLeafTupleData * SpGistLeafTuple
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
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:105
List * list_delete_first(List *list)
Definition: list.c:666
static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Definition: spgscan.c:560