LCOV - code coverage report
Current view: top level - src/backend/statistics - relation_stats.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 67 78 85.9 %
Date: 2024-11-21 08:14:44 Functions: 4 4 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-2024, 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 "statistics/stat_utils.h"
      23             : #include "utils/fmgrprotos.h"
      24             : #include "utils/syscache.h"
      25             : 
      26             : #define DEFAULT_RELPAGES Int32GetDatum(0)
      27             : #define DEFAULT_RELTUPLES Float4GetDatum(-1.0)
      28             : #define DEFAULT_RELALLVISIBLE Int32GetDatum(0)
      29             : 
      30             : /*
      31             :  * Positional argument numbers, names, and types for
      32             :  * relation_statistics_update().
      33             :  */
      34             : 
      35             : enum relation_stats_argnum
      36             : {
      37             :     RELATION_ARG = 0,
      38             :     RELPAGES_ARG,
      39             :     RELTUPLES_ARG,
      40             :     RELALLVISIBLE_ARG,
      41             :     NUM_RELATION_STATS_ARGS
      42             : };
      43             : 
      44             : static struct StatsArgInfo relarginfo[] =
      45             : {
      46             :     [RELATION_ARG] = {"relation", REGCLASSOID},
      47             :     [RELPAGES_ARG] = {"relpages", INT4OID},
      48             :     [RELTUPLES_ARG] = {"reltuples", FLOAT4OID},
      49             :     [RELALLVISIBLE_ARG] = {"relallvisible", INT4OID},
      50             :     [NUM_RELATION_STATS_ARGS] = {0}
      51             : };
      52             : 
      53             : static bool relation_statistics_update(FunctionCallInfo fcinfo, int elevel);
      54             : 
      55             : /*
      56             :  * Internal function for modifying statistics for a relation.
      57             :  */
      58             : static bool
      59         108 : relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
      60             : {
      61             :     Oid         reloid;
      62             :     Relation    crel;
      63             :     HeapTuple   ctup;
      64             :     Form_pg_class pgcform;
      65         108 :     int         replaces[3] = {0};
      66         108 :     Datum       values[3] = {0};
      67         108 :     bool        nulls[3] = {0};
      68         108 :     int         ncols = 0;
      69             :     TupleDesc   tupdesc;
      70         108 :     bool        result = true;
      71             : 
      72         108 :     stats_check_required_arg(fcinfo, relarginfo, RELATION_ARG);
      73         108 :     reloid = PG_GETARG_OID(RELATION_ARG);
      74             : 
      75         108 :     if (RecoveryInProgress())
      76           0 :         ereport(ERROR,
      77             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
      78             :                  errmsg("recovery is in progress"),
      79             :                  errhint("Statistics cannot be modified during recovery.")));
      80             : 
      81         108 :     stats_lock_check_privileges(reloid);
      82             : 
      83             :     /*
      84             :      * Take RowExclusiveLock on pg_class, consistent with
      85             :      * vac_update_relstats().
      86             :      */
      87          78 :     crel = table_open(RelationRelationId, RowExclusiveLock);
      88             : 
      89          78 :     tupdesc = RelationGetDescr(crel);
      90          78 :     ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
      91          78 :     if (!HeapTupleIsValid(ctup))
      92             :     {
      93           0 :         ereport(elevel,
      94             :                 (errcode(ERRCODE_OBJECT_IN_USE),
      95             :                  errmsg("pg_class entry for relid %u not found", reloid)));
      96           0 :         table_close(crel, RowExclusiveLock);
      97           0 :         return false;
      98             :     }
      99             : 
     100          78 :     pgcform = (Form_pg_class) GETSTRUCT(ctup);
     101             : 
     102             :     /* relpages */
     103          78 :     if (!PG_ARGISNULL(RELPAGES_ARG))
     104             :     {
     105          54 :         int32       relpages = PG_GETARG_INT32(RELPAGES_ARG);
     106             : 
     107             :         /*
     108             :          * Partitioned tables may have relpages=-1. Note: for relations with
     109             :          * no storage, relpages=-1 is not used consistently, but must be
     110             :          * supported here.
     111             :          */
     112          54 :         if (relpages < -1)
     113             :         {
     114           0 :             ereport(elevel,
     115             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     116             :                      errmsg("relpages cannot be < -1")));
     117           0 :             result = false;
     118             :         }
     119          54 :         else if (relpages != pgcform->relpages)
     120             :         {
     121          42 :             replaces[ncols] = Anum_pg_class_relpages;
     122          42 :             values[ncols] = Int32GetDatum(relpages);
     123          42 :             ncols++;
     124             :         }
     125             :     }
     126             : 
     127          78 :     if (!PG_ARGISNULL(RELTUPLES_ARG))
     128             :     {
     129          48 :         float       reltuples = PG_GETARG_FLOAT4(RELTUPLES_ARG);
     130             : 
     131          48 :         if (reltuples < -1.0)
     132             :         {
     133           0 :             ereport(elevel,
     134             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     135             :                      errmsg("reltuples cannot be < -1.0")));
     136           0 :             result = false;
     137             :         }
     138          48 :         else if (reltuples != pgcform->reltuples)
     139             :         {
     140          36 :             replaces[ncols] = Anum_pg_class_reltuples;
     141          36 :             values[ncols] = Float4GetDatum(reltuples);
     142          36 :             ncols++;
     143             :         }
     144             : 
     145             :     }
     146             : 
     147          78 :     if (!PG_ARGISNULL(RELALLVISIBLE_ARG))
     148             :     {
     149          48 :         int32       relallvisible = PG_GETARG_INT32(RELALLVISIBLE_ARG);
     150             : 
     151          48 :         if (relallvisible < 0)
     152             :         {
     153           0 :             ereport(elevel,
     154             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     155             :                      errmsg("relallvisible cannot be < 0")));
     156           0 :             result = false;
     157             :         }
     158          48 :         else if (relallvisible != pgcform->relallvisible)
     159             :         {
     160          36 :             replaces[ncols] = Anum_pg_class_relallvisible;
     161          36 :             values[ncols] = Int32GetDatum(relallvisible);
     162          36 :             ncols++;
     163             :         }
     164             :     }
     165             : 
     166             :     /* only update pg_class if there is a meaningful change */
     167          78 :     if (ncols > 0)
     168             :     {
     169             :         HeapTuple   newtup;
     170             : 
     171          66 :         newtup = heap_modify_tuple_by_cols(ctup, tupdesc, ncols, replaces, values,
     172             :                                            nulls);
     173          66 :         CatalogTupleUpdate(crel, &newtup->t_self, newtup);
     174          66 :         heap_freetuple(newtup);
     175             :     }
     176             : 
     177             :     /* release the lock, consistent with vac_update_relstats() */
     178          78 :     table_close(crel, RowExclusiveLock);
     179             : 
     180          78 :     CommandCounterIncrement();
     181             : 
     182          78 :     return result;
     183             : }
     184             : 
     185             : /*
     186             :  * Set statistics for a given pg_class entry.
     187             :  */
     188             : Datum
     189          48 : pg_set_relation_stats(PG_FUNCTION_ARGS)
     190             : {
     191          48 :     relation_statistics_update(fcinfo, ERROR);
     192          42 :     PG_RETURN_VOID();
     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          18 : pg_clear_relation_stats(PG_FUNCTION_ARGS)
     201             : {
     202          18 :     LOCAL_FCINFO(newfcinfo, 4);
     203             : 
     204          18 :     InitFunctionCallInfoData(*newfcinfo, NULL, 4, InvalidOid, NULL, NULL);
     205             : 
     206          18 :     newfcinfo->args[0].value = PG_GETARG_OID(0);
     207          18 :     newfcinfo->args[0].isnull = PG_ARGISNULL(0);
     208          18 :     newfcinfo->args[1].value = DEFAULT_RELPAGES;
     209          18 :     newfcinfo->args[1].isnull = false;
     210          18 :     newfcinfo->args[2].value = DEFAULT_RELTUPLES;
     211          18 :     newfcinfo->args[2].isnull = false;
     212          18 :     newfcinfo->args[3].value = DEFAULT_RELALLVISIBLE;
     213          18 :     newfcinfo->args[3].isnull = false;
     214             : 
     215          18 :     relation_statistics_update(newfcinfo, ERROR);
     216           6 :     PG_RETURN_VOID();
     217             : }
     218             : 
     219             : Datum
     220          60 : pg_restore_relation_stats(PG_FUNCTION_ARGS)
     221             : {
     222          60 :     LOCAL_FCINFO(positional_fcinfo, NUM_RELATION_STATS_ARGS);
     223          60 :     bool        result = true;
     224             : 
     225          60 :     InitFunctionCallInfoData(*positional_fcinfo, NULL,
     226             :                              NUM_RELATION_STATS_ARGS,
     227             :                              InvalidOid, NULL, NULL);
     228             : 
     229          60 :     if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo,
     230             :                                           relarginfo, WARNING))
     231          12 :         result = false;
     232             : 
     233          42 :     if (!relation_statistics_update(positional_fcinfo, WARNING))
     234           0 :         result = false;
     235             : 
     236          30 :     PG_RETURN_BOOL(result);
     237             : }

Generated by: LCOV version 1.14