From 3368fbf006a55f9500716fc5b668d81294bd3db9 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Tue, 6 Jun 2023 16:41:41 +0800 Subject: [PATCH] session: change some privilege columns to case-insensitive (#43443) (#44083) close pingcap/tidb#41048 --- executor/revoke_test.go | 21 +++++++++++++++++++++ session/bootstrap.go | 25 +++++++++++++++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/executor/revoke_test.go b/executor/revoke_test.go index 716a3c65b5be8..00ee7f1495856 100644 --- a/executor/revoke_test.go +++ b/executor/revoke_test.go @@ -22,6 +22,7 @@ import ( "github.com/pingcap/tidb/executor" "github.com/pingcap/tidb/parser/mysql" "github.com/pingcap/tidb/parser/terror" + "github.com/pingcap/tidb/util/collate" "github.com/pingcap/tidb/util/testkit" ) @@ -230,3 +231,23 @@ func (s *testSuite1) TestIssue41773(c *C) { tk.MustExec("REVOKE USAGE ON test.* FROM 't1234'@'%';") tk.MustExec("REVOKE USAGE ON test.xx FROM 't1234'@'%';") } + +// Check https://github.com/pingcap/tidb/issues/41048 +func (s *testSuite1) TestCaseInsensitiveSchemaNames(c *C) { + defer collate.SetNewCollationEnabledForTest(false) + collate.SetNewCollationEnabledForTest(true) + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec(`CREATE TABLE test.TABLE_PRIV(id int, name varchar(20));`) + // Verify the case-insensitive updates for mysql.tables_priv table. + tk.MustExec(`GRANT SELECT ON test.table_priv TO 'root'@'%';`) + tk.MustExec(`revoke SELECT ON test.TABLE_PRIV from 'root'@'%';;`) + + // Verify the case-insensitive updates for mysql.db table. + tk.MustExec(`GRANT SELECT ON test.* TO 'root'@'%';`) + tk.MustExec(`revoke SELECT ON tESt.* from 'root'@'%';;`) + + // Verify the case-insensitive updates for mysql.columns_priv table. + tk.MustExec(`GRANT SELECT (id), INSERT (ID, name) ON tEst.TABLE_PRIV TO 'root'@'%';`) + tk.MustExec(`REVOKE SELECT (ID) ON test.taBle_priv from 'root'@'%';;`) +} diff --git a/session/bootstrap.go b/session/bootstrap.go index 5a1d4edb697b5..ded0639b2afe2 100644 --- a/session/bootstrap.go +++ b/session/bootstrap.go @@ -99,10 +99,23 @@ const ( "Priv LONGTEXT NOT NULL DEFAULT ''," + "PRIMARY KEY (Host, User)" + ")" + + // For `mysql.db`, `mysql.tables_priv` and `mysql.columns_priv` table, we have a slight different + // schema definition with MySQL: columns `DB`/`Table_name`/`Column_name` are defined with case-insensitive + // collation(in MySQL, they are case-sensitive). + + // The reason behind this is that when writing those records, MySQL always converts those names into lower case + // while TiDB does not do so in early implementations, which makes some 'GRANT'/'REVOKE' operations case-sensitive. + + // In order to fix this, we decide to explicitly set case-insensitive collation for the related columns here, to + // make sure: + // * The 'GRANT'/'REVOKE' could be case-insensitive for new clusters(compatible with MySQL). + // * Keep all behaviors unchanged for upgraded cluster. + // CreateDBPrivTable is the SQL statement creates DB scope privilege table in system db. CreateDBPrivTable = `CREATE TABLE IF NOT EXISTS mysql.db ( Host CHAR(255), - DB CHAR(64), + DB CHAR(64) CHARSET utf8mb4 COLLATE utf8mb4_general_ci, User CHAR(32), Select_priv ENUM('N','Y') NOT NULL DEFAULT 'N', Insert_priv ENUM('N','Y') NOT NULL DEFAULT 'N', @@ -127,9 +140,9 @@ const ( // CreateTablePrivTable is the SQL statement creates table scope privilege table in system db. CreateTablePrivTable = `CREATE TABLE IF NOT EXISTS mysql.tables_priv ( Host CHAR(255), - DB CHAR(64), + DB CHAR(64) CHARSET utf8mb4 COLLATE utf8mb4_general_ci, User CHAR(32), - Table_name CHAR(64), + Table_name CHAR(64) CHARSET utf8mb4 COLLATE utf8mb4_general_ci, Grantor CHAR(77), Timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, Table_priv SET('Select','Insert','Update','Delete','Create','Drop','Grant','Index','Alter','Create View','Show View','Trigger','References'), @@ -138,10 +151,10 @@ const ( // CreateColumnPrivTable is the SQL statement creates column scope privilege table in system db. CreateColumnPrivTable = `CREATE TABLE IF NOT EXISTS mysql.columns_priv( Host CHAR(255), - DB CHAR(64), + DB CHAR(64) CHARSET utf8mb4 COLLATE utf8mb4_general_ci, User CHAR(32), - Table_name CHAR(64), - Column_name CHAR(64), + Table_name CHAR(64) CHARSET utf8mb4 COLLATE utf8mb4_general_ci, + Column_name CHAR(64) CHARSET utf8mb4 COLLATE utf8mb4_general_ci, Timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, Column_priv SET('Select','Insert','Update','References'), PRIMARY KEY (Host, DB, User, Table_name, Column_name));`