From d26d4c717dbfb24cc9dfd83044b5c9a377dc954a 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 974828545c..2f46180407 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -135,6 +135,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 4c3edd213f..46005b9203 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -25,6 +25,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; @@ -39,16 +40,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 9781e590a3..906503bd0b 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -28,15 +28,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);