From 869ee4f10eca2acda3d2210198a46d5029a569fc Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Fri, 22 Nov 2024 12:07:46 -0800 Subject: [PATCH] Disallow modifying statistics on system columns. Reported-by: Heikki Linnakangas Discussion: https://postgr.es/m/df3e1c41-4e6c-40ad-9636-98deefe488cd@iki.fi --- src/backend/statistics/attribute_stats.c | 14 ++++++++++++++ src/test/regress/expected/stats_import.out | 15 +++++++++++++++ src/test/regress/sql/stats_import.sql | 15 +++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c index 686f2e639c6..b97ba7b0c0c 100644 --- a/src/backend/statistics/attribute_stats.c +++ b/src/backend/statistics/attribute_stats.c @@ -167,6 +167,13 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) stats_check_required_arg(fcinfo, attarginfo, ATTNAME_ARG); attname = PG_GETARG_NAME(ATTNAME_ARG); attnum = get_attnum(reloid, NameStr(*attname)); + + if (attnum < 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot modify statistics on system column \"%s\"", + NameStr(*attname)))); + if (attnum == InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), @@ -882,6 +889,13 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS) stats_check_required_arg(fcinfo, attarginfo, ATTNAME_ARG); attname = PG_GETARG_NAME(ATTNAME_ARG); attnum = get_attnum(reloid, NameStr(*attname)); + + if (attnum < 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot clear statistics on system column \"%s\"", + NameStr(*attname)))); + if (attnum == InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out index 9186fc01ecc..aab862c97c7 100644 --- a/src/test/regress/expected/stats_import.out +++ b/src/test/regress/expected/stats_import.out @@ -195,6 +195,15 @@ SELECT pg_catalog.pg_set_attribute_stats( avg_width => 2::integer, n_distinct => 0.3::real); ERROR: "relation" cannot be NULL +-- error: attribute is system column +SELECT pg_catalog.pg_set_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'xmin'::name, + inherited => false::boolean, + null_frac => 0.1::real, + avg_width => 2::integer, + n_distinct => 0.3::real); +ERROR: cannot modify statistics on system column "xmin" -- error: attname doesn't exist SELECT pg_catalog.pg_set_attribute_stats( relation => 'stats_import.test'::regclass, @@ -204,6 +213,12 @@ SELECT pg_catalog.pg_set_attribute_stats( avg_width => 2::integer, n_distinct => 0.3::real); ERROR: column "nope" of relation "test" does not exist +-- error: attribute is system column +SELECT pg_catalog.pg_clear_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'ctid'::name, + inherited => false::boolean); +ERROR: cannot clear statistics on system column "ctid" -- error: attname doesn't exist SELECT pg_catalog.pg_clear_attribute_stats( relation => 'stats_import.test'::regclass, diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql index c7d5e017d90..31455b58c1d 100644 --- a/src/test/regress/sql/stats_import.sql +++ b/src/test/regress/sql/stats_import.sql @@ -145,6 +145,15 @@ SELECT pg_catalog.pg_set_attribute_stats( avg_width => 2::integer, n_distinct => 0.3::real); +-- error: attribute is system column +SELECT pg_catalog.pg_set_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'xmin'::name, + inherited => false::boolean, + null_frac => 0.1::real, + avg_width => 2::integer, + n_distinct => 0.3::real); + -- error: attname doesn't exist SELECT pg_catalog.pg_set_attribute_stats( relation => 'stats_import.test'::regclass, @@ -154,6 +163,12 @@ SELECT pg_catalog.pg_set_attribute_stats( avg_width => 2::integer, n_distinct => 0.3::real); +-- error: attribute is system column +SELECT pg_catalog.pg_clear_attribute_stats( + relation => 'stats_import.test'::regclass, + attname => 'ctid'::name, + inherited => false::boolean); + -- error: attname doesn't exist SELECT pg_catalog.pg_clear_attribute_stats( relation => 'stats_import.test'::regclass,