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-2024, 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_slot - get the next 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  */
43 
44 #include "postgres.h"
45 
46 #include "access/amapi.h"
47 #include "access/relation.h"
48 #include "access/reloptions.h"
49 #include "access/relscan.h"
50 #include "access/tableam.h"
51 #include "catalog/index.h"
52 #include "catalog/pg_type.h"
53 #include "nodes/execnodes.h"
54 #include "pgstat.h"
55 #include "storage/lmgr.h"
56 #include "storage/predicate.h"
57 #include "utils/ruleutils.h"
58 #include "utils/snapmgr.h"
59 #include "utils/syscache.h"
60 
61 
62 /* ----------------------------------------------------------------
63  * macros used in index_ routines
64  *
65  * Note: the ReindexIsProcessingIndex() check in RELATION_CHECKS is there
66  * to check that we don't try to scan or do retail insertions into an index
67  * that is currently being rebuilt or pending rebuild. This helps to catch
68  * things that don't work when reindexing system catalogs, as well as prevent
69  * user errors like index expressions that access their own tables. The check
70  * doesn't prevent the actual rebuild because we don't use RELATION_CHECKS
71  * when calling the index AM's ambuild routine, and there is no reason for
72  * ambuild to call its subsidiary routines through this file.
73  * ----------------------------------------------------------------
74  */
75 #define RELATION_CHECKS \
76 do { \
77  Assert(RelationIsValid(indexRelation)); \
78  Assert(PointerIsValid(indexRelation->rd_indam)); \
79  if (unlikely(ReindexIsProcessingIndex(RelationGetRelid(indexRelation)))) \
80  ereport(ERROR, \
81  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
82  errmsg("cannot access index \"%s\" while it is being reindexed", \
83  RelationGetRelationName(indexRelation)))); \
84 } while(0)
85 
86 #define SCAN_CHECKS \
87 ( \
88  AssertMacro(IndexScanIsValid(scan)), \
89  AssertMacro(RelationIsValid(scan->indexRelation)), \
90  AssertMacro(PointerIsValid(scan->indexRelation->rd_indam)) \
91 )
92 
93 #define CHECK_REL_PROCEDURE(pname) \
94 do { \
95  if (indexRelation->rd_indam->pname == NULL) \
96  elog(ERROR, "function \"%s\" is not defined for index \"%s\"", \
97  CppAsString(pname), RelationGetRelationName(indexRelation)); \
98 } while(0)
99 
100 #define CHECK_SCAN_PROCEDURE(pname) \
101 do { \
102  if (scan->indexRelation->rd_indam->pname == NULL) \
103  elog(ERROR, "function \"%s\" is not defined for index \"%s\"", \
104  CppAsString(pname), RelationGetRelationName(scan->indexRelation)); \
105 } while(0)
106 
107 static IndexScanDesc index_beginscan_internal(Relation indexRelation,
108  int nkeys, int norderbys, Snapshot snapshot,
109  ParallelIndexScanDesc pscan, bool temp_snap);
110 static inline void validate_relation_kind(Relation r);
111 
112 
113 /* ----------------------------------------------------------------
114  * index_ interface functions
115  * ----------------------------------------------------------------
116  */
117 
118 /* ----------------
119  * index_open - open an index relation by relation OID
120  *
121  * If lockmode is not "NoLock", the specified kind of lock is
122  * obtained on the index. (Generally, NoLock should only be
123  * used if the caller knows it has some appropriate lock on the
124  * index already.)
125  *
126  * An error is raised if the index does not exist.
127  *
128  * This is a convenience routine adapted for indexscan use.
129  * Some callers may prefer to use relation_open directly.
130  * ----------------
131  */
132 Relation
133 index_open(Oid relationId, LOCKMODE lockmode)
134 {
135  Relation r;
136 
137  r = relation_open(relationId, lockmode);
138 
140 
141  return r;
142 }
143 
144 /* ----------------
145  * try_index_open - open an index relation by relation OID
146  *
147  * Same as index_open, except return NULL instead of failing
148  * if the relation does not exist.
149  * ----------------
150  */
151 Relation
152 try_index_open(Oid relationId, LOCKMODE lockmode)
153 {
154  Relation r;
155 
156  r = try_relation_open(relationId, lockmode);
157 
158  /* leave if index does not exist */
159  if (!r)
160  return NULL;
161 
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  * validate_relation_kind - check the relation's kind
192  *
193  * Make sure relkind is an index or a partitioned index.
194  * ----------------
195  */
196 static inline void
198 {
199  if (r->rd_rel->relkind != RELKIND_INDEX &&
200  r->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
201  ereport(ERROR,
202  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
203  errmsg("\"%s\" is not an index",
205 }
206 
207 
208 /* ----------------
209  * index_insert - insert an index tuple into a relation
210  * ----------------
211  */
212 bool
213 index_insert(Relation indexRelation,
214  Datum *values,
215  bool *isnull,
216  ItemPointer heap_t_ctid,
217  Relation heapRelation,
218  IndexUniqueCheck checkUnique,
219  bool indexUnchanged,
220  IndexInfo *indexInfo)
221 {
223  CHECK_REL_PROCEDURE(aminsert);
224 
225  if (!(indexRelation->rd_indam->ampredlocks))
226  CheckForSerializableConflictIn(indexRelation,
227  (ItemPointer) NULL,
229 
230  return indexRelation->rd_indam->aminsert(indexRelation, values, isnull,
231  heap_t_ctid, heapRelation,
232  checkUnique, indexUnchanged,
233  indexInfo);
234 }
235 
236 /* -------------------------
237  * index_insert_cleanup - clean up after all index inserts are done
238  * -------------------------
239  */
240 void
242  IndexInfo *indexInfo)
243 {
245 
246  if (indexRelation->rd_indam->aminsertcleanup)
247  indexRelation->rd_indam->aminsertcleanup(indexRelation, indexInfo);
248 }
249 
250 /*
251  * index_beginscan - start a scan of an index with amgettuple
252  *
253  * Caller must be holding suitable locks on the heap and the index.
254  */
257  Relation indexRelation,
258  Snapshot snapshot,
259  int nkeys, int norderbys)
260 {
261  IndexScanDesc scan;
262 
263  Assert(snapshot != InvalidSnapshot);
264 
265  scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot, NULL, false);
266 
267  /*
268  * Save additional parameters into the scandesc. Everything else was set
269  * up by RelationGetIndexScan.
270  */
271  scan->heapRelation = heapRelation;
272  scan->xs_snapshot = snapshot;
273 
274  /* prepare to fetch index matches from table */
275  scan->xs_heapfetch = table_index_fetch_begin(heapRelation);
276 
277  return scan;
278 }
279 
280 /*
281  * index_beginscan_bitmap - start a scan of an index with amgetbitmap
282  *
283  * As above, caller had better be holding some lock on the parent heap
284  * relation, even though it's not explicitly mentioned here.
285  */
288  Snapshot snapshot,
289  int nkeys)
290 {
291  IndexScanDesc scan;
292 
293  Assert(snapshot != InvalidSnapshot);
294 
295  scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot, NULL, false);
296 
297  /*
298  * Save additional parameters into the scandesc. Everything else was set
299  * up by RelationGetIndexScan.
300  */
301  scan->xs_snapshot = snapshot;
302 
303  return scan;
304 }
305 
306 /*
307  * index_beginscan_internal --- common code for index_beginscan variants
308  */
309 static IndexScanDesc
311  int nkeys, int norderbys, Snapshot snapshot,
312  ParallelIndexScanDesc pscan, bool temp_snap)
313 {
314  IndexScanDesc scan;
315 
317  CHECK_REL_PROCEDURE(ambeginscan);
318 
319  if (!(indexRelation->rd_indam->ampredlocks))
320  PredicateLockRelation(indexRelation, snapshot);
321 
322  /*
323  * We hold a reference count to the relcache entry throughout the scan.
324  */
325  RelationIncrementReferenceCount(indexRelation);
326 
327  /*
328  * Tell the AM to open a scan.
329  */
330  scan = indexRelation->rd_indam->ambeginscan(indexRelation, nkeys,
331  norderbys);
332  /* Initialize information for parallel scan. */
333  scan->parallel_scan = pscan;
334  scan->xs_temp_snap = temp_snap;
335 
336  return scan;
337 }
338 
339 /* ----------------
340  * index_rescan - (re)start a scan of an index
341  *
342  * During a restart, the caller may specify a new set of scankeys and/or
343  * orderbykeys; but the number of keys cannot differ from what index_beginscan
344  * was told. (Later we might relax that to "must not exceed", but currently
345  * the index AMs tend to assume that scan->numberOfKeys is what to believe.)
346  * To restart the scan without changing keys, pass NULL for the key arrays.
347  * (Of course, keys *must* be passed on the first call, unless
348  * scan->numberOfKeys is zero.)
349  * ----------------
350  */
351 void
353  ScanKey keys, int nkeys,
354  ScanKey orderbys, int norderbys)
355 {
356  SCAN_CHECKS;
357  CHECK_SCAN_PROCEDURE(amrescan);
358 
359  Assert(nkeys == scan->numberOfKeys);
360  Assert(norderbys == scan->numberOfOrderBys);
361 
362  /* Release resources (like buffer pins) from table accesses */
363  if (scan->xs_heapfetch)
365 
366  scan->kill_prior_tuple = false; /* for safety */
367  scan->xs_heap_continue = false;
368 
369  scan->indexRelation->rd_indam->amrescan(scan, keys, nkeys,
370  orderbys, norderbys);
371 }
372 
373 /* ----------------
374  * index_endscan - end a scan
375  * ----------------
376  */
377 void
379 {
380  SCAN_CHECKS;
381  CHECK_SCAN_PROCEDURE(amendscan);
382 
383  /* Release resources (like buffer pins) from table accesses */
384  if (scan->xs_heapfetch)
385  {
387  scan->xs_heapfetch = NULL;
388  }
389 
390  /* End the AM's scan */
391  scan->indexRelation->rd_indam->amendscan(scan);
392 
393  /* Release index refcount acquired by index_beginscan */
395 
396  if (scan->xs_temp_snap)
398 
399  /* Release the scan data structure itself */
400  IndexScanEnd(scan);
401 }
402 
403 /* ----------------
404  * index_markpos - mark a scan position
405  * ----------------
406  */
407 void
409 {
410  SCAN_CHECKS;
411  CHECK_SCAN_PROCEDURE(ammarkpos);
412 
413  scan->indexRelation->rd_indam->ammarkpos(scan);
414 }
415 
416 /* ----------------
417  * index_restrpos - restore a scan position
418  *
419  * NOTE: this only restores the internal scan state of the index AM. See
420  * comments for ExecRestrPos().
421  *
422  * NOTE: For heap, in the presence of HOT chains, mark/restore only works
423  * correctly if the scan's snapshot is MVCC-safe; that ensures that there's at
424  * most one returnable tuple in each HOT chain, and so restoring the prior
425  * state at the granularity of the index AM is sufficient. Since the only
426  * current user of mark/restore functionality is nodeMergejoin.c, this
427  * effectively means that merge-join plans only work for MVCC snapshots. This
428  * could be fixed if necessary, but for now it seems unimportant.
429  * ----------------
430  */
431 void
433 {
435 
436  SCAN_CHECKS;
437  CHECK_SCAN_PROCEDURE(amrestrpos);
438 
439  /* release resources (like buffer pins) from table accesses */
440  if (scan->xs_heapfetch)
442 
443  scan->kill_prior_tuple = false; /* for safety */
444  scan->xs_heap_continue = false;
445 
446  scan->indexRelation->rd_indam->amrestrpos(scan);
447 }
448 
449 /*
450  * index_parallelscan_estimate - estimate shared memory for parallel scan
451  */
452 Size
453 index_parallelscan_estimate(Relation indexRelation, int nkeys, int norderbys,
454  Snapshot snapshot)
455 {
456  Size nbytes;
457 
458  Assert(snapshot != InvalidSnapshot);
459 
461 
462  nbytes = offsetof(ParallelIndexScanDescData, ps_snapshot_data);
463  nbytes = add_size(nbytes, EstimateSnapshotSpace(snapshot));
464  nbytes = MAXALIGN(nbytes);
465 
466  /*
467  * If amestimateparallelscan is not provided, assume there is no
468  * AM-specific data needed. (It's hard to believe that could work, but
469  * it's easy enough to cater to it here.)
470  */
471  if (indexRelation->rd_indam->amestimateparallelscan != NULL)
472  nbytes = add_size(nbytes,
473  indexRelation->rd_indam->amestimateparallelscan(nkeys,
474  norderbys));
475 
476  return nbytes;
477 }
478 
479 /*
480  * index_parallelscan_initialize - initialize parallel scan
481  *
482  * We initialize both the ParallelIndexScanDesc proper and the AM-specific
483  * information which follows it.
484  *
485  * This function calls access method specific initialization routine to
486  * initialize am specific information. Call this just once in the leader
487  * process; then, individual workers attach via index_beginscan_parallel.
488  */
489 void
490 index_parallelscan_initialize(Relation heapRelation, Relation indexRelation,
491  Snapshot snapshot, ParallelIndexScanDesc target)
492 {
493  Size offset;
494 
495  Assert(snapshot != InvalidSnapshot);
496 
498 
499  offset = add_size(offsetof(ParallelIndexScanDescData, ps_snapshot_data),
500  EstimateSnapshotSpace(snapshot));
501  offset = MAXALIGN(offset);
502 
503  target->ps_relid = RelationGetRelid(heapRelation);
504  target->ps_indexid = RelationGetRelid(indexRelation);
505  target->ps_offset = offset;
506  SerializeSnapshot(snapshot, target->ps_snapshot_data);
507 
508  /* aminitparallelscan is optional; assume no-op if not provided by AM */
509  if (indexRelation->rd_indam->aminitparallelscan != NULL)
510  {
511  void *amtarget;
512 
513  amtarget = OffsetToPointer(target, offset);
514  indexRelation->rd_indam->aminitparallelscan(amtarget);
515  }
516 }
517 
518 /* ----------------
519  * index_parallelrescan - (re)start a parallel scan of an index
520  * ----------------
521  */
522 void
524 {
525  SCAN_CHECKS;
526 
527  if (scan->xs_heapfetch)
529 
530  /* amparallelrescan is optional; assume no-op if not provided by AM */
531  if (scan->indexRelation->rd_indam->amparallelrescan != NULL)
533 }
534 
535 /*
536  * index_beginscan_parallel - join parallel index scan
537  *
538  * Caller must be holding suitable locks on the heap and the index.
539  */
541 index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys,
542  int norderbys, ParallelIndexScanDesc pscan)
543 {
544  Snapshot snapshot;
545  IndexScanDesc scan;
546 
547  Assert(RelationGetRelid(heaprel) == pscan->ps_relid);
548  snapshot = RestoreSnapshot(pscan->ps_snapshot_data);
549  RegisterSnapshot(snapshot);
550  scan = index_beginscan_internal(indexrel, nkeys, norderbys, snapshot,
551  pscan, true);
552 
553  /*
554  * Save additional parameters into the scandesc. Everything else was set
555  * up by index_beginscan_internal.
556  */
557  scan->heapRelation = heaprel;
558  scan->xs_snapshot = snapshot;
559 
560  /* prepare to fetch index matches from table */
561  scan->xs_heapfetch = table_index_fetch_begin(heaprel);
562 
563  return scan;
564 }
565 
566 /* ----------------
567  * index_getnext_tid - get the next TID from a scan
568  *
569  * The result is the next TID satisfying the scan keys,
570  * or NULL if no more matching tuples exist.
571  * ----------------
572  */
575 {
576  bool found;
577 
578  SCAN_CHECKS;
579  CHECK_SCAN_PROCEDURE(amgettuple);
580 
581  /* XXX: we should assert that a snapshot is pushed or registered */
583 
584  /*
585  * The AM's amgettuple proc finds the next index entry matching the scan
586  * keys, and puts the TID into scan->xs_heaptid. It should also set
587  * scan->xs_recheck and possibly scan->xs_itup/scan->xs_hitup, though we
588  * pay no attention to those fields here.
589  */
590  found = scan->indexRelation->rd_indam->amgettuple(scan, direction);
591 
592  /* Reset kill flag immediately for safety */
593  scan->kill_prior_tuple = false;
594  scan->xs_heap_continue = false;
595 
596  /* If we're out of index entries, we're done */
597  if (!found)
598  {
599  /* release resources (like buffer pins) from table accesses */
600  if (scan->xs_heapfetch)
602 
603  return NULL;
604  }
606 
608 
609  /* Return the TID of the tuple we found. */
610  return &scan->xs_heaptid;
611 }
612 
613 /* ----------------
614  * index_fetch_heap - get the scan's next heap tuple
615  *
616  * The result is a visible heap tuple associated with the index TID most
617  * recently fetched by index_getnext_tid, or NULL if no more matching tuples
618  * exist. (There can be more than one matching tuple because of HOT chains,
619  * although when using an MVCC snapshot it should be impossible for more than
620  * one such tuple to exist.)
621  *
622  * On success, the buffer containing the heap tup is pinned (the pin will be
623  * dropped in a future index_getnext_tid, index_fetch_heap or index_endscan
624  * call).
625  *
626  * Note: caller must check scan->xs_recheck, and perform rechecking of the
627  * scan keys if required. We do not do that here because we don't have
628  * enough information to do it efficiently in the general case.
629  * ----------------
630  */
631 bool
633 {
634  bool all_dead = false;
635  bool found;
636 
637  found = table_index_fetch_tuple(scan->xs_heapfetch, &scan->xs_heaptid,
638  scan->xs_snapshot, slot,
639  &scan->xs_heap_continue, &all_dead);
640 
641  if (found)
643 
644  /*
645  * If we scanned a whole HOT chain and found only dead tuples, tell index
646  * AM to kill its entry for that TID (this will take effect in the next
647  * amgettuple call, in index_getnext_tid). We do not do this when in
648  * recovery because it may violate MVCC to do so. See comments in
649  * RelationGetIndexScan().
650  */
651  if (!scan->xactStartedInRecovery)
652  scan->kill_prior_tuple = all_dead;
653 
654  return found;
655 }
656 
657 /* ----------------
658  * index_getnext_slot - get the next tuple from a scan
659  *
660  * The result is true if a tuple satisfying the scan keys and the snapshot was
661  * found, false otherwise. The tuple is stored in the specified slot.
662  *
663  * On success, resources (like buffer pins) are likely to be held, and will be
664  * dropped by a future index_getnext_tid, index_fetch_heap or index_endscan
665  * call).
666  *
667  * Note: caller must check scan->xs_recheck, and perform rechecking of the
668  * scan keys if required. We do not do that here because we don't have
669  * enough information to do it efficiently in the general case.
670  * ----------------
671  */
672 bool
674 {
675  for (;;)
676  {
677  if (!scan->xs_heap_continue)
678  {
679  ItemPointer tid;
680 
681  /* Time to fetch the next TID from the index */
682  tid = index_getnext_tid(scan, direction);
683 
684  /* If we're out of index entries, we're done */
685  if (tid == NULL)
686  break;
687 
688  Assert(ItemPointerEquals(tid, &scan->xs_heaptid));
689  }
690 
691  /*
692  * Fetch the next (or only) visible heap tuple for this index entry.
693  * If we don't find anything, loop around and grab the next TID from
694  * the index.
695  */
697  if (index_fetch_heap(scan, slot))
698  return true;
699  }
700 
701  return false;
702 }
703 
704 /* ----------------
705  * index_getbitmap - get all tuples at once from an index scan
706  *
707  * Adds the TIDs of all heap tuples satisfying the scan keys to a bitmap.
708  * Since there's no interlock between the index scan and the eventual heap
709  * access, this is only safe to use with MVCC-based snapshots: the heap
710  * item slot could have been replaced by a newer tuple by the time we get
711  * to it.
712  *
713  * Returns the number of matching tuples found. (Note: this might be only
714  * approximate, so it should only be used for statistical purposes.)
715  * ----------------
716  */
717 int64
719 {
720  int64 ntids;
721 
722  SCAN_CHECKS;
723  CHECK_SCAN_PROCEDURE(amgetbitmap);
724 
725  /* just make sure this is false... */
726  scan->kill_prior_tuple = false;
727 
728  /*
729  * have the am's getbitmap proc do all the work.
730  */
731  ntids = scan->indexRelation->rd_indam->amgetbitmap(scan, bitmap);
732 
734 
735  return ntids;
736 }
737 
738 /* ----------------
739  * index_bulk_delete - do mass deletion of index entries
740  *
741  * callback routine tells whether a given main-heap tuple is
742  * to be deleted
743  *
744  * return value is an optional palloc'd struct of statistics
745  * ----------------
746  */
749  IndexBulkDeleteResult *istat,
751  void *callback_state)
752 {
753  Relation indexRelation = info->index;
754 
756  CHECK_REL_PROCEDURE(ambulkdelete);
757 
758  return indexRelation->rd_indam->ambulkdelete(info, istat,
759  callback, callback_state);
760 }
761 
762 /* ----------------
763  * index_vacuum_cleanup - do post-deletion cleanup of an index
764  *
765  * return value is an optional palloc'd struct of statistics
766  * ----------------
767  */
770  IndexBulkDeleteResult *istat)
771 {
772  Relation indexRelation = info->index;
773 
775  CHECK_REL_PROCEDURE(amvacuumcleanup);
776 
777  return indexRelation->rd_indam->amvacuumcleanup(info, istat);
778 }
779 
780 /* ----------------
781  * index_can_return
782  *
783  * Does the index access method support index-only scans for the given
784  * column?
785  * ----------------
786  */
787 bool
788 index_can_return(Relation indexRelation, int attno)
789 {
791 
792  /* amcanreturn is optional; assume false if not provided by AM */
793  if (indexRelation->rd_indam->amcanreturn == NULL)
794  return false;
795 
796  return indexRelation->rd_indam->amcanreturn(indexRelation, attno);
797 }
798 
799 /* ----------------
800  * index_getprocid
801  *
802  * Index access methods typically require support routines that are
803  * not directly the implementation of any WHERE-clause query operator
804  * and so cannot be kept in pg_amop. Instead, such routines are kept
805  * in pg_amproc. These registered procedure OIDs are assigned numbers
806  * according to a convention established by the access method.
807  * The general index code doesn't know anything about the routines
808  * involved; it just builds an ordered list of them for
809  * each attribute on which an index is defined.
810  *
811  * As of Postgres 8.3, support routines within an operator family
812  * are further subdivided by the "left type" and "right type" of the
813  * query operator(s) that they support. The "default" functions for a
814  * particular indexed attribute are those with both types equal to
815  * the index opclass' opcintype (note that this is subtly different
816  * from the indexed attribute's own type: it may be a binary-compatible
817  * type instead). Only the default functions are stored in relcache
818  * entries --- access methods can use the syscache to look up non-default
819  * functions.
820  *
821  * This routine returns the requested default procedure OID for a
822  * particular indexed attribute.
823  * ----------------
824  */
828  uint16 procnum)
829 {
830  RegProcedure *loc;
831  int nproc;
832  int procindex;
833 
834  nproc = irel->rd_indam->amsupport;
835 
836  Assert(procnum > 0 && procnum <= (uint16) nproc);
837 
838  procindex = (nproc * (attnum - 1)) + (procnum - 1);
839 
840  loc = irel->rd_support;
841 
842  Assert(loc != NULL);
843 
844  return loc[procindex];
845 }
846 
847 /* ----------------
848  * index_getprocinfo
849  *
850  * This routine allows index AMs to keep fmgr lookup info for
851  * support procs in the relcache. As above, only the "default"
852  * functions for any particular indexed attribute are cached.
853  *
854  * Note: the return value points into cached data that will be lost during
855  * any relcache rebuild! Therefore, either use the callinfo right away,
856  * or save it only after having acquired some type of lock on the index rel.
857  * ----------------
858  */
859 FmgrInfo *
862  uint16 procnum)
863 {
864  FmgrInfo *locinfo;
865  int nproc;
866  int optsproc;
867  int procindex;
868 
869  nproc = irel->rd_indam->amsupport;
870  optsproc = irel->rd_indam->amoptsprocnum;
871 
872  Assert(procnum > 0 && procnum <= (uint16) nproc);
873 
874  procindex = (nproc * (attnum - 1)) + (procnum - 1);
875 
876  locinfo = irel->rd_supportinfo;
877 
878  Assert(locinfo != NULL);
879 
880  locinfo += procindex;
881 
882  /* Initialize the lookup info if first time through */
883  if (locinfo->fn_oid == InvalidOid)
884  {
885  RegProcedure *loc = irel->rd_support;
886  RegProcedure procId;
887 
888  Assert(loc != NULL);
889 
890  procId = loc[procindex];
891 
892  /*
893  * Complain if function was not found during IndexSupportInitialize.
894  * This should not happen unless the system tables contain bogus
895  * entries for the index opclass. (If an AM wants to allow a support
896  * function to be optional, it can use index_getprocid.)
897  */
898  if (!RegProcedureIsValid(procId))
899  elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
900  procnum, attnum, RelationGetRelationName(irel));
901 
902  fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt);
903 
904  if (procnum != optsproc)
905  {
906  /* Initialize locinfo->fn_expr with opclass options Const */
907  bytea **attoptions = RelationGetIndexAttOptions(irel, false);
909 
910  set_fn_opclass_options(locinfo, attoptions[attnum - 1]);
911 
912  MemoryContextSwitchTo(oldcxt);
913  }
914  }
915 
916  return locinfo;
917 }
918 
919 /* ----------------
920  * index_store_float8_orderby_distances
921  *
922  * Convert AM distance function's results (that can be inexact)
923  * to ORDER BY types and save them into xs_orderbyvals/xs_orderbynulls
924  * for a possible recheck.
925  * ----------------
926  */
927 void
929  IndexOrderByDistance *distances,
930  bool recheckOrderBy)
931 {
932  int i;
933 
934  Assert(distances || !recheckOrderBy);
935 
936  scan->xs_recheckorderby = recheckOrderBy;
937 
938  for (i = 0; i < scan->numberOfOrderBys; i++)
939  {
940  if (orderByTypes[i] == FLOAT8OID)
941  {
942 #ifndef USE_FLOAT8_BYVAL
943  /* must free any old value to avoid memory leakage */
944  if (!scan->xs_orderbynulls[i])
946 #endif
947  if (distances && !distances[i].isnull)
948  {
949  scan->xs_orderbyvals[i] = Float8GetDatum(distances[i].value);
950  scan->xs_orderbynulls[i] = false;
951  }
952  else
953  {
954  scan->xs_orderbyvals[i] = (Datum) 0;
955  scan->xs_orderbynulls[i] = true;
956  }
957  }
958  else if (orderByTypes[i] == FLOAT4OID)
959  {
960  /* convert distance function's result to ORDER BY type */
961  if (distances && !distances[i].isnull)
962  {
963  scan->xs_orderbyvals[i] = Float4GetDatum((float4) distances[i].value);
964  scan->xs_orderbynulls[i] = false;
965  }
966  else
967  {
968  scan->xs_orderbyvals[i] = (Datum) 0;
969  scan->xs_orderbynulls[i] = true;
970  }
971  }
972  else
973  {
974  /*
975  * If the ordering operator's return value is anything else, we
976  * don't know how to convert the float8 bound calculated by the
977  * distance function to that. The executor won't actually need
978  * the order by values we return here, if there are no lossy
979  * results, so only insist on converting if the *recheck flag is
980  * set.
981  */
982  if (scan->xs_recheckorderby)
983  elog(ERROR, "ORDER BY operator must return float8 or float4 if the distance function is lossy");
984  scan->xs_orderbynulls[i] = true;
985  }
986  }
987 }
988 
989 /* ----------------
990  * index_opclass_options
991  *
992  * Parse opclass-specific options for index column.
993  * ----------------
994  */
995 bytea *
997  bool validate)
998 {
999  int amoptsprocnum = indrel->rd_indam->amoptsprocnum;
1000  Oid procid = InvalidOid;
1001  FmgrInfo *procinfo;
1002  local_relopts relopts;
1003 
1004  /* fetch options support procedure if specified */
1005  if (amoptsprocnum != 0)
1006  procid = index_getprocid(indrel, attnum, amoptsprocnum);
1007 
1008  if (!OidIsValid(procid))
1009  {
1010  Oid opclass;
1011  Datum indclassDatum;
1012  oidvector *indclass;
1013 
1014  if (!DatumGetPointer(attoptions))
1015  return NULL; /* ok, no options, no procedure */
1016 
1017  /*
1018  * Report an error if the opclass's options-parsing procedure does not
1019  * exist but the opclass options are specified.
1020  */
1021  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indrel->rd_indextuple,
1022  Anum_pg_index_indclass);
1023  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1024  opclass = indclass->values[attnum - 1];
1025 
1026  ereport(ERROR,
1027  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1028  errmsg("operator class %s has no options",
1029  generate_opclass_name(opclass))));
1030  }
1031 
1032  init_local_reloptions(&relopts, 0);
1033 
1034  procinfo = index_getprocinfo(indrel, attnum, amoptsprocnum);
1035 
1036  (void) FunctionCall1(procinfo, PointerGetDatum(&relopts));
1037 
1038  return build_local_reloptions(&relopts, attoptions, validate);
1039 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidBlockNumber
Definition: block.h:33
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define OffsetToPointer(base, offset)
Definition: c.h:772
unsigned short uint16
Definition: c.h:505
#define RegProcedureIsValid(p)
Definition: c.h:777
#define MAXALIGN(LEN)
Definition: c.h:811
#define Assert(condition)
Definition: c.h:858
regproc RegProcedure
Definition: c.h:650
float float4
Definition: c.h:629
#define OidIsValid(objectId)
Definition: c.h:775
size_t Size
Definition: c.h:605
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
void set_fn_opclass_options(FmgrInfo *flinfo, bytea *options)
Definition: fmgr.c:2070
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1816
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:660
void IndexScanEnd(IndexScanDesc scan)
Definition: genam.c:142
bool(* IndexBulkDeleteCallback)(ItemPointer itemptr, void *state)
Definition: genam.h:87
IndexUniqueCheck
Definition: genam.h:116
bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction, TupleTableSlot *slot)
Definition: indexam.c:673
IndexBulkDeleteResult * index_vacuum_cleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *istat)
Definition: indexam.c:769
#define CHECK_REL_PROCEDURE(pname)
Definition: indexam.c:93
static void validate_relation_kind(Relation r)
Definition: indexam.c:197
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: indexam.c:213
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:432
static IndexScanDesc index_beginscan_internal(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot, ParallelIndexScanDesc pscan, bool temp_snap)
Definition: indexam.c:310
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:541
IndexScanDesc index_beginscan_bitmap(Relation indexRelation, Snapshot snapshot, int nkeys)
Definition: indexam.c:287
void index_insert_cleanup(Relation indexRelation, IndexInfo *indexInfo)
Definition: indexam.c:241
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
bool index_can_return(Relation indexRelation, int attno)
Definition: indexam.c:788
ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:574
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:860
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:256
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:826
bool index_fetch_heap(IndexScanDesc scan, TupleTableSlot *slot)
Definition: indexam.c:632
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:408
Relation try_index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:152
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:378
Size index_parallelscan_estimate(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot)
Definition: indexam.c:453
#define RELATION_CHECKS
Definition: indexam.c:75
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *istat, IndexBulkDeleteCallback callback, void *callback_state)
Definition: indexam.c:748
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:490
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition: indexam.c:996
int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
Definition: indexam.c:718
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:523
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:352
#define CHECK_SCAN_PROCEDURE(pname)
Definition: indexam.c:100
#define SCAN_CHECKS
Definition: indexam.c:86
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:928
static struct @155 value
int i
Definition: isn.c:73
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:35
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:212
#define MAX_LOCKMODES
Definition: lock.h:82
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
void pfree(void *pointer)
Definition: mcxt.c:1520
int16 attnum
Definition: pg_attribute.h:74
#define pgstat_count_index_tuples(rel, n)
Definition: pgstat.h:630
#define pgstat_count_heap_fetch(rel)
Definition: pgstat.h:620
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Datum Float4GetDatum(float4 X)
Definition: postgres.h:475
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4321
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition: predicate.c:2561
MemoryContextSwitchTo(old_ctx)
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetRelationName(relation)
Definition: rel.h:539
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2173
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2160
bytea ** RelationGetIndexAttOptions(Relation relation, bool copy)
Definition: relcache.c:5884
void RelationClose(Relation relation)
Definition: relcache.c:2193
void init_local_reloptions(local_relopts *relopts, Size relopt_struct_size)
Definition: reloptions.c:734
void * build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
Definition: reloptions.c:1945
char * generate_opclass_name(Oid opclass)
Definition: ruleutils.c:12493
ScanDirection
Definition: sdir.h:25
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
TransactionId RecentXmin
Definition: snapmgr.c:99
void SerializeSnapshot(Snapshot snapshot, char *start_address)
Definition: snapmgr.c:1716
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
Snapshot RestoreSnapshot(char *start_address)
Definition: snapmgr.c:1775
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
Size EstimateSnapshotSpace(Snapshot snapshot)
Definition: snapmgr.c:1692
#define IsMVCCSnapshot(snapshot)
Definition: snapmgr.h:62
#define InvalidSnapshot
Definition: snapshot.h:123
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:88
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
Definition: fmgr.h:57
Oid fn_oid
Definition: fmgr.h:59
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:272
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:289
amrestrpos_function amrestrpos
Definition: amapi.h:286
aminsert_function aminsert
Definition: amapi.h:269
amendscan_function amendscan
Definition: amapi.h:284
uint16 amoptsprocnum
Definition: amapi.h:222
amparallelrescan_function amparallelrescan
Definition: amapi.h:291
bool ampredlocks
Definition: amapi.h:244
uint16 amsupport
Definition: amapi.h:220
amgettuple_function amgettuple
Definition: amapi.h:282
amcanreturn_function amcanreturn
Definition: amapi.h:273
amgetbitmap_function amgetbitmap
Definition: amapi.h:283
ambulkdelete_function ambulkdelete
Definition: amapi.h:271
ammarkpos_function ammarkpos
Definition: amapi.h:285
ambeginscan_function ambeginscan
Definition: amapi.h:280
amrescan_function amrescan
Definition: amapi.h:281
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:290
aminsertcleanup_function aminsertcleanup
Definition: amapi.h:270
bool xs_heap_continue
Definition: relscan.h:148
struct ParallelIndexScanDescData * parallel_scan
Definition: relscan.h:166
bool * xs_orderbynulls
Definition: relscan.h:162
IndexFetchTableData * xs_heapfetch
Definition: relscan.h:150
int numberOfOrderBys
Definition: relscan.h:121
bool xactStartedInRecovery
Definition: relscan.h:130
bool xs_recheckorderby
Definition: relscan.h:163
bool kill_prior_tuple
Definition: relscan.h:128
Relation indexRelation
Definition: relscan.h:118
ItemPointerData xs_heaptid
Definition: relscan.h:147
struct SnapshotData * xs_snapshot
Definition: relscan.h:119
Relation heapRelation
Definition: relscan.h:117
Datum * xs_orderbyvals
Definition: relscan.h:161
Relation index
Definition: genam.h:46
LockRelId lockRelId
Definition: rel.h:46
Definition: rel.h:39
char ps_snapshot_data[FLEXIBLE_ARRAY_MEMBER]
Definition: relscan.h:175
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
LockInfoData rd_lockInfo
Definition: rel.h:114
RegProcedure * rd_support
Definition: rel.h:209
struct HeapTupleData * rd_indextuple
Definition: rel.h:194
MemoryContext rd_indexcxt
Definition: rel.h:204
struct FmgrInfo * rd_supportinfo
Definition: rel.h:210
Form_pg_class rd_rel
Definition: rel.h:111
Definition: c.h:726
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:733
Definition: c.h:687
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510
static IndexFetchTableData * table_index_fetch_begin(Relation rel)
Definition: tableam.h:1202
static void table_index_fetch_reset(struct IndexFetchTableData *scan)
Definition: tableam.h:1212
static void table_index_fetch_end(struct IndexFetchTableData *scan)
Definition: tableam.h:1221
static bool table_index_fetch_tuple(struct IndexFetchTableData *scan, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, bool *call_again, bool *all_dead)
Definition: tableam.h:1251
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46
#define TransactionIdIsValid(xid)
Definition: transam.h:41