From 13797eeb4d188df9cbd67b1dfe39c59396faa0fc Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Fri, 29 Mar 2019 10:45:19 +0800 Subject: [PATCH 01/13] add set default role --- executor/simple.go | 137 +++++++++++++++++++++++++++++ executor/simple_test.go | 42 +++++++++ go.mod | 2 + go.sum | 2 + planner/core/planbuilder.go | 4 +- privilege/privilege.go | 3 + privilege/privileges/privileges.go | 11 +++ 7 files changed, 199 insertions(+), 2 deletions(-) diff --git a/executor/simple.go b/executor/simple.go index 8f645b176d2f5..659d6c3f603b6 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -87,11 +87,148 @@ func (e *SimpleExec) Next(ctx context.Context, req *chunk.RecordBatch) (err erro err = e.executeSetRole(x) case *ast.RevokeRoleStmt: err = e.executeRevokeRole(x) + case *ast.SetDefaultRoleStmt: + err = e.executeSetDefaultRole(x) } e.done = true return err } +func (e *SimpleExec) setDefaultRoleNone(s *ast.SetDefaultRoleStmt) error { + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { + return err + } + for _, u := range s.UserList { + if u.Hostname == "" { + u.Hostname = "%" + } + sql := fmt.Sprintf("DELETE IGNORE FROM mysql.default_roles WHERE USER='%s' AND HOST='%s';", u.Username, u.Hostname) + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) + if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + return rollbackErr + } + return err + } + } + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { + return err + } + return nil +} + +func (e *SimpleExec) setDefaultRoleRegular(s *ast.SetDefaultRoleStmt) error { + for _, user := range s.UserList { + exists, err := userExists(e.ctx, user.Username, user.Hostname) + if err != nil { + return err + } + if !exists { + return ErrCannotUser.GenWithStackByArgs("SET DEFAULT ROLE", user.String()) + } + } + for _, role := range s.RoleList { + exists, err := userExists(e.ctx, role.Username, role.Hostname) + if err != nil { + return err + } + if !exists { + return ErrCannotUser.GenWithStackByArgs("SET DEFAULT ROLE", role.String()) + } + } + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { + return err + } + for _, user := range s.UserList { + if user.Hostname == "" { + user.Hostname = "%" + } + sql := fmt.Sprintf("DELETE IGNORE FROM mysql.default_roles WHERE USER='%s' AND HOST='%s';", user.Username, user.Hostname) + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) + if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + return rollbackErr + } + return err + } + for _, role := range s.RoleList { + sql := fmt.Sprintf("INSERT IGNORE INTO mysql.default_roles values('%s', '%s', '%s', '%s');", user.Hostname, user.Username, role.Hostname, role.Username) + checker := privilege.GetPrivilegeManager(e.ctx) + ok := checker.FindEdge(e.ctx, role, user) + if ok { + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) + if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + return rollbackErr + } + return err + } + } else { + if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + return rollbackErr + } + return ErrRoleNotGranted.GenWithStackByArgs(role.String(), user.String()) + } + } + } + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { + return err + } + return nil +} + +func (e *SimpleExec) setDefaultRoleAll(s *ast.SetDefaultRoleStmt) error { + for _, user := range s.UserList { + exists, err := userExists(e.ctx, user.Username, user.Hostname) + if err != nil { + return err + } + if !exists { + return ErrCannotUser.GenWithStackByArgs("SET DEFAULT ROLE", user.String()) + } + } + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { + return err + } + for _, user := range s.UserList { + if user.Hostname == "" { + user.Hostname = "%" + } + sql := fmt.Sprintf("DELETE IGNORE FROM mysql.default_roles WHERE USER='%s' AND HOST='%s';", user.Username, user.Hostname) + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) + if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + return rollbackErr + } + return err + } + sql = fmt.Sprintf("INSERT IGNORE INTO mysql.default_roles(HOST,USER,DEFAULT_ROLE_HOST,DEFAULT_ROLE_USER) "+ + "SELECT TO_HOST,TO_USER,FROM_HOST,FROM_USER FROM mysql.role_edges WHERE TO_HOST='%s' AND TO_USER='%s';", user.Hostname, user.Username) + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + return rollbackErr + } + return err + } + } + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { + return err + } + return nil +} + +func (e *SimpleExec) executeSetDefaultRole(s *ast.SetDefaultRoleStmt) error { + switch s.SetRoleOpt { + case ast.SetRoleAll: + return e.setDefaultRoleAll(s) + case ast.SetRoleNone: + return e.setDefaultRoleNone(s) + case ast.SetRoleRegular: + return e.setDefaultRoleRegular(s) + } + return nil +} + func (e *SimpleExec) executeSetRole(s *ast.SetRoleStmt) error { checkDup := make(map[string]*auth.RoleIdentity, len(s.RoleList)) // Check whether RoleNameList contain duplicate role name. diff --git a/executor/simple_test.go b/executor/simple_test.go index 6cc38f1778af5..10368349859ef 100644 --- a/executor/simple_test.go +++ b/executor/simple_test.go @@ -160,6 +160,48 @@ func (s *testSuite3) TestRole(c *C) { tk.MustExec(dropRoleSQL) } +func (s *testSuite3) TestDefaultRole(c *C) { + tk := testkit.NewTestKit(c, s.store) + + createRoleSQL := `CREATE ROLE r_1, r_2, r_3, u_1;` + tk.MustExec(createRoleSQL) + + tk.MustExec("insert into mysql.role_edges (FROM_HOST,FROM_USER,TO_HOST,TO_USER) values ('%','r_1','%','u_1')") + tk.MustExec("insert into mysql.role_edges (FROM_HOST,FROM_USER,TO_HOST,TO_USER) values ('%','r_2','%','u_1')") + + tk.MustExec("flush privileges;") + + setRoleSQL := `SET DEFAULT ROLE r_3 TO u_1;` + _, err := tk.Exec(setRoleSQL) + c.Check(err, NotNil) + + setRoleSQL = `SET DEFAULT ROLE r_1 TO u_1;` + _, err = tk.Exec(setRoleSQL) + c.Check(err, IsNil) + result := tk.MustQuery(`SELECT DEFAULT_ROLE_USER FROM mysql.default_roles WHERE USER="u_1"`) + result.Check(testkit.Rows("r_1")) + setRoleSQL = `SET DEFAULT ROLE r_2 TO u_1;` + _, err = tk.Exec(setRoleSQL) + c.Check(err, IsNil) + result = tk.MustQuery(`SELECT DEFAULT_ROLE_USER FROM mysql.default_roles WHERE USER="u_1"`) + result.Check(testkit.Rows("r_2")) + + setRoleSQL = `SET DEFAULT ROLE ALL TO u_1;` + _, err = tk.Exec(setRoleSQL) + c.Check(err, IsNil) + result = tk.MustQuery(`SELECT DEFAULT_ROLE_USER FROM mysql.default_roles WHERE USER="u_1"`) + result.Check(testkit.Rows("r_1", "r_2")) + + setRoleSQL = `SET DEFAULT ROLE NONE TO u_1;` + _, err = tk.Exec(setRoleSQL) + c.Check(err, IsNil) + result = tk.MustQuery(`SELECT DEFAULT_ROLE_USER FROM mysql.default_roles WHERE USER="u_1"`) + result.Check(nil) + + dropRoleSQL := `DROP USER r_1, r_2, r_3, u_1;` + tk.MustExec(dropRoleSQL) +} + func (s *testSuite3) TestUser(c *C) { tk := testkit.NewTestKit(c, s.store) // Make sure user test not in mysql.User. diff --git a/go.mod b/go.mod index ca535624af6d6..9bd4968665bda 100644 --- a/go.mod +++ b/go.mod @@ -90,3 +90,5 @@ require ( sourcegraph.com/sourcegraph/appdash v0.0.0-20180531100431-4c381bd170b4 sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 ) + +replace github.com/pingcap/parser => github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628 diff --git a/go.sum b/go.sum index 6cf70f55d8c18..1574043a04a4e 100644 --- a/go.sum +++ b/go.sum @@ -76,6 +76,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.1 h1:3scN4iuXkNOyP98jF55Lv8a9j1o/Iwv github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628 h1:Ty1H5LGje5mrZJ1kpHu8qcpkqbwSE9vwGw4b66dr90s= +github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 5213025746245..bd408d75f952f 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -268,7 +268,7 @@ func (b *PlanBuilder) Build(node ast.Node) (Plan, error) { case *ast.BinlogStmt, *ast.FlushStmt, *ast.UseStmt, *ast.BeginStmt, *ast.CommitStmt, *ast.RollbackStmt, *ast.CreateUserStmt, *ast.SetPwdStmt, *ast.GrantStmt, *ast.DropUserStmt, *ast.AlterUserStmt, *ast.RevokeStmt, *ast.KillStmt, *ast.DropStatsStmt, - *ast.GrantRoleStmt, *ast.RevokeRoleStmt, *ast.SetRoleStmt: + *ast.GrantRoleStmt, *ast.RevokeRoleStmt, *ast.SetRoleStmt, *ast.SetDefaultRoleStmt: return b.buildSimple(node.(ast.StmtNode)) case ast.DDLNode: return b.buildDDL(x) @@ -1095,7 +1095,7 @@ func (b *PlanBuilder) buildSimple(node ast.StmtNode) (Plan, error) { err := ErrSpecificAccessDenied.GenWithStackByArgs("CREATE USER") b.visitInfo = appendVisitInfo(b.visitInfo, mysql.CreateUserPriv, "", "", "", err) } - case *ast.AlterUserStmt: + case *ast.AlterUserStmt, *ast.SetDefaultRoleStmt: err := ErrSpecificAccessDenied.GenWithStackByArgs("CREATE USER") b.visitInfo = appendVisitInfo(b.visitInfo, mysql.CreateUserPriv, "", "", "", err) case *ast.GrantStmt: diff --git a/privilege/privilege.go b/privilege/privilege.go index b6aa136c6c806..00cfefd13542c 100644 --- a/privilege/privilege.go +++ b/privilege/privilege.go @@ -56,6 +56,9 @@ type Manager interface { // ActiveRoles active roles for current session. // The first illegal role will be returned. ActiveRoles(ctx sessionctx.Context, roleList []*auth.RoleIdentity) (bool, string) + + // FindEdge find if there is an edge between role and user. + FindEdge(ctx sessionctx.Context, role *auth.RoleIdentity, user *auth.UserIdentity) bool } const key keyType = 0 diff --git a/privilege/privileges/privileges.go b/privilege/privileges/privileges.go index a8d8a6cd7d816..90d845235b897 100644 --- a/privilege/privileges/privileges.go +++ b/privilege/privileges/privileges.go @@ -206,3 +206,14 @@ func (p *UserPrivileges) ActiveRoles(ctx sessionctx.Context, roleList []*auth.Ro ctx.GetSessionVars().ActiveRoles = roleList return true, "" } + +// FindEdge implements privilege.Manager FindRelationship interface. +func (p *UserPrivileges) FindEdge(ctx sessionctx.Context, role *auth.RoleIdentity, user *auth.UserIdentity) bool { + mysqlPrivilege := p.Handle.Get() + ok := mysqlPrivilege.FindRole(user.Username, user.Hostname, role) + if !ok { + logutil.Logger(context.Background()).Error("find role failed", zap.Stringer("role", role)) + return false + } + return true +} From 9e29a95fc2c6a33796c2be094cd9279ff8048d01 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Mon, 1 Apr 2019 14:12:20 +0800 Subject: [PATCH 02/13] update parser --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 9bd4968665bda..90fa6635da4d3 100644 --- a/go.mod +++ b/go.mod @@ -91,4 +91,4 @@ require ( sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 ) -replace github.com/pingcap/parser => github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628 +replace github.com/pingcap/parser => github.com/imtbkcat/parser v0.0.0-20190401060923-2536da2cf10a diff --git a/go.sum b/go.sum index 1574043a04a4e..416f4cfd20cf2 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628 h1:Ty1H5LGje5mrZJ1kpHu8qcpkqbwSE9vwGw4b66dr90s= github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= +github.com/imtbkcat/parser v0.0.0-20190401060923-2536da2cf10a h1:sTRC+kfn85I1dtr9DyfqquHuzxsYjXK6E33RnzlxkMU= +github.com/imtbkcat/parser v0.0.0-20190401060923-2536da2cf10a/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= From b8237f1358ab273c4fb7ec42b889fce37aa23d37 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Mon, 1 Apr 2019 15:21:15 +0800 Subject: [PATCH 03/13] add load default role --- session/session.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/session/session.go b/session/session.go index ecf1ac65d7c5e..d547406002111 100644 --- a/session/session.go +++ b/session/session.go @@ -1196,6 +1196,21 @@ func (s *session) Auth(user *auth.UserIdentity, authentication []byte, salt []by user.AuthUsername, user.AuthHostname, success = pm.ConnectionVerification(user.Username, user.Hostname, authentication, salt) if success { s.sessionVars.User = user + // Load default active roles if login successed. + sql := `SELECT DEFAULT_ROLE_HOST, DEFAULT_ROLE_USER FROM %s.%s WHERE HOST='%s' AND USER='%s';` + sql = fmt.Sprintf(sql, mysql.SystemDB, mysql.DefaultRoleTable, user.AuthHostname, user.AuthUsername) + rows, _, err := s.ExecRestrictedSQL(s, sql) + if err != nil { + logutil.Logger(context.Background()).Error("cannot load default role from mysql.default_roles", + zap.Stringer("user", user)) + return false + } + roleList := make([]*auth.RoleIdentity, 0, 10) + for _, r := range rows { + roleHost, roleName := r.GetString(0), r.GetString(1) + roleList = append(roleList, &auth.RoleIdentity{Username: roleName, Hostname: roleHost}) + } + s.sessionVars.ActiveRoles = roleList return true } else if user.Hostname == variable.DefHostname { logutil.Logger(context.Background()).Error("user connection verification failed", @@ -1213,6 +1228,21 @@ func (s *session) Auth(user *auth.UserIdentity, authentication []byte, salt []by AuthUsername: u, AuthHostname: h, } + // Load default active roles if login successed. + sql := `SELECT DEFAULT_ROLE_HOST, DEFAULT_ROLE_USER FROM %s.%s WHERE HOST='%s' AND USER='%s';` + sql = fmt.Sprintf(sql, mysql.SystemDB, mysql.DefaultRoleTable, h, u) + rows, _, err := s.ExecRestrictedSQL(s, sql) + if err != nil { + logutil.Logger(context.Background()).Error("cannot load default role from mysql.default_roles", + zap.Stringer("user", user)) + return false + } + roleList := make([]*auth.RoleIdentity, 0, 10) + for _, r := range rows { + roleHost, roleName := r.GetString(0), r.GetString(1) + roleList = append(roleList, &auth.RoleIdentity{Username: roleName, Hostname: roleHost}) + } + s.sessionVars.ActiveRoles = roleList return true } } From fb75c522a36b7a5aa8fb03d1d6f9b4f3380c01eb Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Thu, 4 Apr 2019 12:16:13 +0800 Subject: [PATCH 04/13] update parser --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 90fa6635da4d3..b3fe7833e6f0b 100644 --- a/go.mod +++ b/go.mod @@ -91,4 +91,4 @@ require ( sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 ) -replace github.com/pingcap/parser => github.com/imtbkcat/parser v0.0.0-20190401060923-2536da2cf10a +replace github.com/pingcap/parser => github.com/imtbkcat/parser v0.0.0-20190404041311-8e362e03d235 diff --git a/go.sum b/go.sum index 416f4cfd20cf2..15d4c81ff37d7 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,8 @@ github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628 h1:Ty1H5LGje5mrZJ1 github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= github.com/imtbkcat/parser v0.0.0-20190401060923-2536da2cf10a h1:sTRC+kfn85I1dtr9DyfqquHuzxsYjXK6E33RnzlxkMU= github.com/imtbkcat/parser v0.0.0-20190401060923-2536da2cf10a/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= +github.com/imtbkcat/parser v0.0.0-20190404041311-8e362e03d235 h1:2hjtxVn3zBjpZls8R672qvluA4gmvqyQcm38NTI7v/Y= +github.com/imtbkcat/parser v0.0.0-20190404041311-8e362e03d235/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= From fd1f0f4c6c297df615b85d56ae26ee37f8193417 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Tue, 9 Apr 2019 17:38:54 +0800 Subject: [PATCH 05/13] cache defaule role table --- executor/simple.go | 3 +- privilege/privilege.go | 3 + privilege/privileges/cache.go | 73 +++++++++++-- privilege/privileges/privileges.go | 6 ++ privilege/privileges/privileges_test.go | 23 ++++ res.txt | 135 ++++++++++++++++++++++++ server/server_test.go | 16 +++ session/session.go | 32 +----- 8 files changed, 253 insertions(+), 38 deletions(-) create mode 100644 res.txt diff --git a/executor/simple.go b/executor/simple.go index 659d6c3f603b6..d009f6dd7d99c 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -226,7 +226,8 @@ func (e *SimpleExec) executeSetDefaultRole(s *ast.SetDefaultRoleStmt) error { case ast.SetRoleRegular: return e.setDefaultRoleRegular(s) } - return nil + err := domain.GetDomain(e.ctx).PrivilegeHandle().Update(e.ctx.(sessionctx.Context)) + return err } func (e *SimpleExec) executeSetRole(s *ast.SetRoleStmt) error { diff --git a/privilege/privilege.go b/privilege/privilege.go index 00cfefd13542c..e94ae4e9f8dae 100644 --- a/privilege/privilege.go +++ b/privilege/privilege.go @@ -59,6 +59,9 @@ type Manager interface { // FindEdge find if there is an edge between role and user. FindEdge(ctx sessionctx.Context, role *auth.RoleIdentity, user *auth.UserIdentity) bool + + // GetDefaultRoles returns all default roles for certain user. + GetDefaultRoles(user, host string) []*auth.RoleIdentity } const key keyType = 0 diff --git a/privilege/privileges/cache.go b/privilege/privileges/cache.go index 2731f6f39dad1..07055813ae2e3 100644 --- a/privilege/privileges/cache.go +++ b/privilege/privileges/cache.go @@ -68,7 +68,7 @@ type dbRecord struct { User string Privileges mysql.PrivilegeType - // patChars is compiled from Host and DB, cached for pattern match performance. + // hostPatChars is compiled from Host and DB, cached for pattern match performance. hostPatChars []byte hostPatTypes []byte @@ -105,7 +105,19 @@ type columnsPrivRecord struct { patTypes []byte } -// RoleGraphEdgesTable is used to cache relationship between and role. +// defaultRoleRecord is used to cache mysql.default_roles +type defaultRoleRecord struct { + Host string + User string + DefaultRoleUser string + DefaultRoleHost string + + // patChars is compiled from Host, cached for pattern match performance. + patChars []byte + patTypes []byte +} + +// roleGraphEdgesTable is used to cache relationship between and role. type roleGraphEdgesTable struct { roleList map[string]bool } @@ -125,11 +137,12 @@ func (g roleGraphEdgesTable) Find(user, host string) bool { // MySQLPrivilege is the in-memory cache of mysql privilege tables. type MySQLPrivilege struct { - User []UserRecord - DB []dbRecord - TablesPriv []tablesPrivRecord - ColumnsPriv []columnsPrivRecord - RoleGraph map[string]roleGraphEdgesTable + User []UserRecord + DB []dbRecord + TablesPriv []tablesPrivRecord + ColumnsPriv []columnsPrivRecord + DefaultRoles []defaultRoleRecord + RoleGraph map[string]roleGraphEdgesTable } // FindRole is used to detect whether there is edges between users and roles. @@ -166,6 +179,14 @@ func (p *MySQLPrivilege) LoadAll(ctx sessionctx.Context) error { log.Warn("mysql.tables_priv missing") } + err = p.LoadDefaultRoles(ctx) + if err != nil { + if !noSuchTable(err) { + return errors.Trace(err) + } + log.Warn("mysql.default_roles missing") + } + err = p.LoadColumnsPrivTable(ctx) if err != nil { if !noSuchTable(err) { @@ -316,6 +337,11 @@ func (p *MySQLPrivilege) LoadColumnsPrivTable(ctx sessionctx.Context) error { return p.loadTable(ctx, "select HIGH_PRIORITY Host,DB,User,Table_name,Column_name,Timestamp,Column_priv from mysql.columns_priv", p.decodeColumnsPrivTableRow) } +// LoadDefaultRoles loads the mysql.columns_priv table from database. +func (p *MySQLPrivilege) LoadDefaultRoles(ctx sessionctx.Context) error { + return p.loadTable(ctx, "select HOST, USER, DEFAULT_ROLE_HOST, DEFAULT_ROLE_USER from mysql.default_roles", p.decodeDefaultRoleTableRow) +} + func (p *MySQLPrivilege) loadTable(sctx sessionctx.Context, sql string, decodeTableRow func(chunk.Row, []*ast.ResultField) error) error { ctx := context.Background() @@ -455,6 +481,25 @@ func (p *MySQLPrivilege) decodeRoleEdgesTable(row chunk.Row, fs []*ast.ResultFie return nil } +func (p *MySQLPrivilege) decodeDefaultRoleTableRow(row chunk.Row, fs []*ast.ResultField) error { + var value defaultRoleRecord + for i, f := range fs { + switch { + case f.ColumnAsName.L == "host": + value.Host = row.GetString(i) + value.patChars, value.patTypes = stringutil.CompilePattern(value.Host, '\\') + case f.ColumnAsName.L == "user": + value.User = row.GetString(i) + case f.ColumnAsName.L == "default_role_host": + value.DefaultRoleHost = row.GetString(i) + case f.ColumnAsName.L == "default_role_user": + value.DefaultRoleUser = row.GetString(i) + } + } + p.DefaultRoles = append(p.DefaultRoles, value) + return nil +} + func (p *MySQLPrivilege) decodeColumnsPrivTableRow(row chunk.Row, fs []*ast.ResultField) error { var value columnsPrivRecord for i, f := range fs { @@ -522,6 +567,10 @@ func (record *columnsPrivRecord) match(user, host, db, table, col string) bool { patternMatch(host, record.patChars, record.patTypes) } +func (record *defaultRoleRecord) match(user, host string) bool { + return record.User == user && patternMatch(host, record.patChars, record.patTypes) +} + // patternMatch matches "%" the same way as ".*" in regular expression, for example, // "10.0.%" would match "10.0.1" "10.0.1.118" ... func patternMatch(str string, patChars, patTypes []byte) bool { @@ -766,6 +815,16 @@ func appendUserPrivilegesTableRow(rows [][]types.Datum, user UserRecord) [][]typ return rows } +func (p *MySQLPrivilege) getDefaultRoles(user, host string) []*auth.RoleIdentity { + ret := make([]*auth.RoleIdentity, 0) + for _, r := range p.DefaultRoles { + if r.match(user, host) { + ret = append(ret, &auth.RoleIdentity{Username: r.DefaultRoleUser, Hostname: r.DefaultRoleHost}) + } + } + return ret +} + // Handle wraps MySQLPrivilege providing thread safe access. type Handle struct { priv atomic.Value diff --git a/privilege/privileges/privileges.go b/privilege/privileges/privileges.go index 90d845235b897..9fdb675ac1b9a 100644 --- a/privilege/privileges/privileges.go +++ b/privilege/privileges/privileges.go @@ -217,3 +217,9 @@ func (p *UserPrivileges) FindEdge(ctx sessionctx.Context, role *auth.RoleIdentit } return true } + +func (p *UserPrivileges) GetDefaultRoles(user, host string) []*auth.RoleIdentity { + mysqlPrivilege := p.Handle.Get() + ret := mysqlPrivilege.getDefaultRoles(user, host) + return ret +} diff --git a/privilege/privileges/privileges_test.go b/privilege/privileges/privileges_test.go index faa66d18ea3ed..1767d6bdd761e 100644 --- a/privilege/privileges/privileges_test.go +++ b/privilege/privileges/privileges_test.go @@ -494,6 +494,29 @@ func (s *testPrivilegeSuite) TestGetEncodedPassword(c *C) { c.Assert(pc.GetEncodedPassword("test_encode_u", "localhost"), Equals, "*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B") } +func (s *testPrivilegeSuite) TestDefaultRoles(c *C) { + rootSe := newSession(c, s.store, s.dbName) + mustExec(c, rootSe, `CREATE USER 'testdefault'@'localhost';`) + mustExec(c, rootSe, `CREATE ROLE 'testdefault_r1'@'localhost', 'testdefault_r2'@'localhost';`) + mustExec(c, rootSe, `GRANT 'testdefault_r1'@'localhost', 'testdefault_r2'@'localhost' TO 'testdefault'@'localhost';`) + + se := newSession(c, s.store, s.dbName) + pc := privilege.GetPrivilegeManager(se) + + ret := pc.GetDefaultRoles("testdefault", "localhost") + c.Assert(len(ret), Equals, 0) + + mustExec(c, rootSe, `SET DEFAULT ROLE ALL TO 'testdefault'@'localhost';`) + mustExec(c, rootSe, `flush privileges;`) + ret = pc.GetDefaultRoles("testdefault", "localhost") + c.Assert(len(ret), Equals, 2) + + mustExec(c, rootSe, `SET DEFAULT ROLE NONE TO 'testdefault'@'localhost';`) + mustExec(c, rootSe, `flush privileges;`) + ret = pc.GetDefaultRoles("testdefault", "localhost") + c.Assert(len(ret), Equals, 0) +} + func mustExec(c *C, se session.Session, sql string) { _, err := se.Execute(context.Background(), sql) c.Assert(err, IsNil) diff --git a/res.txt b/res.txt new file mode 100644 index 0000000000000..c1ba107bf6cb6 --- /dev/null +++ b/res.txt @@ -0,0 +1,135 @@ +cat checklist.md +# Following the checklist saves the reviewers' time and gets your PR reviewed faster. + +# Self Review +Have you reviewed every line of your changes by yourself? + +# Test +Have you added enough test cases to cover the new feature or bug fix? +Also, add comments to describe your test cases. + +# Naming +Do function names keep consistent with its behavior? +Is it easy to infer the function's behavior by its name? + +# Comment +Is there any code that confuses the reviewer? +Add comments on them! You'll be asked to do so anyway. +Make sure there is no syntax or spelling error in your comments. +Some online syntax checking tools like Grammarly may be helpful. + +# Refactor +Is there any way to refactor the code to make it more readable? +If the refactoring touches a lot of existing code, send another PR to do it. + +# Single Purpose +Make sure the PR does only one thing and nothing else. + +# Diff Size +Make sure the diff size is no more than 500, split it into small PRs if it is too large. +GO111MODULE=on go list -f '{{ join .Imports "\n" }}' github.com/pingcap/tidb/store/tikv | grep ^github.com/pingcap/parser$ || exit 0; exit 1 +Running in native mode. +ok github.com/pingcap/tidb/bindinfo (cached) coverage: 76.4% of statements +? github.com/pingcap/tidb/cmd/benchdb [no test files] +? github.com/pingcap/tidb/cmd/benchfilesort [no test files] +? github.com/pingcap/tidb/cmd/benchkv [no test files] +? github.com/pingcap/tidb/cmd/benchraw [no test files] +? github.com/pingcap/tidb/cmd/explaintest [no test files] +ok github.com/pingcap/tidb/cmd/importer (cached) coverage: 1.5% of statements +? github.com/pingcap/tidb/cmd/pluginpkg [no test files] +ok github.com/pingcap/tidb/config (cached) coverage: 86.5% of statements +ok github.com/pingcap/tidb/ddl (cached) coverage: 80.2% of statements +ok github.com/pingcap/tidb/ddl/failtest (cached) coverage: 0.0% of statements +? github.com/pingcap/tidb/ddl/testutil [no test files] +? github.com/pingcap/tidb/ddl/util [no test files] +ok github.com/pingcap/tidb/distsql (cached) coverage: 70.2% of statements +ok github.com/pingcap/tidb/domain (cached) coverage: 50.8% of statements +ok github.com/pingcap/tidb/executor (cached) coverage: 79.3% of statements +ok github.com/pingcap/tidb/executor/aggfuncs (cached) coverage: 47.3% of statements +ok github.com/pingcap/tidb/executor/seqtest (cached) coverage: 0.0% of statements +ok github.com/pingcap/tidb/expression (cached) coverage: 76.9% of statements +ok github.com/pingcap/tidb/expression/aggregation (cached) coverage: 50.9% of statements +ok github.com/pingcap/tidb/infoschema (cached) coverage: 68.8% of statements +ok github.com/pingcap/tidb/infoschema/perfschema (cached) coverage: 77.1% of statements +ok github.com/pingcap/tidb/kv (cached) coverage: 72.5% of statements +ok github.com/pingcap/tidb/meta (cached) coverage: 76.9% of statements +ok github.com/pingcap/tidb/meta/autoid (cached) coverage: 80.1% of statements +ok github.com/pingcap/tidb/metrics (cached) coverage: 0.0% of statements +ok github.com/pingcap/tidb/owner (cached) coverage: 21.8% of statements +? github.com/pingcap/tidb/planner [no test files] +ok github.com/pingcap/tidb/planner/cascades (cached) coverage: 27.3% of statements +ok github.com/pingcap/tidb/planner/core (cached) coverage: 82.2% of statements +ok github.com/pingcap/tidb/planner/failtest (cached) coverage: 0.0% of statements +ok github.com/pingcap/tidb/planner/implementation (cached) coverage: 50.0% of statements +ok github.com/pingcap/tidb/planner/memo (cached) coverage: 88.2% of statements +? github.com/pingcap/tidb/planner/property [no test files] +ok github.com/pingcap/tidb/plugin (cached) coverage: 2.8% of statements +ok github.com/pingcap/tidb/plugin/conn_ip_example (cached) coverage: 0.0% of statements [no tests to run] +? github.com/pingcap/tidb/privilege [no test files] +ok github.com/pingcap/tidb/privilege/privileges (cached) coverage: 76.9% of statements +ok github.com/pingcap/tidb/server 6.492s coverage: 57.2% of statements +ok github.com/pingcap/tidb/session (cached) coverage: 80.7% of statements +? github.com/pingcap/tidb/sessionctx [no test files] +ok github.com/pingcap/tidb/sessionctx/binloginfo (cached) coverage: 90.0% of statements +? github.com/pingcap/tidb/sessionctx/stmtctx [no test files] +ok github.com/pingcap/tidb/sessionctx/variable (cached) coverage: 36.1% of statements +ok github.com/pingcap/tidb/statistics (cached) coverage: 85.3% of statements +ok github.com/pingcap/tidb/store (cached) coverage: 78.9% of statements +? github.com/pingcap/tidb/store/mockoracle [no test files] +ok github.com/pingcap/tidb/store/mockstore (cached) coverage: 66.7% of statements +ok github.com/pingcap/tidb/store/mockstore/mocktikv (cached) coverage: 27.6% of statements +ok github.com/pingcap/tidb/store/tikv (cached) coverage: 68.5% of statements +ok github.com/pingcap/tidb/store/tikv/gcworker (cached) coverage: 48.0% of statements +ok github.com/pingcap/tidb/store/tikv/latch (cached) coverage: 95.2% of statements +? github.com/pingcap/tidb/store/tikv/oracle [no test files] +ok github.com/pingcap/tidb/store/tikv/oracle/oracles (cached) coverage: 19.7% of statements +? github.com/pingcap/tidb/store/tikv/tikvrpc [no test files] +ok github.com/pingcap/tidb/structure (cached) coverage: 82.9% of statements +ok github.com/pingcap/tidb/table (cached) coverage: 77.8% of statements +ok github.com/pingcap/tidb/table/tables (cached) coverage: 69.2% of statements +ok github.com/pingcap/tidb/tablecodec (cached) coverage: 54.7% of statements +? github.com/pingcap/tidb/tidb-server [no test files] +ok github.com/pingcap/tidb/types (cached) coverage: 83.4% of statements +ok github.com/pingcap/tidb/types/json (cached) coverage: 84.7% of statements +ok github.com/pingcap/tidb/types/parser_driver (cached) coverage: 24.7% of statements +ok github.com/pingcap/tidb/util (cached) coverage: 44.8% of statements +ok github.com/pingcap/tidb/util/admin (cached) coverage: 79.6% of statements +ok github.com/pingcap/tidb/util/arena (cached) coverage: 100.0% of statements +ok github.com/pingcap/tidb/util/chunk (cached) coverage: 85.6% of statements +ok github.com/pingcap/tidb/util/codec (cached) coverage: 72.7% of statements +ok github.com/pingcap/tidb/util/disjointset (cached) coverage: 100.0% of statements +ok github.com/pingcap/tidb/util/encrypt (cached) coverage: 95.2% of statements +ok github.com/pingcap/tidb/util/execdetails (cached) coverage: 77.8% of statements +ok github.com/pingcap/tidb/util/filesort (cached) coverage: 84.0% of statements +ok github.com/pingcap/tidb/util/format (cached) coverage: 70.9% of statements +? github.com/pingcap/tidb/util/gcutil [no test files] +ok github.com/pingcap/tidb/util/hack (cached) coverage: 92.3% of statements +? github.com/pingcap/tidb/util/israce [no test files] +ok github.com/pingcap/tidb/util/kvcache (cached) coverage: 80.0% of statements +ok github.com/pingcap/tidb/util/kvencoder (cached) coverage: 78.9% of statements +ok github.com/pingcap/tidb/util/logutil 0.030s coverage: 67.2% of statements +ok github.com/pingcap/tidb/util/memory (cached) coverage: 79.1% of statements +ok github.com/pingcap/tidb/util/mock (cached) coverage: 13.3% of statements +ok github.com/pingcap/tidb/util/mvmap (cached) coverage: 86.6% of statements +ok github.com/pingcap/tidb/util/printer (cached) coverage: 88.3% of statements +ok github.com/pingcap/tidb/util/ranger (cached) coverage: 80.0% of statements +? github.com/pingcap/tidb/util/rowDecoder [no test files] +? github.com/pingcap/tidb/util/set [no test files] +? github.com/pingcap/tidb/util/signal [no test files] +? github.com/pingcap/tidb/util/sqlexec [no test files] +ok github.com/pingcap/tidb/util/stringutil (cached) coverage: 99.1% of statements +ok github.com/pingcap/tidb/util/sys/linux (cached) coverage: 100.0% of statements +ok github.com/pingcap/tidb/util/systimemon (cached) coverage: 100.0% of statements +ok github.com/pingcap/tidb/util/testkit (cached) coverage: 8.0% of statements +? github.com/pingcap/tidb/util/testleak [no test files] +ok github.com/pingcap/tidb/util/testutil (cached) coverage: 46.5% of statements +ok github.com/pingcap/tidb/util/timeutil (cached) coverage: 63.3% of statements +ok github.com/pingcap/tidb/util/tracing (cached) coverage: 93.3% of statements +CGO_ENABLED=1 GO111MODULE=on go build -ldflags '-X "github.com/pingcap/parser/mysql.TiDBReleaseVersion=v3.0.0-beta.1-44-g78f3ec97a-dirty" -X "github.com/pingcap/tidb/util/printer.TiDBBuildTS=2019-04-09 09:36:57" -X "github.com/pingcap/tidb/util/printer.TiDBGitHash=78f3ec97abe263369fe2c02fac738ae2794cfe59" -X "github.com/pingcap/tidb/util/printer.TiDBGitBranch=setdefault" -X "github.com/pingcap/tidb/util/printer.GoVersion=go version go1.12 darwin/amd64" ' -o bin/tidb-server tidb-server/main.go +skip building tidb-server, using existing binary: ../../bin/tidb-server +skip building importer, using existing binary: +building explain-test binary: ./explain_test +start tidb-server, log file: ./explain-test.out +tidb-server(PID: 31103) started +run all explain test cases +explaintest end diff --git a/server/server_test.go b/server/server_test.go index 57179c4c091dd..acbe70e17fd95 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -804,7 +804,10 @@ func runTestShowProcessList(c *C) { func runTestAuth(c *C) { runTests(c, nil, func(dbt *DBTest) { dbt.mustExec(`CREATE USER 'authtest'@'%' IDENTIFIED BY '123';`) + dbt.mustExec(`CREATE ROLE 'authtest_r1'@'%';`) dbt.mustExec(`GRANT ALL on test.* to 'authtest'`) + dbt.mustExec(`GRANT authtest_r1 to 'authtest'`) + dbt.mustExec(`SET DEFAULT ROLE authtest_r1 TO authtest`) dbt.mustExec(`FLUSH PRIVILEGES;`) }) runTests(c, func(config *mysql.Config) { @@ -823,6 +826,19 @@ func runTestAuth(c *C) { c.Assert(err, NotNil, Commentf("Wrong password should be failed")) db.Close() + // Test for loading active roles. + db, err = sql.Open("mysql", getDSN(func(config *mysql.Config) { + config.User = "authtest" + config.Passwd = "123" + })) + rows, err := db.Query("select current_role;") + c.Assert(rows.Next(), IsTrue) + var outA string + err = rows.Scan(&outA) + c.Assert(err, IsNil) + c.Assert(outA, Equals, "`authtest_r1`@`%`") + db.Close() + // Test login use IP that not exists in mysql.user. runTests(c, nil, func(dbt *DBTest) { dbt.mustExec(`CREATE USER 'authtest2'@'localhost' IDENTIFIED BY '123';`) diff --git a/session/session.go b/session/session.go index d547406002111..4fa3d25e251e1 100644 --- a/session/session.go +++ b/session/session.go @@ -1196,21 +1196,7 @@ func (s *session) Auth(user *auth.UserIdentity, authentication []byte, salt []by user.AuthUsername, user.AuthHostname, success = pm.ConnectionVerification(user.Username, user.Hostname, authentication, salt) if success { s.sessionVars.User = user - // Load default active roles if login successed. - sql := `SELECT DEFAULT_ROLE_HOST, DEFAULT_ROLE_USER FROM %s.%s WHERE HOST='%s' AND USER='%s';` - sql = fmt.Sprintf(sql, mysql.SystemDB, mysql.DefaultRoleTable, user.AuthHostname, user.AuthUsername) - rows, _, err := s.ExecRestrictedSQL(s, sql) - if err != nil { - logutil.Logger(context.Background()).Error("cannot load default role from mysql.default_roles", - zap.Stringer("user", user)) - return false - } - roleList := make([]*auth.RoleIdentity, 0, 10) - for _, r := range rows { - roleHost, roleName := r.GetString(0), r.GetString(1) - roleList = append(roleList, &auth.RoleIdentity{Username: roleName, Hostname: roleHost}) - } - s.sessionVars.ActiveRoles = roleList + s.sessionVars.ActiveRoles = pm.GetDefaultRoles(user.AuthUsername, user.AuthHostname) return true } else if user.Hostname == variable.DefHostname { logutil.Logger(context.Background()).Error("user connection verification failed", @@ -1228,21 +1214,7 @@ func (s *session) Auth(user *auth.UserIdentity, authentication []byte, salt []by AuthUsername: u, AuthHostname: h, } - // Load default active roles if login successed. - sql := `SELECT DEFAULT_ROLE_HOST, DEFAULT_ROLE_USER FROM %s.%s WHERE HOST='%s' AND USER='%s';` - sql = fmt.Sprintf(sql, mysql.SystemDB, mysql.DefaultRoleTable, h, u) - rows, _, err := s.ExecRestrictedSQL(s, sql) - if err != nil { - logutil.Logger(context.Background()).Error("cannot load default role from mysql.default_roles", - zap.Stringer("user", user)) - return false - } - roleList := make([]*auth.RoleIdentity, 0, 10) - for _, r := range rows { - roleHost, roleName := r.GetString(0), r.GetString(1) - roleList = append(roleList, &auth.RoleIdentity{Username: roleName, Hostname: roleHost}) - } - s.sessionVars.ActiveRoles = roleList + s.sessionVars.ActiveRoles = pm.GetDefaultRoles(u, h) return true } } From 11a9f30f0cd87277866d177ab19b0ef2557abd36 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Tue, 9 Apr 2019 17:39:54 +0800 Subject: [PATCH 06/13] remove test result --- res.txt | 135 -------------------------------------------------------- 1 file changed, 135 deletions(-) delete mode 100644 res.txt diff --git a/res.txt b/res.txt deleted file mode 100644 index c1ba107bf6cb6..0000000000000 --- a/res.txt +++ /dev/null @@ -1,135 +0,0 @@ -cat checklist.md -# Following the checklist saves the reviewers' time and gets your PR reviewed faster. - -# Self Review -Have you reviewed every line of your changes by yourself? - -# Test -Have you added enough test cases to cover the new feature or bug fix? -Also, add comments to describe your test cases. - -# Naming -Do function names keep consistent with its behavior? -Is it easy to infer the function's behavior by its name? - -# Comment -Is there any code that confuses the reviewer? -Add comments on them! You'll be asked to do so anyway. -Make sure there is no syntax or spelling error in your comments. -Some online syntax checking tools like Grammarly may be helpful. - -# Refactor -Is there any way to refactor the code to make it more readable? -If the refactoring touches a lot of existing code, send another PR to do it. - -# Single Purpose -Make sure the PR does only one thing and nothing else. - -# Diff Size -Make sure the diff size is no more than 500, split it into small PRs if it is too large. -GO111MODULE=on go list -f '{{ join .Imports "\n" }}' github.com/pingcap/tidb/store/tikv | grep ^github.com/pingcap/parser$ || exit 0; exit 1 -Running in native mode. -ok github.com/pingcap/tidb/bindinfo (cached) coverage: 76.4% of statements -? github.com/pingcap/tidb/cmd/benchdb [no test files] -? github.com/pingcap/tidb/cmd/benchfilesort [no test files] -? github.com/pingcap/tidb/cmd/benchkv [no test files] -? github.com/pingcap/tidb/cmd/benchraw [no test files] -? github.com/pingcap/tidb/cmd/explaintest [no test files] -ok github.com/pingcap/tidb/cmd/importer (cached) coverage: 1.5% of statements -? github.com/pingcap/tidb/cmd/pluginpkg [no test files] -ok github.com/pingcap/tidb/config (cached) coverage: 86.5% of statements -ok github.com/pingcap/tidb/ddl (cached) coverage: 80.2% of statements -ok github.com/pingcap/tidb/ddl/failtest (cached) coverage: 0.0% of statements -? github.com/pingcap/tidb/ddl/testutil [no test files] -? github.com/pingcap/tidb/ddl/util [no test files] -ok github.com/pingcap/tidb/distsql (cached) coverage: 70.2% of statements -ok github.com/pingcap/tidb/domain (cached) coverage: 50.8% of statements -ok github.com/pingcap/tidb/executor (cached) coverage: 79.3% of statements -ok github.com/pingcap/tidb/executor/aggfuncs (cached) coverage: 47.3% of statements -ok github.com/pingcap/tidb/executor/seqtest (cached) coverage: 0.0% of statements -ok github.com/pingcap/tidb/expression (cached) coverage: 76.9% of statements -ok github.com/pingcap/tidb/expression/aggregation (cached) coverage: 50.9% of statements -ok github.com/pingcap/tidb/infoschema (cached) coverage: 68.8% of statements -ok github.com/pingcap/tidb/infoschema/perfschema (cached) coverage: 77.1% of statements -ok github.com/pingcap/tidb/kv (cached) coverage: 72.5% of statements -ok github.com/pingcap/tidb/meta (cached) coverage: 76.9% of statements -ok github.com/pingcap/tidb/meta/autoid (cached) coverage: 80.1% of statements -ok github.com/pingcap/tidb/metrics (cached) coverage: 0.0% of statements -ok github.com/pingcap/tidb/owner (cached) coverage: 21.8% of statements -? github.com/pingcap/tidb/planner [no test files] -ok github.com/pingcap/tidb/planner/cascades (cached) coverage: 27.3% of statements -ok github.com/pingcap/tidb/planner/core (cached) coverage: 82.2% of statements -ok github.com/pingcap/tidb/planner/failtest (cached) coverage: 0.0% of statements -ok github.com/pingcap/tidb/planner/implementation (cached) coverage: 50.0% of statements -ok github.com/pingcap/tidb/planner/memo (cached) coverage: 88.2% of statements -? github.com/pingcap/tidb/planner/property [no test files] -ok github.com/pingcap/tidb/plugin (cached) coverage: 2.8% of statements -ok github.com/pingcap/tidb/plugin/conn_ip_example (cached) coverage: 0.0% of statements [no tests to run] -? github.com/pingcap/tidb/privilege [no test files] -ok github.com/pingcap/tidb/privilege/privileges (cached) coverage: 76.9% of statements -ok github.com/pingcap/tidb/server 6.492s coverage: 57.2% of statements -ok github.com/pingcap/tidb/session (cached) coverage: 80.7% of statements -? github.com/pingcap/tidb/sessionctx [no test files] -ok github.com/pingcap/tidb/sessionctx/binloginfo (cached) coverage: 90.0% of statements -? github.com/pingcap/tidb/sessionctx/stmtctx [no test files] -ok github.com/pingcap/tidb/sessionctx/variable (cached) coverage: 36.1% of statements -ok github.com/pingcap/tidb/statistics (cached) coverage: 85.3% of statements -ok github.com/pingcap/tidb/store (cached) coverage: 78.9% of statements -? github.com/pingcap/tidb/store/mockoracle [no test files] -ok github.com/pingcap/tidb/store/mockstore (cached) coverage: 66.7% of statements -ok github.com/pingcap/tidb/store/mockstore/mocktikv (cached) coverage: 27.6% of statements -ok github.com/pingcap/tidb/store/tikv (cached) coverage: 68.5% of statements -ok github.com/pingcap/tidb/store/tikv/gcworker (cached) coverage: 48.0% of statements -ok github.com/pingcap/tidb/store/tikv/latch (cached) coverage: 95.2% of statements -? github.com/pingcap/tidb/store/tikv/oracle [no test files] -ok github.com/pingcap/tidb/store/tikv/oracle/oracles (cached) coverage: 19.7% of statements -? github.com/pingcap/tidb/store/tikv/tikvrpc [no test files] -ok github.com/pingcap/tidb/structure (cached) coverage: 82.9% of statements -ok github.com/pingcap/tidb/table (cached) coverage: 77.8% of statements -ok github.com/pingcap/tidb/table/tables (cached) coverage: 69.2% of statements -ok github.com/pingcap/tidb/tablecodec (cached) coverage: 54.7% of statements -? github.com/pingcap/tidb/tidb-server [no test files] -ok github.com/pingcap/tidb/types (cached) coverage: 83.4% of statements -ok github.com/pingcap/tidb/types/json (cached) coverage: 84.7% of statements -ok github.com/pingcap/tidb/types/parser_driver (cached) coverage: 24.7% of statements -ok github.com/pingcap/tidb/util (cached) coverage: 44.8% of statements -ok github.com/pingcap/tidb/util/admin (cached) coverage: 79.6% of statements -ok github.com/pingcap/tidb/util/arena (cached) coverage: 100.0% of statements -ok github.com/pingcap/tidb/util/chunk (cached) coverage: 85.6% of statements -ok github.com/pingcap/tidb/util/codec (cached) coverage: 72.7% of statements -ok github.com/pingcap/tidb/util/disjointset (cached) coverage: 100.0% of statements -ok github.com/pingcap/tidb/util/encrypt (cached) coverage: 95.2% of statements -ok github.com/pingcap/tidb/util/execdetails (cached) coverage: 77.8% of statements -ok github.com/pingcap/tidb/util/filesort (cached) coverage: 84.0% of statements -ok github.com/pingcap/tidb/util/format (cached) coverage: 70.9% of statements -? github.com/pingcap/tidb/util/gcutil [no test files] -ok github.com/pingcap/tidb/util/hack (cached) coverage: 92.3% of statements -? github.com/pingcap/tidb/util/israce [no test files] -ok github.com/pingcap/tidb/util/kvcache (cached) coverage: 80.0% of statements -ok github.com/pingcap/tidb/util/kvencoder (cached) coverage: 78.9% of statements -ok github.com/pingcap/tidb/util/logutil 0.030s coverage: 67.2% of statements -ok github.com/pingcap/tidb/util/memory (cached) coverage: 79.1% of statements -ok github.com/pingcap/tidb/util/mock (cached) coverage: 13.3% of statements -ok github.com/pingcap/tidb/util/mvmap (cached) coverage: 86.6% of statements -ok github.com/pingcap/tidb/util/printer (cached) coverage: 88.3% of statements -ok github.com/pingcap/tidb/util/ranger (cached) coverage: 80.0% of statements -? github.com/pingcap/tidb/util/rowDecoder [no test files] -? github.com/pingcap/tidb/util/set [no test files] -? github.com/pingcap/tidb/util/signal [no test files] -? github.com/pingcap/tidb/util/sqlexec [no test files] -ok github.com/pingcap/tidb/util/stringutil (cached) coverage: 99.1% of statements -ok github.com/pingcap/tidb/util/sys/linux (cached) coverage: 100.0% of statements -ok github.com/pingcap/tidb/util/systimemon (cached) coverage: 100.0% of statements -ok github.com/pingcap/tidb/util/testkit (cached) coverage: 8.0% of statements -? github.com/pingcap/tidb/util/testleak [no test files] -ok github.com/pingcap/tidb/util/testutil (cached) coverage: 46.5% of statements -ok github.com/pingcap/tidb/util/timeutil (cached) coverage: 63.3% of statements -ok github.com/pingcap/tidb/util/tracing (cached) coverage: 93.3% of statements -CGO_ENABLED=1 GO111MODULE=on go build -ldflags '-X "github.com/pingcap/parser/mysql.TiDBReleaseVersion=v3.0.0-beta.1-44-g78f3ec97a-dirty" -X "github.com/pingcap/tidb/util/printer.TiDBBuildTS=2019-04-09 09:36:57" -X "github.com/pingcap/tidb/util/printer.TiDBGitHash=78f3ec97abe263369fe2c02fac738ae2794cfe59" -X "github.com/pingcap/tidb/util/printer.TiDBGitBranch=setdefault" -X "github.com/pingcap/tidb/util/printer.GoVersion=go version go1.12 darwin/amd64" ' -o bin/tidb-server tidb-server/main.go -skip building tidb-server, using existing binary: ../../bin/tidb-server -skip building importer, using existing binary: -building explain-test binary: ./explain_test -start tidb-server, log file: ./explain-test.out -tidb-server(PID: 31103) started -run all explain test cases -explaintest end From ec7722143eab21e49be2105882d07190e3da9e90 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Tue, 9 Apr 2019 17:47:43 +0800 Subject: [PATCH 07/13] edit go mod --- go.mod | 2 -- go.sum | 6 ------ 2 files changed, 8 deletions(-) diff --git a/go.mod b/go.mod index b3fe7833e6f0b..ca535624af6d6 100644 --- a/go.mod +++ b/go.mod @@ -90,5 +90,3 @@ require ( sourcegraph.com/sourcegraph/appdash v0.0.0-20180531100431-4c381bd170b4 sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 ) - -replace github.com/pingcap/parser => github.com/imtbkcat/parser v0.0.0-20190404041311-8e362e03d235 diff --git a/go.sum b/go.sum index 15d4c81ff37d7..6cf70f55d8c18 100644 --- a/go.sum +++ b/go.sum @@ -76,12 +76,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.1 h1:3scN4iuXkNOyP98jF55Lv8a9j1o/Iwv github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628 h1:Ty1H5LGje5mrZJ1kpHu8qcpkqbwSE9vwGw4b66dr90s= -github.com/imtbkcat/parser v0.0.0-20190326133123-2c136d1b9628/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= -github.com/imtbkcat/parser v0.0.0-20190401060923-2536da2cf10a h1:sTRC+kfn85I1dtr9DyfqquHuzxsYjXK6E33RnzlxkMU= -github.com/imtbkcat/parser v0.0.0-20190401060923-2536da2cf10a/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= -github.com/imtbkcat/parser v0.0.0-20190404041311-8e362e03d235 h1:2hjtxVn3zBjpZls8R672qvluA4gmvqyQcm38NTI7v/Y= -github.com/imtbkcat/parser v0.0.0-20190404041311-8e362e03d235/go.mod h1:qupHD3o7J0aBb3bbVyXRnxe9kKy2MTY/6POS6NO/Ei8= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= From 55e5ee71424c98c6574c1e62309868787365f32b Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Tue, 9 Apr 2019 17:52:10 +0800 Subject: [PATCH 08/13] add comment for exported method --- privilege/privileges/privileges.go | 1 + 1 file changed, 1 insertion(+) diff --git a/privilege/privileges/privileges.go b/privilege/privileges/privileges.go index 9fdb675ac1b9a..98683977255cb 100644 --- a/privilege/privileges/privileges.go +++ b/privilege/privileges/privileges.go @@ -218,6 +218,7 @@ func (p *UserPrivileges) FindEdge(ctx sessionctx.Context, role *auth.RoleIdentit return true } +// GetDefaultRoles returns all default roles for certain user. func (p *UserPrivileges) GetDefaultRoles(user, host string) []*auth.RoleIdentity { mysqlPrivilege := p.Handle.Get() ret := mysqlPrivilege.getDefaultRoles(user, host) From 9f65b4fd457244a69995c5acf1bcc06750ee9aef Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Tue, 9 Apr 2019 17:58:47 +0800 Subject: [PATCH 09/13] fix ci --- server/server_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/server_test.go b/server/server_test.go index acbe70e17fd95..c28404f24ef2e 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -832,6 +832,7 @@ func runTestAuth(c *C) { config.Passwd = "123" })) rows, err := db.Query("select current_role;") + c.Assert(err, IsNil) c.Assert(rows.Next(), IsTrue) var outA string err = rows.Scan(&outA) From 3094c869f2a4ddcc25d6cc0b438a0a7fc5bcb9d3 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Tue, 9 Apr 2019 18:01:58 +0800 Subject: [PATCH 10/13] fix ci --- server/server_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/server_test.go b/server/server_test.go index c28404f24ef2e..8271c2391b584 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -831,6 +831,7 @@ func runTestAuth(c *C) { config.User = "authtest" config.Passwd = "123" })) + c.Assert(err, IsNil) rows, err := db.Query("select current_role;") c.Assert(err, IsNil) c.Assert(rows.Next(), IsTrue) From f3121abbb04ed9d2cbf9c6e1d20514b8cfc56f17 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Thu, 11 Apr 2019 11:31:31 +0800 Subject: [PATCH 11/13] add negtive test for simple_test --- executor/simple_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/executor/simple_test.go b/executor/simple_test.go index 10368349859ef..aaeda7a67beec 100644 --- a/executor/simple_test.go +++ b/executor/simple_test.go @@ -175,6 +175,14 @@ func (s *testSuite3) TestDefaultRole(c *C) { _, err := tk.Exec(setRoleSQL) c.Check(err, NotNil) + setRoleSQL = `SET DEFAULT ROLE r_1 TO u_1000;` + _, err = tk.Exec(setRoleSQL) + c.Check(err, NotNil) + + setRoleSQL = `SET DEFAULT ROLE r_1, r_3 TO u_1;` + _, err = tk.Exec(setRoleSQL) + c.Check(err, NotNil) + setRoleSQL = `SET DEFAULT ROLE r_1 TO u_1;` _, err = tk.Exec(setRoleSQL) c.Check(err, IsNil) From b82747f9f710d21f1c4212999bf9d90b193f602d Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Thu, 11 Apr 2019 12:24:51 +0800 Subject: [PATCH 12/13] add test for cache_test --- privilege/privileges/cache_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/privilege/privileges/cache_test.go b/privilege/privileges/cache_test.go index 032b3586ee120..fe9e6c740035e 100644 --- a/privilege/privileges/cache_test.go +++ b/privilege/privileges/cache_test.go @@ -134,6 +134,25 @@ func (s *testCacheSuite) TestLoadColumnsPrivTable(c *C) { c.Assert(p.ColumnsPriv[1].ColumnPriv, Equals, mysql.SelectPriv) } +func (s *testCacheSuite) TestLoadDefaultRoleTable(c *C) { + se, err := session.CreateSession4Test(s.store) + c.Assert(err, IsNil) + defer se.Close() + mustExec(c, se, "use mysql;") + mustExec(c, se, "truncate table default_roles") + + mustExec(c, se, `INSERT INTO mysql.default_roles VALUES ("%", "test_default_roles", "localhost", "r_1")`) + mustExec(c, se, `INSERT INTO mysql.default_roles VALUES ("%", "test_default_roles", "localhost", "r_2")`) + var p privileges.MySQLPrivilege + err = p.LoadDefaultRoles(se) + c.Assert(err, IsNil) + c.Assert(p.DefaultRoles[0].Host, Equals, `%`) + c.Assert(p.DefaultRoles[0].User, Equals, "test_default_roles") + c.Assert(p.DefaultRoles[0].DefaultRoleHost, Equals, "localhost") + c.Assert(p.DefaultRoles[0].DefaultRoleUser, Equals, "r_1") + c.Assert(p.DefaultRoles[1].DefaultRoleHost, Equals, "localhost") +} + func (s *testCacheSuite) TestPatternMatch(c *C) { se, err := session.CreateSession4Test(s.store) c.Assert(err, IsNil) From 370ef6baa99674670a3b2f1d71ac47abdf19bacc Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Wed, 17 Apr 2019 13:41:47 +0800 Subject: [PATCH 13/13] reduce interface assert --- executor/simple.go | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/executor/simple.go b/executor/simple.go index d009f6dd7d99c..5cd1ef5259d95 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -95,7 +95,8 @@ func (e *SimpleExec) Next(ctx context.Context, req *chunk.RecordBatch) (err erro } func (e *SimpleExec) setDefaultRoleNone(s *ast.SetDefaultRoleStmt) error { - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { + sqlExecutor := e.ctx.(sqlexec.SQLExecutor) + if _, err := sqlExecutor.Execute(context.Background(), "begin"); err != nil { return err } for _, u := range s.UserList { @@ -103,15 +104,15 @@ func (e *SimpleExec) setDefaultRoleNone(s *ast.SetDefaultRoleStmt) error { u.Hostname = "%" } sql := fmt.Sprintf("DELETE IGNORE FROM mysql.default_roles WHERE USER='%s' AND HOST='%s';", u.Username, u.Hostname) - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + if _, err := sqlExecutor.Execute(context.Background(), sql); err != nil { logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) - if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + if _, rollbackErr := sqlExecutor.Execute(context.Background(), "rollback"); rollbackErr != nil { return rollbackErr } return err } } - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { + if _, err := sqlExecutor.Execute(context.Background(), "commit"); err != nil { return err } return nil @@ -136,7 +137,8 @@ func (e *SimpleExec) setDefaultRoleRegular(s *ast.SetDefaultRoleStmt) error { return ErrCannotUser.GenWithStackByArgs("SET DEFAULT ROLE", role.String()) } } - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { + sqlExecutor := e.ctx.(sqlexec.SQLExecutor) + if _, err := sqlExecutor.Execute(context.Background(), "begin"); err != nil { return err } for _, user := range s.UserList { @@ -144,9 +146,9 @@ func (e *SimpleExec) setDefaultRoleRegular(s *ast.SetDefaultRoleStmt) error { user.Hostname = "%" } sql := fmt.Sprintf("DELETE IGNORE FROM mysql.default_roles WHERE USER='%s' AND HOST='%s';", user.Username, user.Hostname) - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + if _, err := sqlExecutor.Execute(context.Background(), sql); err != nil { logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) - if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + if _, rollbackErr := sqlExecutor.Execute(context.Background(), "rollback"); rollbackErr != nil { return rollbackErr } return err @@ -156,22 +158,22 @@ func (e *SimpleExec) setDefaultRoleRegular(s *ast.SetDefaultRoleStmt) error { checker := privilege.GetPrivilegeManager(e.ctx) ok := checker.FindEdge(e.ctx, role, user) if ok { - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + if _, err := sqlExecutor.Execute(context.Background(), sql); err != nil { logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) - if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + if _, rollbackErr := sqlExecutor.Execute(context.Background(), "rollback"); rollbackErr != nil { return rollbackErr } return err } } else { - if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + if _, rollbackErr := sqlExecutor.Execute(context.Background(), "rollback"); rollbackErr != nil { return rollbackErr } return ErrRoleNotGranted.GenWithStackByArgs(role.String(), user.String()) } } } - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { + if _, err := sqlExecutor.Execute(context.Background(), "commit"); err != nil { return err } return nil @@ -187,7 +189,8 @@ func (e *SimpleExec) setDefaultRoleAll(s *ast.SetDefaultRoleStmt) error { return ErrCannotUser.GenWithStackByArgs("SET DEFAULT ROLE", user.String()) } } - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { + sqlExecutor := e.ctx.(sqlexec.SQLExecutor) + if _, err := sqlExecutor.Execute(context.Background(), "begin"); err != nil { return err } for _, user := range s.UserList { @@ -195,23 +198,23 @@ func (e *SimpleExec) setDefaultRoleAll(s *ast.SetDefaultRoleStmt) error { user.Hostname = "%" } sql := fmt.Sprintf("DELETE IGNORE FROM mysql.default_roles WHERE USER='%s' AND HOST='%s';", user.Username, user.Hostname) - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + if _, err := sqlExecutor.Execute(context.Background(), sql); err != nil { logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) - if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + if _, rollbackErr := sqlExecutor.Execute(context.Background(), "rollback"); rollbackErr != nil { return rollbackErr } return err } sql = fmt.Sprintf("INSERT IGNORE INTO mysql.default_roles(HOST,USER,DEFAULT_ROLE_HOST,DEFAULT_ROLE_USER) "+ "SELECT TO_HOST,TO_USER,FROM_HOST,FROM_USER FROM mysql.role_edges WHERE TO_HOST='%s' AND TO_USER='%s';", user.Hostname, user.Username) - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { - if _, rollbackErr := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); rollbackErr != nil { + if _, err := sqlExecutor.Execute(context.Background(), sql); err != nil { + if _, rollbackErr := sqlExecutor.Execute(context.Background(), "rollback"); rollbackErr != nil { return rollbackErr } return err } } - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { + if _, err := sqlExecutor.Execute(context.Background(), "commit"); err != nil { return err } return nil