From a8b8620c0fbdb6eb4639a533cc979791f0e45851 Mon Sep 17 00:00:00 2001
From: Zhong ShiHao <zhong950419@gmail.com>
Date: Thu, 27 Aug 2026 22:15:05 -0400
Subject: [PATCH v2] Add test coverage for pg_clear_attribute_stats() error
 paths

pg_clear_attribute_stats() was called exactly once in the test suite, on
its success path, so none of the ways it can fail were covered.  That gap
let the argument names in cleararginfo[] stay wrong until 11ed011ae22.

Cover the null check for each required argument, a missing schema,
relation and column, a system column, and two relation kinds that cannot
carry statistics.  Also clear an inherited row and check that the
non-inherited one for the same column survives.
---
 src/test/regress/expected/stats_import.out | 152 +++++++++++++++++++++
 src/test/regress/sql/stats_import.sql      | 125 +++++++++++++++++
 2 files changed, 277 insertions(+)

diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out
index f2ccb80cf62..aa667767599 100644
--- a/src/test/regress/expected/stats_import.out
+++ b/src/test/regress/expected/stats_import.out
@@ -1538,6 +1538,158 @@ AND attname = 'arange';
      0
 (1 row)
 
+--
+-- pg_clear_attribute_stats() is not strict, so it checks its required
+-- arguments itself.  Verify that each one is reported under its own
+-- SQL-visible name.
+--
+-- error: schemaname null
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => NULL,
+    relname => 'test',
+    attname => 'arange',
+    inherited => false);
+ERROR:  argument "schemaname" must not be null
+-- error: relname null
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => NULL,
+    attname => 'arange',
+    inherited => false);
+ERROR:  argument "relname" must not be null
+-- error: attname null
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => NULL,
+    inherited => false);
+ERROR:  argument "attname" must not be null
+-- error: inherited null
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'arange',
+    inherited => NULL);
+ERROR:  argument "inherited" must not be null
+--
+-- Remaining error paths of pg_clear_attribute_stats().  The relation is
+-- resolved, and its kind checked, before the column is looked up.
+--
+-- error: schema does not exist
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'nope',
+    relname => 'test',
+    attname => 'arange',
+    inherited => false);
+ERROR:  schema "nope" does not exist
+-- error: relation does not exist
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'nope',
+    attname => 'arange',
+    inherited => false);
+ERROR:  relation "stats_import.nope" does not exist
+-- error: column does not exist
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'nope',
+    inherited => false);
+ERROR:  column "nope" of relation "test" does not exist
+-- error: system column
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'ctid',
+    inherited => false);
+ERROR:  cannot clear statistics on system column "ctid"
+-- error: relkind without statistics, checked before the column lookup
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'testseq',
+    attname => 'last_value',
+    inherited => false);
+ERROR:  cannot modify statistics for relation "testseq"
+DETAIL:  This operation is not supported for sequences.
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'testview',
+    attname => 'id',
+    inherited => false);
+ERROR:  cannot modify statistics for relation "testview"
+DETAIL:  This operation is not supported for views.
+--
+-- Inherited stats are held in separate pg_statistic rows, and only the
+-- rows matching the inherited argument are removed.  Plant one of each
+-- for the same column, clear the inherited one, and check that the
+-- non-inherited one survives.
+--
+SELECT pg_catalog.pg_restore_attribute_stats(
+    'schemaname', 'stats_import',
+    'relname', 'test',
+    'attname', 'arange',
+    'inherited', false::boolean,
+    'null_frac', 0.5::real);
+ pg_restore_attribute_stats 
+----------------------------
+ t
+(1 row)
+
+SELECT pg_catalog.pg_restore_attribute_stats(
+    'schemaname', 'stats_import',
+    'relname', 'test',
+    'attname', 'arange',
+    'inherited', true::boolean,
+    'null_frac', 0.5::real);
+ pg_restore_attribute_stats 
+----------------------------
+ t
+(1 row)
+
+SELECT inherited, count(*)
+FROM pg_stats
+WHERE schemaname = 'stats_import'
+AND tablename = 'test'
+AND attname = 'arange'
+GROUP BY inherited ORDER BY inherited;
+ inherited | count 
+-----------+-------
+ f         |     1
+ t         |     1
+(2 rows)
+
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'arange',
+    inherited => true);
+ pg_clear_attribute_stats 
+--------------------------
+ 
+(1 row)
+
+SELECT inherited, count(*)
+FROM pg_stats
+WHERE schemaname = 'stats_import'
+AND tablename = 'test'
+AND attname = 'arange'
+GROUP BY inherited ORDER BY inherited;
+ inherited | count 
+-----------+-------
+ f         |     1
+(1 row)
+
+-- Clean up the non-inherited row planted above.
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'arange',
+    inherited => false);
+ pg_clear_attribute_stats 
+--------------------------
+ 
+(1 row)
+
 -- temp tables
 CREATE TEMP TABLE stats_temp(i int);
 SELECT pg_restore_relation_stats(
diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql
index 650ce324c7e..9147f7f24e2 100644
--- a/src/test/regress/sql/stats_import.sql
+++ b/src/test/regress/sql/stats_import.sql
@@ -1150,6 +1150,131 @@ AND tablename = 'test'
 AND inherited = false
 AND attname = 'arange';
 
+--
+-- pg_clear_attribute_stats() is not strict, so it checks its required
+-- arguments itself.  Verify that each one is reported under its own
+-- SQL-visible name.
+--
+-- error: schemaname null
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => NULL,
+    relname => 'test',
+    attname => 'arange',
+    inherited => false);
+
+-- error: relname null
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => NULL,
+    attname => 'arange',
+    inherited => false);
+
+-- error: attname null
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => NULL,
+    inherited => false);
+
+-- error: inherited null
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'arange',
+    inherited => NULL);
+
+--
+-- Remaining error paths of pg_clear_attribute_stats().  The relation is
+-- resolved, and its kind checked, before the column is looked up.
+--
+-- error: schema does not exist
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'nope',
+    relname => 'test',
+    attname => 'arange',
+    inherited => false);
+
+-- error: relation does not exist
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'nope',
+    attname => 'arange',
+    inherited => false);
+
+-- error: column does not exist
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'nope',
+    inherited => false);
+
+-- error: system column
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'ctid',
+    inherited => false);
+
+-- error: relkind without statistics, checked before the column lookup
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'testseq',
+    attname => 'last_value',
+    inherited => false);
+
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'testview',
+    attname => 'id',
+    inherited => false);
+
+--
+-- Inherited stats are held in separate pg_statistic rows, and only the
+-- rows matching the inherited argument are removed.  Plant one of each
+-- for the same column, clear the inherited one, and check that the
+-- non-inherited one survives.
+--
+SELECT pg_catalog.pg_restore_attribute_stats(
+    'schemaname', 'stats_import',
+    'relname', 'test',
+    'attname', 'arange',
+    'inherited', false::boolean,
+    'null_frac', 0.5::real);
+
+SELECT pg_catalog.pg_restore_attribute_stats(
+    'schemaname', 'stats_import',
+    'relname', 'test',
+    'attname', 'arange',
+    'inherited', true::boolean,
+    'null_frac', 0.5::real);
+
+SELECT inherited, count(*)
+FROM pg_stats
+WHERE schemaname = 'stats_import'
+AND tablename = 'test'
+AND attname = 'arange'
+GROUP BY inherited ORDER BY inherited;
+
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'arange',
+    inherited => true);
+
+SELECT inherited, count(*)
+FROM pg_stats
+WHERE schemaname = 'stats_import'
+AND tablename = 'test'
+AND attname = 'arange'
+GROUP BY inherited ORDER BY inherited;
+
+-- Clean up the non-inherited row planted above.
+SELECT pg_catalog.pg_clear_attribute_stats(
+    schemaname => 'stats_import',
+    relname => 'test',
+    attname => 'arange',
+    inherited => false);
+
 -- temp tables
 CREATE TEMP TABLE stats_temp(i int);
 SELECT pg_restore_relation_stats(
-- 
2.37.1 (Apple Git-137.1)

