Commit d13db314 authored by Luis Soares's avatar Luis Soares

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.
parent 32058ba9
...@@ -29,3 +29,14 @@ a ...@@ -29,3 +29,14 @@ a
6 6
8 8
drop table foo; 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;
...@@ -82,3 +82,69 @@ select * from foo; ...@@ -82,3 +82,69 @@ select * from foo;
# clean up # clean up
drop table foo; 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
...@@ -1515,6 +1515,7 @@ void close_temporary_tables(THD *thd) ...@@ -1515,6 +1515,7 @@ void close_temporary_tables(THD *thd)
{ {
if (is_user_table(table)) 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; my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id;
/* Set pseudo_thread_id to be that of the processed table */ /* Set pseudo_thread_id to be that of the processed table */
thd->variables.pseudo_thread_id= tmpkeyval(thd, table); thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
...@@ -1544,6 +1545,7 @@ void close_temporary_tables(THD *thd) ...@@ -1544,6 +1545,7 @@ void close_temporary_tables(THD *thd)
thd->clear_error(); thd->clear_error();
CHARSET_INFO *cs_save= thd->variables.character_set_client; CHARSET_INFO *cs_save= thd->variables.character_set_client;
thd->variables.character_set_client= system_charset_info; thd->variables.character_set_client= system_charset_info;
thd->thread_specific_used= TRUE;
Query_log_event qinfo(thd, s_query.ptr(), Query_log_event qinfo(thd, s_query.ptr(),
s_query.length() - 1 /* to remove trailing ',' */, s_query.length() - 1 /* to remove trailing ',' */,
0, FALSE, 0); 0, FALSE, 0);
...@@ -1556,6 +1558,7 @@ void close_temporary_tables(THD *thd) ...@@ -1556,6 +1558,7 @@ void close_temporary_tables(THD *thd)
"Failed to write the DROP statement for temporary tables to binary log"); "Failed to write the DROP statement for temporary tables to binary log");
} }
thd->variables.pseudo_thread_id= save_pseudo_thread_id; thd->variables.pseudo_thread_id= save_pseudo_thread_id;
thd->thread_specific_used= save_thread_specific_used;
} }
else else
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment