PostgreSQL Source Code  git master
indexam.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * indexam.c
4  * general index access method routines
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/access/index/indexam.c
12  *
13  * INTERFACE ROUTINES
14  * index_open - open an index relation by relation OID
15  * index_close - close an index relation
16  * index_beginscan - start a scan of an index with amgettuple
17  * index_beginscan_bitmap - start a scan of an index with amgetbitmap
18  * index_rescan - restart a scan of an index
19  * index_endscan - end a scan
20  * index_insert - insert an index tuple into a relation
21  * index_markpos - mark a scan position
22  * index_restrpos - restore a scan position
23  * index_parallelscan_estimate - estimate shared memory for parallel scan
24  * index_parallelscan_initialize - initialize parallel scan
25  * index_parallelrescan - (re)start a parallel scan of an index
26  * index_beginscan_parallel - join parallel index scan
27  * index_getnext_tid - get the next TID from a scan
28  * index_fetch_heap - get the scan's next heap tuple
29  * index_getnext - get the next heap tuple from a scan
30  * index_getbitmap - get all tuples from a scan
31  * index_bulk_delete - bulk deletion of index tuples
32  * index_vacuum_cleanup - post-deletion cleanup of an index
33  * index_can_return - does index support index-only scans?
34  * index_getprocid - get a support procedure OID
35  * index_getprocinfo - get a support procedure's lookup info
36  *
37  * NOTES
38  * This file contains the index_ routines which used
39  * to be a scattered collection of stuff in access/genam.
40  *
41  *
42  * old comments
43  * Scans are implemented as follows:
44  *
45  * `0' represents an invalid item pointer.
46  * `-' represents an unknown item pointer.
47  * `X' represents a known item pointers.
48  * `+' represents known or invalid item pointers.
49  * `*' represents any item pointers.
50  *
51  * State is represented by a triple of these symbols in the order of
52  * previous, current, next. Note that the case of reverse scans works
53  * identically.
54  *
55  * State Result
56  * (1) + + - + 0 0 (if the next item pointer is invalid)
57  * (2) + X - (otherwise)
58  * (3) * 0 0 * 0 0 (no change)
59  * (4) + X 0 X 0 0 (shift)
60  * (5) * + X + X - (shift, add unknown)
61  *
62  * All other states cannot occur.
63  *
64  * Note: It would be possible to cache the status of the previous and
65  * next item pointer using the flags.
66  *
67  *-------------------------------------------------------------------------
68  */
69 
70 #include "postgres.h"
71 
72 #include "access/amapi.h"
73 #include "access/relscan.h"
74 #include "access/transam.h"
75 #include "access/xlog.h"
76 #include "catalog/catalog.h"
77 #include "catalog/index.h"
78 #include "pgstat.h"
79 #include "storage/bufmgr.h"
80 #include "storage/lmgr.h"
81 #include "storage/predicate.h"
82 #include "utils/snapmgr.h"
83 #include "utils/tqual.h"
84 
85 
86 /* ----------------------------------------------------------------
87  * macros used in index_ routines
88  *
89  * Note: the ReindexIsProcessingIndex() check in RELATION_CHECKS is there
90  * to check that we don't try to scan or do retail insertions into an index
91  * that is currently being rebuilt or pending rebuild. This helps to catch
92  * things that don't work when reindexing system catalogs. The assertion
93  * doesn't prevent the actual rebuild because we don't use RELATION_CHECKS
94  * when calling the index AM's ambuild routine, and there is no reason for
95  * ambuild to call its subsidiary routines through this file.
96  * ----------------------------------------------------------------
97  */
98 #define RELATION_CHECKS \
99 ( \
100  AssertMacro(RelationIsValid(indexRelation)), \
101  AssertMacro(PointerIsValid(indexRelation->rd_amroutine)), \
102  AssertMacro(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))) \
103 )
104 
105 #define SCAN_CHECKS \
106 ( \
107  AssertMacro(IndexScanIsValid(scan)), \
108  AssertMacro(RelationIsValid(scan->indexRelation)), \
109  AssertMacro(PointerIsValid(scan->indexRelation->rd_amroutine)) \
110 )
111 
112 #define CHECK_REL_PROCEDURE(pname) \
113 do { \
114  if (indexRelation->rd_amroutine->pname == NULL) \
115  elog(ERROR, "function %s is not defined for index %s", \
116  CppAsString(pname), RelationGetRelationName(indexRelation)); \
117 } while(0)
118 
119 #define CHECK_SCAN_PROCEDURE(pname) \
120 do { \
121  if (scan->indexRelation->rd_amroutine->pname == NULL) \
122  elog(ERROR, "function %s is not defined for index %s", \
123  CppAsString(pname), RelationGetRelationName(scan->indexRelation)); \
124 } while(0)
125 
126 static IndexScanDesc index_beginscan_internal(Relation indexRelation,
127  int nkeys, int norderbys, Snapshot snapshot,
128  ParallelIndexScanDesc pscan, bool temp_snap);
129 
130 
131 /* ----------------------------------------------------------------
132  * index_ interface functions
133  * ----------------------------------------------------------------
134  */
135 
136 /* ----------------
137  * index_open - open an index relation by relation OID
138  *
139  * If lockmode is not "NoLock", the specified kind of lock is
140  * obtained on the index. (Generally, NoLock should only be
141  * used if the caller knows it has some appropriate lock on the
142  * index already.)
143  *
144  * An error is raised if the index does not exist.
145  *
146  * This is a convenience routine adapted for indexscan use.
147  * Some callers may prefer to use relation_open directly.
148  * ----------------
149  */
150 Relation
151 index_open(Oid relationId, LOCKMODE lockmode)
152 {
153  Relation r;
154 
155  r = relation_open(relationId, lockmode);
156 
157  if (r->rd_rel->relkind != RELKIND_INDEX)
158  ereport(ERROR,
159  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
160  errmsg("\"%s\" is not an index",
162 
163  return r;
164 }
165 
166 /* ----------------
167  * index_close - close an index relation
168  *
169  * If lockmode is not "NoLock", we then release the specified lock.
170  *
171  * Note that it is often sensible to hold a lock beyond index_close;
172  * in that case, the lock is released automatically at xact end.
173  * ----------------
174  */
175 void
176 index_close(Relation relation, LOCKMODE lockmode)
177 {
178  LockRelId relid = relation->rd_lockInfo.lockRelId;
179 
180  Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
181 
182  /* The relcache does the real work... */
183  RelationClose(relation);
184 
185  if (lockmode != NoLock)
186  UnlockRelationId(&relid, lockmode);
187 }
188 
189 /* ----------------
190  * index_insert - insert an index tuple into a relation
191  * ----------------
192  */
193 bool
194 index_insert(Relation indexRelation,
195  Datum *values,
196  bool *isnull,
197  ItemPointer heap_t_ctid,
198  Relation heapRelation,
199  IndexUniqueCheck checkUnique,
200  IndexInfo *indexInfo)
201 {
203  CHECK_REL_PROCEDURE(aminsert);
204 
205  if (!(indexRelation->rd_amroutine->ampredlocks))
206  CheckForSerializableConflictIn(indexRelation,
207  (HeapTuple) NULL,
208  InvalidBuffer);
209 
210  return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull,
211  heap_t_ctid, heapRelation,
212  checkUnique, indexInfo);
213 }
214 
215 /*
216  * index_beginscan - start a scan of an index with amgettuple
217  *
218  * Caller must be holding suitable locks on the heap and the index.
219  */
222  Relation indexRelation,
223  Snapshot snapshot,
224  int nkeys, int norderbys)
225 {
226  IndexScanDesc scan;
227 
228  scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot, NULL, false);
229 
230  /*
231  * Save additional parameters into the scandesc. Everything else was set
232  * up by RelationGetIndexScan.
233  */
234  scan->heapRelation = heapRelation;
235  scan->xs_snapshot = snapshot;
236 
237  return scan;
238 }
239 
240 /*
241  * index_beginscan_bitmap - start a scan of an index with amgetbitmap
242  *
243  * As above, caller had better be holding some lock on the parent heap
244  * relation, even though it's not explicitly mentioned here.
245  */
248  Snapshot snapshot,
249  int nkeys)
250 {
251  IndexScanDesc scan;
252 
253  scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot, NULL, false);
254 
255  /*
256  * Save additional parameters into the scandesc. Everything else was set
257  * up by RelationGetIndexScan.
258  */
259  scan->xs_snapshot = snapshot;
260 
261  return scan;
262 }
263 
264 /*
265  * index_beginscan_internal --- common code for index_beginscan variants
266  */
267 static IndexScanDesc
269  int nkeys, int norderbys, Snapshot snapshot,
270  ParallelIndexScanDesc pscan, bool temp_snap)
271 {
272  IndexScanDesc scan;
273 
275  CHECK_REL_PROCEDURE(ambeginscan);
276 
277  if (!(indexRelation->rd_amroutine->ampredlocks))
278  PredicateLockRelation(indexRelation, snapshot);
279 
280  /*
281  * We hold a reference count to the relcache entry throughout the scan.
282  */
283  RelationIncrementReferenceCount(indexRelation);
284 
285  /*
286  * Tell the AM to open a scan.
287  */
288  scan = indexRelation->rd_amroutine->ambeginscan(indexRelation, nkeys,
289  norderbys);
290  /* Initialize information for parallel scan. */
291  scan->parallel_scan = pscan;
292  scan->xs_temp_snap = temp_snap;
293 
294  return scan;
295 }
296 
297 /* ----------------
298  * index_rescan - (re)start a scan of an index
299  *
300  * During a restart, the caller may specify a new set of scankeys and/or
301  * orderbykeys; but the number of keys cannot differ from what index_beginscan
302  * was told. (Later we might relax that to "must not exceed", but currently
303  * the index AMs tend to assume that scan->numberOfKeys is what to believe.)
304  * To restart the scan without changing keys, pass NULL for the key arrays.
305  * (Of course, keys *must* be passed on the first call, unless
306  * scan->numberOfKeys is zero.)
307  * ----------------
308  */
309 void
311  ScanKey keys, int nkeys,
312  ScanKey orderbys, int norderbys)
313 {
314  SCAN_CHECKS;
315  CHECK_SCAN_PROCEDURE(amrescan);
316 
317  Assert(nkeys == scan->numberOfKeys);
318  Assert(norderbys == scan->numberOfOrderBys);
319 
320  /* Release any held pin on a heap page */
321  if (BufferIsValid(scan->xs_cbuf))
322  {
323  ReleaseBuffer(scan->xs_cbuf);
324  scan->xs_cbuf = InvalidBuffer;
325  }
326 
327  scan->xs_continue_hot = false;
328 
329  scan->kill_prior_tuple = false; /* for safety */
330 
331  scan->indexRelation->rd_amroutine->amrescan(scan, keys, nkeys,
332  orderbys, norderbys);
333 }
334 
335 /* ----------------
336  * index_endscan - end a scan
337  * ----------------
338  */
339 void
341 {
342  SCAN_CHECKS;
343  CHECK_SCAN_PROCEDURE(amendscan);
344 
345  /* Release any held pin on a heap page */
346  if (BufferIsValid(scan->xs_cbuf))
347  {
348  ReleaseBuffer(scan->xs_cbuf);
349  scan->xs_cbuf = InvalidBuffer;
350  }
351 
352  /* End the AM's scan */
353  scan->indexRelation->rd_amroutine->amendscan(scan);
354 
355  /* Release index refcount acquired by index_beginscan */
357 
358  if (scan->xs_temp_snap)
360 
361  /* Release the scan data structure itself */
362  IndexScanEnd(scan);
363 }
364 
365 /* ----------------
366  * index_markpos - mark a scan position
367  * ----------------
368  */
369 void
371 {
372  SCAN_CHECKS;
373  CHECK_SCAN_PROCEDURE(ammarkpos);
374 
375  scan->indexRelation->rd_amroutine->ammarkpos(scan);
376 }
377 
378 /* ----------------
379  * index_restrpos - restore a scan position
380  *
381  * NOTE: this only restores the internal scan state of the index AM.
382  * The current result tuple (scan->xs_ctup) doesn't change. See comments
383  * for ExecRestrPos().
384  *
385  * NOTE: in the presence of HOT chains, mark/restore only works correctly
386  * if the scan's snapshot is MVCC-safe; that ensures that there's at most one
387  * returnable tuple in each HOT chain, and so restoring the prior state at the
388  * granularity of the index AM is sufficient. Since the only current user
389  * of mark/restore functionality is nodeMergejoin.c, this effectively means
390  * that merge-join plans only work for MVCC snapshots. This could be fixed
391  * if necessary, but for now it seems unimportant.
392  * ----------------
393  */
394 void
396 {
398 
399  SCAN_CHECKS;
400  CHECK_SCAN_PROCEDURE(amrestrpos);
401 
402  scan->xs_continue_hot = false;
403 
404  scan->kill_prior_tuple = false; /* for safety */
405 
406  scan->indexRelation->rd_amroutine->amrestrpos(scan);
407 }
408 
409 /*
410  * index_parallelscan_estimate - estimate shared memory for parallel scan
411  *
412  * Currently, we don't pass any information to the AM-specific estimator,
413  * so it can probably only return a constant. In the future, we might need
414  * to pass more information.
415  */
416 Size
418 {
419  Size nbytes;
420 
422 
423  nbytes = offsetof(ParallelIndexScanDescData, ps_snapshot_data);
424  nbytes = add_size(nbytes, EstimateSnapshotSpace(snapshot));
425  nbytes = MAXALIGN(nbytes);
426 
427  /*
428  * If amestimateparallelscan is not provided, assume there is no
429  * AM-specific data needed. (It's hard to believe that could work, but
430  * it's easy enough to cater to it here.)
431  */
432  if (indexRelation->rd_amroutine->amestimateparallelscan != NULL)
433  nbytes = add_size(nbytes,
434  indexRelation->rd_amroutine->amestimateparallelscan());
435 
436  return nbytes;
437 }
438 
439 /*
440  * index_parallelscan_initialize - initialize parallel scan
441  *
442  * We initialize both the ParallelIndexScanDesc proper and the AM-specific
443  * information which follows it.
444  *
445  * This function calls access method specific initialization routine to
446  * initialize am specific information. Call this just once in the leader
447  * process; then, individual workers attach via index_beginscan_parallel.
448  */
449 void
450 index_parallelscan_initialize(Relation heapRelation, Relation indexRelation,
451  Snapshot snapshot, ParallelIndexScanDesc target)
452 {
453  Size offset;
454 
456 
457  offset = add_size(offsetof(ParallelIndexScanDescData, ps_snapshot_data),
458  EstimateSnapshotSpace(snapshot));
459  offset = MAXALIGN(offset);
460 
461  target->ps_relid = RelationGetRelid(heapRelation);
462  target->ps_indexid = RelationGetRelid(indexRelation);
463  target->ps_offset = offset;
464  SerializeSnapshot(snapshot, target->ps_snapshot_data);
465 
466  /* aminitparallelscan is optional; assume no-op if not provided by AM */
467  if (indexRelation->rd_amroutine->aminitparallelscan != NULL)
468  {
469  void *amtarget;
470 
471  amtarget = OffsetToPointer(target, offset);
472  indexRelation->rd_amroutine->aminitparallelscan(amtarget);
473  }
474 }
475 
476 /* ----------------
477  * index_parallelrescan - (re)start a parallel scan of an index
478  * ----------------
479  */
480 void
482 {
483  SCAN_CHECKS;
484 
485  /* amparallelrescan is optional; assume no-op if not provided by AM */
486  if (scan->indexRelation->rd_amroutine->amparallelrescan != NULL)
488 }
489 
490 /*
491  * index_beginscan_parallel - join parallel index scan
492  *
493  * Caller must be holding suitable locks on the heap and the index.
494  */
496 index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys,
497  int norderbys, ParallelIndexScanDesc pscan)
498 {
499  Snapshot snapshot;
500  IndexScanDesc scan;
501 
502  Assert(RelationGetRelid(heaprel) == pscan->ps_relid);
503  snapshot = RestoreSnapshot(pscan->ps_snapshot_data);
504  RegisterSnapshot(snapshot);
505  scan = index_beginscan_internal(indexrel, nkeys, norderbys, snapshot,
506  pscan, true);
507 
508  /*
509  * Save additional parameters into the scandesc. Everything else was set
510  * up by index_beginscan_internal.
511  */
512  scan->heapRelation = heaprel;
513  scan->xs_snapshot = snapshot;
514 
515  return scan;
516 }
517 
518 /* ----------------
519  * index_getnext_tid - get the next TID from a scan
520  *
521  * The result is the next TID satisfying the scan keys,
522  * or NULL if no more matching tuples exist.
523  * ----------------
524  */
527 {
528  bool found;
529 
530  SCAN_CHECKS;
531  CHECK_SCAN_PROCEDURE(amgettuple);
532 
534 
535  /*
536  * The AM's amgettuple proc finds the next index entry matching the scan
537  * keys, and puts the TID into scan->xs_ctup.t_self. It should also set
538  * scan->xs_recheck and possibly scan->xs_itup/scan->xs_hitup, though we
539  * pay no attention to those fields here.
540  */
541  found = scan->indexRelation->rd_amroutine->amgettuple(scan, direction);
542 
543  /* Reset kill flag immediately for safety */
544  scan->kill_prior_tuple = false;
545 
546  /* If we're out of index entries, we're done */
547  if (!found)
548  {
549  /* ... but first, release any held pin on a heap page */
550  if (BufferIsValid(scan->xs_cbuf))
551  {
552  ReleaseBuffer(scan->xs_cbuf);
553  scan->xs_cbuf = InvalidBuffer;
554  }
555  return NULL;
556  }
557 
559 
560  /* Return the TID of the tuple we found. */
561  return &scan->xs_ctup.t_self;
562 }
563 
564 /* ----------------
565  * index_fetch_heap - get the scan's next heap tuple
566  *
567  * The result is a visible heap tuple associated with the index TID most
568  * recently fetched by index_getnext_tid, or NULL if no more matching tuples
569  * exist. (There can be more than one matching tuple because of HOT chains,
570  * although when using an MVCC snapshot it should be impossible for more than
571  * one such tuple to exist.)
572  *
573  * On success, the buffer containing the heap tup is pinned (the pin will be
574  * dropped in a future index_getnext_tid, index_fetch_heap or index_endscan
575  * call).
576  *
577  * Note: caller must check scan->xs_recheck, and perform rechecking of the
578  * scan keys if required. We do not do that here because we don't have
579  * enough information to do it efficiently in the general case.
580  * ----------------
581  */
582 HeapTuple
584 {
585  ItemPointer tid = &scan->xs_ctup.t_self;
586  bool all_dead = false;
587  bool got_heap_tuple;
588 
589  /* We can skip the buffer-switching logic if we're in mid-HOT chain. */
590  if (!scan->xs_continue_hot)
591  {
592  /* Switch to correct buffer if we don't have it already */
593  Buffer prev_buf = scan->xs_cbuf;
594 
595  scan->xs_cbuf = ReleaseAndReadBuffer(scan->xs_cbuf,
596  scan->heapRelation,
598 
599  /*
600  * Prune page, but only if we weren't already on this page
601  */
602  if (prev_buf != scan->xs_cbuf)
604  }
605 
606  /* Obtain share-lock on the buffer so we can examine visibility */
608  got_heap_tuple = heap_hot_search_buffer(tid, scan->heapRelation,
609  scan->xs_cbuf,
610  scan->xs_snapshot,
611  &scan->xs_ctup,
612  &all_dead,
613  !scan->xs_continue_hot);
615 
616  if (got_heap_tuple)
617  {
618  /*
619  * Only in a non-MVCC snapshot can more than one member of the HOT
620  * chain be visible.
621  */
624  return &scan->xs_ctup;
625  }
626 
627  /* We've reached the end of the HOT chain. */
628  scan->xs_continue_hot = false;
629 
630  /*
631  * If we scanned a whole HOT chain and found only dead tuples, tell index
632  * AM to kill its entry for that TID (this will take effect in the next
633  * amgettuple call, in index_getnext_tid). We do not do this when in
634  * recovery because it may violate MVCC to do so. See comments in
635  * RelationGetIndexScan().
636  */
637  if (!scan->xactStartedInRecovery)
638  scan->kill_prior_tuple = all_dead;
639 
640  return NULL;
641 }
642 
643 /* ----------------
644  * index_getnext - get the next heap tuple from a scan
645  *
646  * The result is the next heap tuple satisfying the scan keys and the
647  * snapshot, or NULL if no more matching tuples exist.
648  *
649  * On success, the buffer containing the heap tup is pinned (the pin will be
650  * dropped in a future index_getnext_tid, index_fetch_heap or index_endscan
651  * call).
652  *
653  * Note: caller must check scan->xs_recheck, and perform rechecking of the
654  * scan keys if required. We do not do that here because we don't have
655  * enough information to do it efficiently in the general case.
656  * ----------------
657  */
658 HeapTuple
660 {
661  HeapTuple heapTuple;
662  ItemPointer tid;
663 
664  for (;;)
665  {
666  if (scan->xs_continue_hot)
667  {
668  /*
669  * We are resuming scan of a HOT chain after having returned an
670  * earlier member. Must still hold pin on current heap page.
671  */
672  Assert(BufferIsValid(scan->xs_cbuf));
675  }
676  else
677  {
678  /* Time to fetch the next TID from the index */
679  tid = index_getnext_tid(scan, direction);
680 
681  /* If we're out of index entries, we're done */
682  if (tid == NULL)
683  break;
684  }
685 
686  /*
687  * Fetch the next (or only) visible heap tuple for this index entry.
688  * If we don't find anything, loop around and grab the next TID from
689  * the index.
690  */
691  heapTuple = index_fetch_heap(scan);
692  if (heapTuple != NULL)
693  return heapTuple;
694  }
695 
696  return NULL; /* failure exit */
697 }
698 
699 /* ----------------
700  * index_getbitmap - get all tuples at once from an index scan
701  *
702  * Adds the TIDs of all heap tuples satisfying the scan keys to a bitmap.
703  * Since there's no interlock between the index scan and the eventual heap
704  * access, this is only safe to use with MVCC-based snapshots: the heap
705  * item slot could have been replaced by a newer tuple by the time we get
706  * to it.
707  *
708  * Returns the number of matching tuples found. (Note: this might be only
709  * approximate, so it should only be used for statistical purposes.)
710  * ----------------
711  */
712 int64
714 {
715  int64 ntids;
716 
717  SCAN_CHECKS;
718  CHECK_SCAN_PROCEDURE(amgetbitmap);
719 
720  /* just make sure this is false... */
721  scan->kill_prior_tuple = false;
722 
723  /*
724  * have the am's getbitmap proc do all the work.
725  */
726  ntids = scan->indexRelation->rd_amroutine->amgetbitmap(scan, bitmap);
727 
729 
730  return ntids;
731 }
732 
733 /* ----------------
734  * index_bulk_delete - do mass deletion of index entries
735  *
736  * callback routine tells whether a given main-heap tuple is
737  * to be deleted
738  *
739  * return value is an optional palloc'd struct of statistics
740  * ----------------
741  */
744  IndexBulkDeleteResult *stats,
746  void *callback_state)
747 {
748  Relation indexRelation = info->index;
749 
751  CHECK_REL_PROCEDURE(ambulkdelete);
752 
753  return indexRelation->rd_amroutine->ambulkdelete(info, stats,
754  callback, callback_state);
755 }
756 
757 /* ----------------
758  * index_vacuum_cleanup - do post-deletion cleanup of an index
759  *
760  * return value is an optional palloc'd struct of statistics
761  * ----------------
762  */
765  IndexBulkDeleteResult *stats)
766 {
767  Relation indexRelation = info->index;
768 
770  CHECK_REL_PROCEDURE(amvacuumcleanup);
771 
772  return indexRelation->rd_amroutine->amvacuumcleanup(info, stats);
773 }
774 
775 /* ----------------
776  * index_can_return
777  *
778  * Does the index access method support index-only scans for the given
779  * column?
780  * ----------------
781  */
782 bool
783 index_can_return(Relation indexRelation, int attno)
784 {
786 
787  /* amcanreturn is optional; assume false if not provided by AM */
788  if (indexRelation->rd_amroutine->amcanreturn == NULL)
789  return false;
790 
791  return indexRelation->rd_amroutine->amcanreturn(indexRelation, attno);
792 }
793 
794 /* ----------------
795  * index_getprocid
796  *
797  * Index access methods typically require support routines that are
798  * not directly the implementation of any WHERE-clause query operator
799  * and so cannot be kept in pg_amop. Instead, such routines are kept
800  * in pg_amproc. These registered procedure OIDs are assigned numbers
801  * according to a convention established by the access method.
802  * The general index code doesn't know anything about the routines
803  * involved; it just builds an ordered list of them for
804  * each attribute on which an index is defined.
805  *
806  * As of Postgres 8.3, support routines within an operator family
807  * are further subdivided by the "left type" and "right type" of the
808  * query operator(s) that they support. The "default" functions for a
809  * particular indexed attribute are those with both types equal to
810  * the index opclass' opcintype (note that this is subtly different
811  * from the indexed attribute's own type: it may be a binary-compatible
812  * type instead). Only the default functions are stored in relcache
813  * entries --- access methods can use the syscache to look up non-default
814  * functions.
815  *
816  * This routine returns the requested default procedure OID for a
817  * particular indexed attribute.
818  * ----------------
819  */
822  AttrNumber attnum,
823  uint16 procnum)
824 {
825  RegProcedure *loc;
826  int nproc;
827  int procindex;
828 
829  nproc = irel->rd_amroutine->amsupport;
830 
831  Assert(procnum > 0 && procnum <= (uint16) nproc);
832 
833  procindex = (nproc * (attnum - 1)) + (procnum - 1);
834 
835  loc = irel->rd_support;
836 
837  Assert(loc != NULL);
838 
839  return loc[procindex];
840 }
841 
842 /* ----------------
843  * index_getprocinfo
844  *
845  * This routine allows index AMs to keep fmgr lookup info for
846  * support procs in the relcache. As above, only the "default"
847  * functions for any particular indexed attribute are cached.
848  *
849  * Note: the return value points into cached data that will be lost during
850  * any relcache rebuild! Therefore, either use the callinfo right away,
851  * or save it only after having acquired some type of lock on the index rel.
852  * ----------------
853  */
854 FmgrInfo *
856  AttrNumber attnum,
857  uint16 procnum)
858 {
859  FmgrInfo *locinfo;
860  int nproc;
861  int procindex;
862 
863  nproc = irel->rd_amroutine->amsupport;
864 
865  Assert(procnum > 0 && procnum <= (uint16) nproc);
866 
867  procindex = (nproc * (attnum - 1)) + (procnum - 1);
868 
869  locinfo = irel->rd_supportinfo;
870 
871  Assert(locinfo != NULL);
872 
873  locinfo += procindex;
874 
875  /* Initialize the lookup info if first time through */
876  if (locinfo->fn_oid == InvalidOid)
877  {
878  RegProcedure *loc = irel->rd_support;
879  RegProcedure procId;
880 
881  Assert(loc != NULL);
882 
883  procId = loc[procindex];
884 
885  /*
886  * Complain if function was not found during IndexSupportInitialize.
887  * This should not happen unless the system tables contain bogus
888  * entries for the index opclass. (If an AM wants to allow a support
889  * function to be optional, it can use index_getprocid.)
890  */
891  if (!RegProcedureIsValid(procId))
892  elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
893  procnum, attnum, RelationGetRelationName(irel));
894 
895  fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt);
896  }
897 
898  return locinfo;
899 }
ParallelIndexScanDesc parallel_scan
Definition: relscan.h:140
ambeginscan_function ambeginscan
Definition: amapi.h:208
IndexScanDesc index_beginscan_bitmap(Relation indexRelation, Snapshot snapshot, int nkeys)
Definition: indexam.c:247
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
Definition: fmgr.h:56
ambulkdelete_function ambulkdelete
Definition: amapi.h:201
LockRelId lockRelId
Definition: rel.h:44
uint16 amsupport
Definition: amapi.h:169
Snapshot RestoreSnapshot(char *start_address)
Definition: snapmgr.c:2127
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
FmgrInfo * rd_supportinfo
Definition: rel.h:185
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
amgettuple_function amgettuple
Definition: amapi.h:210
int LOCKMODE
Definition: lockdefs.h:26
void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:167
#define RELATION_CHECKS
Definition: indexam.c:98
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:496
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:370
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition: predicate.c:2498
regproc RegProcedure
Definition: c.h:453
amparallelrescan_function amparallelrescan
Definition: amapi.h:219
Snapshot xs_snapshot
Definition: relscan.h:91
#define InvalidBuffer
Definition: buf.h:25
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:310
int errcode(int sqlerrcode)
Definition: elog.c:575
Relation index
Definition: genam.h:46
bool ampredlocks
Definition: amapi.h:191
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
char ps_snapshot_data[FLEXIBLE_ARRAY_MEMBER]
Definition: relscan.h:149
aminsert_function aminsert
Definition: amapi.h:200
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4326
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:181
#define CHECK_SCAN_PROCEDURE(pname)
Definition: indexam.c:119
Relation indexRelation
Definition: relscan.h:90
#define CHECK_REL_PROCEDURE(pname)
Definition: indexam.c:112
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:417
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:481
Relation heapRelation
Definition: relscan.h:89
IndexUniqueCheck
Definition: genam.h:111
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:395
bool heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call)
Definition: heapam.c:2011
bool index_can_return(Relation indexRelation, int attno)
Definition: indexam.c:783
ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:526
unsigned short uint16
Definition: c.h:305
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2150
amgetbitmap_function amgetbitmap
Definition: amapi.h:211
Buffer xs_cbuf
Definition: relscan.h:121
#define ERROR
Definition: elog.h:43
Definition: rel.h:36
void SerializeSnapshot(Snapshot snapshot, char *start_address)
Definition: snapmgr.c:2068
ItemPointerData t_self
Definition: htup.h:65
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
#define pgstat_count_heap_fetch(rel)
Definition: pgstat.h:1270
bool xs_temp_snap
Definition: relscan.h:97
#define NoLock
Definition: lockdefs.h:34
LockInfoData rd_lockInfo
Definition: rel.h:117
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:202
amendscan_function amendscan
Definition: amapi.h:212
bool xactStartedInRecovery
Definition: relscan.h:102
TransactionId RecentGlobalXmin
Definition: snapmgr.c:166
#define RegProcedureIsValid(p)
Definition: c.h:588
HeapTuple index_fetch_heap(IndexScanDesc scan)
Definition: indexam.c:583
ScanDirection
Definition: sdir.h:22
bool xs_continue_hot
Definition: relscan.h:137
#define RelationGetRelationName(relation)
Definition: rel.h:445
void IndexScanEnd(IndexScanDesc scan)
Definition: genam.c:146
void RelationClose(Relation relation)
Definition: relcache.c:2170
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:132
#define OffsetToPointer(base, offset)
Definition: c.h:583
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:340
#define ereport(elevel, rest)
Definition: elog.h:122
amrescan_function amrescan
Definition: amapi.h:209
RegProcedure * rd_support
Definition: rel.h:184
int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
Definition: indexam.c:713
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
Size EstimateSnapshotSpace(Snapshot snap)
Definition: snapmgr.c:2044
#define MAX_LOCKMODES
Definition: lock.h:85
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2137
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: indexam.c:743
uintptr_t Datum
Definition: postgres.h:372
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define InvalidOid
Definition: postgres_ext.h:36
Oid fn_oid
Definition: fmgr.h:59
static IndexScanDesc index_beginscan_internal(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot, ParallelIndexScanDesc pscan, bool temp_snap)
Definition: indexam.c:268
#define Assert(condition)
Definition: c.h:680
#define IsMVCCSnapshot(snapshot)
Definition: tqual.h:31
HeapTupleData xs_ctup
Definition: relscan.h:120
size_t Size
Definition: c.h:414
#define SCAN_CHECKS
Definition: indexam.c:105
Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, BlockNumber blockNum)
Definition: bufmgr.c:1513
#define MAXALIGN(LEN)
Definition: c.h:633
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
ammarkpos_function ammarkpos
Definition: amapi.h:213
#define pgstat_count_index_tuples(rel, n)
Definition: pgstat.h:1280
IndexBulkDeleteResult * index_vacuum_cleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: indexam.c:764
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:217
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
static Datum values[MAXATTR]
Definition: bootstrap.c:164
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
int errmsg(const char *fmt,...)
Definition: elog.c:797
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:450
MemoryContext rd_indexcxt
Definition: rel.h:179
bool kill_prior_tuple
Definition: relscan.h:100
#define RELKIND_INDEX
Definition: pg_class.h:161
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
int numberOfOrderBys
Definition: relscan.h:93
#define elog
Definition: elog.h:219
void heap_page_prune_opt(Relation relation, Buffer buffer)
Definition: pruneheap.c:74
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:76
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int Buffer
Definition: buf.h:23
amcanreturn_function amcanreturn
Definition: amapi.h:203
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:425
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
#define offsetof(type, field)
Definition: c.h:603
HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:659
bool(* IndexBulkDeleteCallback)(ItemPointer itemptr, void *state)
Definition: genam.h:83
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:218
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: indexam.c:194
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:221
amrestrpos_function amrestrpos
Definition: amapi.h:214
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:821