LCOV - code coverage report
Current view: top level - src/backend/statistics - relation_stats.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 88 93 94.6 %
Date: 2025-04-01 15:15:16 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  * relation_stats.c
       3             :  *
       4             :  *    PostgreSQL relation statistics manipulation
       5             :  *
       6             :  * Code supporting the direct import of relation statistics, similar to
       7             :  * what is done by the ANALYZE command.
       8             :  *
       9             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
      10             :  * Portions Copyright (c) 1994, Regents of the University of California
      11             :  *
      12             :  * IDENTIFICATION
      13             :  *       src/backend/statistics/relation_stats.c
      14             :  *
      15             :  *-------------------------------------------------------------------------
      16             :  */
      17             : 
      18             : #include "postgres.h"
      19             : 
      20             : #include "access/heapam.h"
      21             : #include "catalog/indexing.h"
      22             : #include "catalog/namespace.h"
      23             : #include "statistics/stat_utils.h"
      24             : #include "utils/builtins.h"
      25             : #include "utils/fmgroids.h"
      26             : #include "utils/fmgrprotos.h"
      27             : #include "utils/lsyscache.h"
      28             : #include "utils/syscache.h"
      29             : 
      30             : 
      31             : /*
      32             :  * Positional argument numbers, names, and types for
      33             :  * relation_statistics_update().
      34             :  */
      35             : 
      36             : enum relation_stats_argnum
      37             : {
      38             :     RELSCHEMA_ARG = 0,
      39             :     RELNAME_ARG,
      40             :     RELPAGES_ARG,
      41             :     RELTUPLES_ARG,
      42             :     RELALLVISIBLE_ARG,
      43             :     RELALLFROZEN_ARG,
      44             :     NUM_RELATION_STATS_ARGS
      45             : };
      46             : 
      47             : static struct StatsArgInfo relarginfo[] =
      48             : {
      49             :     [RELSCHEMA_ARG] = {"schemaname", TEXTOID},
      50             :     [RELNAME_ARG] = {"relname", TEXTOID},
      51             :     [RELPAGES_ARG] = {"relpages", INT4OID},
      52             :     [RELTUPLES_ARG] = {"reltuples", FLOAT4OID},
      53             :     [RELALLVISIBLE_ARG] = {"relallvisible", INT4OID},
      54             :     [RELALLFROZEN_ARG] = {"relallfrozen", INT4OID},
      55             :     [NUM_RELATION_STATS_ARGS] = {0}
      56             : };
      57             : 
      58             : static bool relation_statistics_update(FunctionCallInfo fcinfo);
      59             : 
      60             : /*
      61             :  * Internal function for modifying statistics for a relation.
      62             :  */
      63             : static bool
      64        2202 : relation_statistics_update(FunctionCallInfo fcinfo)
      65             : {
      66        2202 :     bool        result = true;
      67             :     char       *nspname;
      68             :     char       *relname;
      69             :     Oid         reloid;
      70             :     Relation    crel;
      71        2202 :     BlockNumber relpages = 0;
      72        2202 :     bool        update_relpages = false;
      73        2202 :     float       reltuples = 0;
      74        2202 :     bool        update_reltuples = false;
      75        2202 :     BlockNumber relallvisible = 0;
      76        2202 :     bool        update_relallvisible = false;
      77        2202 :     BlockNumber relallfrozen = 0;
      78        2202 :     bool        update_relallfrozen = false;
      79             :     HeapTuple   ctup;
      80             :     Form_pg_class pgcform;
      81        2202 :     int         replaces[4] = {0};
      82        2202 :     Datum       values[4] = {0};
      83        2202 :     bool        nulls[4] = {0};
      84        2202 :     int         nreplaces = 0;
      85             : 
      86        2202 :     stats_check_required_arg(fcinfo, relarginfo, RELSCHEMA_ARG);
      87        2190 :     stats_check_required_arg(fcinfo, relarginfo, RELNAME_ARG);
      88             : 
      89        2178 :     nspname = TextDatumGetCString(PG_GETARG_DATUM(RELSCHEMA_ARG));
      90        2178 :     relname = TextDatumGetCString(PG_GETARG_DATUM(RELNAME_ARG));
      91             : 
      92        2178 :     reloid = stats_lookup_relid(nspname, relname);
      93             : 
      94        2172 :     if (RecoveryInProgress())
      95           0 :         ereport(ERROR,
      96             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
      97             :                  errmsg("recovery is in progress"),
      98             :                  errhint("Statistics cannot be modified during recovery.")));
      99             : 
     100        2172 :     stats_lock_check_privileges(reloid);
     101             : 
     102        2154 :     if (!PG_ARGISNULL(RELPAGES_ARG))
     103             :     {
     104        2130 :         relpages = PG_GETARG_UINT32(RELPAGES_ARG);
     105        2130 :         update_relpages = true;
     106             :     }
     107             : 
     108        2154 :     if (!PG_ARGISNULL(RELTUPLES_ARG))
     109             :     {
     110        2118 :         reltuples = PG_GETARG_FLOAT4(RELTUPLES_ARG);
     111        2118 :         if (reltuples < -1.0)
     112             :         {
     113           0 :             ereport(WARNING,
     114             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     115             :                      errmsg("reltuples cannot be < -1.0")));
     116           0 :             result = false;
     117             :         }
     118             :         else
     119        2118 :             update_reltuples = true;
     120             :     }
     121             : 
     122        2154 :     if (!PG_ARGISNULL(RELALLVISIBLE_ARG))
     123             :     {
     124        2118 :         relallvisible = PG_GETARG_UINT32(RELALLVISIBLE_ARG);
     125        2118 :         update_relallvisible = true;
     126             :     }
     127             : 
     128        2154 :     if (!PG_ARGISNULL(RELALLFROZEN_ARG))
     129             :     {
     130        2118 :         relallfrozen = PG_GETARG_UINT32(RELALLFROZEN_ARG);
     131        2118 :         update_relallfrozen = true;
     132             :     }
     133             : 
     134             :     /*
     135             :      * Take RowExclusiveLock on pg_class, consistent with
     136             :      * vac_update_relstats().
     137             :      */
     138        2154 :     crel = table_open(RelationRelationId, RowExclusiveLock);
     139             : 
     140        2154 :     ctup = SearchSysCache1(RELOID, ObjectIdGetDatum(reloid));
     141        2154 :     if (!HeapTupleIsValid(ctup))
     142           0 :         elog(ERROR, "pg_class entry for relid %u not found", reloid);
     143             : 
     144        2154 :     pgcform = (Form_pg_class) GETSTRUCT(ctup);
     145             : 
     146        2154 :     if (update_relpages && relpages != pgcform->relpages)
     147             :     {
     148        1134 :         replaces[nreplaces] = Anum_pg_class_relpages;
     149        1134 :         values[nreplaces] = UInt32GetDatum(relpages);
     150        1134 :         nreplaces++;
     151             :     }
     152             : 
     153        2154 :     if (update_reltuples && reltuples != pgcform->reltuples)
     154             :     {
     155         996 :         replaces[nreplaces] = Anum_pg_class_reltuples;
     156         996 :         values[nreplaces] = Float4GetDatum(reltuples);
     157         996 :         nreplaces++;
     158             :     }
     159             : 
     160        2154 :     if (update_relallvisible && relallvisible != pgcform->relallvisible)
     161             :     {
     162         248 :         replaces[nreplaces] = Anum_pg_class_relallvisible;
     163         248 :         values[nreplaces] = UInt32GetDatum(relallvisible);
     164         248 :         nreplaces++;
     165             :     }
     166             : 
     167        2154 :     if (update_relallfrozen && relallfrozen != pgcform->relallfrozen)
     168             :     {
     169          62 :         replaces[nreplaces] = Anum_pg_class_relallfrozen;
     170          62 :         values[nreplaces] = UInt32GetDatum(relallfrozen);
     171          62 :         nreplaces++;
     172             :     }
     173             : 
     174        2154 :     if (nreplaces > 0)
     175             :     {
     176        1276 :         TupleDesc   tupdesc = RelationGetDescr(crel);
     177             :         HeapTuple   newtup;
     178             : 
     179        1276 :         newtup = heap_modify_tuple_by_cols(ctup, tupdesc, nreplaces,
     180             :                                            replaces, values, nulls);
     181        1276 :         CatalogTupleUpdate(crel, &newtup->t_self, newtup);
     182        1276 :         heap_freetuple(newtup);
     183             :     }
     184             : 
     185        2154 :     ReleaseSysCache(ctup);
     186             : 
     187             :     /* release the lock, consistent with vac_update_relstats() */
     188        2154 :     table_close(crel, RowExclusiveLock);
     189             : 
     190        2154 :     CommandCounterIncrement();
     191             : 
     192        2154 :     return result;
     193             : }
     194             : 
     195             : /*
     196             :  * Clear statistics for a given pg_class entry; that is, set back to initial
     197             :  * stats for a newly-created table.
     198             :  */
     199             : Datum
     200          24 : pg_clear_relation_stats(PG_FUNCTION_ARGS)
     201             : {
     202          24 :     LOCAL_FCINFO(newfcinfo, 6);
     203             : 
     204          24 :     InitFunctionCallInfoData(*newfcinfo, NULL, 6, InvalidOid, NULL, NULL);
     205             : 
     206          24 :     newfcinfo->args[0].value = PG_GETARG_DATUM(0);
     207          24 :     newfcinfo->args[0].isnull = PG_ARGISNULL(0);
     208          24 :     newfcinfo->args[1].value = PG_GETARG_DATUM(1);
     209          24 :     newfcinfo->args[1].isnull = PG_ARGISNULL(1);
     210          24 :     newfcinfo->args[2].value = UInt32GetDatum(0);
     211          24 :     newfcinfo->args[2].isnull = false;
     212          24 :     newfcinfo->args[3].value = Float4GetDatum(-1.0);
     213          24 :     newfcinfo->args[3].isnull = false;
     214          24 :     newfcinfo->args[4].value = UInt32GetDatum(0);
     215          24 :     newfcinfo->args[4].isnull = false;
     216          24 :     newfcinfo->args[5].value = UInt32GetDatum(0);
     217          24 :     newfcinfo->args[5].isnull = false;
     218             : 
     219          24 :     relation_statistics_update(newfcinfo);
     220          12 :     PG_RETURN_VOID();
     221             : }
     222             : 
     223             : Datum
     224        2190 : pg_restore_relation_stats(PG_FUNCTION_ARGS)
     225             : {
     226        2190 :     LOCAL_FCINFO(positional_fcinfo, NUM_RELATION_STATS_ARGS);
     227        2190 :     bool        result = true;
     228             : 
     229        2190 :     InitFunctionCallInfoData(*positional_fcinfo, NULL,
     230             :                              NUM_RELATION_STATS_ARGS,
     231             :                              InvalidOid, NULL, NULL);
     232             : 
     233        2190 :     if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo,
     234             :                                           relarginfo))
     235          24 :         result = false;
     236             : 
     237        2178 :     if (!relation_statistics_update(positional_fcinfo))
     238           0 :         result = false;
     239             : 
     240        2142 :     PG_RETURN_BOOL(result);
     241             : }

Generated by: LCOV version 1.14