MySQL :: MySQL 5.7 Reference Manual :: 5.1.7 Server SQL Modes
5.7.4から5.7.7の間までは、STRICT_{TRANS|ALL}_TABLESは "5.6までのSTRICT_{TRANS|ALL}_TABLES" + "ERROR_FOR_DIVISION_BY_ZERO" + "NO_ZERO_DATE" + "NO_ZERO_IN_DATE" でした。
これが5.7.8からもとに戻ります。STRICT_TRANS_TABLESは5.6までのSTRICT_TRANS_TABLESと同じ効果を持つようになり、同時に暗黙のデフォルトにERROR_FOR_DIVISION_BY_ZERO
, NO_ZERO_DATE, NO_ZERO_IN_DATEが追加されて、動作としては5.7.7までと同じです。
なんでこんな迷走をしたかというと、sql_modeの名前を同じにしてしまったことで、 *同じsql_modeでもバージョンによってエラーになったりならなかったりする* クエリーが存在出来てしまったからです。オチを先に言うと、 バージョンをまたいだレプリケーションが壊れる問題がありました。
MySQL Bugs: #75439: MySQL 5.7 sql_mode problems breaks replication
MySQL 5.6のマスターにMySQL 5.7のスレーブをぶら下げ(スレーブ側が1世代離れたレプリケーションは公式にサポートされています) sql_mode= STRICT_TRANS_TABLES に設定して、
master> CREATE TABLE t1 (dt DATETIME); Query OK, 0 rows affected (0.04 sec) master> SELECT @@sql_mode; +--------------------------------------------+ | @@sql_mode | +--------------------------------------------+ | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | +--------------------------------------------+ 1 row in set (0.00 sec) master> INSERT INTO t1 VALUES ('2015-07-00'); Query OK, 1 row affected (0.00 sec) master> SELECT * FROM t1; +---------------------+ | dt | +---------------------+ | 2015-07-00 00:00:00 | +---------------------+ 1 row in set (0.00 sec) slave> SHOW SLAVE STATUS\G .. Last_SQL_Errno: 1292 Last_SQL_Error: Error 'Incorrect datetime value: '2015-07-00' for column 'dt' at row 1' on query. Default database: 'd1'. Query: 'INSERT INTO t1 VALUES ('2015-07-00')' ..
と、レプリケーションが止まります。レプリケーションにおいてsql_modeは *マスターでクエリーが実行された時にバイナリーログに記録され*, スレーブでクエリーが実行される時にそのsql_modeが復元されます。5.6のSTRICT_TRNAS_TABLESでは2015/07/00は入れられるけれど、5.7.7のSTRICT_TRANS_TABLESではNO_ZERO_IN_DATEとの合わせ技でエラーになるから。
$ mysqlbinlog master-bin.000003 # at 199 #150717 18:21:55 server id 56 end_log_pos 330 CRC32 0x35ed6930 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1437124915/*!*/; SET @@session.pseudo_thread_id=2/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=1075838976/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C utf8 *//*!*/; SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; grant replication slave on *.* to replicator /*!*/; # at 330 #150717 18:22:21 server id 56 end_log_pos 378 CRC32 0x56b39dd7 GTID [commit=yes] SET @@SESSION.GTID_NEXT= 'cdd4d843-2c64-11e5-af02-0242ac11000a:2'/*!*/; # at 378 #150717 18:22:21 server id 56 end_log_pos 466 CRC32 0xc4857014 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1437124941/*!*/; create database d1 /*!*/; # at 466 #150717 18:22:32 server id 56 end_log_pos 514 CRC32 0x02f50263 GTID [commit=yes] SET @@SESSION.GTID_NEXT= 'cdd4d843-2c64-11e5-af02-0242ac11000a:3'/*!*/; # at 514 #150717 18:22:32 server id 56 end_log_pos 613 CRC32 0x4de24e96 Query thread_id=2 exec_time=0 error_code=0 use `d1`/*!*/; SET TIMESTAMP=1437124952/*!*/; CREATE TABLE t1 (dt DATETIME) /*!*/; # at 613 #150717 18:22:48 server id 56 end_log_pos 661 CRC32 0x5a89febd GTID [commit=yes] SET @@SESSION.GTID_NEXT= 'cdd4d843-2c64-11e5-af02-0242ac11000a:4'/*!*/; # at 661 #150717 18:22:48 server id 56 end_log_pos 736 CRC32 0xaeb90296 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1437124968/*!*/; BEGIN /*!*/; # at 736 #150717 18:22:48 server id 56 end_log_pos 842 CRC32 0xbc225a86 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1437124968/*!*/; INSERT INTO t1 VALUES ('2015-07-00') /*!*/; .. $ mysqlbinlog slave-relay-bin.000002 .. # at 400 #150717 18:21:55 server id 56 end_log_pos 330 CRC32 0x35ed6930 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1437124915/*!*/; SET @@session.pseudo_thread_id=2/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=1075838976/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C utf8 *//*!*/; SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; grant replication slave on *.* to replicator /*!*/; # at 531 #150717 18:22:21 server id 56 end_log_pos 378 CRC32 0x56b39dd7 GTID last_committed=0 sequence_number=0 SET @@SESSION.GTID_NEXT= 'cdd4d843-2c64-11e5-af02-0242ac11000a:2'/*!*/; # at 579 #150717 18:22:21 server id 56 end_log_pos 466 CRC32 0xc4857014 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1437124941/*!*/; create database d1 /*!*/; # at 667 #150717 18:22:32 server id 56 end_log_pos 514 CRC32 0x02f50263 GTID last_committed=0 sequence_number=0 SET @@SESSION.GTID_NEXT= 'cdd4d843-2c64-11e5-af02-0242ac11000a:3'/*!*/; # at 715 #150717 18:22:32 server id 56 end_log_pos 613 CRC32 0x4de24e96 Query thread_id=2 exec_time=0 error_code=0 use `d1`/*!*/; SET TIMESTAMP=1437124952/*!*/; CREATE TABLE t1 (dt DATETIME) /*!*/; # at 814 #150717 18:22:48 server id 56 end_log_pos 661 CRC32 0x5a89febd GTID last_committed=0 sequence_number=0 SET @@SESSION.GTID_NEXT= 'cdd4d843-2c64-11e5-af02-0242ac11000a:4'/*!*/; # at 862 #150717 18:22:48 server id 56 end_log_pos 736 CRC32 0xaeb90296 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1437124968/*!*/; BEGIN /*!*/; # at 937 #150717 18:22:48 server id 56 end_log_pos 842 CRC32 0xbc225a86 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1437124968/*!*/; INSERT INTO t1 VALUES ('2015-07-00') /*!*/; # at 1043 #150717 18:22:48 server id 56 end_log_pos 873 CRC32 0xcab86b8a Xid = 23 COMMIT/*!*/; ..
このSET sql_mode= ..の部分(sql_modeは内部的にビット和で表現されているので、STRICT_TRANS_TABLES(= 2097152) + NO_ENGINE_SUBSTITUTION(= 1073741824) = 1075838976と表現されてます)とINSERTクエリーがそのままスレーブで実行されるので、スレーブではエラーになります。
https://github.com/mysql/mysql-server/blob/5.7/sql/sql_class.h#L121-L160
直ったは直ったので気にする必要はないんですが、レプリケーションのsql_modeはどこの値が適用されるか? みたいな話題があったのでネタにしてみました。
0 件のコメント :
コメントを投稿