diff --git a/executor/grant.go b/executor/grant.go index 00cbee41123df..cbe15b2c350d0 100644 --- a/executor/grant.go +++ b/executor/grant.go @@ -72,8 +72,20 @@ func (e *GrantExec) Next(ctx context.Context, req *chunk.Chunk) error { dbName = e.ctx.GetSessionVars().CurrentDB } - // Make sure the table exist. + // For table & column level, check whether table exists and privilege is valid if e.Level.Level == ast.GrantLevelTable { + // Return if privilege is invalid, to fail before not existing table, see issue #29302 + for _, p := range e.Privs { + if len(p.Cols) == 0 { + if !mysql.AllTablePrivs.Has(p.Priv) && p.Priv != mysql.AllPriv && p.Priv != mysql.UsagePriv && p.Priv != mysql.GrantPriv && p.Priv != mysql.ExtendedPriv { + return ErrIllegalGrantForTable + } + } else { + if !mysql.AllColumnPrivs.Has(p.Priv) && p.Priv != mysql.AllPriv && p.Priv != mysql.UsagePriv { + return ErrWrongUsage.GenWithStackByArgs("COLUMN GRANT", "NON-COLUMN PRIVILEGES") + } + } + } dbNameStr := model.NewCIStr(dbName) schema := e.ctx.GetInfoSchema().(infoschema.InfoSchema) tbl, err := schema.TableByName(dbNameStr, model.NewCIStr(e.Level.TableName)) @@ -633,13 +645,6 @@ func composeDBPrivUpdate(sql *strings.Builder, priv mysql.PrivilegeType, value s func composeTablePrivUpdateForGrant(ctx sessionctx.Context, sql *strings.Builder, priv mysql.PrivilegeType, name string, host string, db string, tbl string) error { var newTablePriv, newColumnPriv []string if priv != mysql.AllPriv { - // TODO: https://github.com/pingcap/parser/pull/581 removed privs from all priv lists - // it is to avoid add GRANT in GRANT ALL SQLs - // WithGRANT seems broken, fix it later - if priv != mysql.GrantPriv && !mysql.AllTablePrivs.Has(priv) { - return ErrIllegalGrantForTable - } - currTablePriv, currColumnPriv, err := getTablePriv(ctx, name, host, db, tbl) if err != nil { return err @@ -669,10 +674,6 @@ func composeTablePrivUpdateForGrant(ctx sessionctx.Context, sql *strings.Builder func composeColumnPrivUpdateForGrant(ctx sessionctx.Context, sql *strings.Builder, priv mysql.PrivilegeType, name string, host string, db string, tbl string, col string) error { var newColumnPriv []string if priv != mysql.AllPriv { - if !mysql.AllColumnPrivs.Has(priv) { - return ErrWrongUsage.GenWithStackByArgs("COLUMN GRANT", "NON-COLUMN PRIVILEGES") - } - currColumnPriv, err := getColumnPriv(ctx, name, host, db, tbl, col) if err != nil { return err diff --git a/executor/grant_test.go b/executor/grant_test.go index 906d87e0b5cd2..a42b546e42b05 100644 --- a/executor/grant_test.go +++ b/executor/grant_test.go @@ -615,3 +615,19 @@ func TestGrantDynamicPrivs(t *testing.T) { tk.MustQuery("SELECT Grant_Priv FROM mysql.user WHERE `Host` = '%' AND `User` = 'dyn'").Check(testkit.Rows("Y")) tk.MustQuery("SELECT WITH_GRANT_OPTION FROM mysql.global_grants WHERE `Host` = '%' AND `User` = 'dyn' AND Priv='CONNECTION_ADMIN'").Check(testkit.Rows("Y")) } + +func TestNonExistTableIllegalGrant(t *testing.T) { + t.Parallel() + + store, clean := testkit.CreateMockStore(t) + defer clean() + + tk := testkit.NewTestKit(t, store) + tk.MustExec("create user u29302") + defer tk.MustExec("drop user u29302") + // Table level, not existing table, illegal privilege + tk.MustGetErrCode("grant create temporary tables on NotExistsD29302.NotExistsT29302 to u29302", mysql.ErrIllegalGrantForTable) + tk.MustGetErrCode("grant lock tables on test.NotExistsT29302 to u29302", mysql.ErrIllegalGrantForTable) + // Column level, not existing table, illegal privilege + tk.MustGetErrCode("grant create temporary tables (NotExistsCol) on NotExistsD29302.NotExistsT29302 to u29302;", mysql.ErrWrongUsage) +} diff --git a/privilege/privileges/privileges_test.go b/privilege/privileges/privileges_test.go index 8530cd47fae65..6d9c6dd0d62bc 100644 --- a/privilege/privileges/privileges_test.go +++ b/privilege/privileges/privileges_test.go @@ -2668,6 +2668,7 @@ func TestGrantCreateTmpTables(t *testing.T) { tk.MustExec("CREATE TABLE create_tmp_table_table (a int)") tk.MustExec("GRANT CREATE TEMPORARY TABLES on create_tmp_table_db.* to u1") tk.MustExec("GRANT CREATE TEMPORARY TABLES on *.* to u1") + tk.MustGetErrCode("GRANT CREATE TEMPORARY TABLES on create_tmp_table_db.tmp to u1", mysql.ErrIllegalGrantForTable) // Must set a session user to avoid null pointer dereference tk.Session().Auth(&auth.UserIdentity{ Username: "root",