LCOV - code coverage report
Current view: top level - src/backend/catalog - indexing.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 96.6 % 119 115
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 63.0 % 46 29

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * indexing.c
       4                 :             :  *        This file contains routines to support indexes defined on system
       5                 :             :  *        catalogs.
       6                 :             :  *
       7                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :             :  *
      10                 :             :  *
      11                 :             :  * IDENTIFICATION
      12                 :             :  *        src/backend/catalog/indexing.c
      13                 :             :  *
      14                 :             :  *-------------------------------------------------------------------------
      15                 :             :  */
      16                 :             : #include "postgres.h"
      17                 :             : 
      18                 :             : #include "access/genam.h"
      19                 :             : #include "access/heapam.h"
      20                 :             : #include "access/htup_details.h"
      21                 :             : #include "access/xact.h"
      22                 :             : #include "catalog/index.h"
      23                 :             : #include "catalog/indexing.h"
      24                 :             : #include "executor/executor.h"
      25                 :             : #include "utils/rel.h"
      26                 :             : 
      27                 :             : 
      28                 :             : /*
      29                 :             :  * CatalogOpenIndexes - open the indexes on a system catalog.
      30                 :             :  *
      31                 :             :  * When inserting or updating tuples in a system catalog, call this
      32                 :             :  * to prepare to update the indexes for the catalog.
      33                 :             :  *
      34                 :             :  * In the current implementation, we share code for opening/closing the
      35                 :             :  * indexes with execUtils.c.  But we do not use ExecInsertIndexTuples,
      36                 :             :  * because we don't want to create an EState.  This implies that we
      37                 :             :  * do not support partial or expressional indexes on system catalogs,
      38                 :             :  * nor can we support generalized exclusion constraints.
      39                 :             :  * This could be fixed with localized changes here if we wanted to pay
      40                 :             :  * the extra overhead of building an EState.
      41                 :             :  */
      42                 :             : CatalogIndexState
      43                 :      114252 : CatalogOpenIndexes(Relation heapRel)
      44                 :             : {
      45                 :      114252 :         ResultRelInfo *resultRelInfo;
      46                 :             : 
      47                 :      114252 :         resultRelInfo = makeNode(ResultRelInfo);
      48                 :      114252 :         resultRelInfo->ri_RangeTableIndex = 0;       /* dummy */
      49                 :      114252 :         resultRelInfo->ri_RelationDesc = heapRel;
      50                 :      114252 :         resultRelInfo->ri_TrigDesc = NULL;   /* we don't fire triggers */
      51                 :             : 
      52                 :      114252 :         ExecOpenIndices(resultRelInfo, false);
      53                 :             : 
      54                 :      228504 :         return resultRelInfo;
      55                 :      114252 : }
      56                 :             : 
      57                 :             : /*
      58                 :             :  * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
      59                 :             :  */
      60                 :             : void
      61                 :      114251 : CatalogCloseIndexes(CatalogIndexState indstate)
      62                 :             : {
      63                 :      114251 :         ExecCloseIndices(indstate);
      64                 :      114251 :         pfree(indstate);
      65                 :      114251 : }
      66                 :             : 
      67                 :             : /*
      68                 :             :  * CatalogIndexInsert - insert index entries for one catalog tuple
      69                 :             :  *
      70                 :             :  * This should be called for each inserted or updated catalog tuple.
      71                 :             :  *
      72                 :             :  * This is effectively a cut-down version of ExecInsertIndexTuples.
      73                 :             :  */
      74                 :             : static void
      75                 :      179445 : CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple,
      76                 :             :                                    TU_UpdateIndexes updateIndexes)
      77                 :             : {
      78                 :      179445 :         int                     i;
      79                 :      179445 :         int                     numIndexes;
      80                 :      179445 :         RelationPtr relationDescs;
      81                 :      179445 :         Relation        heapRelation;
      82                 :      179445 :         TupleTableSlot *slot;
      83                 :      179445 :         IndexInfo **indexInfoArray;
      84                 :      179445 :         Datum           values[INDEX_MAX_KEYS];
      85                 :      179445 :         bool            isnull[INDEX_MAX_KEYS];
      86                 :      179445 :         bool            onlySummarized = (updateIndexes == TU_Summarizing);
      87                 :             : 
      88                 :             :         /*
      89                 :             :          * HOT update does not require index inserts. But with asserts enabled we
      90                 :             :          * want to check that it'd be legal to currently insert into the
      91                 :             :          * table/index.
      92                 :             :          */
      93                 :             : #ifndef USE_ASSERT_CHECKING
      94                 :             :         if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
      95                 :             :                 return;
      96                 :             : #endif
      97                 :             : 
      98                 :             :         /* When only updating summarized indexes, the tuple has to be HOT. */
      99   [ -  +  #  # ]:      179445 :         Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple));
     100                 :             : 
     101                 :             :         /*
     102                 :             :          * Get information from the state structure.  Fall out if nothing to do.
     103                 :             :          */
     104                 :      179445 :         numIndexes = indstate->ri_NumIndices;
     105         [ +  + ]:      179445 :         if (numIndexes == 0)
     106                 :        1972 :                 return;
     107                 :      177473 :         relationDescs = indstate->ri_IndexRelationDescs;
     108                 :      177473 :         indexInfoArray = indstate->ri_IndexRelationInfo;
     109                 :      177473 :         heapRelation = indstate->ri_RelationDesc;
     110                 :             : 
     111                 :             :         /* Need a slot to hold the tuple being examined */
     112                 :      177473 :         slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
     113                 :             :                                                                         &TTSOpsHeapTuple);
     114                 :      177473 :         ExecStoreHeapTuple(heapTuple, slot, false);
     115                 :             : 
     116                 :             :         /*
     117                 :             :          * for each index, form and insert the index tuple
     118                 :             :          */
     119         [ +  + ]:      562983 :         for (i = 0; i < numIndexes; i++)
     120                 :             :         {
     121                 :      385510 :                 IndexInfo  *indexInfo;
     122                 :      385510 :                 Relation        index;
     123                 :             : 
     124                 :      385510 :                 indexInfo = indexInfoArray[i];
     125                 :      385510 :                 index = relationDescs[i];
     126                 :             : 
     127                 :             :                 /* If the index is marked as read-only, ignore it */
     128         [ +  - ]:      385510 :                 if (!indexInfo->ii_ReadyForInserts)
     129                 :           0 :                         continue;
     130                 :             : 
     131                 :             :                 /*
     132                 :             :                  * Expressional and partial indexes on system catalogs are not
     133                 :             :                  * supported, nor exclusion constraints, nor deferred uniqueness
     134                 :             :                  */
     135         [ +  - ]:      385510 :                 Assert(indexInfo->ii_Expressions == NIL);
     136         [ -  + ]:      385510 :                 Assert(indexInfo->ii_Predicate == NIL);
     137         [ -  + ]:      385510 :                 Assert(indexInfo->ii_ExclusionOps == NULL);
     138         [ -  + ]:      385510 :                 Assert(index->rd_index->indimmediate);
     139         [ -  + ]:      385510 :                 Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
     140                 :             : 
     141                 :             :                 /* see earlier check above */
     142                 :             : #ifdef USE_ASSERT_CHECKING
     143   [ +  +  -  + ]:      385510 :                 if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
     144                 :             :                 {
     145         [ -  + ]:       32560 :                         Assert(!ReindexIsProcessingIndex(RelationGetRelid(index)));
     146                 :       32560 :                         continue;
     147                 :             :                 }
     148                 :             : #endif                                                  /* USE_ASSERT_CHECKING */
     149                 :             : 
     150                 :             :                 /*
     151                 :             :                  * Skip insertions into non-summarizing indexes if we only need to
     152                 :             :                  * update summarizing indexes.
     153                 :             :                  */
     154   [ -  +  #  # ]:      352950 :                 if (onlySummarized && !indexInfo->ii_Summarizing)
     155                 :           0 :                         continue;
     156                 :             : 
     157                 :             :                 /*
     158                 :             :                  * FormIndexDatum fills in its values and isnull parameters with the
     159                 :             :                  * appropriate values for the column(s) of the index.
     160                 :             :                  */
     161                 :      705900 :                 FormIndexDatum(indexInfo,
     162                 :      352950 :                                            slot,
     163                 :             :                                            NULL,        /* no expression eval to do */
     164                 :      352950 :                                            values,
     165                 :      352950 :                                            isnull);
     166                 :             : 
     167                 :             :                 /*
     168                 :             :                  * The index AM does the rest.
     169                 :             :                  */
     170                 :      705900 :                 index_insert(index,             /* index relation */
     171                 :      352950 :                                          values,        /* array of index Datums */
     172                 :      352950 :                                          isnull,        /* is-null flags */
     173                 :      352950 :                                          &(heapTuple->t_self),   /* tid of heap tuple */
     174                 :      352950 :                                          heapRelation,
     175                 :      352950 :                                          index->rd_index->indisunique ?
     176                 :             :                                          UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
     177                 :             :                                          false,
     178                 :      352950 :                                          indexInfo);
     179         [ +  + ]:      385510 :         }
     180                 :             : 
     181                 :      177473 :         ExecDropSingleTupleTableSlot(slot);
     182                 :      179445 : }
     183                 :             : 
     184                 :             : /*
     185                 :             :  * Subroutine to verify that catalog constraints are honored.
     186                 :             :  *
     187                 :             :  * Tuples inserted via CatalogTupleInsert/CatalogTupleUpdate are generally
     188                 :             :  * "hand made", so that it's possible that they fail to satisfy constraints
     189                 :             :  * that would be checked if they were being inserted by the executor.  That's
     190                 :             :  * a coding error, so we only bother to check for it in assert-enabled builds.
     191                 :             :  */
     192                 :             : #ifdef USE_ASSERT_CHECKING
     193                 :             : 
     194                 :             : static void
     195                 :       63954 : CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup)
     196                 :             : {
     197                 :             :         /*
     198                 :             :          * Currently, the only constraints implemented for system catalogs are
     199                 :             :          * attnotnull constraints.
     200                 :             :          */
     201         [ +  + ]:       63954 :         if (HeapTupleHasNulls(tup))
     202                 :             :         {
     203                 :       54880 :                 TupleDesc       tupdesc = RelationGetDescr(heapRel);
     204                 :       54880 :                 bits8      *bp = tup->t_data->t_bits;
     205                 :             : 
     206         [ +  + ]:     1656390 :                 for (int attnum = 0; attnum < tupdesc->natts; attnum++)
     207                 :             :                 {
     208                 :     1601510 :                         Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
     209                 :             : 
     210   [ +  +  -  + ]:     1601510 :                         Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
     211                 :     1601510 :                 }
     212                 :       54880 :         }
     213                 :       63954 : }
     214                 :             : 
     215                 :             : #else                                                   /* !USE_ASSERT_CHECKING */
     216                 :             : 
     217                 :             : #define CatalogTupleCheckConstraints(heapRel, tup)  ((void) 0)
     218                 :             : 
     219                 :             : #endif                                                  /* USE_ASSERT_CHECKING */
     220                 :             : 
     221                 :             : /*
     222                 :             :  * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
     223                 :             :  *
     224                 :             :  * Insert the tuple data in "tup" into the specified catalog relation.
     225                 :             :  *
     226                 :             :  * This is a convenience routine for the common case of inserting a single
     227                 :             :  * tuple in a system catalog; it inserts a new heap tuple, keeping indexes
     228                 :             :  * current.  Avoid using it for multiple tuples, since opening the indexes
     229                 :             :  * and building the index info structures is moderately expensive.
     230                 :             :  * (Use CatalogTupleInsertWithInfo in such cases.)
     231                 :             :  */
     232                 :             : void
     233                 :       43425 : CatalogTupleInsert(Relation heapRel, HeapTuple tup)
     234                 :             : {
     235                 :       43425 :         CatalogIndexState indstate;
     236                 :             : 
     237                 :       43425 :         CatalogTupleCheckConstraints(heapRel, tup);
     238                 :             : 
     239                 :       43425 :         indstate = CatalogOpenIndexes(heapRel);
     240                 :             : 
     241                 :       43425 :         simple_heap_insert(heapRel, tup);
     242                 :             : 
     243                 :       43425 :         CatalogIndexInsert(indstate, tup, TU_All);
     244                 :       43425 :         CatalogCloseIndexes(indstate);
     245                 :       43425 : }
     246                 :             : 
     247                 :             : /*
     248                 :             :  * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
     249                 :             :  *
     250                 :             :  * This should be used when it's important to amortize CatalogOpenIndexes/
     251                 :             :  * CatalogCloseIndexes work across multiple insertions.  At some point we
     252                 :             :  * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
     253                 :             :  * so that callers needn't trouble over this ... but we don't do so today.
     254                 :             :  */
     255                 :             : void
     256                 :        3002 : CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
     257                 :             :                                                    CatalogIndexState indstate)
     258                 :             : {
     259                 :        3002 :         CatalogTupleCheckConstraints(heapRel, tup);
     260                 :             : 
     261                 :        3002 :         simple_heap_insert(heapRel, tup);
     262                 :             : 
     263                 :        3002 :         CatalogIndexInsert(indstate, tup, TU_All);
     264                 :        3002 : }
     265                 :             : 
     266                 :             : /*
     267                 :             :  * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
     268                 :             :  *
     269                 :             :  * Insert multiple tuples into the given catalog relation at once, with an
     270                 :             :  * amortized cost of CatalogOpenIndexes.
     271                 :             :  */
     272                 :             : void
     273                 :       60096 : CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
     274                 :             :                                                                  int ntuples, CatalogIndexState indstate)
     275                 :             : {
     276                 :             :         /* Nothing to do */
     277         [ -  + ]:       60096 :         if (ntuples <= 0)
     278                 :           0 :                 return;
     279                 :             : 
     280                 :      120192 :         heap_multi_insert(heapRel, slot, ntuples,
     281                 :       60096 :                                           GetCurrentCommandId(true), 0, NULL);
     282                 :             : 
     283                 :             :         /*
     284                 :             :          * There is no equivalent to heap_multi_insert for the catalog indexes, so
     285                 :             :          * we must loop over and insert individually.
     286                 :             :          */
     287         [ +  + ]:      175587 :         for (int i = 0; i < ntuples; i++)
     288                 :             :         {
     289                 :      115491 :                 bool            should_free;
     290                 :      115491 :                 HeapTuple       tuple;
     291                 :             : 
     292                 :      115491 :                 tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
     293                 :      115491 :                 tuple->t_tableOid = slot[i]->tts_tableOid;
     294                 :      115491 :                 CatalogIndexInsert(indstate, tuple, TU_All);
     295                 :             : 
     296         [ +  - ]:      115491 :                 if (should_free)
     297                 :           0 :                         heap_freetuple(tuple);
     298                 :      115491 :         }
     299                 :       60096 : }
     300                 :             : 
     301                 :             : /*
     302                 :             :  * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
     303                 :             :  *
     304                 :             :  * Update the tuple identified by "otid", replacing it with the data in "tup".
     305                 :             :  *
     306                 :             :  * This is a convenience routine for the common case of updating a single
     307                 :             :  * tuple in a system catalog; it updates one heap tuple, keeping indexes
     308                 :             :  * current.  Avoid using it for multiple tuples, since opening the indexes
     309                 :             :  * and building the index info structures is moderately expensive.
     310                 :             :  * (Use CatalogTupleUpdateWithInfo in such cases.)
     311                 :             :  */
     312                 :             : void
     313                 :       16139 : CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
     314                 :             : {
     315                 :       16139 :         CatalogIndexState indstate;
     316                 :       16139 :         TU_UpdateIndexes updateIndexes = TU_All;
     317                 :             : 
     318                 :       16139 :         CatalogTupleCheckConstraints(heapRel, tup);
     319                 :             : 
     320                 :       16139 :         indstate = CatalogOpenIndexes(heapRel);
     321                 :             : 
     322                 :       16139 :         simple_heap_update(heapRel, otid, tup, &updateIndexes);
     323                 :             : 
     324                 :       16139 :         CatalogIndexInsert(indstate, tup, updateIndexes);
     325                 :       16139 :         CatalogCloseIndexes(indstate);
     326                 :       16139 : }
     327                 :             : 
     328                 :             : /*
     329                 :             :  * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
     330                 :             :  *
     331                 :             :  * This should be used when it's important to amortize CatalogOpenIndexes/
     332                 :             :  * CatalogCloseIndexes work across multiple updates.  At some point we
     333                 :             :  * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
     334                 :             :  * so that callers needn't trouble over this ... but we don't do so today.
     335                 :             :  */
     336                 :             : void
     337                 :        1388 : CatalogTupleUpdateWithInfo(Relation heapRel, const ItemPointerData *otid, HeapTuple tup,
     338                 :             :                                                    CatalogIndexState indstate)
     339                 :             : {
     340                 :        1388 :         TU_UpdateIndexes updateIndexes = TU_All;
     341                 :             : 
     342                 :        1388 :         CatalogTupleCheckConstraints(heapRel, tup);
     343                 :             : 
     344                 :        1388 :         simple_heap_update(heapRel, otid, tup, &updateIndexes);
     345                 :             : 
     346                 :        1388 :         CatalogIndexInsert(indstate, tup, updateIndexes);
     347                 :        1388 : }
     348                 :             : 
     349                 :             : /*
     350                 :             :  * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
     351                 :             :  *
     352                 :             :  * Delete the tuple identified by "tid" in the specified catalog.
     353                 :             :  *
     354                 :             :  * With Postgres heaps, there is no index work to do at deletion time;
     355                 :             :  * cleanup will be done later by VACUUM.  However, callers of this function
     356                 :             :  * shouldn't have to know that; we'd like a uniform abstraction for all
     357                 :             :  * catalog tuple changes.  Hence, provide this currently-trivial wrapper.
     358                 :             :  *
     359                 :             :  * The abstraction is a bit leaky in that we don't provide an optimized
     360                 :             :  * CatalogTupleDeleteWithInfo version, because there is currently nothing to
     361                 :             :  * optimize.  If we ever need that, rather than touching a lot of call sites,
     362                 :             :  * it might be better to do something about caching CatalogIndexState.
     363                 :             :  */
     364                 :             : void
     365                 :      118315 : CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
     366                 :             : {
     367                 :      118315 :         simple_heap_delete(heapRel, tid);
     368                 :      118315 : }
        

Generated by: LCOV version 2.3.2-1