LCOV - code coverage report
Current view: top level - src/backend/access/index - indexam.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 199 203 98.0 %
Date: 2021-09-17 16:07:28 Functions: 25 25 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13