Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: Implementing RENAME USER #24413

Merged
merged 51 commits into from
May 19, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
ccc82aa
*: RENAME USER
mjonss May 5, 2021
b8cbec7
Reverted go.mod and go.sum
mjonss May 5, 2021
d320156
*: fix error reporting for RENAME USER when new user exists
mjonss May 6, 2021
4bf8565
RENAME USER - wip issue with panic during atomic rename/swap
mjonss May 7, 2021
6f161ba
Fixed panic due to missing TimeZone in ExecuteInternal.
mjonss May 8, 2021
22017fd
RENAME USER fixed unused variable
mjonss May 8, 2021
06be996
RENAME USER code cleanup
mjonss May 10, 2021
807bc86
RENAME USER added VisitInfo unit test
mjonss May 10, 2021
7e24101
RENAME USER, minor test case change
mjonss May 10, 2021
14babbd
*: RENAME USER
mjonss May 5, 2021
4c74304
Reverted go.mod and go.sum
mjonss May 5, 2021
cd74931
*: fix error reporting for RENAME USER when new user exists
mjonss May 6, 2021
f211e15
RENAME USER - wip issue with panic during atomic rename/swap
mjonss May 7, 2021
a8a2161
Fixed panic due to missing TimeZone in ExecuteInternal.
mjonss May 8, 2021
690bea9
RENAME USER fixed unused variable
mjonss May 8, 2021
5a4ccab
RENAME USER code cleanup
mjonss May 10, 2021
0f99e3d
RENAME USER added VisitInfo unit test
mjonss May 10, 2021
f304980
RENAME USER, minor test case change
mjonss May 10, 2021
807d6b2
Merge remote-tracking branch 'origin/mjonss/rename_user' into mjonss/…
mjonss May 10, 2021
d4f3a92
*: RENAME USER
mjonss May 5, 2021
1e9b1a5
Reverted go.mod and go.sum
mjonss May 5, 2021
9f152d1
*: fix error reporting for RENAME USER when new user exists
mjonss May 6, 2021
771e3e0
RENAME USER - wip issue with panic during atomic rename/swap
mjonss May 7, 2021
b172de5
Fixed panic due to missing TimeZone in ExecuteInternal.
mjonss May 8, 2021
6f52291
RENAME USER fixed unused variable
mjonss May 8, 2021
0d01430
RENAME USER code cleanup
mjonss May 10, 2021
6e7056d
RENAME USER added VisitInfo unit test
mjonss May 10, 2021
03c31b1
RENAME USER, minor test case change
mjonss May 10, 2021
4f3beed
*: RENAME USER
mjonss May 5, 2021
b1f5e51
Reverted go.mod and go.sum
mjonss May 5, 2021
8fcd837
RENAME USER - wip issue with panic during atomic rename/swap
mjonss May 7, 2021
5d671e7
Fixed panic due to missing TimeZone in ExecuteInternal.
mjonss May 8, 2021
2367828
RENAME USER fixed unused variable
mjonss May 8, 2021
8ec68c2
RENAME USER code cleanup
mjonss May 10, 2021
b3a36ac
RENAME USER, minor test case change
mjonss May 10, 2021
f4fe928
RENAME USER, test cleanup
mjonss May 10, 2021
e7315f7
Merge branch 'master' into mjonss/rename_user
mjonss May 10, 2021
66115cf
Merge branch 'mjonss/rename_user' of github.com:mjonss/tidb into mjon…
mjonss May 10, 2021
3f4c242
RENAME USER, removed non-needed comment
mjonss May 10, 2021
407310a
RENAME USER reverted go.sum changes
mjonss May 10, 2021
fabdd2c
RENAME USER reverted go.mod changes
mjonss May 10, 2021
ad610c8
RENAME USER, removed a temporary fix for internal decoding issue
mjonss May 11, 2021
2b76156
RENAME USER, non-logic change, adressed review comments
mjonss May 17, 2021
739a1f4
Merge branch 'master' into mjonss/rename_user
mjonss May 18, 2021
fafa335
Merge branch 'master' into mjonss/rename_user
ti-chi-bot May 19, 2021
7645dee
Merge branch 'master' into mjonss/rename_user
ti-chi-bot May 19, 2021
ab324bd
Merge branch 'master' into mjonss/rename_user
ti-chi-bot May 19, 2021
8f6d99a
Merge branch 'master' into mjonss/rename_user
ti-chi-bot May 19, 2021
1a23a18
Merge branch 'master' into mjonss/rename_user
ti-chi-bot May 19, 2021
d9f7e09
Merge branch 'master' into mjonss/rename_user
ti-chi-bot May 19, 2021
3ea44b3
Merge branch 'master' into mjonss/rename_user
ti-chi-bot May 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 140 additions & 1 deletion executor/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ func (e *SimpleExec) Next(ctx context.Context, req *chunk.Chunk) (err error) {
err = e.executeAlterUser(x)
case *ast.DropUserStmt:
err = e.executeDropUser(x)
case *ast.RenameUserStmt:
err = e.executeRenameUser(x)
case *ast.SetPwdStmt:
err = e.executeSetPwd(x)
case *ast.KillStmt:
Expand Down Expand Up @@ -1048,6 +1050,143 @@ func (e *SimpleExec) executeGrantRole(s *ast.GrantRoleStmt) error {
return nil
}

// Should cover same internal mysql.* tables as DROP USER, so this function is very similar
func (e *SimpleExec) executeRenameUser(s *ast.RenameUserStmt) error {
// Check privileges.
// Check `CREATE USER` privilege.
// TODO: Also allow UPDATE privilege for the mysql system schema?
if !config.GetGlobalConfig().Security.SkipGrantTable {
checker := privilege.GetPrivilegeManager(e.ctx)
if checker == nil {
return errors.New("miss privilege checker")
}
activeRoles := e.ctx.GetSessionVars().ActiveRoles
if !checker.RequestVerification(activeRoles, mysql.SystemDB, "", "", mysql.UpdatePriv) &&
!checker.RequestVerification(activeRoles, "", "", "", mysql.CreateUserPriv) {
return core.ErrSpecificAccessDenied.GenWithStackByArgs("CREATE USER or UPDATE on mysql.*")
}
}
mjonss marked this conversation as resolved.
Show resolved Hide resolved

failedUsers := make([]string, 0, len(s.UserToUsers))
mjonss marked this conversation as resolved.
Show resolved Hide resolved
sysSession, err := e.getSysSession()
defer e.releaseSysSession(sysSession)
if err != nil {
return err
}
sqlExecutor := sysSession.(sqlexec.SQLExecutor)

if _, err := sqlExecutor.ExecuteInternal(context.TODO(), "begin"); err != nil {
return err
}

for _, userToUser := range s.UserToUsers {
oldUser, newUser := userToUser.OldUser, userToUser.NewUser
exists, err := userExists(e.ctx, oldUser.Username, oldUser.Hostname)
if err != nil {
return err
}
if !exists {
failedUsers = append(failedUsers, oldUser.String())
break
}

exists, err = userExists(e.ctx, newUser.Username, newUser.Hostname)
if err != nil {
return err
}
if exists {
failedUsers = append(failedUsers, newUser.String())
break
}

// begin a transaction to rename a user.
// Could be restructured with an array of table, user/host columns and break/continue for easier maintenance.

if err = renameUserHostInSystemTable(sqlExecutor, mysql.UserTable, "User", "Host", userToUser); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 9 system tables to modify. Maybe you can put the params in an array and iterate the array to simplify the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, and that is why I also added a comment about it.

Do you want me to add the refactoring of DROP USER and the new code in this PR or in a separate PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer a separate PR.

failedUsers = append(failedUsers, oldUser.String())
break
}

// delete privileges from mysql.global_priv
if err = renameUserHostInSystemTable(sqlExecutor, mysql.GlobalPrivTable, "User", "Host", userToUser); err != nil {
failedUsers = append(failedUsers, oldUser.String())
if _, err := sqlExecutor.ExecuteInternal(context.TODO(), "rollback"); err != nil {
return err
}
continue
}

// delete privileges from mysql.db
if err = renameUserHostInSystemTable(sqlExecutor, mysql.DBTable, "User", "Host", userToUser); err != nil {
failedUsers = append(failedUsers, oldUser.String())
break
}

// delete privileges from mysql.tables_priv
if err = renameUserHostInSystemTable(sqlExecutor, mysql.TablePrivTable, "User", "Host", userToUser); err != nil {
failedUsers = append(failedUsers, oldUser.String())
break
}

// delete relationship from mysql.role_edges
if err = renameUserHostInSystemTable(sqlExecutor, mysql.RoleEdgeTable, "TO_USER", "TO_HOST", userToUser); err != nil {
failedUsers = append(failedUsers, oldUser.String())
break
}

if err = renameUserHostInSystemTable(sqlExecutor, mysql.RoleEdgeTable, "FROM_USER", "FROM_HOST", userToUser); err != nil {
failedUsers = append(failedUsers, oldUser.String())
// Should we really break here as in DROP USER? it should all be rolled back right for this Old to New rename?
// Since the FROM_USER/HOST is already done
break
}

// delete relationship from mysql.default_roles
if err = renameUserHostInSystemTable(sqlExecutor, mysql.DefaultRoleTable, "DEFAULT_ROLE_USER", "DEFAULT_ROLE_HOST", userToUser); err != nil {
failedUsers = append(failedUsers, oldUser.String())
break
}

if err = renameUserHostInSystemTable(sqlExecutor, mysql.DefaultRoleTable, "USER", "HOST", userToUser); err != nil {
failedUsers = append(failedUsers, oldUser.String())
break
}

// delete relationship from mysql.global_grants
// TODO: add global_grants into the parser
if err = renameUserHostInSystemTable(sqlExecutor, "global_grants", "User", "Host", userToUser); err != nil {
failedUsers = append(failedUsers, oldUser.String())
break
}

// WASHERE:
//TODO: need update columns_priv once we implement columns_priv functionality.
}

if len(failedUsers) == 0 {
if _, err := sqlExecutor.ExecuteInternal(context.TODO(), "commit"); err != nil {
return err
}
} else {
if _, err := sqlExecutor.ExecuteInternal(context.TODO(), "rollback"); err != nil {
return err
}
return ErrCannotUser.GenWithStackByArgs("RENAME USER", strings.Join(failedUsers, ","))
}
domain.GetDomain(e.ctx).NotifyUpdatePrivilege(e.ctx)
return nil
}

func renameUserHostInSystemTable(sqlExecutor sqlexec.SQLExecutor, tableName, usernameColumn, hostColumn string, users *ast.UserToUser) error {
sql := new(strings.Builder)
sqlexec.MustFormatSQL(sql, `UPDATE %n.%n SET %n = %?, %n = %? WHERE %n = %? and %n = %?;`,
mysql.SystemDB, tableName,
usernameColumn, users.NewUser.Username, hostColumn, users.NewUser.Hostname,
usernameColumn, users.OldUser.Username, hostColumn, users.OldUser.Hostname)
_, err := sqlExecutor.ExecuteInternal(context.TODO(), sql.String())
return err
}

func (e *SimpleExec) executeDropUser(s *ast.DropUserStmt) error {
// Check privileges.
// Check `CREATE USER` privilege.
Expand Down Expand Up @@ -1411,7 +1550,7 @@ func (e *SimpleExec) executeDropStats(s *ast.DropStatsStmt) (err error) {

func (e *SimpleExec) autoNewTxn() bool {
switch e.Statement.(type) {
case *ast.CreateUserStmt, *ast.AlterUserStmt, *ast.DropUserStmt:
case *ast.CreateUserStmt, *ast.AlterUserStmt, *ast.DropUserStmt, *ast.RenameUserStmt:
return true
}
return false
Expand Down
5 changes: 3 additions & 2 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,8 @@ func (b *PlanBuilder) Build(ctx context.Context, node ast.Node) (Plan, error) {
case *ast.BinlogStmt, *ast.FlushStmt, *ast.UseStmt, *ast.BRIEStmt,
*ast.BeginStmt, *ast.CommitStmt, *ast.RollbackStmt, *ast.CreateUserStmt, *ast.SetPwdStmt, *ast.AlterInstanceStmt,
*ast.GrantStmt, *ast.DropUserStmt, *ast.AlterUserStmt, *ast.RevokeStmt, *ast.KillStmt, *ast.DropStatsStmt,
*ast.GrantRoleStmt, *ast.RevokeRoleStmt, *ast.SetRoleStmt, *ast.SetDefaultRoleStmt, *ast.ShutdownStmt:
*ast.GrantRoleStmt, *ast.RevokeRoleStmt, *ast.SetRoleStmt, *ast.SetDefaultRoleStmt, *ast.ShutdownStmt,
*ast.RenameUserStmt:
return b.buildSimple(node.(ast.StmtNode))
case ast.DDLNode:
return b.buildDDL(ctx, x)
Expand Down Expand Up @@ -2262,7 +2263,7 @@ func (b *PlanBuilder) buildSimple(node ast.StmtNode) (Plan, error) {
case *ast.AlterInstanceStmt:
err := ErrSpecificAccessDenied.GenWithStack("SUPER")
b.visitInfo = appendVisitInfo(b.visitInfo, mysql.SuperPriv, "", "", "", err)
case *ast.AlterUserStmt:
case *ast.AlterUserStmt, *ast.RenameUserStmt: // TODO: Is RenameUserStmt needed here?
mjonss marked this conversation as resolved.
Show resolved Hide resolved
err := ErrSpecificAccessDenied.GenWithStackByArgs("CREATE USER")
b.visitInfo = appendVisitInfo(b.visitInfo, mysql.CreateUserPriv, "", "", "", err)
case *ast.GrantStmt:
Expand Down
3 changes: 2 additions & 1 deletion session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -2810,7 +2810,8 @@ func logStmt(execStmt *executor.ExecStmt, vars *variable.SessionVars) {
switch stmt := execStmt.StmtNode.(type) {
case *ast.CreateUserStmt, *ast.DropUserStmt, *ast.AlterUserStmt, *ast.SetPwdStmt, *ast.GrantStmt,
*ast.RevokeStmt, *ast.AlterTableStmt, *ast.CreateDatabaseStmt, *ast.CreateIndexStmt, *ast.CreateTableStmt,
*ast.DropDatabaseStmt, *ast.DropIndexStmt, *ast.DropTableStmt, *ast.RenameTableStmt, *ast.TruncateTableStmt:
*ast.DropDatabaseStmt, *ast.DropIndexStmt, *ast.DropTableStmt, *ast.RenameTableStmt, *ast.TruncateTableStmt,
*ast.RenameUserStmt:
user := vars.User
schemaVersion := vars.TxnCtx.SchemaVersion
if ss, ok := execStmt.StmtNode.(ast.SensitiveStmtNode); ok {
Expand Down