Description:
It seems while writing statements with local variables from stored procedure to the STATEMENT-based binary log something wrong happens that end up with incompatible collations while replaying the statement.
This code works on master:
mysql> delimiter //
mysql> CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_test_t11_ins`()
-> BEGIN
-> DECLARE v_id INT;
-> SET v_id=2017;
-> INSERT INTO test.t11 (id,nm, cmt)
-> SELECT
-> id
-> ,nm
-> ,CONCAT( v_id, ' 오뉴이노베이션') AS cmt
-> FROM test.t1;
-> END//
Query OK, 0 rows affected (0,10 sec)
mysql> delimiter ;
mysql> insert into t1 values(1,'aaa');
Query OK, 1 row affected (0,07 sec)
mysql> CALL test.sp_test_t11_ins();
Query OK, 1 row affected (0,07 sec)
mysql> select * from t11;
+------+------+----------------------------+
| id | nm | cmt |
+------+------+----------------------------+
| 1 | aaa | 2017 오뉴이노베이션 |
+------+------+----------------------------+
1 row in set (0,00 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| ao756-bin.000001 | 1793 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0,00 sec)
But can not be replicated by slaves or even replayed on the same master:
openxs@ao756:~/dbs/8.0$ bin/mysqlbinlog -vv -uroot --stop-position=1793 data/ao756-bin.000001 | bin/mysql -uroot --port=3308 test
ERROR 1267 (HY000) at line 108: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,COERCIBLE) for operation 'concat'
How to repeat:
Start any version (I've used 8.0.2 here) with utf8mb4 support, make sure you use MIXED or STATEMENT binlog_format and the create the following simple setup:
mysql> set session binlog_format=STATEMENT;
Query OK, 0 rows affected (0,01 sec)
mysql> CREATE TABLE `t1` (
-> `id` int(11) DEFAULT NULL,
-> `nm` varchar(10) DEFAULT NULL
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0,34 sec)
mysql> CREATE TABLE `t11` (
-> `id` int(11) DEFAULT NULL,
-> `nm` varchar(10) DEFAULT NULL,
-> `cmt` varchar(300) DEFAULT NULL
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0,41 sec)
mysql> delimiter //
mysql> CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_test_t11_ins`()
-> BEGIN
-> DECLARE v_id INT;
-> SET v_id=2017;
-> INSERT INTO test.t11 (id,nm, cmt)
-> SELECT
-> id
-> ,nm
-> ,CONCAT( v_id, ' 오뉴이노베이션') AS cmt
-> FROM test.t1;
-> END//
Query OK, 0 rows affected (0,10 sec)
mysql> delimiter ;
mysql> insert into t1 values(1,'aaa');
Query OK, 1 row affected (0,07 sec)
mysql> CALL test.sp_test_t11_ins();
Query OK, 1 row affected (0,07 sec)
mysql> select * from t11;
+------+------+----------------------------+
| id | nm | cmt |
+------+------+----------------------------+
| 1 | aaa | 2017 오뉴이노베이션 |
+------+------+----------------------------+
1 row in set (0,00 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| ao756-bin.000001 | 1793 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0,00 sec)
mysql> exit
As you can see, everything worked as expected, no errors.
In the binary log we see:
openxs@ao756:~/dbs/8.0$ bin/mysqlbinlog -vv -uroot data/ao756-bin.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#170831 13:43:20 server id 1 end_log_pos 123 CRC32 0xadff738a Start: binlog v 4, server v 8.0.2-dmr-log created 170831 13:43:20 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
BINLOG '
SOinWQ8BAAAAdwAAAHsAAAABAAQAOC4wLjItZG1yLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABI6KdZEwANAAgAAAAABAAEAAAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
AYpz/60=
'/*!*/;
# at 123
#170831 13:43:20 server id 1 end_log_pos 154 CRC32 0x8574ebd2 Previous-GTIDs
# [empty]
# at 154
#170831 13:46:30 server id 1 end_log_pos 229 CRC32 0x45c74adf Anonymous_GTID last_committed=0 sequence_number=1 rbr_only=no original_committed_timestamp=1504176391067504 immediate_commit_timestamp=1504176391067504 transaction_length=274
# original_commit_timestamp=1504176391067504 (2017-08-31 13:46:31.067504 EEST)
# immediate_commit_timestamp=1504176391067504 (2017-08-31 13:46:31.067504 EEST)
/*!80001 SET @@session.original_commit_timestamp=1504176391067504*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 229
#170831 13:46:30 server id 1 end_log_pos 428 CRC32 0x47eb7fa8 Query thread_id=5 exec_time=1 error_code=0 Xid = 10
use `test`/*!*/;
SET TIMESTAMP=1504176390/*!*/;
SET @@session.pseudo_thread_id=5/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=255,@@session.collation_connection=255,@@session.collation_server=255/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE `t1` (
`id` int(11) DEFAULT NULL,
`nm` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
/*!*/;
# at 428
#170831 13:46:43 server id 1 end_log_pos 503 CRC32 0x2a199ae8 Anonymous_GTID last_committed=1 sequence_number=2 rbr_only=no original_committed_timestamp=1504176403537133 immediate_commit_timestamp=1504176403537133 transaction_length=308
# original_commit_timestamp=1504176403537133 (2017-08-31 13:46:43.537133 EEST)
# immediate_commit_timestamp=1504176403537133 (2017-08-31 13:46:43.537133 EEST)
/*!80001 SET @@session.original_commit_timestamp=1504176403537133*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 503
#170831 13:46:43 server id 1 end_log_pos 736 CRC32 0x7d8d5770 Query thread_id=5 exec_time=0 error_code=0 Xid = 11
SET TIMESTAMP=1504176403/*!*/;
CREATE TABLE `t11` (
`id` int(11) DEFAULT NULL,
`nm` varchar(10) DEFAULT NULL,
`cmt` varchar(300) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
/*!*/;
# at 736
#170831 13:47:02 server id 1 end_log_pos 811 CRC32 0x9889743f Anonymous_GTID last_committed=2 sequence_number=3 rbr_only=no original_committed_timestamp=1504176422180287 immediate_commit_timestamp=1504176422180287 transaction_length=381
# original_commit_timestamp=1504176422180287 (2017-08-31 13:47:02.180287 EEST)
# immediate_commit_timestamp=1504176422180287 (2017-08-31 13:47:02.180287 EEST)
/*!80001 SET @@session.original_commit_timestamp=1504176422180287*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 811
#170831 13:47:02 server id 1 end_log_pos 1117 CRC32 0xcc831877 Query thread_id=5 exec_time=0 error_code=0
SET TIMESTAMP=1504176422/*!*/;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_test_t11_ins`()
BEGIN
DECLARE v_id INT;
SET v_id=2017;
INSERT INTO test.t11 (id,nm, cmt)
SELECT
id
,nm
,CONCAT( v_id, ' 오뉴이노베이션') AS cmt
FROM test.t1;
END
/*!*/;
# at 1117
#170831 13:47:34 server id 1 end_log_pos 1192 CRC32 0xfee61968 Anonymous_GTID last_committed=3 sequence_number=4 rbr_only=no original_committed_timestamp=1504176454140282 immediate_commit_timestamp=1504176454140282 transaction_length=289
# original_commit_timestamp=1504176454140282 (2017-08-31 13:47:34.140282 EEST)
# immediate_commit_timestamp=1504176454140282 (2017-08-31 13:47:34.140282 EEST)
/*!80001 SET @@session.original_commit_timestamp=1504176454140282*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 1192
#170831 13:47:34 server id 1 end_log_pos 1271 CRC32 0x9c33d4c2 Query thread_id=5 exec_time=0 error_code=0
SET TIMESTAMP=1504176454/*!*/;
BEGIN
/*!*/;
# at 1271
#170831 13:47:34 server id 1 end_log_pos 1375 CRC32 0xe6634c38 Query thread_id=5 exec_time=0 error_code=0
SET TIMESTAMP=1504176454/*!*/;
insert into t1 values(1,'aaa')
/*!*/;
# at 1375
#170831 13:47:34 server id 1 end_log_pos 1406 CRC32 0x1fed35f2 Xid = 13
COMMIT/*!*/;
# at 1406
#170831 13:47:38 server id 1 end_log_pos 1481 CRC32 0x1bebf313 Anonymous_GTID last_committed=4 sequence_number=5 rbr_only=no original_committed_timestamp=1504176458237077 immediate_commit_timestamp=1504176458237077 transaction_length=387
# original_commit_timestamp=1504176458237077 (2017-08-31 13:47:38.237077 EEST)
# immediate_commit_timestamp=1504176458237077 (2017-08-31 13:47:38.237077 EEST)
/*!80001 SET @@session.original_commit_timestamp=1504176458237077*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 1481
#170831 13:47:38 server id 1 end_log_pos 1560 CRC32 0x53d13bac Query thread_id=5 exec_time=0 error_code=0
SET TIMESTAMP=1504176458/*!*/;
BEGIN
/*!*/;
# at 1560
#170831 13:47:38 server id 1 end_log_pos 1762 CRC32 0x42600eb7 Query thread_id=5 exec_time=0 error_code=0
SET TIMESTAMP=1504176458/*!*/;
INSERT INTO test.t11 (id,nm, cmt)
SELECT
id
,nm
,CONCAT( NAME_CONST('v_id',2017), ' 오뉴이노베이션') AS cmt
FROM test.t1
/*!*/;
# at 1762
#170831 13:47:38 server id 1 end_log_pos 1793 CRC32 0x4b9d1ea1 Xid = 17
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
Now, if we clear up things and try to replay this binary log:
openxs@ao756:~/dbs/8.0$ bin/mysql -uroot --port=3308 test -e'drop table t1, t11'
openxs@ao756:~/dbs/8.0$ bin/mysql -uroot --port=3308 test -e'drop procedure sp_test_t11_ins'
openxs@ao756:~/dbs/8.0$ bin/mysqlbinlog -vv -uroot --stop-position=1793 data/ao756-bin.000001 | bin/mysql -uroot --port=3308 test
ERROR 1267 (HY000) at line 108: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,COERCIBLE) for operation 'concat'
we get the error:
Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,COERCIBLE) for operation 'concat'
as a result, point in time recovery and replication is impossible.
As a workaround, use ROW-based binlog_format.
Suggested fix:
Do something differently so that INT local variables can be used in CONCAT() with utf8mb4 strings without such an error while replayed from the binary log:
Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,COERCIBLE) for operation 'concat'