diff --git a/planner/core/logical_plan_test.go b/planner/core/logical_plan_test.go index 60a8738ac320a..6c5c3b9525d42 100644 --- a/planner/core/logical_plan_test.go +++ b/planner/core/logical_plan_test.go @@ -1073,6 +1073,43 @@ func (s *testPlanSuite) TestVisitInfo(c *C) { {mysql.ShowViewPriv, "test", "", "", nil, false, "", false}, }, }, + { + sql: `grant all privileges on *.* to 'test'@'%'`, + ans: []visitInfo{ + {mysql.SelectPriv, "", "", "", nil, false, "", false}, + {mysql.InsertPriv, "", "", "", nil, false, "", false}, + {mysql.UpdatePriv, "", "", "", nil, false, "", false}, + {mysql.DeletePriv, "", "", "", nil, false, "", false}, + {mysql.CreatePriv, "", "", "", nil, false, "", false}, + {mysql.DropPriv, "", "", "", nil, false, "", false}, + {mysql.ProcessPriv, "", "", "", nil, false, "", false}, + {mysql.ReferencesPriv, "", "", "", nil, false, "", false}, + {mysql.AlterPriv, "", "", "", nil, false, "", false}, + {mysql.ShowDBPriv, "", "", "", nil, false, "", false}, + {mysql.SuperPriv, "", "", "", nil, false, "", false}, + {mysql.ExecutePriv, "", "", "", nil, false, "", false}, + {mysql.IndexPriv, "", "", "", nil, false, "", false}, + {mysql.CreateUserPriv, "", "", "", nil, false, "", false}, + {mysql.CreateTablespacePriv, "", "", "", nil, false, "", false}, + {mysql.TriggerPriv, "", "", "", nil, false, "", false}, + {mysql.CreateViewPriv, "", "", "", nil, false, "", false}, + {mysql.ShowViewPriv, "", "", "", nil, false, "", false}, + {mysql.CreateRolePriv, "", "", "", nil, false, "", false}, + {mysql.DropRolePriv, "", "", "", nil, false, "", false}, + {mysql.CreateTMPTablePriv, "", "", "", nil, false, "", false}, + {mysql.LockTablesPriv, "", "", "", nil, false, "", false}, + {mysql.CreateRoutinePriv, "", "", "", nil, false, "", false}, + {mysql.AlterRoutinePriv, "", "", "", nil, false, "", false}, + {mysql.EventPriv, "", "", "", nil, false, "", false}, + {mysql.ShutdownPriv, "", "", "", nil, false, "", false}, + {mysql.ReloadPriv, "", "", "", nil, false, "", false}, + {mysql.FilePriv, "", "", "", nil, false, "", false}, + {mysql.ConfigPriv, "", "", "", nil, false, "", false}, + {mysql.ReplicationClientPriv, "", "", "", nil, false, "", false}, + {mysql.ReplicationSlavePriv, "", "", "", nil, false, "", false}, + {mysql.GrantPriv, "", "", "", nil, false, "", false}, + }, + }, { sql: `grant select on test.ttt to 'test'@'%'`, ans: []visitInfo{ @@ -1104,6 +1141,57 @@ func (s *testPlanSuite) TestVisitInfo(c *C) { {mysql.ShowViewPriv, "test", "", "", nil, false, "", false}, }, }, + { + sql: `revoke connection_admin on *.* from u1`, + ans: []visitInfo{ + {mysql.ExtendedPriv, "", "", "", nil, false, "CONNECTION_ADMIN", true}, + }, + }, + { + sql: `revoke connection_admin, select on *.* from u1`, + ans: []visitInfo{ + {mysql.ExtendedPriv, "", "", "", nil, false, "CONNECTION_ADMIN", true}, + {mysql.SelectPriv, "", "", "", nil, false, "", false}, + {mysql.GrantPriv, "", "", "", nil, false, "", false}, + }, + }, + { + sql: `revoke all privileges on *.* FROM u1`, + ans: []visitInfo{ + {mysql.SelectPriv, "", "", "", nil, false, "", false}, + {mysql.InsertPriv, "", "", "", nil, false, "", false}, + {mysql.UpdatePriv, "", "", "", nil, false, "", false}, + {mysql.DeletePriv, "", "", "", nil, false, "", false}, + {mysql.CreatePriv, "", "", "", nil, false, "", false}, + {mysql.DropPriv, "", "", "", nil, false, "", false}, + {mysql.ProcessPriv, "", "", "", nil, false, "", false}, + {mysql.ReferencesPriv, "", "", "", nil, false, "", false}, + {mysql.AlterPriv, "", "", "", nil, false, "", false}, + {mysql.ShowDBPriv, "", "", "", nil, false, "", false}, + {mysql.SuperPriv, "", "", "", nil, false, "", false}, + {mysql.ExecutePriv, "", "", "", nil, false, "", false}, + {mysql.IndexPriv, "", "", "", nil, false, "", false}, + {mysql.CreateUserPriv, "", "", "", nil, false, "", false}, + {mysql.CreateTablespacePriv, "", "", "", nil, false, "", false}, + {mysql.TriggerPriv, "", "", "", nil, false, "", false}, + {mysql.CreateViewPriv, "", "", "", nil, false, "", false}, + {mysql.ShowViewPriv, "", "", "", nil, false, "", false}, + {mysql.CreateRolePriv, "", "", "", nil, false, "", false}, + {mysql.DropRolePriv, "", "", "", nil, false, "", false}, + {mysql.CreateTMPTablePriv, "", "", "", nil, false, "", false}, + {mysql.LockTablesPriv, "", "", "", nil, false, "", false}, + {mysql.CreateRoutinePriv, "", "", "", nil, false, "", false}, + {mysql.AlterRoutinePriv, "", "", "", nil, false, "", false}, + {mysql.EventPriv, "", "", "", nil, false, "", false}, + {mysql.ShutdownPriv, "", "", "", nil, false, "", false}, + {mysql.ReloadPriv, "", "", "", nil, false, "", false}, + {mysql.FilePriv, "", "", "", nil, false, "", false}, + {mysql.ConfigPriv, "", "", "", nil, false, "", false}, + {mysql.ReplicationClientPriv, "", "", "", nil, false, "", false}, + {mysql.ReplicationSlavePriv, "", "", "", nil, false, "", false}, + {mysql.GrantPriv, "", "", "", nil, false, "", false}, + }, + }, { sql: `set password for 'root'@'%' = 'xxxxx'`, ans: []visitInfo{}, diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index d035835e86989..eaa327c862d66 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -2264,13 +2264,19 @@ func collectVisitInfoFromRevokeStmt(sctx sessionctx.Context, vi []visitInfo, stm // and you must have the privileges that you are granting. dbName := stmt.Level.DBName tableName := stmt.Level.TableName - if dbName == "" { + // This supports a local revoke SELECT on tablename, but does + // not add dbName to the visitInfo of a *.* grant. + if dbName == "" && stmt.Level.Level != ast.GrantLevelGlobal { dbName = sctx.GetSessionVars().CurrentDB } - vi = appendVisitInfo(vi, mysql.GrantPriv, dbName, tableName, "", nil) - + var nonDynamicPrivilege bool var allPrivs []mysql.PrivilegeType for _, item := range stmt.Privs { + if item.Priv == mysql.ExtendedPriv { + vi = appendDynamicVisitInfo(vi, strings.ToUpper(item.Name), true, nil) // verified in MySQL: requires the dynamic grant option to revoke. + continue + } + nonDynamicPrivilege = true if item.Priv == mysql.AllPriv { switch stmt.Level.Level { case ast.GrantLevelGlobal: @@ -2288,7 +2294,11 @@ func collectVisitInfoFromRevokeStmt(sctx sessionctx.Context, vi []visitInfo, stm for _, priv := range allPrivs { vi = appendVisitInfo(vi, priv, dbName, tableName, "", nil) } - + if nonDynamicPrivilege { + // Dynamic privileges use their own GRANT OPTION. If there were any non-dynamic privilege requests, + // we need to attach the "GLOBAL" version of the GRANT OPTION. + vi = appendVisitInfo(vi, mysql.GrantPriv, dbName, tableName, "", nil) + } return vi } @@ -2297,7 +2307,9 @@ func collectVisitInfoFromGrantStmt(sctx sessionctx.Context, vi []visitInfo, stmt // and you must have the privileges that you are granting. dbName := stmt.Level.DBName tableName := stmt.Level.TableName - if dbName == "" { + // This supports a local revoke SELECT on tablename, but does + // not add dbName to the visitInfo of a *.* grant. + if dbName == "" && stmt.Level.Level != ast.GrantLevelGlobal { dbName = sctx.GetSessionVars().CurrentDB } var nonDynamicPrivilege bool