diff --git a/go/base/context.go b/go/base/context.go index 23fe6f6..e1db5c6 100644 --- a/go/base/context.go +++ b/go/base/context.go @@ -91,6 +91,7 @@ type MigrationContext struct { SkipRenamedColumns bool IsTungsten bool DiscardForeignKeys bool + IncludeMultibyteCharset bool config ContextConfig configMutex *sync.Mutex diff --git a/go/cmd/gh-ost/main.go b/go/cmd/gh-ost/main.go index 74d0f05..49b8849 100644 --- a/go/cmd/gh-ost/main.go +++ b/go/cmd/gh-ost/main.go @@ -121,6 +121,7 @@ func main() { version := flag.Bool("version", false, "Print version & exit") checkFlag := flag.Bool("check-flag", false, "Check if another flag exists/supported. This allows for cross-version scripting. Exits with 0 when all additional provided flags exist, nonzero otherwise. You must provide (dummy) values for flags that require a value. Example: gh-ost --check-flag --cut-over-lock-timeout-seconds --nice-ratio 0") flag.StringVar(&migrationContext.ForceTmpTableName, "force-table-names", "", "table name prefix to be used on the temporary tables") + flag.BoolVar(&migrationContext.IncludeMultibyteCharset, "include-multibyte-charset", false, "charset includes multibyte encoding, e.g. gbk, gb2312, big5, cp932, sjis") flag.CommandLine.SetOutput(os.Stdout) flag.Parse() diff --git a/go/logic/applier.go b/go/logic/applier.go index 227b59e..58cd1df 100644 --- a/go/logic/applier.go +++ b/go/logic/applier.go @@ -69,7 +69,7 @@ func NewApplier(migrationContext *base.MigrationContext) *Applier { func (this *Applier) InitDBConnections() (err error) { - applierUri := this.connectionConfig.GetDBUri(this.migrationContext.DatabaseName) + applierUri := this.connectionConfig.GetDBUri(this.migrationContext.DatabaseName, this.migrationContext.IncludeMultibyteCharset) if this.db, _, err = mysql.GetDB(this.migrationContext.Uuid, applierUri); err != nil { return err } diff --git a/go/logic/inspect.go b/go/logic/inspect.go index 31c81dc..53b9579 100644 --- a/go/logic/inspect.go +++ b/go/logic/inspect.go @@ -40,7 +40,7 @@ func NewInspector(migrationContext *base.MigrationContext) *Inspector { } func (this *Inspector) InitDBConnections() (err error) { - inspectorUri := this.connectionConfig.GetDBUri(this.migrationContext.DatabaseName) + inspectorUri := this.connectionConfig.GetDBUri(this.migrationContext.DatabaseName, this.migrationContext.IncludeMultibyteCharset) if this.db, _, err = mysql.GetDB(this.migrationContext.Uuid, inspectorUri); err != nil { return err } diff --git a/go/logic/streamer.go b/go/logic/streamer.go index 37e7195..713dffd 100644 --- a/go/logic/streamer.go +++ b/go/logic/streamer.go @@ -103,7 +103,7 @@ func (this *EventsStreamer) notifyListeners(binlogEvent *binlog.BinlogDMLEvent) } func (this *EventsStreamer) InitDBConnections() (err error) { - EventsStreamerUri := this.connectionConfig.GetDBUri(this.migrationContext.DatabaseName) + EventsStreamerUri := this.connectionConfig.GetDBUri(this.migrationContext.DatabaseName, this.migrationContext.IncludeMultibyteCharset) if this.db, _, err = mysql.GetDB(this.migrationContext.Uuid, EventsStreamerUri); err != nil { return err } diff --git a/go/logic/throttler.go b/go/logic/throttler.go index 624956a..5bb7b07 100644 --- a/go/logic/throttler.go +++ b/go/logic/throttler.go @@ -183,7 +183,7 @@ func (this *Throttler) collectControlReplicasLag() { ) readReplicaLag := func(connectionConfig *mysql.ConnectionConfig) (lag time.Duration, err error) { - dbUri := connectionConfig.GetDBUri("information_schema") + dbUri := connectionConfig.GetDBUri("information_schema", false) var heartbeatValue string if db, _, err := mysql.GetDB(this.migrationContext.Uuid, dbUri); err != nil { diff --git a/go/mysql/connection.go b/go/mysql/connection.go index 96ae08b..c41ccb9 100644 --- a/go/mysql/connection.go +++ b/go/mysql/connection.go @@ -49,12 +49,16 @@ func (this *ConnectionConfig) Equals(other *ConnectionConfig) bool { return this.Key.Equals(&other.Key) || this.ImpliedKey.Equals(other.ImpliedKey) } -func (this *ConnectionConfig) GetDBUri(databaseName string) string { +func (this *ConnectionConfig) GetDBUri(databaseName string, includeMultibyte bool) string { hostname := this.Key.Hostname var ip = net.ParseIP(hostname) if (ip != nil) && (ip.To4() == nil) { // Wrap IPv6 literals in square brackets hostname = fmt.Sprintf("[%s]", hostname) } - return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?interpolateParams=true&autocommit=true&charset=utf8mb4,utf8,latin1", this.User, this.Password, hostname, this.Key.Port, databaseName) + var multibyteCharset string + if includeMultibyte { + multibyteCharset = ",gbk,gb2312,big5,cp932,sjis" + } + return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?interpolateParams=%t&autocommit=true&charset=utf8mb4,utf8,latin1%s", this.User, this.Password, hostname, this.Key.Port, databaseName, !includeMultibyte, multibyteCharset) } diff --git a/go/mysql/connection_test.go b/go/mysql/connection_test.go index 657feb0..da4b825 100644 --- a/go/mysql/connection_test.go +++ b/go/mysql/connection_test.go @@ -55,3 +55,14 @@ func TestDuplicate(t *testing.T) { test.S(t).ExpectEquals(dup.User, "gromit") test.S(t).ExpectEquals(dup.Password, "penguin") } +func TestGetDBUri(t *testing.T) { + c := NewConnectionConfig() + c.Key = InstanceKey{Hostname: "myhost", Port: 3306} + c.User = "gromit" + c.Password = "penguin" + + uri := c.GetDBUri("test", true) + test.S(t).ExpectEquals(uri, "gromit:penguin@tcp(myhost:3306)/test?interpolateParams=false&autocommit=true&charset=utf8mb4,utf8,latin1,gbk,gb2312,big5,cp932,sjis") + uri = c.GetDBUri("test", false) + test.S(t).ExpectEquals(uri, "gromit:penguin@tcp(myhost:3306)/test?interpolateParams=true&autocommit=true&charset=utf8mb4,utf8,latin1") +} diff --git a/go/mysql/utils.go b/go/mysql/utils.go index 532cbb4..23c4fa6 100644 --- a/go/mysql/utils.go +++ b/go/mysql/utils.go @@ -75,7 +75,7 @@ func GetReplicationLag(informationSchemaDb *gosql.DB, connectionConfig *Connecti } func GetMasterKeyFromSlaveStatus(connectionConfig *ConnectionConfig) (masterKey *InstanceKey, err error) { - currentUri := connectionConfig.GetDBUri("information_schema") + currentUri := connectionConfig.GetDBUri("information_schema", false) // This function is only called once, okay to not have a cached connection pool db, err := gosql.Open("mysql", currentUri) if err != nil {