LCOV - code coverage report
Current view: top level - src/backend/access/index - indexam.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 95.4 % 349 333
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 28 28
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 42.8 % 369 158

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

Generated by: LCOV version 2.3.2-1