github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/interlock/simple.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package interlock
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"os"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/ngaut/pools"
    24  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    25  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    26  	"github.com/whtcorpsinc/BerolinaSQL/auth"
    27  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    28  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    29  	"github.com/whtcorpsinc/errors"
    30  	"github.com/whtcorpsinc/milevadb/causet"
    31  	"github.com/whtcorpsinc/milevadb/causet/embedded"
    32  	"github.com/whtcorpsinc/milevadb/config"
    33  	"github.com/whtcorpsinc/milevadb/ekv"
    34  	"github.com/whtcorpsinc/milevadb/metrics"
    35  	"github.com/whtcorpsinc/milevadb/petri"
    36  	"github.com/whtcorpsinc/milevadb/plugin"
    37  	"github.com/whtcorpsinc/milevadb/privilege"
    38  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    39  	"github.com/whtcorpsinc/milevadb/soliton"
    40  	"github.com/whtcorpsinc/milevadb/soliton/chunk"
    41  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    42  	"github.com/whtcorpsinc/milevadb/soliton/replog"
    43  	"github.com/whtcorpsinc/milevadb/soliton/sqlexec"
    44  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    45  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    46  	"go.uber.org/zap"
    47  )
    48  
    49  var (
    50  	transactionDurationPessimisticRollback = metrics.TransactionDuration.WithLabelValues(metrics.LblPessimistic, metrics.LblRollback)
    51  	transactionDurationOptimisticRollback  = metrics.TransactionDuration.WithLabelValues(metrics.LblOptimistic, metrics.LblRollback)
    52  )
    53  
    54  // SimpleInterDirc represents simple memex interlock.
    55  // For memexs do simple execution.
    56  // includes `UseStmt`, 'SetStmt`, `DoStmt`,
    57  // `BeginStmt`, `CommitStmt`, `RollbackStmt`.
    58  // TODO: list all simple memexs.
    59  type SimpleInterDirc struct {
    60  	baseInterlockingDirectorate
    61  
    62  	Statement ast.StmtNode
    63  	done      bool
    64  	is        schemareplicant.SchemaReplicant
    65  }
    66  
    67  func (e *baseInterlockingDirectorate) getSysStochastik() (stochastikctx.Context, error) {
    68  	dom := petri.GetPetri(e.ctx)
    69  	sysStochastikPool := dom.SysStochastikPool()
    70  	ctx, err := sysStochastikPool.Get()
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	restrictedCtx := ctx.(stochastikctx.Context)
    75  	restrictedCtx.GetStochastikVars().InRestrictedALLEGROSQL = true
    76  	return restrictedCtx, nil
    77  }
    78  
    79  func (e *baseInterlockingDirectorate) releaseSysStochastik(ctx stochastikctx.Context) {
    80  	if ctx == nil {
    81  		return
    82  	}
    83  	dom := petri.GetPetri(e.ctx)
    84  	sysStochastikPool := dom.SysStochastikPool()
    85  	if _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), "rollback"); err != nil {
    86  		ctx.(pools.Resource).Close()
    87  		return
    88  	}
    89  	sysStochastikPool.Put(ctx.(pools.Resource))
    90  }
    91  
    92  // Next implements the InterlockingDirectorate Next interface.
    93  func (e *SimpleInterDirc) Next(ctx context.Context, req *chunk.Chunk) (err error) {
    94  	if e.done {
    95  		return nil
    96  	}
    97  
    98  	if e.autoNewTxn() {
    99  		// Commit the old transaction, like DBS.
   100  		if err := e.ctx.NewTxn(ctx); err != nil {
   101  			return err
   102  		}
   103  		defer func() { e.ctx.GetStochastikVars().SetStatusFlag(allegrosql.ServerStatusInTrans, false) }()
   104  	}
   105  
   106  	switch x := e.Statement.(type) {
   107  	case *ast.GrantRoleStmt:
   108  		err = e.executeGrantRole(x)
   109  	case *ast.UseStmt:
   110  		err = e.executeUse(x)
   111  	case *ast.FlushStmt:
   112  		err = e.executeFlush(x)
   113  	case *ast.AlterInstanceStmt:
   114  		err = e.executeAlterInstance(x)
   115  	case *ast.BeginStmt:
   116  		err = e.executeBegin(ctx, x)
   117  	case *ast.CommitStmt:
   118  		e.executeCommit(x)
   119  	case *ast.RollbackStmt:
   120  		err = e.executeRollback(x)
   121  	case *ast.CreateUserStmt:
   122  		err = e.executeCreateUser(ctx, x)
   123  	case *ast.AlterUserStmt:
   124  		err = e.executeAlterUser(x)
   125  	case *ast.DropUserStmt:
   126  		err = e.executeDropUser(x)
   127  	case *ast.SetPwdStmt:
   128  		err = e.executeSetPwd(x)
   129  	case *ast.KillStmt:
   130  		err = e.executeKillStmt(x)
   131  	case *ast.BinlogStmt:
   132  		// We just ignore it.
   133  		return nil
   134  	case *ast.DropStatsStmt:
   135  		err = e.executeDropStats(x)
   136  	case *ast.SetRoleStmt:
   137  		err = e.executeSetRole(x)
   138  	case *ast.RevokeRoleStmt:
   139  		err = e.executeRevokeRole(x)
   140  	case *ast.SetDefaultRoleStmt:
   141  		err = e.executeSetDefaultRole(x)
   142  	case *ast.ShutdownStmt:
   143  		err = e.executeShutdown(x)
   144  	case *ast.CreateStatisticsStmt:
   145  		err = e.executeCreateStatistics(x)
   146  	case *ast.DropStatisticsStmt:
   147  		err = e.executeDropStatistics(x)
   148  	case *ast.AdminStmt:
   149  		err = e.executeAdminReloadStatistics(x)
   150  	}
   151  	e.done = true
   152  	return err
   153  }
   154  
   155  func (e *SimpleInterDirc) setDefaultRoleNone(s *ast.SetDefaultRoleStmt) error {
   156  	restrictedCtx, err := e.getSysStochastik()
   157  	if err != nil {
   158  		return err
   159  	}
   160  	defer e.releaseSysStochastik(restrictedCtx)
   161  	sqlInterlockingDirectorate := restrictedCtx.(sqlexec.ALLEGROSQLInterlockingDirectorate)
   162  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "begin"); err != nil {
   163  		return err
   164  	}
   165  	for _, u := range s.UserList {
   166  		if u.Hostname == "" {
   167  			u.Hostname = "%"
   168  		}
   169  		allegrosql := fmt.Sprintf("DELETE IGNORE FROM allegrosql.default_roles WHERE USER='%s' AND HOST='%s';", u.Username, u.Hostname)
   170  		if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   171  			logutil.BgLogger().Error(fmt.Sprintf("Error occur when executing %s", allegrosql))
   172  			if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   173  				return rollbackErr
   174  			}
   175  			return err
   176  		}
   177  	}
   178  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "commit"); err != nil {
   179  		return err
   180  	}
   181  	return nil
   182  }
   183  
   184  func (e *SimpleInterDirc) setDefaultRoleRegular(s *ast.SetDefaultRoleStmt) error {
   185  	for _, user := range s.UserList {
   186  		exists, err := userExists(e.ctx, user.Username, user.Hostname)
   187  		if err != nil {
   188  			return err
   189  		}
   190  		if !exists {
   191  			return ErrCannotUser.GenWithStackByArgs("SET DEFAULT ROLE", user.String())
   192  		}
   193  	}
   194  	for _, role := range s.RoleList {
   195  		exists, err := userExists(e.ctx, role.Username, role.Hostname)
   196  		if err != nil {
   197  			return err
   198  		}
   199  		if !exists {
   200  			return ErrCannotUser.GenWithStackByArgs("SET DEFAULT ROLE", role.String())
   201  		}
   202  	}
   203  
   204  	restrictedCtx, err := e.getSysStochastik()
   205  	if err != nil {
   206  		return err
   207  	}
   208  	defer e.releaseSysStochastik(restrictedCtx)
   209  	sqlInterlockingDirectorate := restrictedCtx.(sqlexec.ALLEGROSQLInterlockingDirectorate)
   210  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "begin"); err != nil {
   211  		return err
   212  	}
   213  	for _, user := range s.UserList {
   214  		if user.Hostname == "" {
   215  			user.Hostname = "%"
   216  		}
   217  		allegrosql := fmt.Sprintf("DELETE IGNORE FROM allegrosql.default_roles WHERE USER='%s' AND HOST='%s';", user.Username, user.Hostname)
   218  		if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   219  			logutil.BgLogger().Error(fmt.Sprintf("Error occur when executing %s", allegrosql))
   220  			if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   221  				return rollbackErr
   222  			}
   223  			return err
   224  		}
   225  		for _, role := range s.RoleList {
   226  			allegrosql := fmt.Sprintf("INSERT IGNORE INTO allegrosql.default_roles values('%s', '%s', '%s', '%s');", user.Hostname, user.Username, role.Hostname, role.Username)
   227  			checker := privilege.GetPrivilegeManager(e.ctx)
   228  			ok := checker.FindEdge(e.ctx, role, user)
   229  			if ok {
   230  				if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   231  					logutil.BgLogger().Error(fmt.Sprintf("Error occur when executing %s", allegrosql))
   232  					if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   233  						return rollbackErr
   234  					}
   235  					return err
   236  				}
   237  			} else {
   238  				if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   239  					return rollbackErr
   240  				}
   241  				return ErrRoleNotGranted.GenWithStackByArgs(role.String(), user.String())
   242  			}
   243  		}
   244  	}
   245  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "commit"); err != nil {
   246  		return err
   247  	}
   248  	return nil
   249  }
   250  
   251  func (e *SimpleInterDirc) setDefaultRoleAll(s *ast.SetDefaultRoleStmt) error {
   252  	for _, user := range s.UserList {
   253  		exists, err := userExists(e.ctx, user.Username, user.Hostname)
   254  		if err != nil {
   255  			return err
   256  		}
   257  		if !exists {
   258  			return ErrCannotUser.GenWithStackByArgs("SET DEFAULT ROLE", user.String())
   259  		}
   260  	}
   261  	restrictedCtx, err := e.getSysStochastik()
   262  	if err != nil {
   263  		return err
   264  	}
   265  	defer e.releaseSysStochastik(restrictedCtx)
   266  	sqlInterlockingDirectorate := restrictedCtx.(sqlexec.ALLEGROSQLInterlockingDirectorate)
   267  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "begin"); err != nil {
   268  		return err
   269  	}
   270  	for _, user := range s.UserList {
   271  		if user.Hostname == "" {
   272  			user.Hostname = "%"
   273  		}
   274  		allegrosql := fmt.Sprintf("DELETE IGNORE FROM allegrosql.default_roles WHERE USER='%s' AND HOST='%s';", user.Username, user.Hostname)
   275  		if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   276  			logutil.BgLogger().Error(fmt.Sprintf("Error occur when executing %s", allegrosql))
   277  			if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   278  				return rollbackErr
   279  			}
   280  			return err
   281  		}
   282  		allegrosql = fmt.Sprintf("INSERT IGNORE INTO allegrosql.default_roles(HOST,USER,DEFAULT_ROLE_HOST,DEFAULT_ROLE_USER) "+
   283  			"SELECT TO_HOST,TO_USER,FROM_HOST,FROM_USER FROM allegrosql.role_edges WHERE TO_HOST='%s' AND TO_USER='%s';", user.Hostname, user.Username)
   284  		if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   285  			if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   286  				return rollbackErr
   287  			}
   288  			return err
   289  		}
   290  	}
   291  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "commit"); err != nil {
   292  		return err
   293  	}
   294  	return nil
   295  }
   296  
   297  func (e *SimpleInterDirc) setDefaultRoleForCurrentUser(s *ast.SetDefaultRoleStmt) (err error) {
   298  	checker := privilege.GetPrivilegeManager(e.ctx)
   299  	user, allegrosql := s.UserList[0], ""
   300  	if user.Hostname == "" {
   301  		user.Hostname = "%"
   302  	}
   303  	switch s.SetRoleOpt {
   304  	case ast.SetRoleNone:
   305  		allegrosql = fmt.Sprintf("DELETE IGNORE FROM allegrosql.default_roles WHERE USER='%s' AND HOST='%s';", user.Username, user.Hostname)
   306  	case ast.SetRoleAll:
   307  		allegrosql = fmt.Sprintf("INSERT IGNORE INTO allegrosql.default_roles(HOST,USER,DEFAULT_ROLE_HOST,DEFAULT_ROLE_USER) "+
   308  			"SELECT TO_HOST,TO_USER,FROM_HOST,FROM_USER FROM allegrosql.role_edges WHERE TO_HOST='%s' AND TO_USER='%s';", user.Hostname, user.Username)
   309  	case ast.SetRoleRegular:
   310  		allegrosql = "INSERT IGNORE INTO allegrosql.default_roles values"
   311  		for i, role := range s.RoleList {
   312  			ok := checker.FindEdge(e.ctx, role, user)
   313  			if !ok {
   314  				return ErrRoleNotGranted.GenWithStackByArgs(role.String(), user.String())
   315  			}
   316  			allegrosql += fmt.Sprintf("('%s', '%s', '%s', '%s')", user.Hostname, user.Username, role.Hostname, role.Username)
   317  			if i != len(s.RoleList)-1 {
   318  				allegrosql += ","
   319  			}
   320  		}
   321  	}
   322  
   323  	restrictedCtx, err := e.getSysStochastik()
   324  	if err != nil {
   325  		return err
   326  	}
   327  	defer e.releaseSysStochastik(restrictedCtx)
   328  	sqlInterlockingDirectorate := restrictedCtx.(sqlexec.ALLEGROSQLInterlockingDirectorate)
   329  
   330  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "begin"); err != nil {
   331  		return err
   332  	}
   333  
   334  	deleteALLEGROSQL := fmt.Sprintf("DELETE IGNORE FROM allegrosql.default_roles WHERE USER='%s' AND HOST='%s';", user.Username, user.Hostname)
   335  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), deleteALLEGROSQL); err != nil {
   336  		logutil.BgLogger().Error(fmt.Sprintf("Error occur when executing %s", allegrosql))
   337  		if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   338  			return rollbackErr
   339  		}
   340  		return err
   341  	}
   342  
   343  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   344  		logutil.BgLogger().Error(fmt.Sprintf("Error occur when executing %s", allegrosql))
   345  		if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   346  			return rollbackErr
   347  		}
   348  		return err
   349  	}
   350  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "commit"); err != nil {
   351  		return err
   352  	}
   353  	return nil
   354  }
   355  
   356  func (e *SimpleInterDirc) executeSetDefaultRole(s *ast.SetDefaultRoleStmt) (err error) {
   357  	stochastikVars := e.ctx.GetStochastikVars()
   358  	checker := privilege.GetPrivilegeManager(e.ctx)
   359  	if checker == nil {
   360  		return errors.New("miss privilege checker")
   361  	}
   362  
   363  	if len(s.UserList) == 1 && stochastikVars.User != nil {
   364  		u, h := s.UserList[0].Username, s.UserList[0].Hostname
   365  		if u == stochastikVars.User.Username && h == stochastikVars.User.AuthHostname {
   366  			err = e.setDefaultRoleForCurrentUser(s)
   367  			petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx)
   368  			return
   369  		}
   370  	}
   371  
   372  	activeRoles := stochastikVars.ActiveRoles
   373  	if !checker.RequestVerification(activeRoles, allegrosql.SystemDB, allegrosql.DefaultRoleBlock, "", allegrosql.UFIDelatePriv) {
   374  		if !checker.RequestVerification(activeRoles, "", "", "", allegrosql.CreateUserPriv) {
   375  			return embedded.ErrSpecificAccessDenied.GenWithStackByArgs("CREATE USER")
   376  		}
   377  	}
   378  
   379  	switch s.SetRoleOpt {
   380  	case ast.SetRoleAll:
   381  		err = e.setDefaultRoleAll(s)
   382  	case ast.SetRoleNone:
   383  		err = e.setDefaultRoleNone(s)
   384  	case ast.SetRoleRegular:
   385  		err = e.setDefaultRoleRegular(s)
   386  	}
   387  	if err != nil {
   388  		return
   389  	}
   390  	petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx)
   391  	return
   392  }
   393  
   394  func (e *SimpleInterDirc) setRoleRegular(s *ast.SetRoleStmt) error {
   395  	// Deal with ALLEGROALLEGROSQL like `SET ROLE role1, role2;`
   396  	checkDup := make(map[string]*auth.RoleIdentity, len(s.RoleList))
   397  	// Check whether RoleNameList contain duplicate role name.
   398  	for _, r := range s.RoleList {
   399  		key := r.String()
   400  		checkDup[key] = r
   401  	}
   402  	roleList := make([]*auth.RoleIdentity, 0, 10)
   403  	for _, v := range checkDup {
   404  		roleList = append(roleList, v)
   405  	}
   406  
   407  	checker := privilege.GetPrivilegeManager(e.ctx)
   408  	ok, roleName := checker.ActiveRoles(e.ctx, roleList)
   409  	if !ok {
   410  		u := e.ctx.GetStochastikVars().User
   411  		return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
   412  	}
   413  	return nil
   414  }
   415  
   416  func (e *SimpleInterDirc) setRoleAll(s *ast.SetRoleStmt) error {
   417  	// Deal with ALLEGROALLEGROSQL like `SET ROLE ALL;`
   418  	checker := privilege.GetPrivilegeManager(e.ctx)
   419  	user, host := e.ctx.GetStochastikVars().User.AuthUsername, e.ctx.GetStochastikVars().User.AuthHostname
   420  	roles := checker.GetAllRoles(user, host)
   421  	ok, roleName := checker.ActiveRoles(e.ctx, roles)
   422  	if !ok {
   423  		u := e.ctx.GetStochastikVars().User
   424  		return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
   425  	}
   426  	return nil
   427  }
   428  
   429  func (e *SimpleInterDirc) setRoleAllExcept(s *ast.SetRoleStmt) error {
   430  	// Deal with ALLEGROALLEGROSQL like `SET ROLE ALL EXCEPT role1, role2;`
   431  	for _, r := range s.RoleList {
   432  		if r.Hostname == "" {
   433  			r.Hostname = "%"
   434  		}
   435  	}
   436  	checker := privilege.GetPrivilegeManager(e.ctx)
   437  	user, host := e.ctx.GetStochastikVars().User.AuthUsername, e.ctx.GetStochastikVars().User.AuthHostname
   438  	roles := checker.GetAllRoles(user, host)
   439  
   440  	filter := func(arr []*auth.RoleIdentity, f func(*auth.RoleIdentity) bool) []*auth.RoleIdentity {
   441  		i, j := 0, 0
   442  		for i = 0; i < len(arr); i++ {
   443  			if f(arr[i]) {
   444  				arr[j] = arr[i]
   445  				j++
   446  			}
   447  		}
   448  		return arr[:j]
   449  	}
   450  	banned := func(r *auth.RoleIdentity) bool {
   451  		for _, ban := range s.RoleList {
   452  			if ban.Hostname == r.Hostname && ban.Username == r.Username {
   453  				return false
   454  			}
   455  		}
   456  		return true
   457  	}
   458  
   459  	afterExcept := filter(roles, banned)
   460  	ok, roleName := checker.ActiveRoles(e.ctx, afterExcept)
   461  	if !ok {
   462  		u := e.ctx.GetStochastikVars().User
   463  		return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
   464  	}
   465  	return nil
   466  }
   467  
   468  func (e *SimpleInterDirc) setRoleDefault(s *ast.SetRoleStmt) error {
   469  	// Deal with ALLEGROALLEGROSQL like `SET ROLE DEFAULT;`
   470  	checker := privilege.GetPrivilegeManager(e.ctx)
   471  	user, host := e.ctx.GetStochastikVars().User.AuthUsername, e.ctx.GetStochastikVars().User.AuthHostname
   472  	roles := checker.GetDefaultRoles(user, host)
   473  	ok, roleName := checker.ActiveRoles(e.ctx, roles)
   474  	if !ok {
   475  		u := e.ctx.GetStochastikVars().User
   476  		return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
   477  	}
   478  	return nil
   479  }
   480  
   481  func (e *SimpleInterDirc) setRoleNone(s *ast.SetRoleStmt) error {
   482  	// Deal with ALLEGROALLEGROSQL like `SET ROLE NONE;`
   483  	checker := privilege.GetPrivilegeManager(e.ctx)
   484  	roles := make([]*auth.RoleIdentity, 0)
   485  	ok, roleName := checker.ActiveRoles(e.ctx, roles)
   486  	if !ok {
   487  		u := e.ctx.GetStochastikVars().User
   488  		return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
   489  	}
   490  	return nil
   491  }
   492  
   493  func (e *SimpleInterDirc) executeSetRole(s *ast.SetRoleStmt) error {
   494  	switch s.SetRoleOpt {
   495  	case ast.SetRoleRegular:
   496  		return e.setRoleRegular(s)
   497  	case ast.SetRoleAll:
   498  		return e.setRoleAll(s)
   499  	case ast.SetRoleAllExcept:
   500  		return e.setRoleAllExcept(s)
   501  	case ast.SetRoleNone:
   502  		return e.setRoleNone(s)
   503  	case ast.SetRoleDefault:
   504  		return e.setRoleDefault(s)
   505  	}
   506  	return nil
   507  }
   508  
   509  func (e *SimpleInterDirc) dbAccessDenied(dbname string) error {
   510  	user := e.ctx.GetStochastikVars().User
   511  	u := user.Username
   512  	h := user.Hostname
   513  	if len(user.AuthUsername) > 0 && len(user.AuthHostname) > 0 {
   514  		u = user.AuthUsername
   515  		h = user.AuthHostname
   516  	}
   517  	return ErrDBaccessDenied.GenWithStackByArgs(u, h, dbname)
   518  }
   519  
   520  func (e *SimpleInterDirc) executeUse(s *ast.UseStmt) error {
   521  	dbname := perceptron.NewCIStr(s.DBName)
   522  
   523  	checker := privilege.GetPrivilegeManager(e.ctx)
   524  	if checker != nil && e.ctx.GetStochastikVars().User != nil {
   525  		if !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, dbname.String()) {
   526  			return e.dbAccessDenied(dbname.O)
   527  		}
   528  	}
   529  
   530  	dbinfo, exists := e.is.SchemaByName(dbname)
   531  	if !exists {
   532  		return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs(dbname)
   533  	}
   534  	e.ctx.GetStochastikVars().CurrentDBChanged = dbname.O != e.ctx.GetStochastikVars().CurrentDB
   535  	e.ctx.GetStochastikVars().CurrentDB = dbname.O
   536  	// character_set_database is the character set used by the default database.
   537  	// The server sets this variable whenever the default database changes.
   538  	// See http://dev.allegrosql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_character_set_database
   539  	stochastikVars := e.ctx.GetStochastikVars()
   540  	err := stochastikVars.SetSystemVar(variable.CharsetDatabase, dbinfo.Charset)
   541  	if err != nil {
   542  		return err
   543  	}
   544  	dbDefCauslate := dbinfo.DefCauslate
   545  	if dbDefCauslate == "" {
   546  		// Since we have checked the charset, the dbDefCauslate here shouldn't be "".
   547  		dbDefCauslate = getDefaultDefCauslate(dbinfo.Charset)
   548  	}
   549  	return stochastikVars.SetSystemVar(variable.DefCauslationDatabase, dbDefCauslate)
   550  }
   551  
   552  func (e *SimpleInterDirc) executeBegin(ctx context.Context, s *ast.BeginStmt) error {
   553  	// If BEGIN is the first memex in TxnCtx, we can reuse the existing transaction, without the
   554  	// need to call NewTxn, which commits the existing transaction and begins a new one.
   555  	txnCtx := e.ctx.GetStochastikVars().TxnCtx
   556  	if txnCtx.History != nil {
   557  		err := e.ctx.NewTxn(ctx)
   558  		if err != nil {
   559  			return err
   560  		}
   561  	}
   562  	// With START TRANSACTION, autocommit remains disabled until you end
   563  	// the transaction with COMMIT or ROLLBACK. The autocommit mode then
   564  	// reverts to its previous state.
   565  	e.ctx.GetStochastikVars().SetStatusFlag(allegrosql.ServerStatusInTrans, true)
   566  	// Call ctx.Txn(true) to active pending txn.
   567  	txnMode := s.Mode
   568  	if txnMode == "" {
   569  		txnMode = e.ctx.GetStochastikVars().TxnMode
   570  	}
   571  	if txnMode == ast.Pessimistic {
   572  		e.ctx.GetStochastikVars().TxnCtx.IsPessimistic = true
   573  	}
   574  	txn, err := e.ctx.Txn(true)
   575  	if err != nil {
   576  		return err
   577  	}
   578  	if e.ctx.GetStochastikVars().TxnCtx.IsPessimistic {
   579  		txn.SetOption(ekv.Pessimistic, true)
   580  	}
   581  	return nil
   582  }
   583  
   584  func (e *SimpleInterDirc) executeRevokeRole(s *ast.RevokeRoleStmt) error {
   585  	for _, role := range s.Roles {
   586  		exists, err := userExists(e.ctx, role.Username, role.Hostname)
   587  		if err != nil {
   588  			return errors.Trace(err)
   589  		}
   590  		if !exists {
   591  			return ErrCannotUser.GenWithStackByArgs("REVOKE ROLE", role.String())
   592  		}
   593  	}
   594  
   595  	restrictedCtx, err := e.getSysStochastik()
   596  	if err != nil {
   597  		return err
   598  	}
   599  	defer e.releaseSysStochastik(restrictedCtx)
   600  	sqlInterlockingDirectorate := restrictedCtx.(sqlexec.ALLEGROSQLInterlockingDirectorate)
   601  
   602  	// begin a transaction to insert role graph edges.
   603  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "begin"); err != nil {
   604  		return errors.Trace(err)
   605  	}
   606  	for _, user := range s.Users {
   607  		exists, err := userExists(e.ctx, user.Username, user.Hostname)
   608  		if err != nil {
   609  			return errors.Trace(err)
   610  		}
   611  		if !exists {
   612  			if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); err != nil {
   613  				return errors.Trace(err)
   614  			}
   615  			return ErrCannotUser.GenWithStackByArgs("REVOKE ROLE", user.String())
   616  		}
   617  		for _, role := range s.Roles {
   618  			if role.Hostname == "" {
   619  				role.Hostname = "%"
   620  			}
   621  			allegrosql := fmt.Sprintf(`DELETE IGNORE FROM %s.%s WHERE FROM_HOST='%s' and FROM_USER='%s' and TO_HOST='%s' and TO_USER='%s'`, allegrosql.SystemDB, allegrosql.RoleEdgeBlock, role.Hostname, role.Username, user.Hostname, user.Username)
   622  			if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   623  				if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); err != nil {
   624  					return errors.Trace(err)
   625  				}
   626  				return ErrCannotUser.GenWithStackByArgs("REVOKE ROLE", role.String())
   627  			}
   628  			allegrosql = fmt.Sprintf(`DELETE IGNORE FROM %s.%s WHERE DEFAULT_ROLE_HOST='%s' and DEFAULT_ROLE_USER='%s' and HOST='%s' and USER='%s'`, allegrosql.SystemDB, allegrosql.DefaultRoleBlock, role.Hostname, role.Username, user.Hostname, user.Username)
   629  			if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   630  				if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); err != nil {
   631  					return errors.Trace(err)
   632  				}
   633  				return ErrCannotUser.GenWithStackByArgs("REVOKE ROLE", role.String())
   634  			}
   635  		}
   636  	}
   637  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "commit"); err != nil {
   638  		return err
   639  	}
   640  	petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx)
   641  	return nil
   642  }
   643  
   644  func (e *SimpleInterDirc) executeCommit(s *ast.CommitStmt) {
   645  	e.ctx.GetStochastikVars().SetStatusFlag(allegrosql.ServerStatusInTrans, false)
   646  }
   647  
   648  func (e *SimpleInterDirc) executeRollback(s *ast.RollbackStmt) error {
   649  	sessVars := e.ctx.GetStochastikVars()
   650  	logutil.BgLogger().Debug("execute rollback memex", zap.Uint64("conn", sessVars.ConnectionID))
   651  	sessVars.SetStatusFlag(allegrosql.ServerStatusInTrans, false)
   652  	txn, err := e.ctx.Txn(false)
   653  	if err != nil {
   654  		return err
   655  	}
   656  	if txn.Valid() {
   657  		duration := time.Since(sessVars.TxnCtx.CreateTime).Seconds()
   658  		if sessVars.TxnCtx.IsPessimistic {
   659  			transactionDurationPessimisticRollback.Observe(duration)
   660  		} else {
   661  			transactionDurationOptimisticRollback.Observe(duration)
   662  		}
   663  		sessVars.TxnCtx.ClearDelta()
   664  		return txn.Rollback()
   665  	}
   666  	return nil
   667  }
   668  
   669  func (e *SimpleInterDirc) executeCreateUser(ctx context.Context, s *ast.CreateUserStmt) error {
   670  	// Check `CREATE USER` privilege.
   671  	if !config.GetGlobalConfig().Security.SkipGrantBlock {
   672  		checker := privilege.GetPrivilegeManager(e.ctx)
   673  		if checker == nil {
   674  			return errors.New("miss privilege checker")
   675  		}
   676  		activeRoles := e.ctx.GetStochastikVars().ActiveRoles
   677  		if !checker.RequestVerification(activeRoles, allegrosql.SystemDB, allegrosql.UserBlock, "", allegrosql.InsertPriv) {
   678  			if s.IsCreateRole {
   679  				if !checker.RequestVerification(activeRoles, "", "", "", allegrosql.CreateRolePriv) &&
   680  					!checker.RequestVerification(activeRoles, "", "", "", allegrosql.CreateUserPriv) {
   681  					return embedded.ErrSpecificAccessDenied.GenWithStackByArgs("CREATE ROLE or CREATE USER")
   682  				}
   683  			}
   684  			if !s.IsCreateRole && !checker.RequestVerification(activeRoles, "", "", "", allegrosql.CreateUserPriv) {
   685  				return embedded.ErrSpecificAccessDenied.GenWithStackByArgs("CREATE User")
   686  			}
   687  		}
   688  	}
   689  
   690  	privData, err := tlsOption2GlobalPriv(s.TLSOptions)
   691  	if err != nil {
   692  		return err
   693  	}
   694  
   695  	users := make([]string, 0, len(s.Specs))
   696  	privs := make([]string, 0, len(s.Specs))
   697  	for _, spec := range s.Specs {
   698  		exists, err1 := userExists(e.ctx, spec.User.Username, spec.User.Hostname)
   699  		if err1 != nil {
   700  			return err1
   701  		}
   702  		if exists {
   703  			user := fmt.Sprintf(`'%s'@'%s'`, spec.User.Username, spec.User.Hostname)
   704  			if !s.IfNotExists {
   705  				if s.IsCreateRole {
   706  					return ErrCannotUser.GenWithStackByArgs("CREATE ROLE", user)
   707  				}
   708  				return ErrCannotUser.GenWithStackByArgs("CREATE USER", user)
   709  			}
   710  			err := schemareplicant.ErrUserAlreadyExists.GenWithStackByArgs(user)
   711  			e.ctx.GetStochastikVars().StmtCtx.AppendNote(err)
   712  			continue
   713  		}
   714  		pwd, ok := spec.EncodedPassword()
   715  		if !ok {
   716  			return errors.Trace(ErrPasswordFormat)
   717  		}
   718  		user := fmt.Sprintf(`('%s', '%s', '%s')`, spec.User.Hostname, spec.User.Username, pwd)
   719  		if s.IsCreateRole {
   720  			user = fmt.Sprintf(`('%s', '%s', '%s', 'Y')`, spec.User.Hostname, spec.User.Username, pwd)
   721  		}
   722  		users = append(users, user)
   723  
   724  		if len(privData) != 0 {
   725  			priv := fmt.Sprintf(`('%s', '%s', '%s')`, spec.User.Hostname, spec.User.Username, replog.String(privData))
   726  			privs = append(privs, priv)
   727  		}
   728  	}
   729  	if len(users) == 0 {
   730  		return nil
   731  	}
   732  
   733  	allegrosql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, authentication_string) VALUES %s;`, allegrosql.SystemDB, allegrosql.UserBlock, strings.Join(users, ", "))
   734  	if s.IsCreateRole {
   735  		allegrosql = fmt.Sprintf(`INSERT INTO %s.%s (Host, User, authentication_string, Account_locked) VALUES %s;`, allegrosql.SystemDB, allegrosql.UserBlock, strings.Join(users, ", "))
   736  	}
   737  
   738  	restrictedCtx, err := e.getSysStochastik()
   739  	if err != nil {
   740  		return err
   741  	}
   742  	defer e.releaseSysStochastik(restrictedCtx)
   743  	sqlInterlockingDirectorate := restrictedCtx.(sqlexec.ALLEGROSQLInterlockingDirectorate)
   744  
   745  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "begin"); err != nil {
   746  		return errors.Trace(err)
   747  	}
   748  	_, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql)
   749  	if err != nil {
   750  		if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   751  			return rollbackErr
   752  		}
   753  		return err
   754  	}
   755  	if len(privs) != 0 {
   756  		allegrosql = fmt.Sprintf("INSERT IGNORE INTO %s.%s (Host, User, Priv) VALUES %s", allegrosql.SystemDB, allegrosql.GlobalPrivBlock, strings.Join(privs, ", "))
   757  		_, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql)
   758  		if err != nil {
   759  			if _, rollbackErr := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); rollbackErr != nil {
   760  				return rollbackErr
   761  			}
   762  			return err
   763  		}
   764  	}
   765  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "commit"); err != nil {
   766  		return errors.Trace(err)
   767  	}
   768  	petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx)
   769  	return err
   770  }
   771  
   772  func (e *SimpleInterDirc) executeAlterUser(s *ast.AlterUserStmt) error {
   773  	if s.CurrentAuth != nil {
   774  		user := e.ctx.GetStochastikVars().User
   775  		if user == nil {
   776  			return errors.New("Stochastik user is empty")
   777  		}
   778  		// Use AuthHostname to search the user record, set Hostname as AuthHostname.
   779  		userCopy := *user
   780  		userCopy.Hostname = userCopy.AuthHostname
   781  		spec := &ast.UserSpec{
   782  			User:    &userCopy,
   783  			AuthOpt: s.CurrentAuth,
   784  		}
   785  		s.Specs = []*ast.UserSpec{spec}
   786  	}
   787  
   788  	privData, err := tlsOption2GlobalPriv(s.TLSOptions)
   789  	if err != nil {
   790  		return err
   791  	}
   792  
   793  	failedUsers := make([]string, 0, len(s.Specs))
   794  	for _, spec := range s.Specs {
   795  		if spec.User.CurrentUser {
   796  			user := e.ctx.GetStochastikVars().User
   797  			spec.User.Username = user.Username
   798  			spec.User.Hostname = user.AuthHostname
   799  		}
   800  
   801  		exists, err := userExists(e.ctx, spec.User.Username, spec.User.Hostname)
   802  		if err != nil {
   803  			return err
   804  		}
   805  		if !exists {
   806  			user := fmt.Sprintf(`'%s'@'%s'`, spec.User.Username, spec.User.Hostname)
   807  			failedUsers = append(failedUsers, user)
   808  			continue
   809  		}
   810  		pwd, ok := spec.EncodedPassword()
   811  		if !ok {
   812  			return errors.Trace(ErrPasswordFormat)
   813  		}
   814  		allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET authentication_string = '%s' WHERE Host = '%s' and User = '%s';`,
   815  			allegrosql.SystemDB, allegrosql.UserBlock, pwd, spec.User.Hostname, spec.User.Username)
   816  		_, _, err = e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql)
   817  		if err != nil {
   818  			failedUsers = append(failedUsers, spec.User.String())
   819  		}
   820  
   821  		if len(privData) > 0 {
   822  			allegrosql = fmt.Sprintf("INSERT INTO %s.%s (Host, User, Priv) VALUES ('%s','%s','%s') ON DUPLICATE KEY UFIDelATE Priv = values(Priv)",
   823  				allegrosql.SystemDB, allegrosql.GlobalPrivBlock, spec.User.Hostname, spec.User.Username, replog.String(privData))
   824  			_, _, err = e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql)
   825  			if err != nil {
   826  				failedUsers = append(failedUsers, spec.User.String())
   827  			}
   828  		}
   829  	}
   830  	if len(failedUsers) > 0 {
   831  		// Commit the transaction even if we returns error
   832  		txn, err := e.ctx.Txn(true)
   833  		if err != nil {
   834  			return err
   835  		}
   836  		err = txn.Commit(stochastikctx.SetCommitCtx(context.Background(), e.ctx))
   837  		if err != nil {
   838  			return err
   839  		}
   840  		if !s.IfExists {
   841  			return ErrCannotUser.GenWithStackByArgs("ALTER USER", strings.Join(failedUsers, ","))
   842  		}
   843  		for _, user := range failedUsers {
   844  			err := schemareplicant.ErrUserDropExists.GenWithStackByArgs(user)
   845  			e.ctx.GetStochastikVars().StmtCtx.AppendNote(err)
   846  		}
   847  	}
   848  	petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx)
   849  	return nil
   850  }
   851  
   852  func (e *SimpleInterDirc) executeGrantRole(s *ast.GrantRoleStmt) error {
   853  	stochastikVars := e.ctx.GetStochastikVars()
   854  	for i, user := range s.Users {
   855  		if user.CurrentUser {
   856  			s.Users[i].Username = stochastikVars.User.AuthUsername
   857  			s.Users[i].Hostname = stochastikVars.User.AuthHostname
   858  		}
   859  	}
   860  
   861  	for _, role := range s.Roles {
   862  		exists, err := userExists(e.ctx, role.Username, role.Hostname)
   863  		if err != nil {
   864  			return err
   865  		}
   866  		if !exists {
   867  			return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", role.String())
   868  		}
   869  	}
   870  	for _, user := range s.Users {
   871  		exists, err := userExists(e.ctx, user.Username, user.Hostname)
   872  		if err != nil {
   873  			return err
   874  		}
   875  		if !exists {
   876  			return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", user.String())
   877  		}
   878  	}
   879  
   880  	restrictedCtx, err := e.getSysStochastik()
   881  	if err != nil {
   882  		return err
   883  	}
   884  	defer e.releaseSysStochastik(restrictedCtx)
   885  	sqlInterlockingDirectorate := restrictedCtx.(sqlexec.ALLEGROSQLInterlockingDirectorate)
   886  
   887  	// begin a transaction to insert role graph edges.
   888  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "begin"); err != nil {
   889  		return err
   890  	}
   891  
   892  	for _, user := range s.Users {
   893  		for _, role := range s.Roles {
   894  			allegrosql := fmt.Sprintf(`INSERT IGNORE INTO %s.%s (FROM_HOST, FROM_USER, TO_HOST, TO_USER) VALUES ('%s','%s','%s','%s')`, allegrosql.SystemDB, allegrosql.RoleEdgeBlock, role.Hostname, role.Username, user.Hostname, user.Username)
   895  			if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   896  				logutil.BgLogger().Error(fmt.Sprintf("Error occur when executing %s", allegrosql))
   897  				if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); err != nil {
   898  					return err
   899  				}
   900  				return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", user.String())
   901  			}
   902  		}
   903  	}
   904  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "commit"); err != nil {
   905  		return err
   906  	}
   907  	petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx)
   908  	return nil
   909  }
   910  
   911  func (e *SimpleInterDirc) executeDropUser(s *ast.DropUserStmt) error {
   912  	// Check privileges.
   913  	// Check `CREATE USER` privilege.
   914  	if !config.GetGlobalConfig().Security.SkipGrantBlock {
   915  		checker := privilege.GetPrivilegeManager(e.ctx)
   916  		if checker == nil {
   917  			return errors.New("miss privilege checker")
   918  		}
   919  		activeRoles := e.ctx.GetStochastikVars().ActiveRoles
   920  		if !checker.RequestVerification(activeRoles, allegrosql.SystemDB, allegrosql.UserBlock, "", allegrosql.DeletePriv) {
   921  			if s.IsDropRole {
   922  				if !checker.RequestVerification(activeRoles, "", "", "", allegrosql.DropRolePriv) &&
   923  					!checker.RequestVerification(activeRoles, "", "", "", allegrosql.CreateUserPriv) {
   924  					return embedded.ErrSpecificAccessDenied.GenWithStackByArgs("DROP ROLE or CREATE USER")
   925  				}
   926  			}
   927  			if !s.IsDropRole && !checker.RequestVerification(activeRoles, "", "", "", allegrosql.CreateUserPriv) {
   928  				return embedded.ErrSpecificAccessDenied.GenWithStackByArgs("CREATE USER")
   929  			}
   930  		}
   931  	}
   932  
   933  	failedUsers := make([]string, 0, len(s.UserList))
   934  	sysStochastik, err := e.getSysStochastik()
   935  	defer e.releaseSysStochastik(sysStochastik)
   936  	if err != nil {
   937  		return err
   938  	}
   939  	sqlInterlockingDirectorate := sysStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate)
   940  
   941  	if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "begin"); err != nil {
   942  		return err
   943  	}
   944  
   945  	for _, user := range s.UserList {
   946  		exists, err := userExists(e.ctx, user.Username, user.Hostname)
   947  		if err != nil {
   948  			return err
   949  		}
   950  		if !exists {
   951  			if s.IfExists {
   952  				e.ctx.GetStochastikVars().StmtCtx.AppendNote(schemareplicant.ErrUserDropExists.GenWithStackByArgs(user))
   953  			} else {
   954  				failedUsers = append(failedUsers, user.String())
   955  				break
   956  			}
   957  		}
   958  
   959  		// begin a transaction to delete a user.
   960  		allegrosql := fmt.Sprintf(`DELETE FROM %s.%s WHERE Host = '%s' and User = '%s';`, allegrosql.SystemDB, allegrosql.UserBlock, user.Hostname, user.Username)
   961  		if _, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   962  			failedUsers = append(failedUsers, user.String())
   963  			break
   964  		}
   965  
   966  		// delete privileges from allegrosql.global_priv
   967  		allegrosql = fmt.Sprintf(`DELETE FROM %s.%s WHERE Host = '%s' and User = '%s';`, allegrosql.SystemDB, allegrosql.GlobalPrivBlock, user.Hostname, user.Username)
   968  		if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   969  			failedUsers = append(failedUsers, user.String())
   970  			if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); err != nil {
   971  				return err
   972  			}
   973  			continue
   974  		}
   975  
   976  		// delete privileges from allegrosql.EDB
   977  		allegrosql = fmt.Sprintf(`DELETE FROM %s.%s WHERE Host = '%s' and User = '%s';`, allegrosql.SystemDB, allegrosql.DBBlock, user.Hostname, user.Username)
   978  		if _, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   979  			failedUsers = append(failedUsers, user.String())
   980  			break
   981  		}
   982  
   983  		// delete privileges from allegrosql.blocks_priv
   984  		allegrosql = fmt.Sprintf(`DELETE FROM %s.%s WHERE Host = '%s' and User = '%s';`, allegrosql.SystemDB, allegrosql.BlockPrivBlock, user.Hostname, user.Username)
   985  		if _, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   986  			failedUsers = append(failedUsers, user.String())
   987  			break
   988  		}
   989  
   990  		// delete relationship from allegrosql.role_edges
   991  		allegrosql = fmt.Sprintf(`DELETE FROM %s.%s WHERE TO_HOST = '%s' and TO_USER = '%s';`, allegrosql.SystemDB, allegrosql.RoleEdgeBlock, user.Hostname, user.Username)
   992  		if _, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   993  			failedUsers = append(failedUsers, user.String())
   994  			break
   995  		}
   996  
   997  		allegrosql = fmt.Sprintf(`DELETE FROM %s.%s WHERE FROM_HOST = '%s' and FROM_USER = '%s';`, allegrosql.SystemDB, allegrosql.RoleEdgeBlock, user.Hostname, user.Username)
   998  		if _, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
   999  			failedUsers = append(failedUsers, user.String())
  1000  			break
  1001  		}
  1002  
  1003  		// delete relationship from allegrosql.default_roles
  1004  		allegrosql = fmt.Sprintf(`DELETE FROM %s.%s WHERE DEFAULT_ROLE_HOST = '%s' and DEFAULT_ROLE_USER = '%s';`, allegrosql.SystemDB, allegrosql.DefaultRoleBlock, user.Hostname, user.Username)
  1005  		if _, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
  1006  			failedUsers = append(failedUsers, user.String())
  1007  			break
  1008  		}
  1009  
  1010  		allegrosql = fmt.Sprintf(`DELETE FROM %s.%s WHERE HOST = '%s' and USER = '%s';`, allegrosql.SystemDB, allegrosql.DefaultRoleBlock, user.Hostname, user.Username)
  1011  		if _, err = sqlInterlockingDirectorate.InterDircute(context.Background(), allegrosql); err != nil {
  1012  			failedUsers = append(failedUsers, user.String())
  1013  			break
  1014  		}
  1015  		//TODO: need delete defCausumns_priv once we implement defCausumns_priv functionality.
  1016  	}
  1017  
  1018  	if len(failedUsers) == 0 {
  1019  		if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "commit"); err != nil {
  1020  			return err
  1021  		}
  1022  	} else {
  1023  		if _, err := sqlInterlockingDirectorate.InterDircute(context.Background(), "rollback"); err != nil {
  1024  			return err
  1025  		}
  1026  		if s.IsDropRole {
  1027  			return ErrCannotUser.GenWithStackByArgs("DROP ROLE", strings.Join(failedUsers, ","))
  1028  		}
  1029  		return ErrCannotUser.GenWithStackByArgs("DROP USER", strings.Join(failedUsers, ","))
  1030  	}
  1031  	petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx)
  1032  	return nil
  1033  }
  1034  
  1035  func userExists(ctx stochastikctx.Context, name string, host string) (bool, error) {
  1036  	allegrosql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User='%s' AND Host='%s';`, allegrosql.SystemDB, allegrosql.UserBlock, name, host)
  1037  	rows, _, err := ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql)
  1038  	if err != nil {
  1039  		return false, err
  1040  	}
  1041  	return len(rows) > 0, nil
  1042  }
  1043  
  1044  func (e *SimpleInterDirc) executeSetPwd(s *ast.SetPwdStmt) error {
  1045  	var u, h string
  1046  	if s.User == nil {
  1047  		if e.ctx.GetStochastikVars().User == nil {
  1048  			return errors.New("Stochastik error is empty")
  1049  		}
  1050  		u = e.ctx.GetStochastikVars().User.AuthUsername
  1051  		h = e.ctx.GetStochastikVars().User.AuthHostname
  1052  	} else {
  1053  		checker := privilege.GetPrivilegeManager(e.ctx)
  1054  		activeRoles := e.ctx.GetStochastikVars().ActiveRoles
  1055  		if checker != nil && !checker.RequestVerification(activeRoles, "", "", "", allegrosql.SuperPriv) {
  1056  			return ErrDBaccessDenied.GenWithStackByArgs(u, h, "allegrosql")
  1057  		}
  1058  		u = s.User.Username
  1059  		h = s.User.Hostname
  1060  	}
  1061  	exists, err := userExists(e.ctx, u, h)
  1062  	if err != nil {
  1063  		return err
  1064  	}
  1065  	if !exists {
  1066  		return errors.Trace(ErrPasswordNoMatch)
  1067  	}
  1068  
  1069  	// uFIDelate allegrosql.user
  1070  	allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET authentication_string='%s' WHERE User='%s' AND Host='%s';`, allegrosql.SystemDB, allegrosql.UserBlock, auth.EncodePassword(s.Password), u, h)
  1071  	_, _, err = e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql)
  1072  	petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx)
  1073  	return err
  1074  }
  1075  
  1076  func (e *SimpleInterDirc) executeKillStmt(s *ast.KillStmt) error {
  1077  	conf := config.GetGlobalConfig()
  1078  	if s.MilevaDBExtension || conf.CompatibleKillQuery {
  1079  		sm := e.ctx.GetStochastikManager()
  1080  		if sm == nil {
  1081  			return nil
  1082  		}
  1083  		sm.Kill(s.ConnectionID, s.Query)
  1084  	} else {
  1085  		err := errors.New("Invalid operation. Please use 'KILL MilevaDB [CONNECTION | QUERY] connectionID' instead")
  1086  		e.ctx.GetStochastikVars().StmtCtx.AppendWarning(err)
  1087  	}
  1088  	return nil
  1089  }
  1090  
  1091  func (e *SimpleInterDirc) executeFlush(s *ast.FlushStmt) error {
  1092  	switch s.Tp {
  1093  	case ast.FlushBlocks:
  1094  		if s.ReadLock {
  1095  			return errors.New("FLUSH TABLES WITH READ LOCK is not supported.  Please use @@milevadb_snapshot")
  1096  		}
  1097  	case ast.FlushPrivileges:
  1098  		// If skip-grant-causet is configured, do not flush privileges.
  1099  		// Because LoadPrivilegeLoop does not run and the privilege Handle is nil,
  1100  		// Call dom.PrivilegeHandle().UFIDelate would panic.
  1101  		if config.GetGlobalConfig().Security.SkipGrantBlock {
  1102  			return nil
  1103  		}
  1104  
  1105  		dom := petri.GetPetri(e.ctx)
  1106  		sysStochastikPool := dom.SysStochastikPool()
  1107  		ctx, err := sysStochastikPool.Get()
  1108  		if err != nil {
  1109  			return err
  1110  		}
  1111  		defer sysStochastikPool.Put(ctx)
  1112  		err = dom.PrivilegeHandle().UFIDelate(ctx.(stochastikctx.Context))
  1113  		return err
  1114  	case ast.FlushMilevaDBPlugin:
  1115  		dom := petri.GetPetri(e.ctx)
  1116  		for _, pluginName := range s.Plugins {
  1117  			err := plugin.NotifyFlush(dom, pluginName)
  1118  			if err != nil {
  1119  				return err
  1120  			}
  1121  		}
  1122  	}
  1123  	return nil
  1124  }
  1125  
  1126  func (e *SimpleInterDirc) executeAlterInstance(s *ast.AlterInstanceStmt) error {
  1127  	if s.ReloadTLS {
  1128  		logutil.BgLogger().Info("execute reload tls", zap.Bool("NoRollbackOnError", s.NoRollbackOnError))
  1129  		sm := e.ctx.GetStochastikManager()
  1130  		tlsCfg, err := soliton.LoadTLSCertificates(
  1131  			variable.SysVars["ssl_ca"].Value,
  1132  			variable.SysVars["ssl_key"].Value,
  1133  			variable.SysVars["ssl_cert"].Value,
  1134  		)
  1135  		if err != nil {
  1136  			if !s.NoRollbackOnError || config.GetGlobalConfig().Security.RequireSecureTransport {
  1137  				return err
  1138  			}
  1139  			logutil.BgLogger().Warn("reload TLS fail but keep working without TLS due to 'no rollback on error'")
  1140  		}
  1141  		sm.UFIDelateTLSConfig(tlsCfg)
  1142  	}
  1143  	return nil
  1144  }
  1145  
  1146  func (e *SimpleInterDirc) executeDropStats(s *ast.DropStatsStmt) error {
  1147  	h := petri.GetPetri(e.ctx).StatsHandle()
  1148  	err := h.DeleteBlockStatsFromKV(s.Block.BlockInfo.ID)
  1149  	if err != nil {
  1150  		return err
  1151  	}
  1152  	return h.UFIDelate(schemareplicant.GetSchemaReplicant(e.ctx))
  1153  }
  1154  
  1155  func (e *SimpleInterDirc) autoNewTxn() bool {
  1156  	switch e.Statement.(type) {
  1157  	case *ast.CreateUserStmt, *ast.AlterUserStmt, *ast.DropUserStmt:
  1158  		return true
  1159  	}
  1160  	return false
  1161  }
  1162  
  1163  func (e *SimpleInterDirc) executeShutdown(s *ast.ShutdownStmt) error {
  1164  	sessVars := e.ctx.GetStochastikVars()
  1165  	logutil.BgLogger().Info("execute shutdown memex", zap.Uint64("conn", sessVars.ConnectionID))
  1166  	p, err := os.FindProcess(os.Getpid())
  1167  	if err != nil {
  1168  		return err
  1169  	}
  1170  
  1171  	// Call with async
  1172  	go asyncDelayShutdown(p, time.Second)
  1173  
  1174  	return nil
  1175  }
  1176  
  1177  // #14239 - https://github.com/whtcorpsinc/milevadb/issues/14239
  1178  // Need repair 'shutdown' command behavior.
  1179  // Response of MilevaDB is different to MyALLEGROSQL.
  1180  // This function need to run with async perceptron, otherwise it will causet main coroutine
  1181  func asyncDelayShutdown(p *os.Process, delay time.Duration) {
  1182  	time.Sleep(delay)
  1183  	err := p.Kill()
  1184  	if err != nil {
  1185  		panic(err)
  1186  	}
  1187  }
  1188  
  1189  func (e *SimpleInterDirc) executeCreateStatistics(s *ast.CreateStatisticsStmt) (err error) {
  1190  	// Not support Cardinality and Dependency statistics type for now.
  1191  	if s.StatsType == ast.StatsTypeCardinality || s.StatsType == ast.StatsTypeDependency {
  1192  		return terror.ClassOptimizer.New(allegrosql.ErrInternal, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrInternal]).GenWithStack("Cardinality and Dependency statistics types are not supported")
  1193  	}
  1194  	if _, ok := e.is.SchemaByName(s.Block.Schema); !ok {
  1195  		return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs(s.Block.Schema)
  1196  	}
  1197  	t, err := e.is.BlockByName(s.Block.Schema, s.Block.Name)
  1198  	if err != nil {
  1199  		return schemareplicant.ErrBlockNotExists.GenWithStackByArgs(s.Block.Schema, s.Block.Name)
  1200  	}
  1201  	tblInfo := t.Meta()
  1202  	defCausIDs := make([]int64, 0, 2)
  1203  	// Check whether defCausumns exist.
  1204  	for _, defCausName := range s.DeferredCausets {
  1205  		defCaus := causet.FindDefCaus(t.VisibleDefCauss(), defCausName.Name.L)
  1206  		if defCaus == nil {
  1207  			return terror.ClassDBS.New(allegrosql.ErrKeyDeferredCausetDoesNotExits, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrKeyDeferredCausetDoesNotExits]).GenWithStack("defCausumn does not exist: %s", defCausName.Name.L)
  1208  		}
  1209  		if s.StatsType == ast.StatsTypeCorrelation && tblInfo.PKIsHandle && allegrosql.HasPriKeyFlag(defCaus.Flag) {
  1210  			warn := errors.New("No need to create correlation statistics on the integer primary key defCausumn")
  1211  			e.ctx.GetStochastikVars().StmtCtx.AppendWarning(warn)
  1212  			return nil
  1213  		}
  1214  		defCausIDs = append(defCausIDs, defCaus.ID)
  1215  	}
  1216  	if len(defCausIDs) != 2 && (s.StatsType == ast.StatsTypeCorrelation || s.StatsType == ast.StatsTypeDependency) {
  1217  		return terror.ClassOptimizer.New(allegrosql.ErrInternal, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrInternal]).GenWithStack("Only support Correlation and Dependency statistics types on 2 defCausumns")
  1218  	}
  1219  	if len(defCausIDs) < 1 && s.StatsType == ast.StatsTypeCardinality {
  1220  		return terror.ClassOptimizer.New(allegrosql.ErrInternal, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrInternal]).GenWithStack("Only support Cardinality statistics type on at least 2 defCausumns")
  1221  	}
  1222  	// TODO: check whether covering index exists for cardinality / dependency types.
  1223  
  1224  	// Call utilities of statistics.Handle to modify system blocks instead of doing DML directly,
  1225  	// because locking in Handle can guarantee the correctness of `version` in system blocks.
  1226  	return petri.GetPetri(e.ctx).StatsHandle().InsertExtendedStats(s.StatsName, s.Block.Schema.L, defCausIDs, int(s.StatsType), tblInfo.ID, s.IfNotExists)
  1227  }
  1228  
  1229  func (e *SimpleInterDirc) executeDropStatistics(s *ast.DropStatisticsStmt) error {
  1230  	EDB := e.ctx.GetStochastikVars().CurrentDB
  1231  	if EDB == "" {
  1232  		return embedded.ErrNoDB
  1233  	}
  1234  	// Call utilities of statistics.Handle to modify system blocks instead of doing DML directly,
  1235  	// because locking in Handle can guarantee the correctness of `version` in system blocks.
  1236  	return petri.GetPetri(e.ctx).StatsHandle().MarkExtendedStatsDeleted(s.StatsName, EDB, -1)
  1237  }
  1238  
  1239  func (e *SimpleInterDirc) executeAdminReloadStatistics(s *ast.AdminStmt) error {
  1240  	if s.Tp != ast.AdminReloadStatistics {
  1241  		return terror.ClassOptimizer.New(allegrosql.ErrInternal, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrInternal]).GenWithStack("This AdminStmt is not ADMIN RELOAD STATISTICS")
  1242  	}
  1243  	return petri.GetPetri(e.ctx).StatsHandle().ReloadExtendedStatistics()
  1244  }