From 9e9bbb8cb4a8dad0a14a164b5778bdccd0383ea5 Mon Sep 17 00:00:00 2001 From: Aibek B Date: Mon, 11 Dec 2023 16:18:36 +0600 Subject: [PATCH] [upstream] PS-8927, Bug #112364 (create table like doesn't write the charset on binlog if its created from a temporary table) (#5149) https://jira.percona.com/browse/PS-8927 When creating a table with CREATE TABLE ... LIKE ... from a temporary table, the create table isn't written entirely on the binary log, causing an error on the replica, which will create the table with the charset from the default database. Doesn't happen with persistent tables. This patch solves the problem by forcing the CHARSET to be present into CREATE TABLE statement of the binary log, as the reference table is temporary and may not exist on replica. (cherry picked from commit 3ae440228f9c9f9c0483a7290b80103e707b6cd1) --- .../binlog_nogtid/r/binlog_row_binlog.result | 2 +- .../r/binlog_row_binlog_myisam.result | 2 +- .../binlog_nogtid/r/binlog_stm_binlog.result | 2 +- .../r/binlog_stm_binlog_myisam.result | 2 +- .../suite/rpl/r/rpl_tmp_table_and_DDL.result | 6 +++ .../suite/rpl/t/rpl_tmp_table_and_DDL.test | 41 +++++++++++++++++++ sql/sql_table.cc | 3 +- 7 files changed, 53 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog.result b/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog.result index 1159cff628ba..966517eadf0d 100644 --- a/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog.result @@ -645,7 +645,7 @@ binlog.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t2` ( binlog.000001 # Xid # # COMMIT /* XID */ binlog.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t3` ( `a` int DEFAULT NULL -) ENGINE=InnoDB +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci binlog.000001 # Query # # BEGIN binlog.000001 # Table_map # # table_id: # (mysql.user) binlog.000001 # Write_rows # # table_id: # flags: STMT_END_F diff --git a/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog_myisam.result b/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog_myisam.result index 9077aea75497..d1c88c2fa1c8 100644 --- a/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog_myisam.result +++ b/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog_myisam.result @@ -143,7 +143,7 @@ binlog.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t2` ( ) binlog.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t3` ( `a` int DEFAULT NULL -) ENGINE=InnoDB +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci binlog.000001 # Query # # BEGIN binlog.000001 # Table_map # # table_id: # (mysql.user) binlog.000001 # Write_rows # # table_id: # flags: STMT_END_F diff --git a/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog.result b/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog.result index fe2398e4e829..57b0bc5e099b 100644 --- a/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog.result @@ -425,7 +425,7 @@ binlog.000001 # Query # # use `test`; create table t1 (a int) binlog.000001 # Query # # use `test`; create table if not exists t2 select * from t1 binlog.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t3` ( `a` int DEFAULT NULL -) ENGINE=InnoDB +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci binlog.000001 # Query # # BEGIN binlog.000001 # Query # # use `mysql`; INSERT IGNORE INTO user SET host='localhost', user='@#@', authentication_string='*1111111111111111111111111111111111111111' binlog.000001 # Xid # # COMMIT /* XID */ diff --git a/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog_myisam.result b/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog_myisam.result index a6a76810fce8..9bf3937e2d2f 100644 --- a/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog_myisam.result +++ b/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog_myisam.result @@ -140,7 +140,7 @@ binlog.000001 # Query # # use `test`; create table t1 (a int) binlog.000001 # Query # # use `test`; create table if not exists t2 select * from t1 binlog.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t3` ( `a` int DEFAULT NULL -) ENGINE=InnoDB +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci binlog.000001 # Query # # BEGIN binlog.000001 # Query # # use `mysql`; INSERT IGNORE INTO user SET host='localhost', user='@#@', authentication_string='*1111111111111111111111111111111111111111' binlog.000001 # Xid # # COMMIT /* XID */ diff --git a/mysql-test/suite/rpl/r/rpl_tmp_table_and_DDL.result b/mysql-test/suite/rpl/r/rpl_tmp_table_and_DDL.result index fcb2d549c56a..4c4e2b70eaa6 100644 --- a/mysql-test/suite/rpl/r/rpl_tmp_table_and_DDL.result +++ b/mysql-test/suite/rpl/r/rpl_tmp_table_and_DDL.result @@ -111,4 +111,10 @@ include/assert.inc ["t1 on master and temp_t1 have the same storage engine"] include/assert.inc ["t1 on slave and temp_t1 have the same storage engine"] DROP TEMPORARY TABLE temp_t1; DROP TABLE t1; +CREATE TEMPORARY TABLE temp_t1 (c1 INT) DEFAULT CHARSET=latin1; +CREATE TABLE t1 LIKE temp_t1; +include/assert.inc ["t1 on master and temp_t1 have the same character set"] +include/assert.inc ["t1 on slave and temp_t1 have the same character set"] +DROP TEMPORARY TABLE temp_t1; +DROP TABLE t1; include/rpl/deinit.inc diff --git a/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL.test b/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL.test index c2ade1294e36..acbb5ddde786 100644 --- a/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL.test +++ b/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL.test @@ -199,6 +199,47 @@ CREATE TABLE t1 LIKE temp_t1; --let $assert_text= "t1 on slave and temp_t1 have the same storage engine" --source include/assert.inc +# Cleanup +--connection master +DROP TEMPORARY TABLE temp_t1; +DROP TABLE t1; + +--sync_slave_with_master +# +# BUG#112364 +# CREATE TABLE LIKE does not write the charset on binary log +# when using row based replication +# +--connection master + +# Define temp_t1 character set and collation +--let $charset_temp_t1= latin1 +--let $collation_temp_t1= latin1_swedish_ci + +# Create the temporary tables +--eval CREATE TEMPORARY TABLE temp_t1 (c1 INT) DEFAULT CHARSET=$charset_temp_t1 + +# Create t1 based on temporary tables +CREATE TABLE t1 LIKE temp_t1; +--sync_slave_with_master + +# On master +--connection master +# Assert that t1 have the same character set as temp_t1 +--let $collation_t1= query_get_value(SHOW TABLE STATUS WHERE Name='t1', Collation, 1) +--let $assert_cond= "$collation_t1" = "$collation_temp_t1" +--let $assert_text= "t1 on master and temp_t1 have the same character set" +--source include/assert.inc + + +# On slave +--connection slave +# Assert that t1 have the same character set as temp_t1 +--let $collation_t1= query_get_value(SHOW TABLE STATUS WHERE Name='t1', Collation, 1) +--let $assert_cond= "$collation_t1" = "$collation_temp_t1" +--let $assert_text= "t1 on slave and temp_t1 have the same character set" +--source include/assert.inc + # Cleanup --connection master DROP TEMPORARY TABLE temp_t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 78a026113038..034c54dbaf2f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -11320,9 +11320,10 @@ bool mysql_create_like_table(THD *thd, Table_ref *table, Table_ref *src_table, /* As the reference table is temporary and may not exist on slave, we - must force the ENGINE to be present into CREATE TABLE. + must force the ENGINE and CHARSET to be present into CREATE TABLE. */ create_info->used_fields |= HA_CREATE_USED_ENGINE; + create_info->used_fields |= HA_CREATE_USED_DEFAULT_CHARSET; const bool result [[maybe_unused]] = store_create_info( thd, table, &query, create_info, true /* show_database */,