From 24f7afe7bcb1befec02f7c6efe884229bda3ff39 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 3 Mar 2010 12:16:18 +0000 Subject: [PATCH] BUG#51226: mysqlbinlog replay: ERROR 1146 when using temp tables + failing statements Implicit DROP event for temporary table is not getting LOG_EVENT_THREAD_SPECIFIC_F flag, because, in the previous executed statement in the same thread, which might even be a failed statement, the thread_specific_used flag is set to FALSE (in mysql_reset_thd_for_next_command) and not set to TRUE before connection is shutdown. This means that implicit DROP event will take the FALSE value from thread_specific_used and will not set LOG_EVENT_THREAD_SPECIFIC_F in the event header. As a consequence, mysqlbinlog will not print the pseudo_thread_id from the DROP event, because one of the requirements for the printout is that this flag is set to TRUE. We fix this by setting thread_specific_used whenever we are binlogging a DROP in close_temporary_tables, and resetting it to its previous value afterward. --- .../suite/binlog/r/binlog_tmp_table.result | 11 ++++ .../suite/binlog/t/binlog_tmp_table.test | 66 +++++++++++++++++++ sql/sql_base.cc | 3 + 3 files changed, 80 insertions(+) diff --git a/mysql-test/suite/binlog/r/binlog_tmp_table.result b/mysql-test/suite/binlog/r/binlog_tmp_table.result index 14b1963ffd9..91702aa7335 100644 --- a/mysql-test/suite/binlog/r/binlog_tmp_table.result +++ b/mysql-test/suite/binlog/r/binlog_tmp_table.result @@ -29,3 +29,14 @@ a 6 8 drop table foo; +RESET MASTER; +create database b51226; +use b51226; +create temporary table t1(i int); +use b51226; +create temporary table t1(i int); +create temporary table t1(i int); +ERROR 42S01: Table 't1' already exists +insert into t1 values(1); +DROP DATABASE b51226; +FLUSH LOGS; diff --git a/mysql-test/suite/binlog/t/binlog_tmp_table.test b/mysql-test/suite/binlog/t/binlog_tmp_table.test index 54af8a8cb68..b4ef1e51a0b 100644 --- a/mysql-test/suite/binlog/t/binlog_tmp_table.test +++ b/mysql-test/suite/binlog/t/binlog_tmp_table.test @@ -82,3 +82,69 @@ select * from foo; # clean up drop table foo; + +################################################################# +# BUG#51226 +################################################################# + +RESET MASTER; + +-- let $dbname=b51226 + +connect (con1,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connect (con2,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); + +# +# action: on con1 create the database and the tmp table +# +-- connection con1 +-- eval create database $dbname +-- eval use $dbname +create temporary table t1(i int); + +# +# action: on con1 create the tmp table +# +-- connection con2 +-- eval use $dbname +create temporary table t1(i int); + +# action: at this point, the last event binlogged contains the +# pseudo_thread_id from con2. So now we switch to con1, issue +# a statement that fails and close the connection (which logs +# implicitely a DROP TEMPORARY TABLE). +# +# Before the patch this would not log con1's pseudo_thread_id +# because the failing statement would reset THD context +# (unsetting the thread_specific_used flag, and consequently, +# causing the DROP event to be logged without pseudo_thread_id +# in its header). + +-- connection con1 +-- error 1050 +create temporary table t1(i int); +-- disconnect con1 + +-- connection default +-- let $wait_binlog_event= DROP +-- source include/wait_for_binlog_event.inc + +# action: insert in the t1. This would cause the the test to fail, +# because when replaying the binlog the previous implicit drop +# temp table would have been executed under the wrong +# pseudo_thread_id, dropping the tmp table on con2. +-- connection con2 +insert into t1 values(1); +-- disconnect con2 + +-- connection default +-- let $wait_binlog_event= DROP +-- source include/wait_for_binlog_event.inc + +-- eval DROP DATABASE $dbname +FLUSH LOGS; + +# assertion: assert that when replaying the binary log will succeed, +# instead of failing with "Table 'XXX.YYY' doesn't exist" +-- let $MYSQLD_DATADIR= `select @@datadir` +-- exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 | $MYSQL diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 06e4b1d3e63..9256d3d907f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1515,6 +1515,7 @@ void close_temporary_tables(THD *thd) { if (is_user_table(table)) { + bool save_thread_specific_used= thd->thread_specific_used; my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); @@ -1544,6 +1545,7 @@ void close_temporary_tables(THD *thd) thd->clear_error(); CHARSET_INFO *cs_save= thd->variables.character_set_client; thd->variables.character_set_client= system_charset_info; + thd->thread_specific_used= TRUE; Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE, 0); @@ -1556,6 +1558,7 @@ void close_temporary_tables(THD *thd) "Failed to write the DROP statement for temporary tables to binary log"); } thd->variables.pseudo_thread_id= save_pseudo_thread_id; + thd->thread_specific_used= save_thread_specific_used; } else {