LCOV - differential code coverage report
Current view: top level - src/backend/catalog - indexing.c (source / functions) Coverage Total Hit UNC LBC UIC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 95.5 % 88 84 1 1 2 46 14 24 4 57 2
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 10 10 7 1 2 7 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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 CBC     2201807 : CatalogOpenIndexes(Relation heapRel)
      44                 : {
      45                 :     ResultRelInfo *resultRelInfo;
      46                 : 
      47         2201807 :     resultRelInfo = makeNode(ResultRelInfo);
      48         2201807 :     resultRelInfo->ri_RangeTableIndex = 0;   /* dummy */
      49         2201807 :     resultRelInfo->ri_RelationDesc = heapRel;
      50         2201807 :     resultRelInfo->ri_TrigDesc = NULL;   /* we don't fire triggers */
      51                 : 
      52         2201807 :     ExecOpenIndices(resultRelInfo, false);
      53                 : 
      54         2201807 :     return resultRelInfo;
      55                 : }
      56                 : 
      57                 : /*
      58                 :  * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
      59                 :  */
      60                 : void
      61         2201806 : CatalogCloseIndexes(CatalogIndexState indstate)
      62                 : {
      63         2201806 :     ExecCloseIndices(indstate);
      64         2201806 :     pfree(indstate);
      65         2201806 : }
      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 GNC     3684548 : 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         3684548 :     bool        onlySummarized = (updateIndexes == TU_Summarizing);
      87                 : 
      88 ECB             :     /*
      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 GNC     3684548 :     Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple));
     100                 : 
     101                 :     /*
     102                 :      * Get information from the state structure.  Fall out if nothing to do.
     103                 :      */
     104 CBC     3684548 :     numIndexes = indstate->ri_NumIndices;
     105 GIC     3684548 :     if (numIndexes == 0)
     106          601765 :         return;
     107         3082783 :     relationDescs = indstate->ri_IndexRelationDescs;
     108         3082783 :     indexInfoArray = indstate->ri_IndexRelationInfo;
     109 CBC     3082783 :     heapRelation = indstate->ri_RelationDesc;
     110 ECB             : 
     111                 :     /* Need a slot to hold the tuple being examined */
     112 CBC     3082783 :     slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
     113 ECB             :                                     &TTSOpsHeapTuple);
     114 CBC     3082783 :     ExecStoreHeapTuple(heapTuple, slot, false);
     115                 : 
     116                 :     /*
     117 ECB             :      * for each index, form and insert the index tuple
     118                 :      */
     119 CBC     9135002 :     for (i = 0; i < numIndexes; i++)
     120                 :     {
     121                 :         IndexInfo  *indexInfo;
     122                 :         Relation    index;
     123                 : 
     124         6052220 :         indexInfo = indexInfoArray[i];
     125 GIC     6052220 :         index = relationDescs[i];
     126                 : 
     127                 :         /* If the index is marked as read-only, ignore it */
     128         6052220 :         if (!indexInfo->ii_ReadyForInserts)
     129 LBC           0 :             continue;
     130 ECB             : 
     131                 :         /*
     132                 :          * Expressional and partial indexes on system catalogs are not
     133                 :          * supported, nor exclusion constraints, nor deferred uniqueness
     134 EUB             :          */
     135 GIC     6052220 :         Assert(indexInfo->ii_Expressions == NIL);
     136         6052220 :         Assert(indexInfo->ii_Predicate == NIL);
     137         6052220 :         Assert(indexInfo->ii_ExclusionOps == NULL);
     138         6052220 :         Assert(index->rd_index->indimmediate);
     139         6052220 :         Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
     140 ECB             : 
     141                 :         /* see earlier check above */
     142                 : #ifdef USE_ASSERT_CHECKING
     143 GNC     6052220 :         if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
     144 ECB             :         {
     145 GIC      372809 :             Assert(!ReindexIsProcessingIndex(RelationGetRelid(index)));
     146          372809 :             continue;
     147                 :         }
     148 ECB             : #endif                          /* USE_ASSERT_CHECKING */
     149                 : 
     150                 :         /*
     151                 :          * Skip insertions into non-summarizing indexes if we only need
     152                 :          * to update summarizing indexes.
     153                 :          */
     154 GNC     5679411 :         if (onlySummarized && !indexInfo->ii_Summarizing)
     155 UNC           0 :             continue;
     156                 : 
     157 ECB             :         /*
     158                 :          * FormIndexDatum fills in its values and isnull parameters with the
     159                 :          * appropriate values for the column(s) of the index.
     160                 :          */
     161 GIC     5679411 :         FormIndexDatum(indexInfo,
     162                 :                        slot,
     163                 :                        NULL,    /* no expression eval to do */
     164                 :                        values,
     165                 :                        isnull);
     166 ECB             : 
     167 EUB             :         /*
     168                 :          * The index AM does the rest.
     169                 :          */
     170 GIC     5679411 :         index_insert(index,     /* index relation */
     171                 :                      values,    /* array of index Datums */
     172                 :                      isnull,    /* is-null flags */
     173 ECB             :                      &(heapTuple->t_self),   /* tid of heap tuple */
     174                 :                      heapRelation,
     175 GIC     5679411 :                      index->rd_index->indisunique ?
     176                 :                      UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
     177                 :                      false,
     178                 :                      indexInfo);
     179                 :     }
     180                 : 
     181         3082782 :     ExecDropSingleTupleTableSlot(slot);
     182 ECB             : }
     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 GIC     1576638 : CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup)
     196                 : {
     197                 :     /*
     198                 :      * Currently, the only constraints implemented for system catalogs are
     199                 :      * attnotnull constraints.
     200                 :      */
     201         1576638 :     if (HeapTupleHasNulls(tup))
     202                 :     {
     203         1227024 :         TupleDesc   tupdesc = RelationGetDescr(heapRel);
     204         1227024 :         bits8      *bp = tup->t_data->t_bits;
     205                 : 
     206        30099598 :         for (int attnum = 0; attnum < tupdesc->natts; attnum++)
     207 ECB             :         {
     208 GIC    28872574 :             Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
     209                 : 
     210        28872574 :             Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
     211                 :         }
     212                 :     }
     213 CBC     1576638 : }
     214                 : 
     215 ECB             : #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 GIC     1244023 : CatalogTupleInsert(Relation heapRel, HeapTuple tup)
     234                 : {
     235                 :     CatalogIndexState indstate;
     236                 : 
     237         1244023 :     CatalogTupleCheckConstraints(heapRel, tup);
     238                 : 
     239         1244023 :     indstate = CatalogOpenIndexes(heapRel);
     240                 : 
     241         1244023 :     simple_heap_insert(heapRel, tup);
     242                 : 
     243 GNC     1244023 :     CatalogIndexInsert(indstate, tup, TU_All);
     244 GIC     1244022 :     CatalogCloseIndexes(indstate);
     245 CBC     1244022 : }
     246                 : 
     247                 : /*
     248                 :  * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
     249 ECB             :  *
     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 CBC      131381 : CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
     257 ECB             :                            CatalogIndexState indstate)
     258                 : {
     259 GIC      131381 :     CatalogTupleCheckConstraints(heapRel, tup);
     260                 : 
     261          131381 :     simple_heap_insert(heapRel, tup);
     262                 : 
     263 GNC      131381 :     CatalogIndexInsert(indstate, tup, TU_All);
     264 GIC      131381 : }
     265                 : 
     266                 : /*
     267                 :  * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
     268 ECB             :  *
     269                 :  * Insert multiple tuples into the given catalog relation at once, with an
     270                 :  * amortized cost of CatalogOpenIndexes.
     271                 :  */
     272                 : void
     273 CBC      808773 : CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
     274                 :                                  int ntuples, CatalogIndexState indstate)
     275 ECB             : {
     276                 :     /* Nothing to do */
     277 GIC      808773 :     if (ntuples <= 0)
     278 UIC           0 :         return;
     279                 : 
     280 GIC      808773 :     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 ECB             :      * we must loop over and insert individually.
     286                 :      */
     287 GIC     2916683 :     for (int i = 0; i < ntuples; i++)
     288                 :     {
     289 ECB             :         bool        should_free;
     290 EUB             :         HeapTuple   tuple;
     291                 : 
     292 CBC     2107910 :         tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
     293 GIC     2107910 :         tuple->t_tableOid = slot[i]->tts_tableOid;
     294 GNC     2107910 :         CatalogIndexInsert(indstate, tuple, TU_All);
     295                 : 
     296 GIC     2107910 :         if (should_free)
     297 UIC           0 :             heap_freetuple(tuple);
     298                 :     }
     299 ECB             : }
     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 EUB             :  * and building the index info structures is moderately expensive.
     310                 :  * (Use CatalogTupleUpdateWithInfo in such cases.)
     311                 :  */
     312                 : void
     313 GIC      187858 : CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
     314                 : {
     315                 :     CatalogIndexState indstate;
     316 GNC      187858 :     TU_UpdateIndexes updateIndexes = TU_All;
     317                 : 
     318 GIC      187858 :     CatalogTupleCheckConstraints(heapRel, tup);
     319                 : 
     320          187858 :     indstate = CatalogOpenIndexes(heapRel);
     321                 : 
     322 GNC      187858 :     simple_heap_update(heapRel, otid, tup, &updateIndexes);
     323                 : 
     324          187858 :     CatalogIndexInsert(indstate, tup, updateIndexes);
     325 GIC      187858 :     CatalogCloseIndexes(indstate);
     326 CBC      187858 : }
     327                 : 
     328                 : /*
     329 ECB             :  * 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 CBC       13376 : CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
     338 ECB             :                            CatalogIndexState indstate)
     339                 : {
     340 GNC       13376 :     TU_UpdateIndexes updateIndexes = TU_All;
     341                 : 
     342 GIC       13376 :     CatalogTupleCheckConstraints(heapRel, tup);
     343                 : 
     344 GNC       13376 :     simple_heap_update(heapRel, otid, tup, &updateIndexes);
     345                 : 
     346           13376 :     CatalogIndexInsert(indstate, tup, updateIndexes);
     347 GIC       13376 : }
     348                 : 
     349                 : /*
     350                 :  * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
     351                 :  *
     352 ECB             :  * 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 GIC      534713 : CatalogTupleDelete(Relation heapRel, ItemPointer tid)
     366                 : {
     367          534713 :     simple_heap_delete(heapRel, tid);
     368          534713 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a