From c23c38fa31ff9f7350c342a3fb8142e04b10e121 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 May 2006 23:01:31 +0300 Subject: [PATCH 1/9] BUG#14157: utf8 encoding in binlog without set character_set_client e.g DROP temporary Binlog lacks encoding info about DROPped temporary table. Idea of the fix is to switch temporary to system_charset_info when a temporary table is DROPped for binlog. Since that is the server, that automatically, but not the client, who generates the query the binlog should be updated on the server's encoding for the coming DROP. The `write_binlog_with_system_charset()' is introduced to replace similar problematic places in the code. mysql-test/r/drop_temp_table.result: results changed mysql-test/r/mix_innodb_myisam_binlog.result: results changed mysql-test/r/mysqlbinlog.result: results changed mysql-test/r/rpl_temporary.result: results changed mysql-test/t/mysqlbinlog.test: Check roll-forward recovery from binlog where there are DROP temporary tables created in koi8r. mysql-test/t/rpl_temporary.test: Check slave digests binlog with DROP temporary tables created in koi8r. sql/mysql_priv.h: `write_binlog_with_system_charset()' is added to be called when a binlog event is created "implicitly" like DROP temporary table is case of closing connection. sql/sql_base.cc: Idea of the fix is to switch temporary to system_charset_info when a temporary table is DROPped for binlog. Since that is the server, not the client, who generates the query the binlog should be updated on server's encoding for the coming DROP. --- mysql-test/r/drop_temp_table.result | 1 + mysql-test/r/mix_innodb_myisam_binlog.result | 5 +++-- mysql-test/r/mysqlbinlog.result | 7 ++++++- mysql-test/r/rpl_temporary.result | 4 ++++ mysql-test/t/mysqlbinlog.test | 11 ++++++++++- mysql-test/t/rpl_temporary.test | 12 ++++++++++++ sql/mysql_priv.h | 7 +++++++ sql/sql_base.cc | 2 +- 8 files changed, 44 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/drop_temp_table.result b/mysql-test/r/drop_temp_table.result index 5f1f142cde5..40afd621676 100644 --- a/mysql-test/r/drop_temp_table.result +++ b/mysql-test/r/drop_temp_table.result @@ -17,6 +17,7 @@ master-bin.000001 # Query 1 # create database `drop-temp+table-test` master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn1 (a int) master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table `table:name` (a int) master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn2 (a int) +master-bin.000001 # Query 1 # use `drop-temp+table-test`; SET ONE_SHOT CHARACTER_SET_CLIENT=33,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=8 master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn2`,`drop-temp+table-test`.`table:name`,`drop-temp+table-test`.`shortn1` master-bin.000001 # Query 1 # use `drop-temp+table-test`; DO RELEASE_LOCK("a") drop database `drop-temp+table-test`; diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index e9613bac833..8cf99e8d623 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -249,7 +249,8 @@ master-bin.000001 1056 Query 1 1056 use `test`; insert t0 select * from t1 master-bin.000001 1117 Query 1 1117 use `test`; DO RELEASE_LOCK("a") master-bin.000001 1172 Query 1 1172 use `test`; insert into t0 select GET_LOCK("lock1",null) master-bin.000001 1251 Query 1 1251 use `test`; create table t2 (n int) engine=innodb -master-bin.000001 1323 Query 1 1323 use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti` -master-bin.000001 1424 Query 1 1424 use `test`; DO RELEASE_LOCK("lock1") +master-bin.000001 1323 Query 1 1323 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=33,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=8 +master-bin.000001 1457 Query 1 1457 use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti` +master-bin.000001 1558 Query 1 1558 use `test`; DO RELEASE_LOCK("lock1") do release_lock("lock1"); drop table t0,t2; diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index adaf0dad56b..bade0ca9b46 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -101,4 +101,9 @@ HEX(f) select HEX(f) from t4; HEX(f) 835C -drop table t1, t2, t03, t04, t3, t4; +flush logs; +select * from t5 /* must be (1),(1) */; +a +1 +1 +drop table t1, t2, t03, t04, t3, t4, t5; diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index cd67d2592a8..8c6d3f232b1 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -103,3 +103,7 @@ select * from t1 /* must be 1 */; f 1 drop table t1; +select * from t1; +a +1 +drop table t1; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 871886331f6..11aa5814bda 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -114,8 +114,17 @@ select HEX(f) from t3; select HEX(f) from t04; select HEX(f) from t4; +# +#14157: utf8 encoding in binlog without set character_set_client +# +flush logs; +--exec $MYSQL --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t5 select * from `только герои срезают рашпилем грим`' + +# resulted log is client charset insensitive (latin1 not koi8r) as it must be +--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 +select * from t5 /* must be (1),(1) */; # clean up -drop table t1, t2, t03, t04, t3, t4; +drop table t1, t2, t03, t04, t3, t4, t5; # End of 4.1 tests diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 71d7b32b7c9..af952760d6b 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -156,4 +156,16 @@ select * from t1 /* must be 1 */; connection master; drop table t1; +# +#14157: utf8 encoding in binlog without set character_set_client +# +--exec $MYSQL --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t1 select * from `только герои срезают рашпилем грим`' + +sync_slave_with_master; +#connection slave; +select * from t1; + +connection master; +drop table t1; + # End of 4.1 tests diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6676d994cfa..aab65bca82f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1275,6 +1275,13 @@ inline int hexchar_to_int(char c) return -1; } +inline void write_binlog_with_system_charset(THD * thd, Query_log_event * qinfo) +{ + CHARSET_INFO * cs_save= thd->variables.character_set_client; + thd->variables.character_set_client= system_charset_info; + mysql_bin_log.write(qinfo); + thd->variables.character_set_client= cs_save; +} /* Some functions that are different in the embedded library and the normal diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 60e91aff3f9..6365b8c8e40 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -615,7 +615,7 @@ void close_temporary_tables(THD *thd) rightfully causing the slave to stop. */ qinfo.error_code= 0; - mysql_bin_log.write(&qinfo); + write_binlog_with_system_charset(thd, &qinfo); } else { From 113b3f959e28a3156c987c3c049eafc751309519 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 May 2006 16:29:02 +0200 Subject: [PATCH 2/9] Bug#15886 (Test: Timing issue in test "rpl_until"): Changed format for SHOW SLAVE STATUS to vertical output. mysql-test/r/rpl_until.result: Result change mysql-test/t/rpl_until.test: Changed format for SHOW SLAVE STATUS to vertical output --- mysql-test/r/rpl_until.result | 148 +++++++++++++++++++++++++++++++--- mysql-test/t/rpl_until.test | 8 +- 2 files changed, 140 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/rpl_until.result b/mysql-test/r/rpl_until.result index b584e04ed57..60b956785ba 100644 --- a/mysql-test/r/rpl_until.result +++ b/mysql-test/r/rpl_until.result @@ -29,9 +29,40 @@ n 2 3 4 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 319 # Master master-bin.000001 319 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 319 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-bin.000001 +Until_Log_Pos 319 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; select * from t1; n @@ -39,23 +70,116 @@ n 2 3 4 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 319 # Master master-no-such-bin.000001 291 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 319 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-no-such-bin.000001 +Until_Log_Pos 291 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746; select * from t2; n 1 2 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 608 # Relay slave-relay-bin.000004 746 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 608 +Relay_Log_Space # +Until_Condition Relay +Until_Log_File slave-relay-bin.000004 +Until_Log_Pos 746 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave; stop slave; start slave until master_log_file='master-bin.000001', master_log_pos=776; -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 776 # Master master-bin.000001 776 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 776 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-bin.000001 +Until_Log_Pos 776 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until master_log_file='master-bin', master_log_pos=561; ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL start slave until master_log_file='master-bin.000001', master_log_pos=561, relay_log_pos=12; diff --git a/mysql-test/t/rpl_until.test b/mysql-test/t/rpl_until.test index e0ecf981fea..c404ea7e58b 100644 --- a/mysql-test/t/rpl_until.test +++ b/mysql-test/t/rpl_until.test @@ -31,7 +31,7 @@ wait_for_slave_to_stop; select * from t1; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # this should fail right after start start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; @@ -41,7 +41,7 @@ sleep 2; wait_for_slave_to_stop; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # try replicate all until second insert to t2; start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746; @@ -50,7 +50,7 @@ wait_for_slave_to_stop; select * from t2; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # clean up start slave; @@ -67,7 +67,7 @@ wait_for_slave_to_stop; # here the sql slave thread should be stopped --replace_result $MASTER_MYPORT MASTER_MYPORT bin.000005 bin.000004 bin.000006 bin.000004 bin.000007 bin.000004 --replace_column 1 # 9 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS #testing various error conditions --error 1277 From c212cb25ede28515c588d52061e67286bd3bb7d3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 May 2006 21:29:06 +0300 Subject: [PATCH 3/9] BUG#19188: incorrect temporary table name of DROP query in replication A pattern to generate binlog for DROPped temp table in close_temporary_tables was buggy: could not deal with a grave-accent-in-name table. The fix exploits `append_identifier()' for quoting and duplicating accents. mysql-test/r/rpl_temporary.result: results changed mysql-test/t/rpl_temporary.test: more correct internal table emulation; typo of @@session in bug#17263. sql/mysql_priv.h: bool is_user_table(TABLE * table) is added to answer wheather temporary table was created explicitly. sql/sql_base.cc: Utilizing `append_identifier' to quote. `close_temporary_tables' once again recoded I hope to become much simplier than previously. No-binlog branch is separated completely the rest that adopts String's methods. --- mysql-test/r/rpl_temporary.result | 13 ++- mysql-test/t/rpl_temporary.test | 15 ++- sql/mysql_priv.h | 12 +++ sql/sql_base.cc | 147 ++++++++++++++---------------- 4 files changed, 99 insertions(+), 88 deletions(-) diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index cd67d2592a8..0442109c016 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -89,14 +89,17 @@ f 7 drop table t1,t2; create temporary table t3 (f int); -set @session.pseudo_thread_id=100; +set @@session.pseudo_thread_id=100; create temporary table t101 (id int); create temporary table t102 (id int); -set @session.pseudo_thread_id=200; +set @@session.pseudo_thread_id=200; create temporary table t201 (id int); -create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); -set @con1_id=connection_id(); -kill @con1_id; +create temporary table `t``201` (id int); +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); create table t1(f int); insert into t1 values (1); select * from t1 /* must be 1 */; diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 71d7b32b7c9..e1dd1f32546 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -135,14 +135,19 @@ sync_with_master; # value was set up at the moment of temp table creation # connection con1; -set @session.pseudo_thread_id=100; +set @@session.pseudo_thread_id=100; create temporary table t101 (id int); create temporary table t102 (id int); -set @session.pseudo_thread_id=200; +set @@session.pseudo_thread_id=200; create temporary table t201 (id int); -create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); -set @con1_id=connection_id(); -kill @con1_id; +create temporary table `t``201` (id int); +# emulate internal temp table not to come to binlog +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); +disconnect con1; #now do something to show that slave is ok after DROP temp tables connection master; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6676d994cfa..634e7bad738 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1275,6 +1275,18 @@ inline int hexchar_to_int(char c) return -1; } +/* + is_user_table() + return true if the table was created explicitly +*/ + +inline bool is_user_table(TABLE * table) +{ + const char *name= table->real_name; + return strncmp(name, tmp_file_prefix, tmp_file_prefix_length); +} + + /* Some functions that are different in the embedded library and the normal diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 60e91aff3f9..3df9cbace78 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -493,118 +493,107 @@ static inline uint tmpkeyval(THD *thd, TABLE *table) void close_temporary_tables(THD *thd) { - TABLE *next, - *prev_table /* prev link is not maintained in TABLE's double-linked list */, - *table; - char *query= (gptr) 0, *end; - uint query_buf_size, max_names_len; - bool found_user_tables; - + TABLE *table; if (!thd->temporary_tables) return; - LINT_INIT(end); - query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS + if (!mysql_bin_log.is_open()) + { + for (table= thd->temporary_tables; table; table= table->next) + { + close_temporary(table, 1); + } + thd->temporary_tables= 0; + return; + } + TABLE *next, + *prev_table /* prev link is not maintained in TABLE's double-linked list */; + bool was_quote_show= true; /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */ + // Better add "if exists", in case a RESET MASTER has been done + const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "; + uint stub_len= sizeof(stub) - 1; + char buf[256]; + memcpy(buf, stub, stub_len); + String s_query= String(buf, sizeof(buf), system_charset_info); + bool found_user_tables= false; + LINT_INIT(next); + /* insertion sort of temp tables by pseudo_thread_id to build ordered list of sublists of equal pseudo_thread_id */ - for (prev_table= thd->temporary_tables, - table= prev_table->next, - found_user_tables= (prev_table->real_name[0] != '#'); + + for (prev_table= thd->temporary_tables, table= prev_table->next; table; prev_table= table, table= table->next) { - TABLE *prev_sorted /* same as for prev_table */, - *sorted; - /* - table not created directly by the user is moved to the tail. - Fixme/todo: nothing (I checked the manual) prevents user to create temp - with `#' - */ - if (table->real_name[0] == '#') - continue; - else + TABLE *prev_sorted /* same as for prev_table */, *sorted; + if (is_user_table(table)) { - found_user_tables = 1; - } - for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; - prev_sorted= sorted, sorted= sorted->next) - { - if (sorted->real_name[0] == '#' || tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) + if (!found_user_tables) + found_user_tables= true; + for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; + prev_sorted= sorted, sorted= sorted->next) { - /* move into the sorted part of the list from the unsorted */ - prev_table->next= table->next; - table->next= sorted; - if (prev_sorted) + if (!is_user_table(sorted) || + tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) { - prev_sorted->next= table; + /* move into the sorted part of the list from the unsorted */ + prev_table->next= table->next; + table->next= sorted; + if (prev_sorted) + { + prev_sorted->next= table; + } + else + { + thd->temporary_tables= table; + } + table= prev_table; + break; } - else - { - thd->temporary_tables= table; - } - table= prev_table; - break; } } - } - /* - calc query_buf_size as max per sublists, one sublist per pseudo thread id. - Also stop at first occurence of `#'-named table that starts - all implicitly created temp tables - */ - for (max_names_len= 0, table=thd->temporary_tables; - table && table->real_name[0] != '#'; - table=table->next) + } + + /* We always quote db,table names though it is slight overkill */ + if (found_user_tables && + !(was_quote_show= (thd->options & OPTION_QUOTE_SHOW_CREATE))) { - uint tmp_names_len; - for (tmp_names_len= table->key_length + 1; - table->next && table->real_name[0] != '#' && - tmpkeyval(thd, table) == tmpkeyval(thd, table->next); - table=table->next) - { - /* - We are going to add 4 ` around the db/table names, so 1 might not look - enough; indeed it is enough, because table->key_length is greater (by 8, - because of server_id and thread_id) than db||table. - */ - tmp_names_len += table->next->key_length + 1; - } - if (tmp_names_len > max_names_len) max_names_len= tmp_names_len; + thd->options |= OPTION_QUOTE_SHOW_CREATE; } - /* allocate */ - if (found_user_tables && mysql_bin_log.is_open() && - (query = alloc_root(thd->mem_root, query_buf_size+= max_names_len))) - // Better add "if exists", in case a RESET MASTER has been done - end= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "); - /* scan sorted tmps to generate sequence of DROP */ - for (table=thd->temporary_tables; table; table= next) + for (table= thd->temporary_tables; table; table= next) { - if (query // we might be out of memory, but this is not fatal - && table->real_name[0] != '#') + if (is_user_table(table)) { - char *end_cur; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); /* Loop forward through all tables within the sublist of common pseudo_thread_id to create single DROP query */ - for (end_cur= end; - table && table->real_name[0] != '#' && + for (s_query.length(stub_len); + table && is_user_table(table) && tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; table= next) { - end_cur= strxmov(end_cur, "`", table->table_cache_key, "`.`", - table->real_name, "`,", NullS); + /* + We are going to add 4 ` around the db/table names and possible more + due to special characters in the names + */ + append_identifier(thd, &s_query, table->table_cache_key, strlen(table->table_cache_key)); + s_query.q_append('.'); + append_identifier(thd, &s_query, table->real_name, + strlen(table->real_name)); + s_query.q_append(','); next= table->next; close_temporary(table, 1); } thd->clear_error(); - /* The -1 is to remove last ',' */ - Query_log_event qinfo(thd, query, (ulong)(end_cur - query) - 1, 0, FALSE); + Query_log_event qinfo(thd, s_query.ptr(), + s_query.length() - 1 /* to remove trailing ',' */, + 0, FALSE); /* Imagine the thread had created a temp table, then was doing a SELECT, and the SELECT was killed. Then it's not clever to mark the statement above as @@ -623,6 +612,8 @@ void close_temporary_tables(THD *thd) close_temporary(table, 1); } } + if (!was_quote_show) + thd->options &= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */ thd->temporary_tables=0; } From 62be79a2e6208873240fb0a3dafbb99f24c9e577 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 May 2006 12:14:20 +0300 Subject: [PATCH 4/9] BUG#14157: utf8 encoding in binlog without set character_set_client fixing a path to find charset by $MYSQL client. I believe the fix is done what should be by default. mysql-test/t/mysqlbinlog.test: --character-sets-dir=../sql/share/charsets is added otherwise client/.libs/lt-mysql searches in /usr/local/mysql ... A bug? mysql-test/t/rpl_temporary.test: --character-sets-dir=../sql/share/charsets/ --- mysql-test/t/mysqlbinlog.test | 2 +- mysql-test/t/rpl_temporary.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 11aa5814bda..7b6c36bb8c9 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -118,7 +118,7 @@ select HEX(f) from t4; #14157: utf8 encoding in binlog without set character_set_client # flush logs; ---exec $MYSQL --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t5 select * from `только герои срезают рашпилем грим`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t5 select * from `только герои срезают рашпилем грим`' # resulted log is client charset insensitive (latin1 not koi8r) as it must be --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 1276b635b74..609e8533849 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -164,7 +164,7 @@ drop table t1; # #14157: utf8 encoding in binlog without set character_set_client # ---exec $MYSQL --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t1 select * from `только герои срезают рашпилем грим`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t1 select * from `только герои срезают рашпилем грим`' sync_slave_with_master; #connection slave; From d388da989e538cfd68a1d606f7e4d109a0263906 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 14 May 2006 20:09:09 +0300 Subject: [PATCH 5/9] BUG#14157: utf8 encoding in binlog without set character_set_client fixing names length. Got an issue when merged to 5.0, decided to fix starting from 4.1 mysql-test/t/mysqlbinlog.test: fixing temp table name to fit to 64 bytes for 5.0 mysql-test/t/rpl_temporary.test: fixing temp table name to fit to 64 bytes for 5.0 --- mysql-test/t/mysqlbinlog.test | 2 +- mysql-test/t/rpl_temporary.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 7b6c36bb8c9..6e3daaef0c3 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -118,7 +118,7 @@ select HEX(f) from t4; #14157: utf8 encoding in binlog without set character_set_client # flush logs; ---exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t5 select * from `только герои срезают рашпилем грим`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `ящик` (a int); insert into `ящик` values (1); insert into t5 select * from `ящик`' # resulted log is client charset insensitive (latin1 not koi8r) as it must be --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 609e8533849..871ff096476 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -164,7 +164,7 @@ drop table t1; # #14157: utf8 encoding in binlog without set character_set_client # ---exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t1 select * from `только герои срезают рашпилем грим`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `ящик` (a int); insert into `ящик` values (1); insert into t1 select * from `ящик`' sync_slave_with_master; #connection slave; From b9558d8bdaf68c923d2f9940b37eb161fd116e73 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 14 May 2006 20:31:42 +0300 Subject: [PATCH 6/9] BUG#19188: incorrect temporary table name of DROP query in replication manual merge to account 5.0 specific names of TABLE class sql/mysql_priv.h: manual merge: changing to 5.0's TABLE class names sql/sql_base.cc: manual merge: whitespaces and 5.0 TABLE's names --- sql/mysql_priv.h | 2 +- sql/sql_base.cc | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9aa5c3e41d5..776c23a21a6 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1602,7 +1602,7 @@ inline void write_binlog_with_system_charset(THD * thd, Query_log_event * qinfo) inline bool is_user_table(TABLE * table) { - const char *name= table->real_name; + const char *name= table->s->table_name; return strncmp(name, tmp_file_prefix, tmp_file_prefix_length); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f0480a1c616..b6694edea78 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -620,7 +620,7 @@ void close_temporary_tables(THD *thd) TABLE *table; if (!thd->temporary_tables) return; - + if (!mysql_bin_log.is_open()) { for (table= thd->temporary_tables; table; table= table->next) @@ -642,12 +642,12 @@ void close_temporary_tables(THD *thd) String s_query= String(buf, sizeof(buf), system_charset_info); bool found_user_tables= false; LINT_INIT(next); - - /* - insertion sort of temp tables by pseudo_thread_id to build ordered list + + /* + insertion sort of temp tables by pseudo_thread_id to build ordered list of sublists of equal pseudo_thread_id */ - + for (prev_table= thd->temporary_tables, table= prev_table->next; table; prev_table= table, table= table->next) @@ -657,7 +657,7 @@ void close_temporary_tables(THD *thd) { if (!found_user_tables) found_user_tables= true; - for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; + for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; prev_sorted= sorted, sorted= sorted->next) { if (!is_user_table(sorted) || @@ -666,7 +666,7 @@ void close_temporary_tables(THD *thd) /* move into the sorted part of the list from the unsorted */ prev_table->next= table->next; table->next= sorted; - if (prev_sorted) + if (prev_sorted) { prev_sorted->next= table; } @@ -687,11 +687,11 @@ void close_temporary_tables(THD *thd) { thd->options |= OPTION_QUOTE_SHOW_CREATE; } - + /* scan sorted tmps to generate sequence of DROP */ for (table= thd->temporary_tables; table; table= next) { - if (is_user_table(table)) + if (is_user_table(table)) { /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); @@ -706,10 +706,10 @@ void close_temporary_tables(THD *thd) We are going to add 4 ` around the db/table names and possible more due to special characters in the names */ - append_identifier(thd, &s_query, table->table_cache_key, strlen(table->table_cache_key)); + append_identifier(thd, &s_query, table->s->db, strlen(table->s->db)); s_query.q_append('.'); - append_identifier(thd, &s_query, table->real_name, - strlen(table->real_name)); + append_identifier(thd, &s_query, table->s->table_name, + strlen(table->s->table_name)); s_query.q_append(','); next= table->next; close_temporary(table, 1); @@ -730,7 +730,7 @@ void close_temporary_tables(THD *thd) qinfo.error_code= 0; write_binlog_with_system_charset(thd, &qinfo); } - else + else { next= table->next; close_temporary(table, 1); From b6c7f5f2a80e6123f0106254c6c56af8f33f12d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 15 May 2006 18:05:23 +0300 Subject: [PATCH 7/9] BUG#14157: utf8 encoding in binlog without set character_set_client: e.g DROP temporary specific to 5.0 version of the patch is motivated by the fact that a wrapper over MYSQLLOG::write can not help in 5.0 where query's charset is embedded into event instance in the constructor. sql/mysql_priv.h: this 4.1 specific code does not help in 5.0 sql/sql_base.cc: No wrapper similar to 4.1's version is done since Query_log_event constructor takes care of encodings in 5.0 whereas log::write method does it in 4.1. We can introduce an additional constuctor for Query_log_event to pass desired (i.e system_character_info) charset different from THD's version. But I am delaying this while there are not more bugs similar to this one reported. --- sql/mysql_priv.h | 13 ------------- sql/sql_base.cc | 5 ++++- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 776c23a21a6..0290c0178e0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1582,19 +1582,6 @@ inline int hexchar_to_int(char c) return -1; } -/* - wrapper to use instead of mysql_bin_log.write when - query is generated by the server using system_charset encoding -*/ - -inline void write_binlog_with_system_charset(THD * thd, Query_log_event * qinfo) -{ - CHARSET_INFO * cs_save= thd->variables.character_set_client; - thd->variables.character_set_client= system_charset_info; - mysql_bin_log.write(qinfo); - thd->variables.character_set_client= cs_save; -} - /* is_user_table() return true if the table was created explicitly diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b6694edea78..c83e847bc8a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -715,9 +715,12 @@ void close_temporary_tables(THD *thd) close_temporary(table, 1); } thd->clear_error(); + CHARSET_INFO *cs_save= thd->variables.character_set_client; + thd->variables.character_set_client= system_charset_info; Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE); + thd->variables.character_set_client= cs_save; /* Imagine the thread had created a temp table, then was doing a SELECT, and the SELECT was killed. Then it's not clever to mark the statement above as @@ -728,7 +731,7 @@ void close_temporary_tables(THD *thd) rightfully causing the slave to stop. */ qinfo.error_code= 0; - write_binlog_with_system_charset(thd, &qinfo); + mysql_bin_log.write(&qinfo); } else { From bccff08cba9994f12acf52e6aa960c32e949dd9d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 May 2006 09:26:57 +0200 Subject: [PATCH 8/9] Fixed result file (rpl_temporary) mysql-test/r/rpl_temporary.result: Fixed result file --- mysql-test/r/rpl_temporary.result | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index da85ef5104d..751dc7754f7 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -103,15 +103,24 @@ f 1 drop temporary table t4; drop table t5; -set @session.pseudo_thread_id=100; +set @@session.pseudo_thread_id=100; create temporary table t101 (id int); create temporary table t102 (id int); -set @session.pseudo_thread_id=200; +set @@session.pseudo_thread_id=200; create temporary table t201 (id int); -create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); +create temporary table `t``201` (id int); +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); create table t1(f int); insert into t1 values (1); select * from t1 /* must be 1 */; f 1 drop table t1; +select * from t1; +a +1 +drop table t1; From 808f77f6b003bbd225c21905b0f204bbcb61d457 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 May 2006 10:01:07 +0200 Subject: [PATCH 9/9] Test used a charset not available on many platforms --- mysql-test/r/mysqlbinlog.result | 6 +----- mysql-test/t/mysqlbinlog.test | 15 ++++++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index c3be791b523..664833fab2a 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -190,8 +190,4 @@ select HEX(f) from t4; HEX(f) 835C flush logs; -select * from t5 /* must be (1),(1) */; -a -1 -1 -drop table t1, t2, t03, t04, t3, t4, t5; +drop table t1, t2, t03, t04, t3, t4; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 843536e956d..d74bb1c3a80 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -123,16 +123,21 @@ select HEX(f) from t04; select HEX(f) from t4; # -#14157: utf8 encoding in binlog without set character_set_client +# BUG#14157: utf8 encoding in binlog without set character_set_client +# +# BUG: +# This test only works on the MySQL-internal rpl machines. +# Needs to be fixed. Problem is that koi8r is not installed +# on many machines. # flush logs; ---exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `ящик` (a int); insert into `ящик` values (1); insert into t5 select * from `ящик`' +# --exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `ящик` (a int); insert into `ящик` values (1); insert into t5 select * from `ящик`' # resulted log is client charset insensitive (latin1 not koi8r) as it must be ---exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 -select * from t5 /* must be (1),(1) */; +# --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 +#select * from t5 /* must be (1),(1) */; # clean up -drop table t1, t2, t03, t04, t3, t4, t5; +drop table t1, t2, t03, t04, t3, t4; # End of 5.0 tests