LCOV - code coverage report
Current view: top level - src/backend/catalog - indexing.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 94.2 % 69 65
Test Date: 2026-02-28 02:14:46 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit

            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       791098 : CatalogOpenIndexes(Relation heapRel)
      44              : {
      45              :     ResultRelInfo *resultRelInfo;
      46              : 
      47       791098 :     resultRelInfo = makeNode(ResultRelInfo);
      48       791098 :     resultRelInfo->ri_RangeTableIndex = 0;   /* dummy */
      49       791098 :     resultRelInfo->ri_RelationDesc = heapRel;
      50       791098 :     resultRelInfo->ri_TrigDesc = NULL;   /* we don't fire triggers */
      51              : 
      52       791098 :     ExecOpenIndices(resultRelInfo, false);
      53              : 
      54       791098 :     return resultRelInfo;
      55              : }
      56              : 
      57              : /*
      58              :  * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
      59              :  */
      60              : void
      61       791092 : CatalogCloseIndexes(CatalogIndexState indstate)
      62              : {
      63       791092 :     ExecCloseIndices(indstate);
      64       791092 :     pfree(indstate);
      65       791092 : }
      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      1400164 : CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple,
      76              :                    TU_UpdateIndexes updateIndexes)
      77              : {
      78              :     int         i;
      79              :     int         numIndexes;
      80              :     RelationPtr relationDescs;
      81              :     Relation    heapRelation;
      82              :     TupleTableSlot *slot;
      83              :     IndexInfo **indexInfoArray;
      84              :     Datum       values[INDEX_MAX_KEYS];
      85              :     bool        isnull[INDEX_MAX_KEYS];
      86      1400164 :     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      1400164 :     if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
      95       181896 :         return;
      96              : #endif
      97              : 
      98              :     /* When only updating summarized indexes, the tuple has to be HOT. */
      99              :     Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple));
     100              : 
     101              :     /*
     102              :      * Get information from the state structure.  Fall out if nothing to do.
     103              :      */
     104      1318891 :     numIndexes = indstate->ri_NumIndices;
     105      1318891 :     if (numIndexes == 0)
     106       100623 :         return;
     107      1218268 :     relationDescs = indstate->ri_IndexRelationDescs;
     108      1218268 :     indexInfoArray = indstate->ri_IndexRelationInfo;
     109      1218268 :     heapRelation = indstate->ri_RelationDesc;
     110              : 
     111              :     /* Need a slot to hold the tuple being examined */
     112      1218268 :     slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
     113              :                                     &TTSOpsHeapTuple);
     114      1218268 :     ExecStoreHeapTuple(heapTuple, slot, false);
     115              : 
     116              :     /*
     117              :      * for each index, form and insert the index tuple
     118              :      */
     119      3828623 :     for (i = 0; i < numIndexes; i++)
     120              :     {
     121              :         IndexInfo  *indexInfo;
     122              :         Relation    index;
     123              : 
     124      2610357 :         indexInfo = indexInfoArray[i];
     125      2610357 :         index = relationDescs[i];
     126              : 
     127              :         /* If the index is marked as read-only, ignore it */
     128      2610357 :         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              :         Assert(indexInfo->ii_Expressions == NIL);
     136              :         Assert(indexInfo->ii_Predicate == NIL);
     137              :         Assert(indexInfo->ii_ExclusionOps == NULL);
     138              :         Assert(index->rd_index->indimmediate);
     139              :         Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
     140              : 
     141              :         /* see earlier check above */
     142              : #ifdef USE_ASSERT_CHECKING
     143              :         if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
     144              :         {
     145              :             Assert(!ReindexIsProcessingIndex(RelationGetRelid(index)));
     146              :             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      2610357 :         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      2610357 :         FormIndexDatum(indexInfo,
     162              :                        slot,
     163              :                        NULL,    /* no expression eval to do */
     164              :                        values,
     165              :                        isnull);
     166              : 
     167              :         /*
     168              :          * The index AM does the rest.
     169              :          */
     170      2610357 :         index_insert(index,     /* index relation */
     171              :                      values,    /* array of index Datums */
     172              :                      isnull,    /* is-null flags */
     173              :                      &(heapTuple->t_self),   /* tid of heap tuple */
     174              :                      heapRelation,
     175      2610357 :                      index->rd_index->indisunique ?
     176              :                      UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
     177              :                      false,
     178              :                      indexInfo);
     179              :     }
     180              : 
     181      1218266 :     ExecDropSingleTupleTableSlot(slot);
     182              : }
     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              : CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup)
     196              : {
     197              :     /*
     198              :      * Currently, the only constraints implemented for system catalogs are
     199              :      * attnotnull constraints.
     200              :      */
     201              :     if (HeapTupleHasNulls(tup))
     202              :     {
     203              :         TupleDesc   tupdesc = RelationGetDescr(heapRel);
     204              :         bits8      *bp = tup->t_data->t_bits;
     205              : 
     206              :         for (int attnum = 0; attnum < tupdesc->natts; attnum++)
     207              :         {
     208              :             Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
     209              : 
     210              :             Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
     211              :         }
     212              :     }
     213              : }
     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       349537 : CatalogTupleInsert(Relation heapRel, HeapTuple tup)
     234              : {
     235              :     CatalogIndexState indstate;
     236              : 
     237              :     CatalogTupleCheckConstraints(heapRel, tup);
     238              : 
     239       349537 :     indstate = CatalogOpenIndexes(heapRel);
     240              : 
     241       349537 :     simple_heap_insert(heapRel, tup);
     242              : 
     243       349537 :     CatalogIndexInsert(indstate, tup, TU_All);
     244       349536 :     CatalogCloseIndexes(indstate);
     245       349536 : }
     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        28752 : CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
     257              :                            CatalogIndexState indstate)
     258              : {
     259              :     CatalogTupleCheckConstraints(heapRel, tup);
     260              : 
     261        28752 :     simple_heap_insert(heapRel, tup);
     262              : 
     263        28752 :     CatalogIndexInsert(indstate, tup, TU_All);
     264        28752 : }
     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       373547 : CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
     274              :                                  int ntuples, CatalogIndexState indstate)
     275              : {
     276              :     /* Nothing to do */
     277       373547 :     if (ntuples <= 0)
     278            0 :         return;
     279              : 
     280       373547 :     heap_multi_insert(heapRel, slot, ntuples,
     281              :                       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      1279121 :     for (int i = 0; i < ntuples; i++)
     288              :     {
     289              :         bool        should_free;
     290              :         HeapTuple   tuple;
     291              : 
     292       905574 :         tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
     293       905574 :         tuple->t_tableOid = slot[i]->tts_tableOid;
     294       905574 :         CatalogIndexInsert(indstate, tuple, TU_All);
     295              : 
     296       905574 :         if (should_free)
     297            0 :             heap_freetuple(tuple);
     298              :     }
     299              : }
     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        93073 : CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
     314              : {
     315              :     CatalogIndexState indstate;
     316        93073 :     TU_UpdateIndexes updateIndexes = TU_All;
     317              : 
     318              :     CatalogTupleCheckConstraints(heapRel, tup);
     319              : 
     320        93073 :     indstate = CatalogOpenIndexes(heapRel);
     321              : 
     322        93073 :     simple_heap_update(heapRel, otid, tup, &updateIndexes);
     323              : 
     324        93072 :     CatalogIndexInsert(indstate, tup, updateIndexes);
     325        93071 :     CatalogCloseIndexes(indstate);
     326        93071 : }
     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        23229 : CatalogTupleUpdateWithInfo(Relation heapRel, const ItemPointerData *otid, HeapTuple tup,
     338              :                            CatalogIndexState indstate)
     339              : {
     340        23229 :     TU_UpdateIndexes updateIndexes = TU_All;
     341              : 
     342              :     CatalogTupleCheckConstraints(heapRel, tup);
     343              : 
     344        23229 :     simple_heap_update(heapRel, otid, tup, &updateIndexes);
     345              : 
     346        23229 :     CatalogIndexInsert(indstate, tup, updateIndexes);
     347        23229 : }
     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       658765 : CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
     366              : {
     367       658765 :     simple_heap_delete(heapRel, tid);
     368       658765 : }
        

Generated by: LCOV version 2.0-1