From a8b8620c0fbdb6eb4639a533cc979791f0e45851 Mon Sep 17 00:00:00 2001 From: Zhong ShiHao 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)