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-2018, 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  r->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
159  ereport(ERROR,
160  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
161  errmsg("\"%s\" is not an index",
163 
164  return r;
165 }
166 
167 /* ----------------
168  * index_close - close an index relation
169  *
170  * If lockmode is not "NoLock", we then release the specified lock.
171  *
172  * Note that it is often sensible to hold a lock beyond index_close;
173  * in that case, the lock is released automatically at xact end.
174  * ----------------
175  */
176 void
177 index_close(Relation relation, LOCKMODE lockmode)
178 {
179  LockRelId relid = relation->rd_lockInfo.lockRelId;
180 
181  Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
182 
183  /* The relcache does the real work... */
184  RelationClose(relation);
185 
186  if (lockmode != NoLock)
187  UnlockRelationId(&relid, lockmode);
188 }
189 
190 /* ----------------
191  * index_insert - insert an index tuple into a relation
192  * ----------------
193  */
194 bool
195 index_insert(Relation indexRelation,
196  Datum *values,
197  bool *isnull,
198  ItemPointer heap_t_ctid,
199  Relation heapRelation,
200  IndexUniqueCheck checkUnique,
201  IndexInfo *indexInfo)
202 {
204  CHECK_REL_PROCEDURE(aminsert);
205 
206  if (!(indexRelation->rd_amroutine->ampredlocks))
207  CheckForSerializableConflictIn(indexRelation,
208  (HeapTuple) NULL,
209  InvalidBuffer);
210 
211  return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull,
212  heap_t_ctid, heapRelation,
213  checkUnique, indexInfo);
214 }
215 
216 /*
217  * index_beginscan - start a scan of an index with amgettuple
218  *
219  * Caller must be holding suitable locks on the heap and the index.
220  */
223  Relation indexRelation,
224  Snapshot snapshot,
225  int nkeys, int norderbys)
226 {
227  IndexScanDesc scan;
228 
229  scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot, NULL, false);
230 
231  /*
232  * Save additional parameters into the scandesc. Everything else was set
233  * up by RelationGetIndexScan.
234  */
235  scan->heapRelation = heapRelation;
236  scan->xs_snapshot = snapshot;
237 
238  return scan;
239 }
240 
241 /*
242  * index_beginscan_bitmap - start a scan of an index with amgetbitmap
243  *
244  * As above, caller had better be holding some lock on the parent heap
245  * relation, even though it's not explicitly mentioned here.
246  */
249  Snapshot snapshot,
250  int nkeys)
251 {
252  IndexScanDesc scan;
253 
254  scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot, NULL, false);
255 
256  /*
257  * Save additional parameters into the scandesc. Everything else was set
258  * up by RelationGetIndexScan.
259  */
260  scan->xs_snapshot = snapshot;
261 
262  return scan;
263 }
264 
265 /*
266  * index_beginscan_internal --- common code for index_beginscan variants
267  */
268 static IndexScanDesc
270  int nkeys, int norderbys, Snapshot snapshot,
271  ParallelIndexScanDesc pscan, bool temp_snap)
272 {
273  IndexScanDesc scan;
274 
276  CHECK_REL_PROCEDURE(ambeginscan);
277 
278  if (!(indexRelation->rd_amroutine->ampredlocks))
279  PredicateLockRelation(indexRelation, snapshot);
280 
281  /*
282  * We hold a reference count to the relcache entry throughout the scan.
283  */
284  RelationIncrementReferenceCount(indexRelation);
285 
286  /*
287  * Tell the AM to open a scan.
288  */
289  scan = indexRelation->rd_amroutine->ambeginscan(indexRelation, nkeys,
290  norderbys);
291  /* Initialize information for parallel scan. */
292  scan->parallel_scan = pscan;
293  scan->xs_temp_snap = temp_snap;
294 
295  return scan;
296 }
297 
298 /* ----------------
299  * index_rescan - (re)start a scan of an index
300  *
301  * During a restart, the caller may specify a new set of scankeys and/or
302  * orderbykeys; but the number of keys cannot differ from what index_beginscan
303  * was told. (Later we might relax that to "must not exceed", but currently
304  * the index AMs tend to assume that scan->numberOfKeys is what to believe.)
305  * To restart the scan without changing keys, pass NULL for the key arrays.
306  * (Of course, keys *must* be passed on the first call, unless
307  * scan->numberOfKeys is zero.)
308  * ----------------
309  */
310 void
312  ScanKey keys, int nkeys,
313  ScanKey orderbys, int norderbys)
314 {
315  SCAN_CHECKS;
316  CHECK_SCAN_PROCEDURE(amrescan);
317 
318  Assert(nkeys == scan->numberOfKeys);
319  Assert(norderbys == scan->numberOfOrderBys);
320 
321  /* Release any held pin on a heap page */
322  if (BufferIsValid(scan->xs_cbuf))
323  {
324  ReleaseBuffer(scan->xs_cbuf);
325  scan->xs_cbuf = InvalidBuffer;
326  }
327 
328  scan->xs_continue_hot = false;
329 
330  scan->kill_prior_tuple = false; /* for safety */
331 
332  scan->indexRelation->rd_amroutine->amrescan(scan, keys, nkeys,
333  orderbys, norderbys);
334 }
335 
336 /* ----------------
337  * index_endscan - end a scan
338  * ----------------
339  */
340 void
342 {
343  SCAN_CHECKS;
344  CHECK_SCAN_PROCEDURE(amendscan);
345 
346  /* Release any held pin on a heap page */
347  if (BufferIsValid(scan->xs_cbuf))
348  {
349  ReleaseBuffer(scan->xs_cbuf);
350  scan->xs_cbuf = InvalidBuffer;
351  }
352 
353  /* End the AM's scan */
354  scan->indexRelation->rd_amroutine->amendscan(scan);
355 
356  /* Release index refcount acquired by index_beginscan */
358 
359  if (scan->xs_temp_snap)
361 
362  /* Release the scan data structure itself */
363  IndexScanEnd(scan);
364 }
365 
366 /* ----------------
367  * index_markpos - mark a scan position
368  * ----------------
369  */
370 void
372 {
373  SCAN_CHECKS;
374  CHECK_SCAN_PROCEDURE(ammarkpos);
375 
376  scan->indexRelation->rd_amroutine->ammarkpos(scan);
377 }
378 
379 /* ----------------
380  * index_restrpos - restore a scan position
381  *
382  * NOTE: this only restores the internal scan state of the index AM.
383  * The current result tuple (scan->xs_ctup) doesn't change. See comments
384  * for ExecRestrPos().
385  *
386  * NOTE: in the presence of HOT chains, mark/restore only works correctly
387  * if the scan's snapshot is MVCC-safe; that ensures that there's at most one
388  * returnable tuple in each HOT chain, and so restoring the prior state at the
389  * granularity of the index AM is sufficient. Since the only current user
390  * of mark/restore functionality is nodeMergejoin.c, this effectively means
391  * that merge-join plans only work for MVCC snapshots. This could be fixed
392  * if necessary, but for now it seems unimportant.
393  * ----------------
394  */
395 void
397 {
399 
400  SCAN_CHECKS;
401  CHECK_SCAN_PROCEDURE(amrestrpos);
402 
403  scan->xs_continue_hot = false;
404 
405  scan->kill_prior_tuple = false; /* for safety */
406 
407  scan->indexRelation->rd_amroutine->amrestrpos(scan);
408 }
409 
410 /*
411  * index_parallelscan_estimate - estimate shared memory for parallel scan
412  *
413  * Currently, we don't pass any information to the AM-specific estimator,
414  * so it can probably only return a constant. In the future, we might need
415  * to pass more information.
416  */
417 Size
419 {
420  Size nbytes;
421 
423 
424  nbytes = offsetof(ParallelIndexScanDescData, ps_snapshot_data);
425  nbytes = add_size(nbytes, EstimateSnapshotSpace(snapshot));
426  nbytes = MAXALIGN(nbytes);
427 
428  /*
429  * If amestimateparallelscan is not provided, assume there is no
430  * AM-specific data needed. (It's hard to believe that could work, but
431  * it's easy enough to cater to it here.)
432  */
433  if (indexRelation->rd_amroutine->amestimateparallelscan != NULL)
434  nbytes = add_size(nbytes,
435  indexRelation->rd_amroutine->amestimateparallelscan());
436 
437  return nbytes;
438 }
439 
440 /*
441  * index_parallelscan_initialize - initialize parallel scan
442  *
443  * We initialize both the ParallelIndexScanDesc proper and the AM-specific
444  * information which follows it.
445  *
446  * This function calls access method specific initialization routine to
447  * initialize am specific information. Call this just once in the leader
448  * process; then, individual workers attach via index_beginscan_parallel.
449  */
450 void
451 index_parallelscan_initialize(Relation heapRelation, Relation indexRelation,
452  Snapshot snapshot, ParallelIndexScanDesc target)
453 {
454  Size offset;
455 
457 
458  offset = add_size(offsetof(ParallelIndexScanDescData, ps_snapshot_data),
459  EstimateSnapshotSpace(snapshot));
460  offset = MAXALIGN(offset);
461 
462  target->ps_relid = RelationGetRelid(heapRelation);
463  target->ps_indexid = RelationGetRelid(indexRelation);
464  target->ps_offset = offset;
465  SerializeSnapshot(snapshot, target->ps_snapshot_data);
466 
467  /* aminitparallelscan is optional; assume no-op if not provided by AM */
468  if (indexRelation->rd_amroutine->aminitparallelscan != NULL)
469  {
470  void *amtarget;
471 
472  amtarget = OffsetToPointer(target, offset);
473  indexRelation->rd_amroutine->aminitparallelscan(amtarget);
474  }
475 }
476 
477 /* ----------------
478  * index_parallelrescan - (re)start a parallel scan of an index
479  * ----------------
480  */
481 void
483 {
484  SCAN_CHECKS;
485 
486  /* amparallelrescan is optional; assume no-op if not provided by AM */
487  if (scan->indexRelation->rd_amroutine->amparallelrescan != NULL)
489 }
490 
491 /*
492  * index_beginscan_parallel - join parallel index scan
493  *
494  * Caller must be holding suitable locks on the heap and the index.
495  */
497 index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys,
498  int norderbys, ParallelIndexScanDesc pscan)
499 {
500  Snapshot snapshot;
501  IndexScanDesc scan;
502 
503  Assert(RelationGetRelid(heaprel) == pscan->ps_relid);
504  snapshot = RestoreSnapshot(pscan->ps_snapshot_data);
505  RegisterSnapshot(snapshot);
506  scan = index_beginscan_internal(indexrel, nkeys, norderbys, snapshot,
507  pscan, true);
508 
509  /*
510  * Save additional parameters into the scandesc. Everything else was set
511  * up by index_beginscan_internal.
512  */
513  scan->heapRelation = heaprel;
514  scan->xs_snapshot = snapshot;
515 
516  return scan;
517 }
518 
519 /* ----------------
520  * index_getnext_tid - get the next TID from a scan
521  *
522  * The result is the next TID satisfying the scan keys,
523  * or NULL if no more matching tuples exist.
524  * ----------------
525  */
528 {
529  bool found;
530 
531  SCAN_CHECKS;
532  CHECK_SCAN_PROCEDURE(amgettuple);
533 
535 
536  /*
537  * The AM's amgettuple proc finds the next index entry matching the scan
538  * keys, and puts the TID into scan->xs_ctup.t_self. It should also set
539  * scan->xs_recheck and possibly scan->xs_itup/scan->xs_hitup, though we
540  * pay no attention to those fields here.
541  */
542  found = scan->indexRelation->rd_amroutine->amgettuple(scan, direction);
543 
544  /* Reset kill flag immediately for safety */
545  scan->kill_prior_tuple = false;
546 
547  /* If we're out of index entries, we're done */
548  if (!found)
549  {
550  /* ... but first, release any held pin on a heap page */
551  if (BufferIsValid(scan->xs_cbuf))
552  {
553  ReleaseBuffer(scan->xs_cbuf);
554  scan->xs_cbuf = InvalidBuffer;
555  }
556  return NULL;
557  }
558 
560 
561  /* Return the TID of the tuple we found. */
562  return &scan->xs_ctup.t_self;
563 }
564 
565 /* ----------------
566  * index_fetch_heap - get the scan's next heap tuple
567  *
568  * The result is a visible heap tuple associated with the index TID most
569  * recently fetched by index_getnext_tid, or NULL if no more matching tuples
570  * exist. (There can be more than one matching tuple because of HOT chains,
571  * although when using an MVCC snapshot it should be impossible for more than
572  * one such tuple to exist.)
573  *
574  * On success, the buffer containing the heap tup is pinned (the pin will be
575  * dropped in a future index_getnext_tid, index_fetch_heap or index_endscan
576  * call).
577  *
578  * Note: caller must check scan->xs_recheck, and perform rechecking of the
579  * scan keys if required. We do not do that here because we don't have
580  * enough information to do it efficiently in the general case.
581  * ----------------
582  */
583 HeapTuple
585 {
586  ItemPointer tid = &scan->xs_ctup.t_self;
587  bool all_dead = false;
588  bool got_heap_tuple;
589 
590  /* We can skip the buffer-switching logic if we're in mid-HOT chain. */
591  if (!scan->xs_continue_hot)
592  {
593  /* Switch to correct buffer if we don't have it already */
594  Buffer prev_buf = scan->xs_cbuf;
595 
596  scan->xs_cbuf = ReleaseAndReadBuffer(scan->xs_cbuf,
597  scan->heapRelation,
599 
600  /*
601  * Prune page, but only if we weren't already on this page
602  */
603  if (prev_buf != scan->xs_cbuf)
605  }
606 
607  /* Obtain share-lock on the buffer so we can examine visibility */
609  got_heap_tuple = heap_hot_search_buffer(tid, scan->heapRelation,
610  scan->xs_cbuf,
611  scan->xs_snapshot,
612  &scan->xs_ctup,
613  &all_dead,
614  !scan->xs_continue_hot);
616 
617  if (got_heap_tuple)
618  {
619  /*
620  * Only in a non-MVCC snapshot can more than one member of the HOT
621  * chain be visible.
622  */
625  return &scan->xs_ctup;
626  }
627 
628  /* We've reached the end of the HOT chain. */
629  scan->xs_continue_hot = false;
630 
631  /*
632  * If we scanned a whole HOT chain and found only dead tuples, tell index
633  * AM to kill its entry for that TID (this will take effect in the next
634  * amgettuple call, in index_getnext_tid). We do not do this when in
635  * recovery because it may violate MVCC to do so. See comments in
636  * RelationGetIndexScan().
637  */
638  if (!scan->xactStartedInRecovery)
639  scan->kill_prior_tuple = all_dead;
640 
641  return NULL;
642 }
643 
644 /* ----------------
645  * index_getnext - get the next heap tuple from a scan
646  *
647  * The result is the next heap tuple satisfying the scan keys and the
648  * snapshot, or NULL if no more matching tuples exist.
649  *
650  * On success, the buffer containing the heap tup is pinned (the pin will be
651  * dropped in a future index_getnext_tid, index_fetch_heap or index_endscan
652  * call).
653  *
654  * Note: caller must check scan->xs_recheck, and perform rechecking of the
655  * scan keys if required. We do not do that here because we don't have
656  * enough information to do it efficiently in the general case.
657  * ----------------
658  */
659 HeapTuple
661 {
662  HeapTuple heapTuple;
663  ItemPointer tid;
664 
665  for (;;)
666  {
667  if (scan->xs_continue_hot)
668  {
669  /*
670  * We are resuming scan of a HOT chain after having returned an
671  * earlier member. Must still hold pin on current heap page.
672  */
673  Assert(BufferIsValid(scan->xs_cbuf));
676  }
677  else
678  {
679  /* Time to fetch the next TID from the index */
680  tid = index_getnext_tid(scan, direction);
681 
682  /* If we're out of index entries, we're done */
683  if (tid == NULL)
684  break;
685  }
686 
687  /*
688  * Fetch the next (or only) visible heap tuple for this index entry.
689  * If we don't find anything, loop around and grab the next TID from
690  * the index.
691  */
692  heapTuple = index_fetch_heap(scan);
693  if (heapTuple != NULL)
694  return heapTuple;
695  }
696 
697  return NULL; /* failure exit */
698 }
699 
700 /* ----------------
701  * index_getbitmap - get all tuples at once from an index scan
702  *
703  * Adds the TIDs of all heap tuples satisfying the scan keys to a bitmap.
704  * Since there's no interlock between the index scan and the eventual heap
705  * access, this is only safe to use with MVCC-based snapshots: the heap
706  * item slot could have been replaced by a newer tuple by the time we get
707  * to it.
708  *
709  * Returns the number of matching tuples found. (Note: this might be only
710  * approximate, so it should only be used for statistical purposes.)
711  * ----------------
712  */
713 int64
715 {
716  int64 ntids;
717 
718  SCAN_CHECKS;
719  CHECK_SCAN_PROCEDURE(amgetbitmap);
720 
721  /* just make sure this is false... */
722  scan->kill_prior_tuple = false;
723 
724  /*
725  * have the am's getbitmap proc do all the work.
726  */
727  ntids = scan->indexRelation->rd_amroutine->amgetbitmap(scan, bitmap);
728 
730 
731  return ntids;
732 }
733 
734 /* ----------------
735  * index_bulk_delete - do mass deletion of index entries
736  *
737  * callback routine tells whether a given main-heap tuple is
738  * to be deleted
739  *
740  * return value is an optional palloc'd struct of statistics
741  * ----------------
742  */
745  IndexBulkDeleteResult *stats,
747  void *callback_state)
748 {
749  Relation indexRelation = info->index;
750 
752  CHECK_REL_PROCEDURE(ambulkdelete);
753 
754  return indexRelation->rd_amroutine->ambulkdelete(info, stats,
755  callback, callback_state);
756 }
757 
758 /* ----------------
759  * index_vacuum_cleanup - do post-deletion cleanup of an index
760  *
761  * return value is an optional palloc'd struct of statistics
762  * ----------------
763  */
766  IndexBulkDeleteResult *stats)
767 {
768  Relation indexRelation = info->index;
769 
771  CHECK_REL_PROCEDURE(amvacuumcleanup);
772 
773  return indexRelation->rd_amroutine->amvacuumcleanup(info, stats);
774 }
775 
776 /* ----------------
777  * index_can_return
778  *
779  * Does the index access method support index-only scans for the given
780  * column?
781  * ----------------
782  */
783 bool
784 index_can_return(Relation indexRelation, int attno)
785 {
787 
788  /* amcanreturn is optional; assume false if not provided by AM */
789  if (indexRelation->rd_amroutine->amcanreturn == NULL)
790  return false;
791 
792  return indexRelation->rd_amroutine->amcanreturn(indexRelation, attno);
793 }
794 
795 /* ----------------
796  * index_getprocid
797  *
798  * Index access methods typically require support routines that are
799  * not directly the implementation of any WHERE-clause query operator
800  * and so cannot be kept in pg_amop. Instead, such routines are kept
801  * in pg_amproc. These registered procedure OIDs are assigned numbers
802  * according to a convention established by the access method.
803  * The general index code doesn't know anything about the routines
804  * involved; it just builds an ordered list of them for
805  * each attribute on which an index is defined.
806  *
807  * As of Postgres 8.3, support routines within an operator family
808  * are further subdivided by the "left type" and "right type" of the
809  * query operator(s) that they support. The "default" functions for a
810  * particular indexed attribute are those with both types equal to
811  * the index opclass' opcintype (note that this is subtly different
812  * from the indexed attribute's own type: it may be a binary-compatible
813  * type instead). Only the default functions are stored in relcache
814  * entries --- access methods can use the syscache to look up non-default
815  * functions.
816  *
817  * This routine returns the requested default procedure OID for a
818  * particular indexed attribute.
819  * ----------------
820  */
823  AttrNumber attnum,
824  uint16 procnum)
825 {
826  RegProcedure *loc;
827  int nproc;
828  int procindex;
829 
830  nproc = irel->rd_amroutine->amsupport;
831 
832  Assert(procnum > 0 && procnum <= (uint16) nproc);
833 
834  procindex = (nproc * (attnum - 1)) + (procnum - 1);
835 
836  loc = irel->rd_support;
837 
838  Assert(loc != NULL);
839 
840  return loc[procindex];
841 }
842 
843 /* ----------------
844  * index_getprocinfo
845  *
846  * This routine allows index AMs to keep fmgr lookup info for
847  * support procs in the relcache. As above, only the "default"
848  * functions for any particular indexed attribute are cached.
849  *
850  * Note: the return value points into cached data that will be lost during
851  * any relcache rebuild! Therefore, either use the callinfo right away,
852  * or save it only after having acquired some type of lock on the index rel.
853  * ----------------
854  */
855 FmgrInfo *
857  AttrNumber attnum,
858  uint16 procnum)
859 {
860  FmgrInfo *locinfo;
861  int nproc;
862  int procindex;
863 
864  nproc = irel->rd_amroutine->amsupport;
865 
866  Assert(procnum > 0 && procnum <= (uint16) nproc);
867 
868  procindex = (nproc * (attnum - 1)) + (procnum - 1);
869 
870  locinfo = irel->rd_supportinfo;
871 
872  Assert(locinfo != NULL);
873 
874  locinfo += procindex;
875 
876  /* Initialize the lookup info if first time through */
877  if (locinfo->fn_oid == InvalidOid)
878  {
879  RegProcedure *loc = irel->rd_support;
880  RegProcedure procId;
881 
882  Assert(loc != NULL);
883 
884  procId = loc[procindex];
885 
886  /*
887  * Complain if function was not found during IndexSupportInitialize.
888  * This should not happen unless the system tables contain bogus
889  * entries for the index opclass. (If an AM wants to allow a support
890  * function to be optional, it can use index_getprocid.)
891  */
892  if (!RegProcedureIsValid(procId))
893  elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
894  procnum, attnum, RelationGetRelationName(irel));
895 
896  fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt);
897  }
898 
899  return locinfo;
900 }
ParallelIndexScanDesc parallel_scan
Definition: relscan.h:141
ambeginscan_function ambeginscan
Definition: amapi.h:208
IndexScanDesc index_beginscan_bitmap(Relation indexRelation, Snapshot snapshot, int nkeys)
Definition: indexam.c:248
#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:856
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:497
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:371
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition: predicate.c:2498
regproc RegProcedure
Definition: c.h:461
amparallelrescan_function amparallelrescan
Definition: amapi.h:219
Snapshot xs_snapshot
Definition: relscan.h:92
#define InvalidBuffer
Definition: buf.h:25
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:311
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:150
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:91
#define CHECK_REL_PROCEDURE(pname)
Definition: indexam.c:112
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:418
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:482
Relation heapRelation
Definition: relscan.h:90
IndexUniqueCheck
Definition: genam.h:111
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:396
bool heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call)
Definition: heapam.c:2034
bool index_can_return(Relation indexRelation, int attno)
Definition: indexam.c:784
ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:527
unsigned short uint16
Definition: c.h:313
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2113
amgetbitmap_function amgetbitmap
Definition: amapi.h:211
Buffer xs_cbuf
Definition: relscan.h:122
#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:1286
bool xs_temp_snap
Definition: relscan.h:98
#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:103
TransactionId RecentGlobalXmin
Definition: snapmgr.c:166
#define RegProcedureIsValid(p)
Definition: c.h:596
HeapTuple index_fetch_heap(IndexScanDesc scan)
Definition: indexam.c:584
ScanDirection
Definition: sdir.h:22
bool xs_continue_hot
Definition: relscan.h:138
#define RelationGetRelationName(relation)
Definition: rel.h:445
void IndexScanEnd(IndexScanDesc scan)
Definition: genam.c:146
void RelationClose(Relation relation)
Definition: relcache.c:2133
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:132
#define OffsetToPointer(base, offset)
Definition: c.h:591
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:341
#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:714
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
Size EstimateSnapshotSpace(Snapshot snap)
Definition: snapmgr.c:2044
#define MAX_LOCKMODES
Definition: lock.h:85
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2100
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: indexam.c:744
uintptr_t Datum
Definition: postgres.h:365
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:269
#define Assert(condition)
Definition: c.h:688
#define IsMVCCSnapshot(snapshot)
Definition: tqual.h:31
HeapTupleData xs_ctup
Definition: relscan.h:121
size_t Size
Definition: c.h:422
#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:641
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
ammarkpos_function ammarkpos
Definition: amapi.h:213
#define pgstat_count_index_tuples(rel, n)
Definition: pgstat.h:1296
IndexBulkDeleteResult * index_vacuum_cleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: indexam.c:765
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:217
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
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:451
MemoryContext rd_indexcxt
Definition: rel.h:179
bool kill_prior_tuple
Definition: relscan.h:101
#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:94
#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:611
HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:660
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:195
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:222
amrestrpos_function amrestrpos
Definition: amapi.h:214
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:822