LCOV - code coverage report
Current view: top level - src/backend/catalog - indexing.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 65 69 94.2 %
Date: 2024-04-20 08:11:12 Functions: 9 9 100.0 %
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-2024, 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     1259078 : CatalogOpenIndexes(Relation heapRel)
      44             : {
      45             :     ResultRelInfo *resultRelInfo;
      46             : 
      47     1259078 :     resultRelInfo = makeNode(ResultRelInfo);
      48     1259078 :     resultRelInfo->ri_RangeTableIndex = 0;   /* dummy */
      49     1259078 :     resultRelInfo->ri_RelationDesc = heapRel;
      50     1259078 :     resultRelInfo->ri_TrigDesc = NULL;   /* we don't fire triggers */
      51             : 
      52     1259078 :     ExecOpenIndices(resultRelInfo, false);
      53             : 
      54     1259078 :     return resultRelInfo;
      55             : }
      56             : 
      57             : /*
      58             :  * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
      59             :  */
      60             : void
      61     1259076 : CatalogCloseIndexes(CatalogIndexState indstate)
      62             : {
      63     1259076 :     ExecCloseIndices(indstate);
      64     1259076 :     pfree(indstate);
      65     1259076 : }
      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     2308098 : 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     2308098 :     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     2308098 :     if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
      95      291748 :         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     2174350 :     numIndexes = indstate->ri_NumIndices;
     105     2174350 :     if (numIndexes == 0)
     106      158000 :         return;
     107     2016350 :     relationDescs = indstate->ri_IndexRelationDescs;
     108     2016350 :     indexInfoArray = indstate->ri_IndexRelationInfo;
     109     2016350 :     heapRelation = indstate->ri_RelationDesc;
     110             : 
     111             :     /* Need a slot to hold the tuple being examined */
     112     2016350 :     slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
     113             :                                     &TTSOpsHeapTuple);
     114     2016350 :     ExecStoreHeapTuple(heapTuple, slot, false);
     115             : 
     116             :     /*
     117             :      * for each index, form and insert the index tuple
     118             :      */
     119     6367886 :     for (i = 0; i < numIndexes; i++)
     120             :     {
     121             :         IndexInfo  *indexInfo;
     122             :         Relation    index;
     123             : 
     124     4351538 :         indexInfo = indexInfoArray[i];
     125     4351538 :         index = relationDescs[i];
     126             : 
     127             :         /* If the index is marked as read-only, ignore it */
     128     4351538 :         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     4351538 :         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     4351538 :         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     4351538 :         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     4351538 :                      index->rd_index->indisunique ?
     176             :                      UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
     177             :                      false,
     178             :                      indexInfo);
     179             :     }
     180             : 
     181     2016348 :     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      538828 : CatalogTupleInsert(Relation heapRel, HeapTuple tup)
     234             : {
     235             :     CatalogIndexState indstate;
     236             : 
     237             :     CatalogTupleCheckConstraints(heapRel, tup);
     238             : 
     239      538828 :     indstate = CatalogOpenIndexes(heapRel);
     240             : 
     241      538828 :     simple_heap_insert(heapRel, tup);
     242             : 
     243      538828 :     CatalogIndexInsert(indstate, tup, TU_All);
     244      538826 :     CatalogCloseIndexes(indstate);
     245      538826 : }
     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       45902 : CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
     257             :                            CatalogIndexState indstate)
     258             : {
     259             :     CatalogTupleCheckConstraints(heapRel, tup);
     260             : 
     261       45902 :     simple_heap_insert(heapRel, tup);
     262             : 
     263       45902 :     CatalogIndexInsert(indstate, tup, TU_All);
     264       45902 : }
     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      608636 : CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
     274             :                                  int ntuples, CatalogIndexState indstate)
     275             : {
     276             :     /* Nothing to do */
     277      608636 :     if (ntuples <= 0)
     278           0 :         return;
     279             : 
     280      608636 :     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     2142006 :     for (int i = 0; i < ntuples; i++)
     288             :     {
     289             :         bool        should_free;
     290             :         HeapTuple   tuple;
     291             : 
     292     1533370 :         tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
     293     1533370 :         tuple->t_tableOid = slot[i]->tts_tableOid;
     294     1533370 :         CatalogIndexInsert(indstate, tuple, TU_All);
     295             : 
     296     1533370 :         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      160094 : CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
     314             : {
     315             :     CatalogIndexState indstate;
     316      160094 :     TU_UpdateIndexes updateIndexes = TU_All;
     317             : 
     318             :     CatalogTupleCheckConstraints(heapRel, tup);
     319             : 
     320      160094 :     indstate = CatalogOpenIndexes(heapRel);
     321             : 
     322      160094 :     simple_heap_update(heapRel, otid, tup, &updateIndexes);
     323             : 
     324      160094 :     CatalogIndexInsert(indstate, tup, updateIndexes);
     325      160094 :     CatalogCloseIndexes(indstate);
     326      160094 : }
     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       29904 : CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
     338             :                            CatalogIndexState indstate)
     339             : {
     340       29904 :     TU_UpdateIndexes updateIndexes = TU_All;
     341             : 
     342             :     CatalogTupleCheckConstraints(heapRel, tup);
     343             : 
     344       29904 :     simple_heap_update(heapRel, otid, tup, &updateIndexes);
     345             : 
     346       29904 :     CatalogIndexInsert(indstate, tup, updateIndexes);
     347       29904 : }
     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     1145020 : CatalogTupleDelete(Relation heapRel, ItemPointer tid)
     366             : {
     367     1145020 :     simple_heap_delete(heapRel, tid);
     368     1145020 : }

Generated by: LCOV version 1.14