diff options
| -rw-r--r-- | src/backend/commands/statscmds.c | 17 | ||||
| -rw-r--r-- | src/backend/commands/tablecmds.c | 2 | ||||
| -rw-r--r-- | src/backend/tcop/utility.c | 2 | ||||
| -rw-r--r-- | src/include/commands/defrem.h | 2 | ||||
| -rw-r--r-- | src/test/regress/expected/stats_ext.out | 36 | ||||
| -rw-r--r-- | src/test/regress/sql/stats_ext.sql | 33 |
6 files changed, 88 insertions, 4 deletions
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index 3568edbb553..f2546c9bf08 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -62,7 +62,7 @@ compare_int16(const void *a, const void *b) * CREATE STATISTICS */ ObjectAddress -CreateStatistics(CreateStatsStmt *stmt) +CreateStatistics(CreateStatsStmt *stmt, bool check_rights) { int16 attnums[STATS_MAX_DIMENSIONS]; int nattnums = 0; @@ -173,6 +173,21 @@ CreateStatistics(CreateStatsStmt *stmt) namestrcpy(&stxname, namestr); /* + * Check we have creation rights in target namespace. Skip check if + * caller doesn't want it. + */ + if (check_rights) + { + AclResult aclresult; + + aclresult = object_aclcheck(NamespaceRelationId, namespaceId, + GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_SCHEMA, + get_namespace_name(namespaceId)); + } + + /* * Deal with the possibility that the statistics object already exists. */ if (SearchSysCacheExists2(STATEXTNAMENSP, diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index a5d1b458c69..7aae9d208c4 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8873,7 +8873,7 @@ ATExecAddStatistics(AlteredTableInfo *tab, Relation rel, /* The CreateStatsStmt has already been through transformStatsStmt */ Assert(stmt->transformed); - address = CreateStatistics(stmt); + address = CreateStatistics(stmt, !is_rebuild); return address; } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 7e0114f6218..b366394ca81 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1902,7 +1902,7 @@ ProcessUtilitySlow(ParseState *pstate, /* Run parse analysis ... */ stmt = transformStatsStmt(relid, stmt, queryString); - address = CreateStatistics(stmt); + address = CreateStatistics(stmt, true); } break; diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 478203ed4c4..83423d3ba13 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -81,7 +81,7 @@ extern void RemoveOperatorById(Oid operOid); extern ObjectAddress AlterOperator(AlterOperatorStmt *stmt); /* commands/statscmds.c */ -extern ObjectAddress CreateStatistics(CreateStatsStmt *stmt); +extern ObjectAddress CreateStatistics(CreateStatsStmt *stmt, bool check_rights); extern ObjectAddress AlterStatistics(AlterStatsStmt *stmt); extern void RemoveStatisticsById(Oid statsOid); extern void RemoveStatisticsDataById(Oid statsOid, bool inh); diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 6bd4739e08e..d3fd25326c8 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -3407,6 +3407,40 @@ SELECT statistics_name, most_common_vals FROM pg_stats_ext_exprs x s_expr | {1} (2 rows) +-- CREATE STATISTICS checks for CREATE on the schema +RESET SESSION AUTHORIZATION; +CREATE SCHEMA sts_sch1 CREATE TABLE sts_sch1.tbl (a INT, b INT); +CREATE SCHEMA sts_sch2; +GRANT USAGE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1; +ALTER TABLE sts_sch1.tbl OWNER TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b FROM sts_sch1.tbl; +ERROR: permission denied for schema sts_sch1 +CREATE STATISTICS sts_sch2.fail ON a, b FROM sts_sch1.tbl; +ERROR: permission denied for schema sts_sch2 +RESET SESSION AUTHORIZATION; +GRANT CREATE ON SCHEMA sts_sch1 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.fail ON a, b FROM sts_sch1.tbl; +ERROR: permission denied for schema sts_sch2 +RESET SESSION AUTHORIZATION; +REVOKE CREATE ON SCHEMA sts_sch1 FROM regress_stats_user1; +GRANT CREATE ON SCHEMA sts_sch2 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b FROM sts_sch1.tbl; +ERROR: permission denied for schema sts_sch1 +CREATE STATISTICS sts_sch2.pass1 ON a, b FROM sts_sch1.tbl; +RESET SESSION AUTHORIZATION; +GRANT CREATE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.pass2 ON a, b FROM sts_sch1.tbl; +-- re-creating statistics via ALTER TABLE bypasses checks for CREATE on schema +RESET SESSION AUTHORIZATION; +REVOKE CREATE ON SCHEMA sts_sch1, sts_sch2 FROM regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +ALTER TABLE sts_sch1.tbl ALTER COLUMN a TYPE SMALLINT; -- Tidy up DROP OPERATOR <<< (int, int); DROP FUNCTION op_leak(int, int); @@ -3419,4 +3453,6 @@ NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to table tststats.priv_test_parent_tbl drop cascades to table tststats.priv_test_tbl drop cascades to view tststats.priv_test_view +DROP SCHEMA sts_sch1, sts_sch2 CASCADE; +NOTICE: drop cascades to table sts_sch1.tbl DROP USER regress_stats_user1; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index a83ea3d5679..39433085a21 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -1739,6 +1739,38 @@ SELECT statistics_name, most_common_vals FROM pg_stats_ext x SELECT statistics_name, most_common_vals FROM pg_stats_ext_exprs x WHERE tablename = 'stats_ext_tbl' ORDER BY ROW(x.*); +-- CREATE STATISTICS checks for CREATE on the schema +RESET SESSION AUTHORIZATION; +CREATE SCHEMA sts_sch1 CREATE TABLE sts_sch1.tbl (a INT, b INT); +CREATE SCHEMA sts_sch2; +GRANT USAGE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1; +ALTER TABLE sts_sch1.tbl OWNER TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.fail ON a, b FROM sts_sch1.tbl; +RESET SESSION AUTHORIZATION; +GRANT CREATE ON SCHEMA sts_sch1 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.fail ON a, b FROM sts_sch1.tbl; +RESET SESSION AUTHORIZATION; +REVOKE CREATE ON SCHEMA sts_sch1 FROM regress_stats_user1; +GRANT CREATE ON SCHEMA sts_sch2 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.pass1 ON a, b FROM sts_sch1.tbl; +RESET SESSION AUTHORIZATION; +GRANT CREATE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.pass2 ON a, b FROM sts_sch1.tbl; + +-- re-creating statistics via ALTER TABLE bypasses checks for CREATE on schema +RESET SESSION AUTHORIZATION; +REVOKE CREATE ON SCHEMA sts_sch1, sts_sch2 FROM regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +ALTER TABLE sts_sch1.tbl ALTER COLUMN a TYPE SMALLINT; + -- Tidy up DROP OPERATOR <<< (int, int); DROP FUNCTION op_leak(int, int); @@ -1747,4 +1779,5 @@ DROP FUNCTION op_leak(record, record); RESET SESSION AUTHORIZATION; DROP TABLE stats_ext_tbl; DROP SCHEMA tststats CASCADE; +DROP SCHEMA sts_sch1, sts_sch2 CASCADE; DROP USER regress_stats_user1; |
