PostgreSQL Source Code  git master
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-2018, 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.attLeafType.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",
198  "SP-GiST traversal-value context",
200 
201  /* Set up indexTupDesc and xs_hitupdesc in case it's an index-only scan */
202  so->indexTupDesc = scan->xs_hitupdesc = RelationGetDescr(rel);
203 
204  scan->opaque = so;
205 
206  return scan;
207 }
208 
209 void
210 spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
211  ScanKey orderbys, int norderbys)
212 {
214 
215  /* clear traversal context before proceeding to the next scan */
217 
218  /* copy scankeys into local storage */
219  if (scankey && scan->numberOfKeys > 0)
220  {
221  memmove(scan->keyData, scankey,
222  scan->numberOfKeys * sizeof(ScanKeyData));
223  }
224 
225  /* preprocess scankeys, set up the representation in *so */
226  spgPrepareScanKeys(scan);
227 
228  /* set up starting stack entries */
230 }
231 
232 void
234 {
236 
239 }
240 
241 /*
242  * Test whether a leaf tuple satisfies all the scan keys
243  *
244  * *leafValue is set to the reconstructed datum, if provided
245  * *recheck is set true if any of the operators are lossy
246  */
247 static bool
249  SpGistLeafTuple leafTuple, bool isnull,
251  void *traversalValue,
252  Datum *leafValue, bool *recheck)
253 {
254  bool result;
255  Datum leafDatum;
258  FmgrInfo *procinfo;
259  MemoryContext oldCtx;
260 
261  if (isnull)
262  {
263  /* Should not have arrived on a nulls page unless nulls are wanted */
264  Assert(so->searchNulls);
265  *leafValue = (Datum) 0;
266  *recheck = false;
267  return true;
268  }
269 
270  leafDatum = SGLTDATUM(leafTuple, &so->state);
271 
272  /* use temp context for calling leaf_consistent */
273  oldCtx = MemoryContextSwitchTo(so->tempCxt);
274 
275  in.scankeys = so->keyData;
276  in.nkeys = so->numberOfKeys;
279  in.level = level;
280  in.returnData = so->want_itup;
281  in.leafDatum = leafDatum;
282 
283  out.leafValue = (Datum) 0;
284  out.recheck = false;
285 
286  procinfo = index_getprocinfo(index, 1, SPGIST_LEAF_CONSISTENT_PROC);
287  result = DatumGetBool(FunctionCall2Coll(procinfo,
288  index->rd_indcollation[0],
289  PointerGetDatum(&in),
290  PointerGetDatum(&out)));
291 
292  *leafValue = out.leafValue;
293  *recheck = out.recheck;
294 
295  MemoryContextSwitchTo(oldCtx);
296 
297  return result;
298 }
299 
300 /*
301  * Walk the tree and report all tuples passing the scan quals to the storeRes
302  * subroutine.
303  *
304  * If scanWholeIndex is true, we'll do just that. If not, we'll stop at the
305  * next page boundary once we have reported at least one tuple.
306  */
307 static void
308 spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex,
309  storeRes_func storeRes, Snapshot snapshot)
310 {
312  bool reportedSome = false;
313 
314  while (scanWholeIndex || !reportedSome)
315  {
316  ScanStackEntry *stackEntry;
317  BlockNumber blkno;
318  OffsetNumber offset;
319  Page page;
320  bool isnull;
321 
322  /* Pull next to-do item from the list */
323  if (so->scanStack == NIL)
324  break; /* there are no more pages to scan */
325 
326  stackEntry = (ScanStackEntry *) linitial(so->scanStack);
328 
329 redirect:
330  /* Check for interrupts, just in case of infinite loop */
332 
333  blkno = ItemPointerGetBlockNumber(&stackEntry->ptr);
334  offset = ItemPointerGetOffsetNumber(&stackEntry->ptr);
335 
336  if (buffer == InvalidBuffer)
337  {
338  buffer = ReadBuffer(index, blkno);
339  LockBuffer(buffer, BUFFER_LOCK_SHARE);
340  }
341  else if (blkno != BufferGetBlockNumber(buffer))
342  {
343  UnlockReleaseBuffer(buffer);
344  buffer = ReadBuffer(index, blkno);
345  LockBuffer(buffer, BUFFER_LOCK_SHARE);
346  }
347  /* else new pointer points to the same page, no work needed */
348 
349  page = BufferGetPage(buffer);
350  TestForOldSnapshot(snapshot, index, page);
351 
352  isnull = SpGistPageStoresNulls(page) ? true : false;
353 
354  if (SpGistPageIsLeaf(page))
355  {
356  SpGistLeafTuple leafTuple;
358  Datum leafValue = (Datum) 0;
359  bool recheck = false;
360 
361  if (SpGistBlockIsRoot(blkno))
362  {
363  /* When root is a leaf, examine all its tuples */
364  for (offset = FirstOffsetNumber; offset <= max; offset++)
365  {
366  leafTuple = (SpGistLeafTuple)
367  PageGetItem(page, PageGetItemId(page, offset));
368  if (leafTuple->tupstate != SPGIST_LIVE)
369  {
370  /* all tuples on root should be live */
371  elog(ERROR, "unexpected SPGiST tuple state: %d",
372  leafTuple->tupstate);
373  }
374 
375  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
376  if (spgLeafTest(index, so,
377  leafTuple, isnull,
378  stackEntry->level,
379  stackEntry->reconstructedValue,
380  stackEntry->traversalValue,
381  &leafValue,
382  &recheck))
383  {
384  storeRes(so, &leafTuple->heapPtr,
385  leafValue, isnull, recheck);
386  reportedSome = true;
387  }
388  }
389  }
390  else
391  {
392  /* Normal case: just examine the chain we arrived at */
393  while (offset != InvalidOffsetNumber)
394  {
395  Assert(offset >= FirstOffsetNumber && offset <= max);
396  leafTuple = (SpGistLeafTuple)
397  PageGetItem(page, PageGetItemId(page, offset));
398  if (leafTuple->tupstate != SPGIST_LIVE)
399  {
400  if (leafTuple->tupstate == SPGIST_REDIRECT)
401  {
402  /* redirection tuple should be first in chain */
403  Assert(offset == ItemPointerGetOffsetNumber(&stackEntry->ptr));
404  /* transfer attention to redirect point */
405  stackEntry->ptr = ((SpGistDeadTuple) leafTuple)->pointer;
407  goto redirect;
408  }
409  if (leafTuple->tupstate == SPGIST_DEAD)
410  {
411  /* dead tuple should be first in chain */
412  Assert(offset == ItemPointerGetOffsetNumber(&stackEntry->ptr));
413  /* No live entries on this page */
414  Assert(leafTuple->nextOffset == InvalidOffsetNumber);
415  break;
416  }
417  /* We should not arrive at a placeholder */
418  elog(ERROR, "unexpected SPGiST tuple state: %d",
419  leafTuple->tupstate);
420  }
421 
422  Assert(ItemPointerIsValid(&leafTuple->heapPtr));
423  if (spgLeafTest(index, so,
424  leafTuple, isnull,
425  stackEntry->level,
426  stackEntry->reconstructedValue,
427  stackEntry->traversalValue,
428  &leafValue,
429  &recheck))
430  {
431  storeRes(so, &leafTuple->heapPtr,
432  leafValue, isnull, recheck);
433  reportedSome = true;
434  }
435 
436  offset = leafTuple->nextOffset;
437  }
438  }
439  }
440  else /* page is inner */
441  {
442  SpGistInnerTuple innerTuple;
445  FmgrInfo *procinfo;
446  SpGistNodeTuple *nodes;
447  SpGistNodeTuple node;
448  int i;
449  MemoryContext oldCtx;
450 
451  innerTuple = (SpGistInnerTuple) PageGetItem(page,
452  PageGetItemId(page, offset));
453 
454  if (innerTuple->tupstate != SPGIST_LIVE)
455  {
456  if (innerTuple->tupstate == SPGIST_REDIRECT)
457  {
458  /* transfer attention to redirect point */
459  stackEntry->ptr = ((SpGistDeadTuple) innerTuple)->pointer;
461  goto redirect;
462  }
463  elog(ERROR, "unexpected SPGiST tuple state: %d",
464  innerTuple->tupstate);
465  }
466 
467  /* use temp context for calling inner_consistent */
468  oldCtx = MemoryContextSwitchTo(so->tempCxt);
469 
470  in.scankeys = so->keyData;
471  in.nkeys = so->numberOfKeys;
472  in.reconstructedValue = stackEntry->reconstructedValue;
474  in.traversalValue = stackEntry->traversalValue;
475  in.level = stackEntry->level;
476  in.returnData = so->want_itup;
477  in.allTheSame = innerTuple->allTheSame;
478  in.hasPrefix = (innerTuple->prefixSize > 0);
479  in.prefixDatum = SGITDATUM(innerTuple, &so->state);
480  in.nNodes = innerTuple->nNodes;
481  in.nodeLabels = spgExtractNodeLabels(&so->state, innerTuple);
482 
483  /* collect node pointers */
484  nodes = (SpGistNodeTuple *) palloc(sizeof(SpGistNodeTuple) * in.nNodes);
485  SGITITERATE(innerTuple, i, node)
486  {
487  nodes[i] = node;
488  }
489 
490  memset(&out, 0, sizeof(out));
491 
492  if (!isnull)
493  {
494  /* use user-defined inner consistent method */
495  procinfo = index_getprocinfo(index, 1, SPGIST_INNER_CONSISTENT_PROC);
496  FunctionCall2Coll(procinfo,
497  index->rd_indcollation[0],
498  PointerGetDatum(&in),
499  PointerGetDatum(&out));
500  }
501  else
502  {
503  /* force all children to be visited */
504  out.nNodes = in.nNodes;
505  out.nodeNumbers = (int *) palloc(sizeof(int) * in.nNodes);
506  for (i = 0; i < in.nNodes; i++)
507  out.nodeNumbers[i] = i;
508  }
509 
510  MemoryContextSwitchTo(oldCtx);
511 
512  /* If allTheSame, they should all or none of 'em match */
513  if (innerTuple->allTheSame)
514  if (out.nNodes != 0 && out.nNodes != in.nNodes)
515  elog(ERROR, "inconsistent inner_consistent results for allTheSame inner tuple");
516 
517  for (i = 0; i < out.nNodes; i++)
518  {
519  int nodeN = out.nodeNumbers[i];
520 
521  Assert(nodeN >= 0 && nodeN < in.nNodes);
522  if (ItemPointerIsValid(&nodes[nodeN]->t_tid))
523  {
524  ScanStackEntry *newEntry;
525 
526  /* Create new work item for this node */
527  newEntry = palloc(sizeof(ScanStackEntry));
528  newEntry->ptr = nodes[nodeN]->t_tid;
529  if (out.levelAdds)
530  newEntry->level = stackEntry->level + out.levelAdds[i];
531  else
532  newEntry->level = stackEntry->level;
533  /* Must copy value out of temp context */
534  if (out.reconstructedValues)
535  newEntry->reconstructedValue =
538  so->state.attLeafType.attlen);
539  else
540  newEntry->reconstructedValue = (Datum) 0;
541 
542  /*
543  * Elements of out.traversalValues should be allocated in
544  * in.traversalMemoryContext, which is actually a long
545  * lived context of index scan.
546  */
547  newEntry->traversalValue = (out.traversalValues) ?
548  out.traversalValues[i] : NULL;
549 
550  so->scanStack = lcons(newEntry, so->scanStack);
551  }
552  }
553  }
554 
555  /* done with this scan stack entry */
556  freeScanStackEntry(so, stackEntry);
557  /* clear temp context before proceeding to the next one */
559  }
560 
561  if (buffer != InvalidBuffer)
562  UnlockReleaseBuffer(buffer);
563 }
564 
565 /* storeRes subroutine for getbitmap case */
566 static void
568  Datum leafValue, bool isnull, bool recheck)
569 {
570  tbm_add_tuples(so->tbm, heapPtr, 1, recheck);
571  so->ntids++;
572 }
573 
574 int64
576 {
578 
579  /* Copy want_itup to *so so we don't need to pass it around separately */
580  so->want_itup = false;
581 
582  so->tbm = tbm;
583  so->ntids = 0;
584 
585  spgWalk(scan->indexRelation, so, true, storeBitmap, scan->xs_snapshot);
586 
587  return so->ntids;
588 }
589 
590 /* storeRes subroutine for gettuple case */
591 static void
593  Datum leafValue, bool isnull, bool recheck)
594 {
596  so->heapPtrs[so->nPtrs] = *heapPtr;
597  so->recheck[so->nPtrs] = recheck;
598  if (so->want_itup)
599  {
600  /*
601  * Reconstruct index data. We have to copy the datum out of the temp
602  * context anyway, so we may as well create the tuple here.
603  */
605  &leafValue,
606  &isnull);
607  }
608  so->nPtrs++;
609 }
610 
611 bool
613 {
615 
616  if (dir != ForwardScanDirection)
617  elog(ERROR, "SP-GiST only supports forward scan direction");
618 
619  /* Copy want_itup to *so so we don't need to pass it around separately */
620  so->want_itup = scan->xs_want_itup;
621 
622  for (;;)
623  {
624  if (so->iPtr < so->nPtrs)
625  {
626  /* continuing to return tuples from a leaf page */
627  scan->xs_ctup.t_self = so->heapPtrs[so->iPtr];
628  scan->xs_recheck = so->recheck[so->iPtr];
629  scan->xs_hitup = so->reconTups[so->iPtr];
630  so->iPtr++;
631  return true;
632  }
633 
634  if (so->want_itup)
635  {
636  /* Must pfree reconstructed tuples to avoid memory leak */
637  int i;
638 
639  for (i = 0; i < so->nPtrs; i++)
640  pfree(so->reconTups[i]);
641  }
642  so->iPtr = so->nPtrs = 0;
643 
644  spgWalk(scan->indexRelation, so, false, storeGettuple,
645  scan->xs_snapshot);
646 
647  if (so->nPtrs == 0)
648  break; /* must have completed scan */
649  }
650 
651  return false;
652 }
653 
654 bool
656 {
657  SpGistCache *cache;
658 
659  /* We can do it if the opclass config function says so */
660  cache = spgGetCache(index);
661 
662  return cache->config.canReturnData;
663 }
Datum reconstructedValue
Definition: spgist.h:172
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define SPGIST_DEAD
#define NIL
Definition: pg_list.h:69
Definition: fmgr.h:56
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:822
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
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:248
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:93
#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:50
#define RelationGetDescr(relation)
Definition: rel.h:433
#define SPGIST_REDIRECT
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
#define PointerGetDatum(X)
Definition: postgres.h:541
#define SGITITERATE(x, i, nt)
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
SpGistTypeDesc attLeafType
ItemPointerData t_tid
Definition: itup.h:37
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void * traversalValue
Definition: spgist.h:142
Snapshot xs_snapshot
Definition: relscan.h:92
#define InvalidBuffer
Definition: buf.h:25
MemoryContext tempCxt
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: spgscan.c:210
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 BlockNumber
Definition: block.h:31
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1133
static void freeScanStackEntry(SpGistScanOpaque so, ScanStackEntry *stackEntry)
Definition: spgscan.c:41
#define SPGIST_ROOT_BLKNO
void spgendscan(IndexScanDesc scan)
Definition: spgscan.c:233
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
Datum reconstructedValue
Definition: spgist.h:141
TupleDesc xs_hitupdesc
Definition: relscan.h:118
HeapTuple reconTups[MaxIndexTuplesPerPage]
bool spgcanreturn(Relation index, int attno)
Definition: spgscan.c:655
void(* storeRes_func)(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck)
Definition: spgscan.c:27
static void freeScanStack(SpGistScanOpaque so)
Definition: spgscan.c:54
Relation indexRelation
Definition: relscan.h:91
uint16 OffsetNumber
Definition: off.h:24
#define SGITDATUM(x, s)
Definition: type.h:89
#define true
Definition: c.h:279
void pfree(void *pointer)
Definition: mcxt.c:1031
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:165
MemoryContext traversalMemoryContext
Definition: spgist.h:143
#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:169
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
unsigned int prefixSize
Datum reconstructedValue
Definition: spgscan.c:32
#define SPGIST_NULL_BLKNO
#define memmove(d, s, c)
Definition: c.h:1135
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:592
#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:378
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:175
SpGistDeadTupleData * SpGistDeadTuple
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: spgscan.c:575
#define SK_SEARCHNOTNULL
Definition: skey.h:122
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define SK_ISNULL
Definition: skey.h:115
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void ** traversalValues
Definition: spgist.h:161
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
List * lappend(List *list, void *datum)
Definition: list.c:128
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
spgConfigOut config
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
unsigned int tupstate
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:367
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
SpGistScanOpaqueData * SpGistScanOpaque
Datum * nodeLabels
Definition: spgist.h:152
#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:308
bool xs_want_itup
Definition: relscan.h:97
List * lcons(void *datum, List *list)
Definition: list.c:259
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
HeapTupleData xs_ctup
Definition: relscan.h:121
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:160
OffsetNumber nextOffset
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
ScanKey keyData
Definition: relscan.h:95
ScanKey scankeys
Definition: spgist.h:138
static void resetSpGistScanOpaque(SpGistScanOpaque so)
Definition: spgscan.c:71
#define DatumGetPointer(X)
Definition: postgres.h:534
MemoryContext traversalCxt
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define MaxIndexTuplesPerPage
Definition: itup.h:145
void * palloc(Size size)
Definition: mcxt.c:924
HeapTuple xs_hitup
Definition: relscan.h:117
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition: spgscan.c:612
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:173
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:98
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:127
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:567