From 0204f27fd00902d599cc9aa912b377392f4ce6d5 Mon Sep 17 00:00:00 2001 From: Fariha Shaikh Date: Tue, 10 Mar 2026 20:39:24 +0000 Subject: [PATCH] MDEV-39028 DROP PARTITION should only require DROP privilege ALTER TABLE ... DROP PARTITION requires both ALTER and DROP privileges, which is inconsistent with TRUNCATE PARTITION that only requires DROP. This prevents fine-grained privilege separation since users who need to drop partitions must also be granted ALTER, allowing them to perform any other DDL changes on the table. Change DROP PARTITION to require only DROP privilege, consistent with TRUNCATE PARTITION. Users allowed to drop the table should also be allowed to drop partitions without needing ALTER rights. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. --- mysql-test/main/partition_grant.result | 46 +++++++++++++++++++++- mysql-test/main/partition_grant.test | 54 +++++++++++++++++++++++++- sql/sql_alter.cc | 9 +++-- 3 files changed, 103 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/partition_grant.result b/mysql-test/main/partition_grant.result index c269896975db8..aeb0be8c8df7a 100644 --- a/mysql-test/main/partition_grant.result +++ b/mysql-test/main/partition_grant.result @@ -25,7 +25,6 @@ connection default; revoke alter on mysqltest_1.* from mysqltest_1@localhost; connect conn3,localhost,mysqltest_1,,mysqltest_1; alter table t1 drop partition p3; -ERROR 42000: ALTER command denied to user 'mysqltest_1'@'localhost' for table `mysqltest_1`.`t1` disconnect conn3; connection default; revoke select,alter,drop on mysqltest_1.* from mysqltest_1@localhost; @@ -49,3 +48,48 @@ drop table t1; drop user mysqltest_1@localhost; drop schema mysqltest_1; End of 5.1 tests +# +# MDEV-39028: DROP PARTITION should only require DROP privilege +# +CREATE DATABASE mysqltest_2; +USE mysqltest_2; +CREATE TABLE t1 (a INT) +PARTITION BY LIST (a) ( +PARTITION p1 VALUES IN (1), +PARTITION p2 VALUES IN (2), +PARTITION p3 VALUES IN (3)); +INSERT INTO t1 VALUES (1),(2),(3); +CREATE USER mysqltest_2@localhost; +# Test with only DROP privilege (should succeed) +GRANT DROP ON mysqltest_2.* TO mysqltest_2@localhost; +connect conn_drop,localhost,mysqltest_2,,mysqltest_2; +SHOW GRANTS FOR CURRENT_USER; +Grants for mysqltest_2@localhost +GRANT USAGE ON *.* TO `mysqltest_2`@`localhost` +GRANT DROP ON `mysqltest_2`.* TO `mysqltest_2`@`localhost` +ALTER TABLE t1 DROP PARTITION p1; +disconnect conn_drop; +connection default; +REVOKE DROP ON mysqltest_2.* FROM mysqltest_2@localhost; +# Test with only ALTER privilege (should fail) +GRANT ALTER ON mysqltest_2.* TO mysqltest_2@localhost; +connect conn_alter,localhost,mysqltest_2,,mysqltest_2; +SHOW GRANTS FOR CURRENT_USER; +Grants for mysqltest_2@localhost +GRANT USAGE ON *.* TO `mysqltest_2`@`localhost` +GRANT ALTER ON `mysqltest_2`.* TO `mysqltest_2`@`localhost` +ALTER TABLE t1 DROP PARTITION p2; +ERROR 42000: DROP command denied to user 'mysqltest_2'@'localhost' for table `mysqltest_2`.`t1` +disconnect conn_alter; +connection default; +REVOKE ALTER ON mysqltest_2.* FROM mysqltest_2@localhost; +# Test with no privileges (should fail) +GRANT SELECT ON mysqltest_2.* TO mysqltest_2@localhost; +connect conn_none,localhost,mysqltest_2,,mysqltest_2; +ALTER TABLE t1 DROP PARTITION p3; +ERROR 42000: DROP command denied to user 'mysqltest_2'@'localhost' for table `mysqltest_2`.`t1` +disconnect conn_none; +connection default; +DROP TABLE t1; +DROP USER mysqltest_2@localhost; +DROP DATABASE mysqltest_2; diff --git a/mysql-test/main/partition_grant.test b/mysql-test/main/partition_grant.test index a5df218bb1038..45ce64fef8333 100644 --- a/mysql-test/main/partition_grant.test +++ b/mysql-test/main/partition_grant.test @@ -46,7 +46,6 @@ connection default; revoke alter on mysqltest_1.* from mysqltest_1@localhost; connect (conn3,localhost,mysqltest_1,,mysqltest_1); ---error ER_TABLEACCESS_DENIED_ERROR alter table t1 drop partition p3; disconnect conn3; @@ -80,3 +79,56 @@ drop user mysqltest_1@localhost; drop schema mysqltest_1; --echo End of 5.1 tests + +--echo # +--echo # MDEV-39028: DROP PARTITION should only require DROP privilege +--echo # + +CREATE DATABASE mysqltest_2; +USE mysqltest_2; + +CREATE TABLE t1 (a INT) + PARTITION BY LIST (a) ( + PARTITION p1 VALUES IN (1), + PARTITION p2 VALUES IN (2), + PARTITION p3 VALUES IN (3)); +INSERT INTO t1 VALUES (1),(2),(3); + +CREATE USER mysqltest_2@localhost; + +--echo # Test with only DROP privilege (should succeed) +GRANT DROP ON mysqltest_2.* TO mysqltest_2@localhost; + +connect (conn_drop,localhost,mysqltest_2,,mysqltest_2); +SHOW GRANTS FOR CURRENT_USER; +ALTER TABLE t1 DROP PARTITION p1; +disconnect conn_drop; + +connection default; +REVOKE DROP ON mysqltest_2.* FROM mysqltest_2@localhost; + +--echo # Test with only ALTER privilege (should fail) +GRANT ALTER ON mysqltest_2.* TO mysqltest_2@localhost; + +connect (conn_alter,localhost,mysqltest_2,,mysqltest_2); +SHOW GRANTS FOR CURRENT_USER; +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 DROP PARTITION p2; +disconnect conn_alter; + +connection default; +REVOKE ALTER ON mysqltest_2.* FROM mysqltest_2@localhost; + +--echo # Test with no privileges (should fail) +GRANT SELECT ON mysqltest_2.* TO mysqltest_2@localhost; + +connect (conn_none,localhost,mysqltest_2,,mysqltest_2); +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 DROP PARTITION p3; +disconnect conn_none; + +connection default; + +DROP TABLE t1; +DROP USER mysqltest_2@localhost; +DROP DATABASE mysqltest_2; diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 9e4bc4c2d349e..d5bd26ca2f4bd 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -542,11 +542,12 @@ bool Sql_cmd_alter_table::execute(THD *thd) DBUG_RETURN(TRUE); } /* - We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well - as for RENAME TO, as being done by SQLCOM_RENAME_TABLE + DROP PARTITION only requires DROP privilege (not ALTER), consistent + with TRUNCATE PARTITION, but RENAME TO requires both ALTER and DROP */ - if ((alter_info.partition_flags & ALTER_PARTITION_DROP) || - (alter_info.flags & ALTER_RENAME)) + if (alter_info.partition_flags & ALTER_PARTITION_DROP) + priv_needed= DROP_ACL; + else if (alter_info.flags & ALTER_RENAME) priv_needed|= DROP_ACL; /* Must be set in the parser */