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 uint32 flags)
263{
264 IndexScanDesc scan;
265
266 Assert(snapshot != InvalidSnapshot);
267
268 /* Check that a historic snapshot is not used for non-catalog tables */
269 if (IsHistoricMVCCSnapshot(snapshot) &&
271 {
274 errmsg("cannot query non-catalog table \"%s\" during logical decoding",
275 RelationGetRelationName(heapRelation))));
276 }
277
278 scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot, NULL, false);
279
280 /*
281 * Save additional parameters into the scandesc. Everything else was set
282 * up by RelationGetIndexScan.
283 */
284 scan->heapRelation = heapRelation;
285 scan->xs_snapshot = snapshot;
286 scan->instrument = instrument;
287
288 /* prepare to fetch index matches from table */
289 scan->xs_heapfetch = table_index_fetch_begin(heapRelation, flags);
290
291 return scan;
292}
293
294/*
295 * index_beginscan_bitmap - start a scan of an index with amgetbitmap
296 *
297 * As above, caller had better be holding some lock on the parent heap
298 * relation, even though it's not explicitly mentioned here.
299 */
302 Snapshot snapshot,
303 IndexScanInstrumentation *instrument,
304 int nkeys)
305{
306 IndexScanDesc scan;
307
308 Assert(snapshot != InvalidSnapshot);
309
310 scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot, NULL, false);
311
312 /*
313 * Save additional parameters into the scandesc. Everything else was set
314 * up by RelationGetIndexScan.
315 */
316 scan->xs_snapshot = snapshot;
317 scan->instrument = instrument;
318
319 return scan;
320}
321
322/*
323 * index_beginscan_internal --- common code for index_beginscan variants
324 */
325static IndexScanDesc
327 int nkeys, int norderbys, Snapshot snapshot,
329{
330 IndexScanDesc scan;
331
333 CHECK_REL_PROCEDURE(ambeginscan);
334
335 if (!(indexRelation->rd_indam->ampredlocks))
336 PredicateLockRelation(indexRelation, snapshot);
337
338 /*
339 * We hold a reference count to the relcache entry throughout the scan.
340 */
341 RelationIncrementReferenceCount(indexRelation);
342
343 /*
344 * Tell the AM to open a scan.
345 */
346 scan = indexRelation->rd_indam->ambeginscan(indexRelation, nkeys,
347 norderbys);
348 /* Initialize information for parallel scan. */
349 scan->parallel_scan = pscan;
350 scan->xs_temp_snap = temp_snap;
351
352 return scan;
353}
354
355/* ----------------
356 * index_rescan - (re)start a scan of an index
357 *
358 * During a restart, the caller may specify a new set of scankeys and/or
359 * orderbykeys; but the number of keys cannot differ from what index_beginscan
360 * was told. (Later we might relax that to "must not exceed", but currently
361 * the index AMs tend to assume that scan->numberOfKeys is what to believe.)
362 * To restart the scan without changing keys, pass NULL for the key arrays.
363 * (Of course, keys *must* be passed on the first call, unless
364 * scan->numberOfKeys is zero.)
365 * ----------------
366 */
367void
369 ScanKey keys, int nkeys,
370 ScanKey orderbys, int norderbys)
371{
373 CHECK_SCAN_PROCEDURE(amrescan);
374
375 Assert(nkeys == scan->numberOfKeys);
376 Assert(norderbys == scan->numberOfOrderBys);
377
378 /* reset table AM state for rescan */
379 if (scan->xs_heapfetch)
381
382 scan->kill_prior_tuple = false; /* for safety */
383 scan->xs_heap_continue = false;
384
385 scan->indexRelation->rd_indam->amrescan(scan, keys, nkeys,
386 orderbys, norderbys);
387}
388
389/* ----------------
390 * index_endscan - end a scan
391 * ----------------
392 */
393void
395{
397 CHECK_SCAN_PROCEDURE(amendscan);
398
399 /* Release resources (like buffer pins) from table accesses */
400 if (scan->xs_heapfetch)
401 {
403 scan->xs_heapfetch = NULL;
404 }
405
406 /* End the AM's scan */
407 scan->indexRelation->rd_indam->amendscan(scan);
408
409 /* Release index refcount acquired by index_beginscan */
411
412 if (scan->xs_temp_snap)
414
415 /* Release the scan data structure itself */
416 IndexScanEnd(scan);
417}
418
419/* ----------------
420 * index_markpos - mark a scan position
421 * ----------------
422 */
423void
425{
427 CHECK_SCAN_PROCEDURE(ammarkpos);
428
429 scan->indexRelation->rd_indam->ammarkpos(scan);
430}
431
432/* ----------------
433 * index_restrpos - restore a scan position
434 *
435 * NOTE: this only restores the internal scan state of the index AM. See
436 * comments for ExecRestrPos().
437 *
438 * NOTE: For heap, in the presence of HOT chains, mark/restore only works
439 * correctly if the scan's snapshot is MVCC-safe; that ensures that there's at
440 * most one returnable tuple in each HOT chain, and so restoring the prior
441 * state at the granularity of the index AM is sufficient. Since the only
442 * current user of mark/restore functionality is nodeMergejoin.c, this
443 * effectively means that merge-join plans only work for MVCC snapshots. This
444 * could be fixed if necessary, but for now it seems unimportant.
445 * ----------------
446 */
447void
449{
451
453 CHECK_SCAN_PROCEDURE(amrestrpos);
454
455 /* reset table AM state for restoring the marked position */
456 if (scan->xs_heapfetch)
458
459 scan->kill_prior_tuple = false; /* for safety */
460 scan->xs_heap_continue = false;
461
462 scan->indexRelation->rd_indam->amrestrpos(scan);
463}
464
465/*
466 * Estimates the shared memory needed for parallel scan, including any
467 * AM-specific parallel scan state.
468 */
469Size
470index_parallelscan_estimate(Relation indexRelation, int nkeys, int norderbys,
471 Snapshot snapshot)
472{
473 Size nbytes;
474
476
477 nbytes = offsetof(ParallelIndexScanDescData, ps_snapshot_data);
478 nbytes = add_size(nbytes, EstimateSnapshotSpace(snapshot));
479 nbytes = MAXALIGN(nbytes);
480
481 /*
482 * If parallel scan index AM interface can't be used (or index AM provides
483 * no such interface), assume there is no AM-specific data needed
484 */
485 if (indexRelation->rd_indam->amestimateparallelscan != NULL)
486 nbytes = add_size(nbytes,
487 indexRelation->rd_indam->amestimateparallelscan(indexRelation,
488 nkeys,
489 norderbys));
490
491 return nbytes;
492}
493
494/*
495 * index_parallelscan_initialize - initialize parallel scan
496 *
497 * We initialize both the ParallelIndexScanDesc proper and the AM-specific
498 * information which follows it.
499 *
500 * This function calls access method specific initialization routine to
501 * initialize am specific information. Call this just once in the leader
502 * process; then, individual workers attach via index_beginscan_parallel.
503 */
504void
506 Snapshot snapshot,
508{
509 Size offset;
510
512
513 offset = add_size(offsetof(ParallelIndexScanDescData, ps_snapshot_data),
514 EstimateSnapshotSpace(snapshot));
515 offset = MAXALIGN(offset);
516
517 target->ps_locator = heapRelation->rd_locator;
518 target->ps_indexlocator = indexRelation->rd_locator;
519 target->ps_offset_am = 0;
520 SerializeSnapshot(snapshot, target->ps_snapshot_data);
521
522 /* aminitparallelscan is optional; assume no-op if not provided by AM */
523 if (indexRelation->rd_indam->aminitparallelscan != NULL)
524 {
525 void *amtarget;
526
527 target->ps_offset_am = offset;
528 amtarget = OffsetToPointer(target, target->ps_offset_am);
529 indexRelation->rd_indam->aminitparallelscan(amtarget);
530 }
531}
532
533/* ----------------
534 * index_parallelrescan - (re)start a parallel scan of an index
535 * ----------------
536 */
537void
539{
541
542 /* reset table AM state for rescan */
543 if (scan->xs_heapfetch)
545
546 /* amparallelrescan is optional; assume no-op if not provided by AM */
549}
550
551/*
552 * index_beginscan_parallel - join parallel index scan
553 *
554 * flags is a bitmask of ScanOptions affecting the underlying table scan. No
555 * SO_INTERNAL_FLAGS are permitted.
556 *
557 * Caller must be holding suitable locks on the heap and the index.
558 */
561 IndexScanInstrumentation *instrument,
562 int nkeys, int norderbys,
564 uint32 flags)
565{
566 Snapshot snapshot;
567 IndexScanDesc scan;
568
569 Assert(RelFileLocatorEquals(heaprel->rd_locator, pscan->ps_locator));
570 Assert(RelFileLocatorEquals(indexrel->rd_locator, pscan->ps_indexlocator));
571
572 snapshot = RestoreSnapshot(pscan->ps_snapshot_data);
573 RegisterSnapshot(snapshot);
574 scan = index_beginscan_internal(indexrel, nkeys, norderbys, snapshot,
575 pscan, true);
576
577 /*
578 * Save additional parameters into the scandesc. Everything else was set
579 * up by index_beginscan_internal.
580 */
581 scan->heapRelation = heaprel;
582 scan->xs_snapshot = snapshot;
583 scan->instrument = instrument;
584
585 /* prepare to fetch index matches from table */
586 scan->xs_heapfetch = table_index_fetch_begin(heaprel, flags);
587
588 return scan;
589}
590
591/* ----------------
592 * index_getnext_tid - get the next TID from a scan
593 *
594 * The result is the next TID satisfying the scan keys,
595 * or NULL if no more matching tuples exist.
596 * ----------------
597 */
600{
601 bool found;
602
604 CHECK_SCAN_PROCEDURE(amgettuple);
605
606 /* XXX: we should assert that a snapshot is pushed or registered */
608
609 /*
610 * The AM's amgettuple proc finds the next index entry matching the scan
611 * keys, and puts the TID into scan->xs_heaptid. It should also set
612 * scan->xs_recheck and possibly scan->xs_itup/scan->xs_hitup, though we
613 * pay no attention to those fields here.
614 */
615 found = scan->indexRelation->rd_indam->amgettuple(scan, direction);
616
617 /* Reset kill flag immediately for safety */
618 scan->kill_prior_tuple = false;
619 scan->xs_heap_continue = false;
620
621 /* If we're out of index entries, we're done */
622 if (!found)
623 {
624 /* reset table AM state */
625 if (scan->xs_heapfetch)
627
628 return NULL;
629 }
631
633
634 /* Return the TID of the tuple we found. */
635 return &scan->xs_heaptid;
636}
637
638/* ----------------
639 * index_fetch_heap - get the scan's next heap tuple
640 *
641 * The result is a visible heap tuple associated with the index TID most
642 * recently fetched by index_getnext_tid, or NULL if no more matching tuples
643 * exist. (There can be more than one matching tuple because of HOT chains,
644 * although when using an MVCC snapshot it should be impossible for more than
645 * one such tuple to exist.)
646 *
647 * On success, the buffer containing the heap tup is pinned (the pin will be
648 * dropped in a future index_getnext_tid, index_fetch_heap or index_endscan
649 * call).
650 *
651 * Note: caller must check scan->xs_recheck, and perform rechecking of the
652 * scan keys if required. We do not do that here because we don't have
653 * enough information to do it efficiently in the general case.
654 * ----------------
655 */
656bool
658{
659 bool all_dead = false;
660 bool found;
661
662 found = table_index_fetch_tuple(scan->xs_heapfetch, &scan->xs_heaptid,
663 scan->xs_snapshot, slot,
664 &scan->xs_heap_continue, &all_dead);
665
666 if (found)
668
669 /*
670 * If we scanned a whole HOT chain and found only dead tuples, tell index
671 * AM to kill its entry for that TID (this will take effect in the next
672 * amgettuple call, in index_getnext_tid). We do not do this when in
673 * recovery because it may violate MVCC to do so. See comments in
674 * RelationGetIndexScan().
675 */
676 if (!scan->xactStartedInRecovery)
678
679 return found;
680}
681
682/* ----------------
683 * index_getnext_slot - get the next tuple from a scan
684 *
685 * The result is true if a tuple satisfying the scan keys and the snapshot was
686 * found, false otherwise. The tuple is stored in the specified slot.
687 *
688 * On success, resources (like buffer pins) are likely to be held, and will be
689 * dropped by a future index_getnext_tid, index_fetch_heap or index_endscan
690 * call).
691 *
692 * Note: caller must check scan->xs_recheck, and perform rechecking of the
693 * scan keys if required. We do not do that here because we don't have
694 * enough information to do it efficiently in the general case.
695 * ----------------
696 */
697bool
699{
700 for (;;)
701 {
702 if (!scan->xs_heap_continue)
703 {
704 ItemPointer tid;
705
706 /* Time to fetch the next TID from the index */
707 tid = index_getnext_tid(scan, direction);
708
709 /* If we're out of index entries, we're done */
710 if (tid == NULL)
711 break;
712
713 Assert(ItemPointerEquals(tid, &scan->xs_heaptid));
714 }
715
716 /*
717 * Fetch the next (or only) visible heap tuple for this index entry.
718 * If we don't find anything, loop around and grab the next TID from
719 * the index.
720 */
722 if (index_fetch_heap(scan, slot))
723 return true;
724 }
725
726 return false;
727}
728
729/* ----------------
730 * index_getbitmap - get all tuples at once from an index scan
731 *
732 * Adds the TIDs of all heap tuples satisfying the scan keys to a bitmap.
733 * Since there's no interlock between the index scan and the eventual heap
734 * access, this is only safe to use with MVCC-based snapshots: the heap
735 * item slot could have been replaced by a newer tuple by the time we get
736 * to it.
737 *
738 * Returns the number of matching tuples found. (Note: this might be only
739 * approximate, so it should only be used for statistical purposes.)
740 * ----------------
741 */
742int64
744{
745 int64 ntids;
746
748 CHECK_SCAN_PROCEDURE(amgetbitmap);
749
750 /* just make sure this is false... */
751 scan->kill_prior_tuple = false;
752
753 /*
754 * have the am's getbitmap proc do all the work.
755 */
756 ntids = scan->indexRelation->rd_indam->amgetbitmap(scan, bitmap);
757
759
760 return ntids;
761}
762
763/* ----------------
764 * index_bulk_delete - do mass deletion of index entries
765 *
766 * callback routine tells whether a given main-heap tuple is
767 * to be deleted
768 *
769 * return value is an optional palloc'd struct of statistics
770 * ----------------
771 */
776 void *callback_state)
777{
778 Relation indexRelation = info->index;
779
781 CHECK_REL_PROCEDURE(ambulkdelete);
782
783 return indexRelation->rd_indam->ambulkdelete(info, istat,
784 callback, callback_state);
785}
786
787/* ----------------
788 * index_vacuum_cleanup - do post-deletion cleanup of an index
789 *
790 * return value is an optional palloc'd struct of statistics
791 * ----------------
792 */
796{
797 Relation indexRelation = info->index;
798
800 CHECK_REL_PROCEDURE(amvacuumcleanup);
801
802 return indexRelation->rd_indam->amvacuumcleanup(info, istat);
803}
804
805/* ----------------
806 * index_can_return
807 *
808 * Does the index access method support index-only scans for the given
809 * column?
810 * ----------------
811 */
812bool
813index_can_return(Relation indexRelation, int attno)
814{
816
817 /* amcanreturn is optional; assume false if not provided by AM */
818 if (indexRelation->rd_indam->amcanreturn == NULL)
819 return false;
820
821 return indexRelation->rd_indam->amcanreturn(indexRelation, attno);
822}
823
824/* ----------------
825 * index_getprocid
826 *
827 * Index access methods typically require support routines that are
828 * not directly the implementation of any WHERE-clause query operator
829 * and so cannot be kept in pg_amop. Instead, such routines are kept
830 * in pg_amproc. These registered procedure OIDs are assigned numbers
831 * according to a convention established by the access method.
832 * The general index code doesn't know anything about the routines
833 * involved; it just builds an ordered list of them for
834 * each attribute on which an index is defined.
835 *
836 * As of Postgres 8.3, support routines within an operator family
837 * are further subdivided by the "left type" and "right type" of the
838 * query operator(s) that they support. The "default" functions for a
839 * particular indexed attribute are those with both types equal to
840 * the index opclass' opcintype (note that this is subtly different
841 * from the indexed attribute's own type: it may be a binary-compatible
842 * type instead). Only the default functions are stored in relcache
843 * entries --- access methods can use the syscache to look up non-default
844 * functions.
845 *
846 * This routine returns the requested default procedure OID for a
847 * particular indexed attribute.
848 * ----------------
849 */
854{
855 RegProcedure *loc;
856 int nproc;
857 int procindex;
858
859 nproc = irel->rd_indam->amsupport;
860
861 Assert(procnum > 0 && procnum <= (uint16) nproc);
862
863 procindex = (nproc * (attnum - 1)) + (procnum - 1);
864
865 loc = irel->rd_support;
866
867 Assert(loc != NULL);
868
869 return loc[procindex];
870}
871
872/* ----------------
873 * index_getprocinfo
874 *
875 * This routine allows index AMs to keep fmgr lookup info for
876 * support procs in the relcache. As above, only the "default"
877 * functions for any particular indexed attribute are cached.
878 *
879 * Note: the return value points into cached data that will be lost during
880 * any relcache rebuild! Therefore, either use the callinfo right away,
881 * or save it only after having acquired some type of lock on the index rel.
882 * ----------------
883 */
884FmgrInfo *
888{
890 int nproc;
891 int optsproc;
892 int procindex;
893
894 nproc = irel->rd_indam->amsupport;
896
897 Assert(procnum > 0 && procnum <= (uint16) nproc);
898
899 procindex = (nproc * (attnum - 1)) + (procnum - 1);
900
901 locinfo = irel->rd_supportinfo;
902
903 Assert(locinfo != NULL);
904
906
907 /* Initialize the lookup info if first time through */
908 if (locinfo->fn_oid == InvalidOid)
909 {
910 RegProcedure *loc = irel->rd_support;
912
913 Assert(loc != NULL);
914
915 procId = loc[procindex];
916
917 /*
918 * Complain if function was not found during IndexSupportInitialize.
919 * This should not happen unless the system tables contain bogus
920 * entries for the index opclass. (If an AM wants to allow a support
921 * function to be optional, it can use index_getprocid.)
922 */
924 elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
926
928
929 if (procnum != optsproc)
930 {
931 /* Initialize locinfo->fn_expr with opclass options Const */
932 bytea **attoptions = RelationGetIndexAttOptions(irel, false);
934
935 set_fn_opclass_options(locinfo, attoptions[attnum - 1]);
936
938 }
939 }
940
941 return locinfo;
942}
943
944/* ----------------
945 * index_store_float8_orderby_distances
946 *
947 * Convert AM distance function's results (that can be inexact)
948 * to ORDER BY types and save them into xs_orderbyvals/xs_orderbynulls
949 * for a possible recheck.
950 * ----------------
951 */
952void
954 IndexOrderByDistance *distances,
955 bool recheckOrderBy)
956{
957 int i;
958
959 Assert(distances || !recheckOrderBy);
960
962
963 for (i = 0; i < scan->numberOfOrderBys; i++)
964 {
965 if (orderByTypes[i] == FLOAT8OID)
966 {
967 if (distances && !distances[i].isnull)
968 {
969 scan->xs_orderbyvals[i] = Float8GetDatum(distances[i].value);
970 scan->xs_orderbynulls[i] = false;
971 }
972 else
973 {
974 scan->xs_orderbyvals[i] = (Datum) 0;
975 scan->xs_orderbynulls[i] = true;
976 }
977 }
978 else if (orderByTypes[i] == FLOAT4OID)
979 {
980 /* convert distance function's result to ORDER BY type */
981 if (distances && !distances[i].isnull)
982 {
983 scan->xs_orderbyvals[i] = Float4GetDatum((float4) distances[i].value);
984 scan->xs_orderbynulls[i] = false;
985 }
986 else
987 {
988 scan->xs_orderbyvals[i] = (Datum) 0;
989 scan->xs_orderbynulls[i] = true;
990 }
991 }
992 else
993 {
994 /*
995 * If the ordering operator's return value is anything else, we
996 * don't know how to convert the float8 bound calculated by the
997 * distance function to that. The executor won't actually need
998 * the order by values we return here, if there are no lossy
999 * results, so only insist on converting if the *recheck flag is
1000 * set.
1001 */
1002 if (scan->xs_recheckorderby)
1003 elog(ERROR, "ORDER BY operator must return float8 or float4 if the distance function is lossy");
1004 scan->xs_orderbynulls[i] = true;
1005 }
1006 }
1007}
1008
1009/* ----------------
1010 * index_opclass_options
1011 *
1012 * Parse opclass-specific options for index column.
1013 * ----------------
1014 */
1015bytea *
1017 bool validate)
1018{
1019 int amoptsprocnum = indrel->rd_indam->amoptsprocnum;
1020 Oid procid = InvalidOid;
1023
1024 /* fetch options support procedure if specified */
1025 if (amoptsprocnum != 0)
1026 procid = index_getprocid(indrel, attnum, amoptsprocnum);
1027
1028 if (!OidIsValid(procid))
1029 {
1030 Oid opclass;
1033
1034 if (!DatumGetPointer(attoptions))
1035 return NULL; /* ok, no options, no procedure */
1036
1037 /*
1038 * Report an error if the opclass's options-parsing procedure does not
1039 * exist but the opclass options are specified.
1040 */
1044 opclass = indclass->values[attnum - 1];
1045
1046 ereport(ERROR,
1048 errmsg("operator class %s has no options",
1049 generate_opclass_name(opclass))));
1050 }
1051
1053
1054 procinfo = index_getprocinfo(indrel, attnum, amoptsprocnum);
1055
1057
1058 return build_local_reloptions(&relopts, attoptions, validate);
1059}
int16 AttrNumber
Definition attnum.h:21
static bool validate(Port *port, const char *auth, const char **logdetail)
Definition auth-oauth.c:672
#define InvalidBlockNumber
Definition block.h:33
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define OffsetToPointer(base, offset)
Definition c.h:855
#define RegProcedureIsValid(p)
Definition c.h:862
#define MAXALIGN(LEN)
Definition c.h:896
#define Assert(condition)
Definition c.h:943
int64_t int64
Definition c.h:621
regproc RegProcedure
Definition c.h:734
uint16_t uint16
Definition c.h:623
uint32_t uint32
Definition c.h:624
float float4
Definition c.h:713
#define OidIsValid(objectId)
Definition c.h:858
size_t Size
Definition c.h:689
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
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
bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction, TupleTableSlot *slot)
Definition indexam.c:698
#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
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:885
void index_restrpos(IndexScanDesc scan)
Definition indexam.c:448
IndexBulkDeleteResult * index_vacuum_cleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *istat)
Definition indexam.c:794
bytea * index_opclass_options(Relation indrel, AttrNumber attnum, Datum attoptions, bool validate)
Definition indexam.c:1016
static IndexScanDesc index_beginscan_internal(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot, ParallelIndexScanDesc pscan, bool temp_snap)
Definition indexam.c:326
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *istat, IndexBulkDeleteCallback callback, void *callback_state)
Definition indexam.c:773
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, IndexScanInstrumentation *instrument, int nkeys, int norderbys, uint32 flags)
Definition indexam.c:257
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, IndexScanInstrumentation *instrument, int nkeys, int norderbys, ParallelIndexScanDesc pscan, uint32 flags)
Definition indexam.c:560
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:813
ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction)
Definition indexam.c:599
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:851
bool index_fetch_heap(IndexScanDesc scan, TupleTableSlot *slot)
Definition indexam.c:657
void index_markpos(IndexScanDesc scan)
Definition indexam.c:424
Relation try_index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:153
void index_endscan(IndexScanDesc scan)
Definition indexam.c:394
Size index_parallelscan_estimate(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot)
Definition indexam.c:470
#define RELATION_CHECKS
Definition indexam.c:76
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition indexam.c:505
IndexScanDesc index_beginscan_bitmap(Relation indexRelation, Snapshot snapshot, IndexScanInstrumentation *instrument, int nkeys)
Definition indexam.c:301
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
Definition indexam.c:743
void index_parallelrescan(IndexScanDesc scan)
Definition indexam.c:538
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition indexam.c:368
#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:953
static struct @177 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:737
#define pgstat_count_heap_fetch(rel)
Definition pgstat.h:727
static Datum Float4GetDatum(float4 X)
Definition postgres.h:481
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
static Datum Float8GetDatum(float8 X)
Definition postgres.h:515
#define PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
unsigned int Oid
void CheckForSerializableConflictIn(Relation relation, const ItemPointerData *tid, BlockNumber blkno)
Definition predicate.c:4266
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition predicate.c:2506
static int fb(int x)
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition rel.h:695
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:792
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:1048
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:186
struct ParallelIndexScanDescData * parallel_scan
Definition relscan.h:204
bool * xs_orderbynulls
Definition relscan.h:200
IndexFetchTableData * xs_heapfetch
Definition relscan.h:188
bool xactStartedInRecovery
Definition relscan.h:162
bool xs_recheckorderby
Definition relscan.h:201
struct IndexScanInstrumentation * instrument
Definition relscan.h:172
bool kill_prior_tuple
Definition relscan.h:160
Relation indexRelation
Definition relscan.h:150
ItemPointerData xs_heaptid
Definition relscan.h:185
struct SnapshotData * xs_snapshot
Definition relscan.h:151
Relation heapRelation
Definition relscan.h:149
Datum * xs_orderbyvals
Definition relscan.h:199
Relation index
Definition genam.h:54
LockRelId lockRelId
Definition rel.h:46
RelFileLocator ps_indexlocator
Definition relscan.h:211
RelFileLocator ps_locator
Definition relscan.h:210
char ps_snapshot_data[FLEXIBLE_ARRAY_MEMBER]
Definition relscan.h:213
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:815
Definition c.h:776
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
static void table_index_fetch_reset(struct IndexFetchTableData *scan)
Definition tableam.h:1266
static void table_index_fetch_end(struct IndexFetchTableData *scan)
Definition tableam.h:1275
static bool table_index_fetch_tuple(struct IndexFetchTableData *scan, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, bool *call_again, bool *all_dead)
Definition tableam.h:1305
static IndexFetchTableData * table_index_fetch_begin(Relation rel, uint32 flags)
Definition tableam.h:1246
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
#define TransactionIdIsValid(xid)
Definition transam.h:41