From 943a113bcb6fb913814ae32cbd4dd1ed29498750 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Fri, 15 Jan 2021 23:24:19 +0100 Subject: [PATCH] Disallow CREATE STATISTICS on system catalogs Add a check that CREATE STATISTICS does not add extended statistics on system catalogs, similarly to indexes etc. It can be overriden using the allow_system_table_mods GUC. This bug exists since 7b504eb282c, adding the extended statistics, so backpatch all the way back to PostgreSQL 10. Author: Tomas Vondra Reported-by: Dean Rasheed Backpatch-through: 10 Discussion: https://postgr.es/m/CAEZATCXAPrrOKwEsyZKQ4uzzJQWBCt6QAvOcgqRGdWwT1zb%2BrQ%40mail.gmail.com --- src/backend/commands/statscmds.c | 7 +++++++ src/test/regress/expected/stats_ext.out | 12 +++++++----- src/test/regress/sql/stats_ext.sql | 12 +++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index 34d11c2a980..5678d31d0b6 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -132,6 +132,13 @@ CreateStatistics(CreateStatsStmt *stmt) if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner)) aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind), RelationGetRelationName(rel)); + + /* Creating statistics on system catalogs is not allowed */ + if (!allowSystemTableMods && IsSystemRelation(rel)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied: \"%s\" is a system catalog", + RelationGetRelationName(rel)))); } Assert(rel); diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index cd4b60314cc..f2a1863c7b1 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -23,6 +23,7 @@ begin end; $$; -- Verify failures +CREATE TABLE ext_stats_test (x int, y int, z int); CREATE STATISTICS tst; ERROR: syntax error at or near ";" LINE 1: CREATE STATISTICS tst; @@ -37,16 +38,17 @@ LINE 1: CREATE STATISTICS tst FROM sometab; ^ CREATE STATISTICS tst ON a, b FROM nonexistent; ERROR: relation "nonexistent" does not exist -CREATE STATISTICS tst ON a, b FROM pg_class; +CREATE STATISTICS tst ON a, b FROM ext_stats_test; ERROR: column "a" does not exist -CREATE STATISTICS tst ON relname, relname, relnatts FROM pg_class; +CREATE STATISTICS tst ON x, x, y FROM ext_stats_test; ERROR: duplicate column name in statistics definition -CREATE STATISTICS tst ON relnatts + relpages FROM pg_class; +CREATE STATISTICS tst ON x + y FROM ext_stats_test; ERROR: only simple column references are allowed in CREATE STATISTICS -CREATE STATISTICS tst ON (relpages, reltuples) FROM pg_class; +CREATE STATISTICS tst ON (x, y) FROM ext_stats_test; ERROR: only simple column references are allowed in CREATE STATISTICS -CREATE STATISTICS tst (unrecognized) ON relname, relnatts FROM pg_class; +CREATE STATISTICS tst (unrecognized) ON x, y FROM ext_stats_test; ERROR: unrecognized statistics kind "unrecognized" +DROP TABLE ext_stats_test; -- Ensure stats are dropped sanely, and test IF NOT EXISTS while at it CREATE TABLE ab1 (a INTEGER, b INTEGER, c INTEGER); CREATE STATISTICS IF NOT EXISTS ab1_a_b_stats ON a, b FROM ab1; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index 992959cb6a3..85dcf8be099 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -26,15 +26,17 @@ end; $$; -- Verify failures +CREATE TABLE ext_stats_test (x int, y int, z int); CREATE STATISTICS tst; CREATE STATISTICS tst ON a, b; CREATE STATISTICS tst FROM sometab; CREATE STATISTICS tst ON a, b FROM nonexistent; -CREATE STATISTICS tst ON a, b FROM pg_class; -CREATE STATISTICS tst ON relname, relname, relnatts FROM pg_class; -CREATE STATISTICS tst ON relnatts + relpages FROM pg_class; -CREATE STATISTICS tst ON (relpages, reltuples) FROM pg_class; -CREATE STATISTICS tst (unrecognized) ON relname, relnatts FROM pg_class; +CREATE STATISTICS tst ON a, b FROM ext_stats_test; +CREATE STATISTICS tst ON x, x, y FROM ext_stats_test; +CREATE STATISTICS tst ON x + y FROM ext_stats_test; +CREATE STATISTICS tst ON (x, y) FROM ext_stats_test; +CREATE STATISTICS tst (unrecognized) ON x, y FROM ext_stats_test; +DROP TABLE ext_stats_test; -- Ensure stats are dropped sanely, and test IF NOT EXISTS while at it CREATE TABLE ab1 (a INTEGER, b INTEGER, c INTEGER);