diff --git a/dm/checker/checker.go b/dm/checker/checker.go index b659fda538..445e4929d4 100644 --- a/dm/checker/checker.go +++ b/dm/checker/checker.go @@ -304,6 +304,7 @@ func (c *Checker) Init(ctx context.Context) (err error) { c.checkList = append(c.checkList, checker.NewTargetPrivilegeChecker( c.instances[0].targetDB.DB, c.instances[0].targetDBInfo, + c.instances[0].targetDB.Version, )) } // sourceID -> DB @@ -334,6 +335,7 @@ func (c *Checker) Init(ctx context.Context) (err error) { c.checkList = append(c.checkList, checker.NewSourceDumpPrivilegeChecker( instance.sourceDB.DB, instance.sourceDBinfo, + instance.sourceDB.Version, info.sourceID2SourceTables[sourceID], exportCfg.Consistency, c.dumpWholeInstance, @@ -364,7 +366,7 @@ func (c *Checker) Init(ctx context.Context) (err error) { c.checkList = append(c.checkList, checker.NewMySQLBinlogRowImageChecker(instance.sourceDB.DB, instance.sourceDBinfo)) } if _, ok := c.checkingItems[config.ReplicationPrivilegeChecking]; ok { - c.checkList = append(c.checkList, checker.NewSourceReplicationPrivilegeChecker(instance.sourceDB.DB, instance.sourceDBinfo)) + c.checkList = append(c.checkList, checker.NewSourceReplicationPrivilegeChecker(instance.sourceDB.DB, instance.sourceDBinfo, instance.sourceDB.Version)) } if _, ok := c.checkingItems[config.OnlineDDLChecking]; c.onlineDDL != nil && ok { c.checkList = append(c.checkList, checker.NewOnlineDDLChecker(instance.sourceDB.DB, info.sourceID2InterestedDB[i], c.onlineDDL, instance.baList)) diff --git a/dm/pkg/checker/conn_checker.go b/dm/pkg/checker/conn_checker.go index 21b85a6098..e6fc4567ac 100644 --- a/dm/pkg/checker/conn_checker.go +++ b/dm/pkg/checker/conn_checker.go @@ -94,7 +94,7 @@ func (c *connNumberChecker) check(ctx context.Context, checkerName string, neede markCheckError(result, err) return result } - err2 := verifyPrivilegesWithResult(result, grants, neededPriv) + err2 := verifyPrivilegesWithResult(result, grants, neededPriv, c.toCheckDB.Version) if err2 != nil { // no enough privilege to check the user's connection number result.State = StateWarning diff --git a/dm/pkg/checker/privilege.go b/dm/pkg/checker/privilege.go index 17731913fa..3ed20f68c3 100644 --- a/dm/pkg/checker/privilege.go +++ b/dm/pkg/checker/privilege.go @@ -54,12 +54,14 @@ type SourceDumpPrivilegeChecker struct { checkTables []filter.Table consistency string dumpWholeInstance bool + version string } // NewSourceDumpPrivilegeChecker returns a RealChecker. func NewSourceDumpPrivilegeChecker( db *sql.DB, dbinfo *dbutil.DBConfig, + version string, checkTables []filter.Table, consistency string, dumpWholeInstance bool, @@ -70,6 +72,7 @@ func NewSourceDumpPrivilegeChecker( checkTables: checkTables, consistency: consistency, dumpWholeInstance: dumpWholeInstance, + version: version, } } @@ -107,7 +110,7 @@ func (pc *SourceDumpPrivilegeChecker) Check(ctx context.Context) *Result { dumpRequiredPrivs[mysql.LockTablesPriv] = priv{needGlobal: true} } - err2 := verifyPrivilegesWithResult(result, grants, dumpRequiredPrivs) + err2 := verifyPrivilegesWithResult(result, grants, dumpRequiredPrivs, pc.version) if err2 != nil { result.Errors = append(result.Errors, err2) result.Instruction = "Please grant the required privileges to the account." @@ -126,13 +129,14 @@ func (pc *SourceDumpPrivilegeChecker) Name() string { // SourceReplicatePrivilegeChecker checks replication privileges of source DB. type SourceReplicatePrivilegeChecker struct { - db *sql.DB - dbinfo *dbutil.DBConfig + db *sql.DB + dbinfo *dbutil.DBConfig + version string } // NewSourceReplicationPrivilegeChecker returns a RealChecker. -func NewSourceReplicationPrivilegeChecker(db *sql.DB, dbinfo *dbutil.DBConfig) RealChecker { - return &SourceReplicatePrivilegeChecker{db: db, dbinfo: dbinfo} +func NewSourceReplicationPrivilegeChecker(db *sql.DB, dbinfo *dbutil.DBConfig, version string) RealChecker { + return &SourceReplicatePrivilegeChecker{db: db, dbinfo: dbinfo, version: version} } // Check implements the RealChecker interface. @@ -154,7 +158,7 @@ func (pc *SourceReplicatePrivilegeChecker) Check(ctx context.Context) *Result { mysql.ReplicationSlavePriv: {needGlobal: true}, mysql.ReplicationClientPriv: {needGlobal: true}, } - err2 := verifyPrivilegesWithResult(result, grants, replRequiredPrivs) + err2 := verifyPrivilegesWithResult(result, grants, replRequiredPrivs, pc.version) if err2 != nil { result.Errors = append(result.Errors, err2) result.State = StateFailure @@ -169,12 +173,13 @@ func (pc *SourceReplicatePrivilegeChecker) Name() string { } type TargetPrivilegeChecker struct { - db *sql.DB - dbinfo *dbutil.DBConfig + db *sql.DB + dbinfo *dbutil.DBConfig + version string } -func NewTargetPrivilegeChecker(db *sql.DB, dbinfo *dbutil.DBConfig) RealChecker { - return &TargetPrivilegeChecker{db: db, dbinfo: dbinfo} +func NewTargetPrivilegeChecker(db *sql.DB, dbinfo *dbutil.DBConfig, version string) RealChecker { + return &TargetPrivilegeChecker{db: db, dbinfo: dbinfo, version: version} } func (t *TargetPrivilegeChecker) Name() string { @@ -203,7 +208,7 @@ func (t *TargetPrivilegeChecker) Check(ctx context.Context) *Result { mysql.DropPriv: {needGlobal: true}, mysql.IndexPriv: {needGlobal: true}, } - err2 := verifyPrivilegesWithResult(result, grants, replRequiredPrivs) + err2 := verifyPrivilegesWithResult(result, grants, replRequiredPrivs, t.version) if err2 != nil { result.Errors = append(result.Errors, err2) // because we cannot be very precisely sure about which table @@ -217,8 +222,9 @@ func verifyPrivilegesWithResult( result *Result, grants []string, requiredPriv map[mysql.PrivilegeType]priv, + version string, ) *Error { - lackedPriv, err := VerifyPrivileges(grants, requiredPriv) + lackedPriv, err := VerifyPrivileges(grants, requiredPriv, version) if err != nil { // nolint return NewError("%s", err.Error()) @@ -284,12 +290,19 @@ func LackedPrivilegesAsStr(lackPriv map[mysql.PrivilegeType]priv) string { func VerifyPrivileges( grants []string, lackPrivs map[mysql.PrivilegeType]priv, + version string, ) (map[mysql.PrivilegeType]priv, error) { if len(grants) == 0 { return nil, errors.New("there is no such grant defined for current user on host '%%'") } p := parser.New() + + // Support for BINLOG MONITOR and other MariaDB things + if strings.Contains(version, "MariaDB") { + p.SetMariaDB(true) + } + for _, grant := range grants { if len(lackPrivs) == 0 { break diff --git a/dm/pkg/checker/privilege_test.go b/dm/pkg/checker/privilege_test.go index f984bd6a57..710059c09b 100644 --- a/dm/pkg/checker/privilege_test.go +++ b/dm/pkg/checker/privilege_test.go @@ -213,7 +213,7 @@ func TestVerifyDumpPrivileges(t *testing.T) { if cs.dumpWholeInstance { dumpRequiredPrivs[mysql.SelectPriv] = priv{needGlobal: true} } - err := verifyPrivilegesWithResult(result, cs.grants, dumpRequiredPrivs) + err := verifyPrivilegesWithResult(result, cs.grants, dumpRequiredPrivs, "8.0.11") if cs.dumpState == StateSuccess { require.Nil(t, err, "grants: %v", cs.grants) } else { @@ -325,7 +325,7 @@ func TestVerifyReplicationPrivileges(t *testing.T) { mysql.ReplicationSlavePriv: {needGlobal: true}, mysql.ReplicationClientPriv: {needGlobal: true}, } - err := verifyPrivilegesWithResult(result, cs.grants, replRequiredPrivs) + err := verifyPrivilegesWithResult(result, cs.grants, replRequiredPrivs, "8.0.11") if cs.replicationState == StateSuccess { require.Nil(t, err, "grants: %v", cs.grants) } else { @@ -405,7 +405,7 @@ func TestVerifyPrivilegesWildcard(t *testing.T) { dbs: genTableLevelPrivs(cs.checkTables), }, } - err := verifyPrivilegesWithResult(result, cs.grants, requiredPrivs) + err := verifyPrivilegesWithResult(result, cs.grants, requiredPrivs, "8.0.11") if cs.replicationState == StateSuccess { require.Nil(t, err, "grants: %v", cs.grants) } else { @@ -469,7 +469,7 @@ func TestVerifyTargetPrivilege(t *testing.T) { mysql.AlterPriv: {needGlobal: true}, mysql.DropPriv: {needGlobal: true}, } - err := verifyPrivilegesWithResult(result, cs.grants, replRequiredPrivs) + err := verifyPrivilegesWithResult(result, cs.grants, replRequiredPrivs, "8.0.11") if cs.checkState == StateSuccess { require.Nil(t, err, "grants: %v", cs.grants) } else { diff --git a/dm/pkg/conn/basedb.go b/dm/pkg/conn/basedb.go index 372b84dfdd..0707675ccf 100644 --- a/dm/pkg/conn/basedb.go +++ b/dm/pkg/conn/basedb.go @@ -201,7 +201,7 @@ type BaseDB struct { doNotClose bool // SELECT VERSION() - version string + Version string } // NewBaseDB returns *BaseDB object for test. @@ -213,7 +213,7 @@ func NewBaseDB(db *sql.DB, scope terror.ErrScope, version string, doFuncInClose Retry: &retry.FiniteRetryStrategy{}, Scope: scope, doFuncInClose: doFuncInClose, - version: version, + Version: version, } } @@ -238,7 +238,7 @@ func NewBaseDBForTestWithVersion(db *sql.DB, version string, doFuncInClose ...fu Retry: &retry.FiniteRetryStrategy{}, Scope: terror.ScopeNotSet, doFuncInClose: doFuncInClose, - version: version, + Version: version, } } @@ -398,7 +398,7 @@ func (d *BaseDB) needsModernTerminology() bool { // - https://mariadb.com/docs/server/reference/sql-statements/administrative-sql-statements/show/show-replica-hosts // // Old syntax is still accepted. - if strings.Contains(d.version, "MariaDB") { + if strings.Contains(d.Version, "MariaDB") { return false } @@ -406,7 +406,7 @@ func (d *BaseDB) needsModernTerminology() bool { // MySQL 8.4 removed `SHOW MASTER STATUS`. minVer := semver.New("8.4.0") - v, err := semver.NewVersion(d.version) + v, err := semver.NewVersion(d.Version) if err != nil { return false } diff --git a/dm/pkg/conn/basedb_test.go b/dm/pkg/conn/basedb_test.go index 9036456b25..581b776a01 100644 --- a/dm/pkg/conn/basedb_test.go +++ b/dm/pkg/conn/basedb_test.go @@ -121,7 +121,7 @@ func TestNeedsModernTerminology(t *testing.T) { } for _, tc := range cases { - b.version = tc.version - require.Equal(t, tc.modern, b.needsModernTerminology(), b.version) + b.Version = tc.version + require.Equal(t, tc.modern, b.needsModernTerminology(), b.Version) } }