diff --git a/pkg/meta/sql.go b/pkg/meta/sql.go index 62af001893fb4..ef7bdedaf32d2 100644 --- a/pkg/meta/sql.go +++ b/pkg/meta/sql.go @@ -198,6 +198,19 @@ type dbSnap struct { chunk map[string]*chunk } +func recoveryMysqlPwd(addr string) string { + colonIndex := strings.Index(addr, ":") + atIndex := strings.LastIndex(addr, "@") + pwd := addr[colonIndex+1 : atIndex] + parse, err := url.Parse("mysql://root:" + pwd + "@127.0.0.1") + if err == nil { + if originPwd, ok := parse.User.Password(); ok { + addr = fmt.Sprintf("%s:%s%s", addr[:colonIndex], originPwd, addr[atIndex:]) + } + } + return addr +} + func newSQLMeta(driver, addr string, conf *Config) (Meta, error) { var searchPath string if driver == "postgres" { @@ -218,17 +231,7 @@ func newSQLMeta(driver, addr string, conf *Config) (Meta, error) { // escaping is not necessary for mysql password https://github.com/go-sql-driver/mysql#password if driver == "mysql" { - colonIndex := strings.Index(addr, ":") - atIndex := strings.LastIndex(addr, "@") - pwd := addr[colonIndex+1 : atIndex] - parse, err := url.Parse("mysql://root:" + pwd + "@127.0.0.1") - if err != nil { - return nil, fmt.Errorf("parse url %s failed: %s", addr, err) - } - originPwd, ok := parse.User.Password() - if ok { - addr = fmt.Sprintf("%s:%s%s", addr[:colonIndex], originPwd, addr[atIndex:]) - } + addr = recoveryMysqlPwd(addr) } engine, err := xorm.NewEngine(driver, addr) diff --git a/pkg/meta/sql_test.go b/pkg/meta/sql_test.go index 7a3106f707a16..3b74e9f51c8f0 100644 --- a/pkg/meta/sql_test.go +++ b/pkg/meta/sql_test.go @@ -57,3 +57,50 @@ func TestPostgreSQLClientWithSearchPath(t *testing.T) { //skip mutate t.Fatalf("TestPostgreSQLClientWithSearchPath error: %s", err) } } + +func TestRecoveryMysqlPwd(t *testing.T) { //skip mutate + testCase := []struct { + addr string + expect string + }{ + // no special char + {"root:password@localhost:3306/db1", + "root:password@localhost:3306/db1", + }, + + // set from env @ + {"root:pass%40word@localhost:3306/db1", + "root:pass@word@localhost:3306/db1", + }, + + // direct pass special char @ + {"root:pass@word@localhost:3306/db1", + "root:pass@word@localhost:3306/db1", + }, + + // set from env | + {"root:pass%7Cword@localhost:3306/db1", + "root:pass|word@localhost:3306/db1", + }, + + // direct pass special char | + {"root:pass|word@localhost:3306/db1", + "root:pass|word@localhost:3306/db1", + }, + + // set from env : + {"root:pass%3Aword@localhost:3306/db1", + "root:pass:word@localhost:3306/db1", + }, + + // direct pass special char : + {"root:pass:word@localhost:3306/db1", + "root:pass:word@localhost:3306/db1", + }, + } + for _, tc := range testCase { + if got := recoveryMysqlPwd(tc.addr); got != tc.expect { + t.Fatalf("recoveryMysqlPwd error: expect %s but got %s", tc.expect, got) + } + } +}