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