Skip to content
This repository has been archived by the owner on Nov 24, 2023. It is now read-only.

Commit

Permalink
loader, syncer: Update sql_mode to more compatible (#1869) (#1894)
Browse files Browse the repository at this point in the history
  • Loading branch information
ti-chi-bot committed Jul 22, 2021
1 parent 356f5b6 commit 04f010c
Show file tree
Hide file tree
Showing 17 changed files with 384 additions and 4 deletions.
9 changes: 8 additions & 1 deletion loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,10 +528,17 @@ func (l *Loader) Init(ctx context.Context) (err error) {
break
}
}

if !hasSQLMode {
lcfg.To.Session["sql_mode"] = l.cfg.LoaderConfig.SQLMode
sqlModes, err3 := utils.AdjustSQLModeCompatible(l.cfg.LoaderConfig.SQLMode)
if err3 != nil {
l.logger.Warn("cannot adjust sql_mode compatible, the sql_mode will stay the same", log.ShortError(err3))
}
lcfg.To.Session["sql_mode"] = sqlModes
}

l.logger.Info("loader's sql_mode is", zap.String("sqlmode", lcfg.To.Session["sql_mode"]))

l.toDB, l.toDBConns, err = createConns(tctx, lcfg, l.cfg.PoolSize)
if err != nil {
return err
Expand Down
53 changes: 53 additions & 0 deletions pkg/utils/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,3 +524,56 @@ func AddGSetWithPurged(ctx context.Context, gset gtid.Set, conn *sql.Conn) (gtid
_ = ret.Set(newGset)
return ret, nil
}

// AdjustSQLModeCompatible adjust downstream sql mode to compatible.
// TODO: When upstream's datatime is 2020-00-00, 2020-00-01, 2020-06-00
// and so on, downstream will be 2019-11-30, 2019-12-01, 2020-05-31,
// as if set the 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE'.
// This is because the implementation of go-mysql, that you can see
// https://github.com/go-mysql-org/go-mysql/blob/master/replication/row_event.go#L1063-L1087
func AdjustSQLModeCompatible(sqlModes string) (string, error) {
needDisable := []string{
"NO_ZERO_IN_DATE",
"NO_ZERO_DATE",
"ERROR_FOR_DIVISION_BY_ZERO",
"NO_AUTO_CREATE_USER",
"STRICT_TRANS_TABLES",
"STRICT_ALL_TABLES",
}
needEnable := []string{
"IGNORE_SPACE",
"NO_AUTO_VALUE_ON_ZERO",
"ALLOW_INVALID_DATES",
}
disable := strings.Join(needDisable, ",")
enable := strings.Join(needEnable, ",")

mode, err := tmysql.GetSQLMode(sqlModes)
if err != nil {
return sqlModes, err
}
disableMode, err2 := tmysql.GetSQLMode(disable)
if err2 != nil {
return sqlModes, err2
}
enableMode, err3 := tmysql.GetSQLMode(enable)
if err3 != nil {
return sqlModes, err3
}
// About this bit manipulation, details can be seen
// https://github.com/pingcap/dm/pull/1869#discussion_r669771966
mode = (mode &^ disableMode) | enableMode

return GetSQLModeStrBySQLMode(mode), nil
}

// GetSQLModeStrBySQLMode get string represent of sql_mode by sql_mode.
func GetSQLModeStrBySQLMode(sqlMode tmysql.SQLMode) string {
var sqlModeStr []string
for str, SQLMode := range tmysql.Str2SQLMode {
if sqlMode&SQLMode != 0 {
sqlModeStr = append(sqlModeStr, str)
}
}
return strings.Join(sqlModeStr, ",")
}
9 changes: 6 additions & 3 deletions syncer/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2777,10 +2777,13 @@ func (s *Syncer) createDBs(ctx context.Context) error {
if !hasSQLMode {
sqlMode, err2 := utils.GetGlobalVariable(ctx, s.fromDB.BaseDB.DB, "sql_mode")
if err2 != nil {
s.tctx.L().Warn("cannot get sql_mode from upstream database", log.ShortError(err2))
} else {
s.cfg.To.Session["sql_mode"] = sqlMode
s.tctx.L().Warn("cannot get sql_mode from upstream database, the sql_mode will be assigned \"IGNORE_SPACE, NO_AUTO_VALUE_ON_ZERO, ALLOW_INVALID_DATES\"", log.ShortError(err2))
}
sqlModes, err3 := utils.AdjustSQLModeCompatible(sqlMode)
if err3 != nil {
s.tctx.L().Warn("cannot adjust sql_mode compatible, the sql_mode will be assigned stay the same", log.ShortError(err3))
}
s.cfg.To.Session["sql_mode"] = sqlModes
}

dbCfg = s.cfg.To
Expand Down
3 changes: 3 additions & 0 deletions tests/handle_error/conf/double-source-no-sharding.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ target-database:
user: "test"
password: "/Q7B9DizNLLTTfiZHv9WoEAKamfpIUs="

session:
sql_mode: "STRICT_TRANS_TABLES"

mysql-instances:
- source-id: "mysql-replica-01"
block-allow-list: "instance"
Expand Down
2 changes: 2 additions & 0 deletions tests/others_integration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ downstream_more_column
expression_filter
fake_rotate_event
metrics
sql_mode

56 changes: 56 additions & 0 deletions tests/sql_mode/conf/diff_config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# diff Configuration.

log-level = "info"

chunk-size = 20

check-thread-count = 4

sample-percent = 100

use-checksum = true

fix-sql-file = "fix.sql"

# tables need to check.
[[check-tables]]
schema = "sql_mode"
tables = ["~.*"]

[[source-db]]
host = "127.0.0.1"
port = 3306
user = "root"
password = "123456"
instance-id = "source-1"

[[table-config]]
schema = "sql_mode"
table = "t_1"

[[table-config.source-tables]]
instance-id = "source-1"
schema = "sql_mode"
table = "t_1"

[[source-db]]
host = "127.0.0.1"
port = 3307
user = "root"
password = "123456"
instance-id = "source-2"

[[table-config]]
schema = "sql_mode"
table = "t_2"

[[table-config.source-tables]]
instance-id = "source-2"
schema = "sql_mode"
table = "t_2"

[target-db]
host = "127.0.0.1"
port = 4000
user = "test"
password = "123456"
4 changes: 4 additions & 0 deletions tests/sql_mode/conf/dm-master.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Master Configuration.
master-addr = ":8261"
advertise-addr = "127.0.0.1:8261"
auto-compaction-retention = "3s"
46 changes: 46 additions & 0 deletions tests/sql_mode/conf/dm-task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: sql_mode
task-mode: all
is-sharding: false
meta-schema: "dm_meta"
enable-heartbeat: false

target-database:
host: "127.0.0.1"
port: 4000
user: "root"
password: ""

mysql-instances:
- source-id: "mysql-replica-01"
block-allow-list: "instance"
mydumper-config-name: "global"
loader-config-name: "global"
syncer-config-name: "global"

- source-id: "mysql-replica-02"
block-allow-list: "instance"
mydumper-config-name: "global"
loader-config-name: "global"
syncer-config-name: "global"

block-allow-list:
instance:
do-dbs: ["sql_mode"]

mydumpers:
global:
threads: 4
chunk-filesize: 0
skip-tz-utc: true
extra-args: "--statement-size=4000"

loaders:
global:
pool-size: 16
dir: "./dumped_data"

syncers:
global:
worker-count: 16
batch: 100
2 changes: 2 additions & 0 deletions tests/sql_mode/conf/dm-worker1.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name = "worker1"
join = "127.0.0.1:8261"
2 changes: 2 additions & 0 deletions tests/sql_mode/conf/dm-worker2.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name = "worker2"
join = "127.0.0.1:8261"
11 changes: 11 additions & 0 deletions tests/sql_mode/conf/source1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
source-id: mysql-replica-01
flavor: ''
enable-gtid: false
enable-relay: true
relay-binlog-name: ''
relay-binlog-gtid: ''
from:
host: 127.0.0.1
user: root
password: /Q7B9DizNLLTTfiZHv9WoEAKamfpIUs=
port: 3306
11 changes: 11 additions & 0 deletions tests/sql_mode/conf/source2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
source-id: mysql-replica-02
flavor: ''
enable-gtid: false
enable-relay: true
relay-binlog-name: ''
relay-binlog-gtid: ''
from:
host: 127.0.0.1
user: root
password: /Q7B9DizNLLTTfiZHv9WoEAKamfpIUs=
port: 3307
32 changes: 32 additions & 0 deletions tests/sql_mode/data/db1.increment.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
set @@session.SQL_MODE='';
use `sql_mode`;

-- test sql_mode PIPES_AS_CONCAT
insert into t_1(num) values('pipes'||'as'||'concat');

-- test sql_mode ANSI_QUOTES
insert into t_1(name) values("a");

-- test sql_mode IGNORE_SPACE
create table sum (id int not null, primary key(id));

-- test sql_mode NO_AUTO_VALUE_ON_ZERO
insert into t_1(id, name) values (30, 'a');
insert into t_1(id, name) values (0, 'b');
insert into t_1(id, name) values (0, 'c');

-- test sql_mode NO_BACKSLASH_ESCAPES
insert into t_1(name) values ('\\b');

-- test sql_mode STRICT_TRANS_TABLES && STRICT_ALL_TABLES && NO_ZERO_IN_DATE && NO_ZERO_DATE && ALLOW_INVALID_DATES
insert into t_1(dt) values('0000-06-00');
insert into t_1(dt) values('0000-00-01');
insert into t_1(dt) values('0000-06-01');
insert into t_1(dt) values('0000-00-00');

-- test sql_mode ERROR_FOR_DIVISION_BY_ZERO
insert into t_1(num) values(4/0);

-- test sql_mode NO_AUTO_CREATE_USER
drop user if exists 'no_auto_create_user';
grant select on *.* to 'no_auto_create_user';
42 changes: 42 additions & 0 deletions tests/sql_mode/data/db1.prepare.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
set @@session.SQL_MODE='';

drop database if exists `sql_mode`;
create database `sql_mode`;
use `sql_mode`;
CREATE TABLE `t_1` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(60),
`num` int,
`dt` datetime,
PRIMARY KEY (id)
);

-- test sql_mode PIPES_AS_CONCAT
insert into t_1(num) values('pipes'||'as'||'concat');

-- test sql_mode ANSI_QUOTES
insert into t_1(name) values("a");

-- test sql_mode IGNORE_SPACE
create table count (id int not null, primary key(id));

-- test sql_mode NO_AUTO_VALUE_ON_ZERO
insert into t_1(id, name) values (10, 'a');
insert into t_1(id, name) values (0, 'b');
insert into t_1(id, name) values (0, 'c');

-- test sql_mode NO_BACKSLASH_ESCAPES
insert into t_1(name) values ('\\a');

-- test sql_mode STRICT_TRANS_TABLES && STRICT_ALL_TABLES && NO_ZERO_IN_DATE && NO_ZERO_DATE && ALLOW_INVALID_DATES
insert into t_1(dt) values('0000-06-00');
insert into t_1(dt) values('0000-00-01');
insert into t_1(dt) values('0000-06-01');
insert into t_1(dt) values('0000-00-00');

-- test sql_mode ERROR_FOR_DIVISION_BY_ZERO
insert into t_1(num) values(4/0);

-- test sql_mode NO_AUTO_CREATE_USER
drop user if exists 'no_auto_create_user';
grant select on *.* to 'no_auto_create_user';
24 changes: 24 additions & 0 deletions tests/sql_mode/data/db2.increment.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
set @@session.sql_mode='ONLY_FULL_GROUP_BY,NO_UNSIGNED_SUBTRACTION,NO_DIR_IN_CREATE,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ALLOW_INVALID_DATES,ERROR_FOR_DIVISION_BY_ZERO,HIGH_NOT_PRECEDENCE,NO_ENGINE_SUBSTITUTION,REAL_AS_FLOAT';
-- NO_AUTO_CREATE_USER set failed in mysql8.0

use sql_mode;

-- test sql_mode PIPES_AS_CONCAT
set @@session.sql_mode=concat(@@session.sql_mode, ',PIPES_AS_CONCAT');
insert into t_2(name) values('pipes'||'as'||'concat');

-- test sql_mode ANSI_QUOTES
insert into t_2(name) values("a");

-- test sql_mode IGNORE_SPACE
set @@session.sql_mode=concat(@@session.sql_mode, ',IGNORE_SPACE');
insert into t_2(name) values(concat ('ignore', 'space'));

-- test sql_mode NO_AUTO_VALUE_ON_ZERO
set @@session.sql_mode=concat(@@session.sql_mode, ',NO_AUTO_VALUE_ON_ZERO');
insert into t_2(id, name) values (20, 'a');
replace into t_2(id, name) values (0, 'c');

-- test sql_mode NO_BACKSLASH_ESCAPES
set @@session.sql_mode=concat(@@session.sql_mode, ',NO_BACKSLASH_ESCAPES');
insert into t_2(name) values ('\\a');
33 changes: 33 additions & 0 deletions tests/sql_mode/data/db2.prepare.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
set @@session.sql_mode='ONLY_FULL_GROUP_BY,NO_UNSIGNED_SUBTRACTION,NO_DIR_IN_CREATE,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ALLOW_INVALID_DATES,ERROR_FOR_DIVISION_BY_ZERO,HIGH_NOT_PRECEDENCE,NO_ENGINE_SUBSTITUTION,REAL_AS_FLOAT';
-- NO_AUTO_CREATE_USER set failed in mysql8.0

drop database if exists `sql_mode`;
create database `sql_mode`;
use `sql_mode`;
CREATE TABLE `t_2` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(60),
`num` int,
`dt` datetime,
PRIMARY KEY (id)
);

-- test sql_mode PIPES_AS_CONCAT
set @@session.sql_mode=concat(@@session.sql_mode, ',PIPES_AS_CONCAT');
insert into t_2(name) values('pipes'||'as'||'concat');

-- test sql_mode ANSI_QUOTES
insert into t_2(name) values("a");

-- test sql_mode IGNORE_SPACE
set @@session.sql_mode=concat(@@session.sql_mode, ',IGNORE_SPACE');
insert into t_2(name) values(concat ('ignore', 'space'));

-- test sql_mode NO_AUTO_VALUE_ON_ZERO
set @@session.sql_mode=concat(@@session.sql_mode, ',NO_AUTO_VALUE_ON_ZERO');
insert into t_2(id, name) values (10, 'a');
insert into t_2(id, name) values (0, 'b');

-- test sql_mode NO_BACKSLASH_ESCAPES
set @@session.sql_mode=concat(@@session.sql_mode, ',NO_BACKSLASH_ESCAPES');
insert into t_2(name) values ('\\a');
Loading

0 comments on commit 04f010c

Please sign in to comment.