From 094dc240a4199a473980b00db2af92eacb6f1ae1 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 d9f158f72060..634eba3bb98c 100644 --- a/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog_nogtid/r/binlog_row_binlog.result @@ -650,7 +650,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 08aedf5ee2ed..c156fc6be02a 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 @@ -148,7 +148,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 20b3da92a307..7b16d39da258 100644 --- a/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog_nogtid/r/binlog_stm_binlog.result @@ -430,7 +430,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 c3887d933ec3..cbe207b658c2 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 @@ -145,7 +145,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 e858415b81c4..41a9581a518c 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_end.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 69971c8c5f16..58b3f7737901 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 ee7ec99cad7c..5d0d18553f67 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -11146,9 +11146,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 */,