From 82d82a58131a7a260a4ec011e6bbb2898f8cb3b4 Mon Sep 17 00:00:00 2001 From: Corey Huinker Date: Mon, 3 Aug 2026 13:56:58 -0400 Subject: [PATCH v3 12/15] Create stats_util functions for recovery check, table locking. Add new function stats_check_recovery() which standardizes the check for whether the instance is in recovery or not. This function takes an elevel parameter so that both ERROR and WARNING scenarios are handled. Add function stats_check_lock_relation() to standardize the RangeVarGetRelidExtended() calls that are common to all levels of statitics modification. --- src/backend/statistics/attribute_stats.c | 22 +++---------- src/backend/statistics/extended_stats_funcs.c | 26 +++------------ src/backend/statistics/relation_stats.c | 11 ++----- src/backend/statistics/stat_utils.c | 33 +++++++++++++++++++ src/include/statistics/stat_utils.h | 2 ++ 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c index 08d294607ac..348ccc355df 100644 --- a/src/backend/statistics/attribute_stats.c +++ b/src/backend/statistics/attribute_stats.c @@ -154,7 +154,6 @@ attribute_statistics_update(const NullableDatum *args) char *attname; AttrNumber attnum; bool inherited; - Oid locked_table = InvalidOid; stats_check_required_arg(&args[ATTARG_ATTRELSCHEMA], attarginfo[ATTARG_ATTRELSCHEMA].argname); stats_check_required_arg(&args[ATTARG_ATTRELNAME], attarginfo[ATTARG_ATTRELNAME].argname); @@ -162,16 +161,10 @@ attribute_statistics_update(const NullableDatum *args) nspname = TextDatumGetCString(args[ATTARG_ATTRELSCHEMA].value); relname = TextDatumGetCString(args[ATTARG_ATTRELNAME].value); - if (RecoveryInProgress()) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("recovery is in progress"), - errhint("Statistics cannot be modified during recovery."))); + stats_check_recovery(ERROR); /* lock before looking up attribute */ - reloid = RangeVarGetRelidExtended(makeRangeVar(nspname, relname, -1), - ShareUpdateExclusiveLock, 0, - RangeVarCallbackForStats, &locked_table); + reloid = stats_check_lock_relation(nspname, relname); /* user can specify either attname or attnum, but not both */ if (!args[ATTARG_ATTNAME].isnull) @@ -669,7 +662,6 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS) char *attname; AttrNumber attnum; bool inherited; - Oid locked_table = InvalidOid; stats_check_required_arg(&fcinfo->args[C_ATTARG_ATTRELSCHEMA], cleararginfo[C_ATTARG_ATTRELSCHEMA].argname); stats_check_required_arg(&fcinfo->args[C_ATTARG_ATTRELNAME], cleararginfo[C_ATTARG_ATTRELNAME].argname); @@ -679,15 +671,9 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS) nspname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTARG_ATTRELSCHEMA)); relname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTARG_ATTRELNAME)); - if (RecoveryInProgress()) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("recovery is in progress"), - errhint("Statistics cannot be modified during recovery."))); + stats_check_recovery(ERROR); - reloid = RangeVarGetRelidExtended(makeRangeVar(nspname, relname, -1), - ShareUpdateExclusiveLock, 0, - RangeVarCallbackForStats, &locked_table); + reloid = stats_check_lock_relation(nspname, relname); attname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTARG_ATTNAME)); attnum = get_attnum(reloid, attname); diff --git a/src/backend/statistics/extended_stats_funcs.c b/src/backend/statistics/extended_stats_funcs.c index 58692bcf1f0..6db48022a63 100644 --- a/src/backend/statistics/extended_stats_funcs.c +++ b/src/backend/statistics/extended_stats_funcs.c @@ -350,7 +350,6 @@ extended_statistics_update(const NullableDatum *args) int32 *atttypmods = NULL; Oid *atttypcolls = NULL; Oid relid; - Oid locked_table = InvalidOid; /* * Fill out the StakindFlags "has" structure based on which parameters @@ -370,14 +369,8 @@ extended_statistics_update(const NullableDatum *args) has.dependencies = !args[EXTARG_DEPENDENCIES].isnull; has.expressions = !args[EXTARG_EXPRESSIONS].isnull; - if (RecoveryInProgress()) - { - ereport(WARNING, - errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("recovery is in progress"), - errhint("Statistics cannot be modified during recovery.")); + if (!stats_check_recovery(WARNING)) return false; - } /* relation arguments */ stats_check_required_arg(&args[EXTARG_RELSCHEMA], extarginfo[EXTARG_RELSCHEMA].argname); @@ -399,9 +392,7 @@ extended_statistics_update(const NullableDatum *args) * done before any locks are taken, even before any attempts related to * the extended stats object. */ - relid = RangeVarGetRelidExtended(makeRangeVar(relnspname, relname, -1), - ShareUpdateExclusiveLock, 0, - RangeVarCallbackForStats, &locked_table); + relid = stats_check_lock_relation(relnspname, relname); nspoid = get_namespace_oid(nspname, true); if (nspoid == InvalidOid) @@ -1759,7 +1750,6 @@ pg_clear_extended_stats(PG_FUNCTION_ARGS) Relation pg_stext; HeapTuple tup; Form_pg_statistic_ext stxform; - Oid locked_table = InvalidOid; /* relation arguments */ stats_check_required_arg(&fcinfo->args[EXTARG_RELSCHEMA], extarginfo[EXTARG_RELSCHEMA].argname); @@ -1775,14 +1765,8 @@ pg_clear_extended_stats(PG_FUNCTION_ARGS) stats_check_required_arg(&fcinfo->args[EXTARG_INHERITED], extarginfo[EXTARG_INHERITED].argname); inherited = PG_GETARG_BOOL(EXTARG_INHERITED); - if (RecoveryInProgress()) - { - ereport(WARNING, - errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("recovery is in progress"), - errhint("Statistics cannot be modified during recovery.")); + if (!stats_check_recovery(WARNING)) PG_RETURN_VOID(); - } /* * First open the relation where we expect to find the statistics. This @@ -1790,9 +1774,7 @@ pg_clear_extended_stats(PG_FUNCTION_ARGS) * done before any locks are taken, even before any attempts related to * the extended stats object. */ - relid = RangeVarGetRelidExtended(makeRangeVar(relnspname, relname, -1), - ShareUpdateExclusiveLock, 0, - RangeVarCallbackForStats, &locked_table); + relid = stats_check_lock_relation(relnspname, relname); /* Now check if the namespace of the stats object exists. */ nspoid = get_namespace_oid(nspname, true); diff --git a/src/backend/statistics/relation_stats.c b/src/backend/statistics/relation_stats.c index 99432502245..f8a357ba97d 100644 --- a/src/backend/statistics/relation_stats.c +++ b/src/backend/statistics/relation_stats.c @@ -78,7 +78,6 @@ relation_statistics_update(const NullableDatum *args) char *nspname; char *relname; Oid reloid; - Oid locked_table = InvalidOid; stats_check_required_arg(&args[RELARG_SCHEMA], relarginfo[RELARG_SCHEMA].argname); stats_check_required_arg(&args[RELARG_RELNAME], relarginfo[RELARG_RELNAME].argname); @@ -86,15 +85,9 @@ relation_statistics_update(const NullableDatum *args) nspname = TextDatumGetCString(args[RELARG_SCHEMA].value); relname = TextDatumGetCString(args[RELARG_RELNAME].value); - if (RecoveryInProgress()) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("recovery is in progress"), - errhint("Statistics cannot be modified during recovery."))); + stats_check_recovery(ERROR); - reloid = RangeVarGetRelidExtended(makeRangeVar(nspname, relname, -1), - ShareUpdateExclusiveLock, 0, - RangeVarCallbackForStats, &locked_table); + reloid = stats_check_lock_relation(nspname, relname); return relation_statistics_update_internal(reloid, &args[RELARG_VERSION], diff --git a/src/backend/statistics/stat_utils.c b/src/backend/statistics/stat_utils.c index f4d238c5ce0..df6af751bc4 100644 --- a/src/backend/statistics/stat_utils.c +++ b/src/backend/statistics/stat_utils.c @@ -26,6 +26,7 @@ #include "catalog/pg_statistic.h" #include "funcapi.h" #include "miscadmin.h" +#include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "statistics/stat_utils.h" #include "storage/lmgr.h" @@ -810,3 +811,35 @@ statatt_check_bounds_histogram(Datum arrayval) return true; } + +/* + * Check and restrict use of statistics functions during recovery. + */ +bool +stats_check_recovery(int elevel) +{ + if (RecoveryInProgress()) + { + ereport(elevel, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("recovery is in progress"), + errhint("Statistics cannot be modified during recovery.")); + return false; + } + + return true; +} + +/* + * Ensure that the relation exists and is properly locked before modifying any + * statistics. + */ +Oid +stats_check_lock_relation(const char *nspname, const char *relname) +{ + Oid locked_table = InvalidOid; + + return RangeVarGetRelidExtended(makeRangeVar((char *) nspname, (char *) relname, -1), + ShareUpdateExclusiveLock, 0, + RangeVarCallbackForStats, &locked_table); +} diff --git a/src/include/statistics/stat_utils.h b/src/include/statistics/stat_utils.h index 4bdf7275425..97b1ab8d2eb 100644 --- a/src/include/statistics/stat_utils.h +++ b/src/include/statistics/stat_utils.h @@ -33,6 +33,8 @@ extern bool stats_check_arg_array(const NullableDatum *arg, extern bool stats_check_arg_pair(const NullableDatum *arg1, const NullableDatum *arg2, const char *argname1, const char *argname2); +extern bool stats_check_recovery(int elevel); +extern Oid stats_check_lock_relation(const char *nspname, const char *relname); extern void RangeVarCallbackForStats(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg); -- 2.50.1 (Apple Git-155)