Skip to content

Commit e697fe6

Browse files
committed
executor: canonicalize db/table names for table-scope GRANT and REVOKE using infoschema metadata
close #67175
1 parent fb17a41 commit e697fe6

4 files changed

Lines changed: 100 additions & 1 deletion

File tree

pkg/executor/grant.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ func (e *GrantExec) Next(ctx context.Context, _ *chunk.Chunk) error {
119119
if tbl != nil && tbl.Meta().Name.L != strings.ToLower(e.Level.TableName) {
120120
return infoschema.ErrTableNotExists.GenWithStackByArgs(dbName, e.Level.TableName)
121121
}
122+
if tbl != nil {
123+
// Use the real table name from schema metadata.
124+
// This makes `t` and `T` write to the same privilege row.
125+
e.Level.TableName = tbl.Meta().Name.O
126+
}
127+
if db, succ := schema.SchemaByName(dbNameStr); succ {
128+
dbName = db.Name.O
129+
}
122130
if len(e.Level.DBName) > 0 {
123131
// The database name should also match.
124132
db, succ := schema.SchemaByName(dbNameStr)

pkg/executor/grant_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/pingcap/tidb/pkg/parser/mysql"
2323
"github.com/pingcap/tidb/pkg/parser/terror"
2424
"github.com/pingcap/tidb/pkg/testkit"
25+
"github.com/pingcap/tidb/pkg/util/collate"
2526
"github.com/pingcap/tidb/pkg/util/dbterror/exeerrors"
2627
"github.com/stretchr/testify/require"
2728
)
@@ -103,6 +104,23 @@ func TestGrantDBScope(t *testing.T) {
103104
require.True(t, terror.ErrorEqual(err, exeerrors.ErrWrongUsage.GenWithStackByArgs("DB GRANT", "NON-DB PRIVILEGES")))
104105
}
105106

107+
func TestGrantDBScopeCaseInsensitiveWithNewCollationDisabled(t *testing.T) {
108+
oldNewCollationEnabled := collate.NewCollationEnabled()
109+
collate.SetNewCollationEnabledForTest(false)
110+
defer collate.SetNewCollationEnabledForTest(oldNewCollationEnabled)
111+
112+
store := testkit.CreateMockStore(t)
113+
tk := testkit.NewTestKit(t, store)
114+
115+
tk.MustExec(`DROP USER IF EXISTS 'testDBCase'@'%'`)
116+
tk.MustExec(`CREATE USER 'testDBCase'@'%' IDENTIFIED BY '123'`)
117+
118+
tk.MustExec(`GRANT SELECT ON test.* TO 'testDBCase'@'%'`)
119+
tk.MustExec(`GRANT SELECT ON TEST.* TO 'testDBCase'@'%'`)
120+
tk.MustQuery(`SELECT DB, Select_priv FROM mysql.db WHERE User='testDBCase' AND Host='%' ORDER BY DB`).
121+
Check(testkit.Rows("test Y"))
122+
}
123+
106124
func TestGrantTableScope(t *testing.T) {
107125
store := testkit.CreateMockStore(t)
108126

@@ -146,6 +164,25 @@ func TestGrantTableScope(t *testing.T) {
146164
"[executor:1144]Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used")
147165
}
148166

167+
func TestGrantTableScopeCaseInsensitiveWithNewCollationDisabled(t *testing.T) {
168+
oldNewCollationEnabled := collate.NewCollationEnabled()
169+
collate.SetNewCollationEnabledForTest(false)
170+
defer collate.SetNewCollationEnabledForTest(oldNewCollationEnabled)
171+
172+
store := testkit.CreateMockStore(t)
173+
tk := testkit.NewTestKit(t, store)
174+
175+
tk.MustExec(`DROP USER IF EXISTS 'testTblCase'@'%'`)
176+
tk.MustExec(`CREATE USER 'testTblCase'@'%' IDENTIFIED BY '123'`)
177+
tk.MustExec(`DROP TABLE IF EXISTS test.issue66867_grant`)
178+
tk.MustExec(`CREATE TABLE test.issue66867_grant(c1 int)`)
179+
180+
tk.MustExec(`GRANT SELECT ON test.issue66867_grant TO 'testTblCase'@'%'`)
181+
tk.MustExec(`GRANT SELECT ON test.ISSUE66867_GRANT TO 'testTblCase'@'%'`)
182+
tk.MustQuery(`SELECT Table_name, Table_priv FROM mysql.tables_priv WHERE User='testTblCase' AND Host='%' AND DB='test' ORDER BY Table_name`).
183+
Check(testkit.Rows("issue66867_grant Select"))
184+
}
185+
149186
func TestGrantColumnScope(t *testing.T) {
150187
store := testkit.CreateMockStore(t)
151188

pkg/executor/revoke.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,24 @@ func (e *RevokeExec) revokeOneUser(ctx context.Context, internalSession sessionc
172172
return errors.Errorf("There is no such grant defined for user '%s' on host '%s' on database %s", user, host, dbName)
173173
}
174174
case ast.GrantLevelTable:
175-
ok, err := tableUserExists(internalSession, user, host, dbName, e.Level.TableName)
175+
tblName := e.Level.TableName
176+
if len(dbName) > 0 {
177+
// Normalize db/table names before checking mysql.tables_priv.
178+
// Different input case should still map to the same object.
179+
dbNameCI := ast.NewCIStr(dbName)
180+
if db, succ := e.is.SchemaByName(dbNameCI); succ {
181+
dbName = db.Name.O
182+
}
183+
tbl, err := e.is.TableByName(ctx, dbNameCI, ast.NewCIStr(e.Level.TableName))
184+
if err != nil && !terror.ErrorEqual(err, infoschema.ErrTableNotExists) {
185+
return err
186+
}
187+
if err == nil {
188+
// Use the real table name from schema metadata.
189+
tblName = tbl.Meta().Name.O
190+
}
191+
}
192+
ok, err := tableUserExists(internalSession, user, host, dbName, tblName)
176193
if err != nil {
177194
return err
178195
}

pkg/executor/revoke_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/pingcap/tidb/pkg/executor"
2424
"github.com/pingcap/tidb/pkg/parser/mysql"
2525
"github.com/pingcap/tidb/pkg/testkit"
26+
"github.com/pingcap/tidb/pkg/util/collate"
2627
"github.com/stretchr/testify/require"
2728
)
2829

@@ -82,6 +83,23 @@ func TestRevokeDBScope(t *testing.T) {
8283
}
8384
}
8485

86+
func TestRevokeDBScopeCaseInsensitiveWithNewCollationDisabled(t *testing.T) {
87+
oldNewCollationEnabled := collate.NewCollationEnabled()
88+
collate.SetNewCollationEnabledForTest(false)
89+
defer collate.SetNewCollationEnabledForTest(oldNewCollationEnabled)
90+
91+
store := testkit.CreateMockStore(t)
92+
tk := testkit.NewTestKit(t, store)
93+
94+
tk.MustExec(`DROP USER IF EXISTS 'testDBCaseRevoke'@'%'`)
95+
tk.MustExec(`CREATE USER 'testDBCaseRevoke'@'%' IDENTIFIED BY '123'`)
96+
97+
tk.MustExec(`GRANT SELECT ON test.* TO 'testDBCaseRevoke'@'%'`)
98+
tk.MustExec(`REVOKE SELECT ON TEST.* FROM 'testDBCaseRevoke'@'%'`)
99+
tk.MustQuery(`SELECT DB FROM mysql.db WHERE User='testDBCaseRevoke' AND Host='%'`).
100+
Check(testkit.Rows())
101+
}
102+
85103
func TestRevokeTableScope(t *testing.T) {
86104
store := testkit.CreateMockStore(t)
87105
tk := testkit.NewTestKit(t, store)
@@ -123,6 +141,25 @@ func TestRevokeTableScope(t *testing.T) {
123141
require.Len(t, rows, 0)
124142
}
125143

144+
func TestRevokeTableScopeCaseInsensitiveWithNewCollationDisabled(t *testing.T) {
145+
oldNewCollationEnabled := collate.NewCollationEnabled()
146+
collate.SetNewCollationEnabledForTest(false)
147+
defer collate.SetNewCollationEnabledForTest(oldNewCollationEnabled)
148+
149+
store := testkit.CreateMockStore(t)
150+
tk := testkit.NewTestKit(t, store)
151+
152+
tk.MustExec(`DROP USER IF EXISTS 'testTblCaseRevoke'@'%'`)
153+
tk.MustExec(`CREATE USER 'testTblCaseRevoke'@'%' IDENTIFIED BY '123'`)
154+
tk.MustExec(`DROP TABLE IF EXISTS test.issue66867_revoke`)
155+
tk.MustExec(`CREATE TABLE test.issue66867_revoke(c1 int)`)
156+
157+
tk.MustExec(`GRANT SELECT ON test.issue66867_revoke TO 'testTblCaseRevoke'@'%'`)
158+
tk.MustExec(`REVOKE SELECT ON test.ISSUE66867_REVOKE FROM 'testTblCaseRevoke'@'%'`)
159+
tk.MustQuery(`SELECT Table_name FROM mysql.tables_priv WHERE User='testTblCaseRevoke' AND Host='%' AND DB='test'`).
160+
Check(testkit.Rows())
161+
}
162+
126163
func TestRevokeColumnScope(t *testing.T) {
127164
store := testkit.CreateMockStore(t)
128165
tk := testkit.NewTestKit(t, store)

0 commit comments

Comments
 (0)