From 56a6f2d8ff7a308a49beb00464d2eb02a491a4f2 Mon Sep 17 00:00:00 2001 From: Aibek B Date: Mon, 11 Dec 2023 16:18:36 +0600 Subject: [PATCH] PS-8927: 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. --- .../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 b1ac9f3bded6..f6aae9b41cc1 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 a8ba80a188d5..51642774338f 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 7da99670c2e0..0e55bca54b14 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 3cfa280abd02..550e97d38773 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 8d7ef2d7177a..ae1fa30094b5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -11274,9 +11274,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; bool result [[maybe_unused]] = store_create_info( thd, table, &query, create_info, true /* show_database */,