LCOV - code coverage report
Current view: top level - src/backend/catalog - indexing.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 94.2 % 69 65
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 65.0 % 20 13

             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                 :     1004179 : CatalogOpenIndexes(Relation heapRel)
      44                 :             : {
      45                 :             :     ResultRelInfo *resultRelInfo;
      46                 :             : 
      47                 :     1004179 :     resultRelInfo = makeNode(ResultRelInfo);
      48                 :     1004179 :     resultRelInfo->ri_RangeTableIndex = 0;   /* dummy */
      49                 :     1004179 :     resultRelInfo->ri_RelationDesc = heapRel;
      50                 :     1004179 :     resultRelInfo->ri_TrigDesc = NULL;   /* we don't fire triggers */
      51                 :             : 
      52                 :     1004179 :     ExecOpenIndices(resultRelInfo, false);
      53                 :             : 
      54                 :     1004179 :     return resultRelInfo;
      55                 :             : }
      56                 :             : 
      57                 :             : /*
      58                 :             :  * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
      59                 :             :  */
      60                 :             : void
      61                 :     1004171 : CatalogCloseIndexes(CatalogIndexState indstate)
      62                 :             : {
      63                 :     1004171 :     ExecCloseIndices(indstate);
      64                 :     1004171 :     pfree(indstate);
      65                 :     1004171 : }
      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                 :     1739959 : 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                 :     1739959 :     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   [ +  +  +  - ]:     1739959 :     if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
      95                 :      221892 :         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                 :     1638850 :     numIndexes = indstate->ri_NumIndices;
     105         [ +  + ]:     1638850 :     if (numIndexes == 0)
     106                 :      120783 :         return;
     107                 :     1518067 :     relationDescs = indstate->ri_IndexRelationDescs;
     108                 :     1518067 :     indexInfoArray = indstate->ri_IndexRelationInfo;
     109                 :     1518067 :     heapRelation = indstate->ri_RelationDesc;
     110                 :             : 
     111                 :             :     /* Need a slot to hold the tuple being examined */
     112                 :     1518067 :     slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
     113                 :             :                                     &TTSOpsHeapTuple);
     114                 :     1518067 :     ExecStoreHeapTuple(heapTuple, slot, false);
     115                 :             : 
     116                 :             :     /*
     117                 :             :      * for each index, form and insert the index tuple
     118                 :             :      */
     119         [ +  + ]:     4760014 :     for (i = 0; i < numIndexes; i++)
     120                 :             :     {
     121                 :             :         IndexInfo  *indexInfo;
     122                 :             :         Relation    index;
     123                 :             : 
     124                 :     3241949 :         indexInfo = indexInfoArray[i];
     125                 :     3241949 :         index = relationDescs[i];
     126                 :             : 
     127                 :             :         /* If the index is marked as read-only, ignore it */
     128         [ -  + ]:     3241949 :         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   [ -  +  -  - ]:     3241949 :         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                 :     3241949 :         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                 :     3241949 :         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                 :     3241949 :                      index->rd_index->indisunique ?
     176                 :             :                      UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
     177                 :             :                      false,
     178                 :             :                      indexInfo);
     179                 :             :     }
     180                 :             : 
     181                 :     1518065 :     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                 :             :         uint8      *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                 :      436410 : CatalogTupleInsert(Relation heapRel, HeapTuple tup)
     234                 :             : {
     235                 :             :     CatalogIndexState indstate;
     236                 :             : 
     237                 :             :     CatalogTupleCheckConstraints(heapRel, tup);
     238                 :             : 
     239                 :      436410 :     indstate = CatalogOpenIndexes(heapRel);
     240                 :             : 
     241                 :      436410 :     simple_heap_insert(heapRel, tup);
     242                 :             : 
     243                 :      436410 :     CatalogIndexInsert(indstate, tup, TU_All);
     244                 :      436409 :     CatalogCloseIndexes(indstate);
     245                 :      436409 : }
     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                 :       34017 : CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
     257                 :             :                            CatalogIndexState indstate)
     258                 :             : {
     259                 :             :     CatalogTupleCheckConstraints(heapRel, tup);
     260                 :             : 
     261                 :       34017 :     simple_heap_insert(heapRel, tup);
     262                 :             : 
     263                 :       34017 :     CatalogIndexInsert(indstate, tup, TU_All);
     264                 :       34017 : }
     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                 :      486463 : CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
     274                 :             :                                  int ntuples, CatalogIndexState indstate)
     275                 :             : {
     276                 :             :     /* Nothing to do */
     277         [ -  + ]:      486463 :     if (ntuples <= 0)
     278                 :           0 :         return;
     279                 :             : 
     280                 :      486463 :     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         [ +  + ]:     1613632 :     for (int i = 0; i < ntuples; i++)
     288                 :             :     {
     289                 :             :         bool        should_free;
     290                 :             :         HeapTuple   tuple;
     291                 :             : 
     292                 :     1127169 :         tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
     293                 :     1127169 :         tuple->t_tableOid = slot[i]->tts_tableOid;
     294                 :     1127169 :         CatalogIndexInsert(indstate, tuple, TU_All);
     295                 :             : 
     296         [ -  + ]:     1127169 :         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                 :      114763 : CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
     314                 :             : {
     315                 :             :     CatalogIndexState indstate;
     316                 :      114763 :     TU_UpdateIndexes updateIndexes = TU_All;
     317                 :             : 
     318                 :             :     CatalogTupleCheckConstraints(heapRel, tup);
     319                 :             : 
     320                 :      114763 :     indstate = CatalogOpenIndexes(heapRel);
     321                 :             : 
     322                 :      114763 :     simple_heap_update(heapRel, otid, tup, &updateIndexes);
     323                 :             : 
     324                 :      114762 :     CatalogIndexInsert(indstate, tup, updateIndexes);
     325                 :      114761 :     CatalogCloseIndexes(indstate);
     326                 :      114761 : }
     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                 :       27601 : CatalogTupleUpdateWithInfo(Relation heapRel, const ItemPointerData *otid, HeapTuple tup,
     338                 :             :                            CatalogIndexState indstate)
     339                 :             : {
     340                 :       27601 :     TU_UpdateIndexes updateIndexes = TU_All;
     341                 :             : 
     342                 :             :     CatalogTupleCheckConstraints(heapRel, tup);
     343                 :             : 
     344                 :       27601 :     simple_heap_update(heapRel, otid, tup, &updateIndexes);
     345                 :             : 
     346                 :       27601 :     CatalogIndexInsert(indstate, tup, updateIndexes);
     347                 :       27601 : }
     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                 :      831270 : CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
     366                 :             : {
     367                 :      831270 :     simple_heap_delete(heapRel, tid);
     368                 :      831270 : }
        

Generated by: LCOV version 2.0-1