List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:February 11 2010 1:18pm
Subject:bzr commit into mysql-5.5-next-mr branch (davi:3090) Bug#42643
View as plain text  
# At a local mysql-5.5-next-mr repository of davi

 3090 Davi Arnaut	2010-02-11
      Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
      
      The problem was that TRUNCATE TABLE didn't take a exclusive lock
      on a table if it resorted to a truncating via a delete of all rows
      in the table. Specifically for InnoDB tables, this could break
      proper isolation as InnoDB ends up aborting some granted locks when
      deleting all rows of a table.
      
      The solution is to take a exclusive metadata lock before TRUNCATE
      TABLE can proceed. This guarantees that no other transaction is
      using the table.
     @ mysql-test/extra/binlog_tests/binlog_truncate.test
        Add test cae for Bug#42643
     @ mysql-test/include/mix1.inc
        Update test case as TRUNCATE TABLE now grabs a exclusive lock.
     @ mysql-test/r/innodb_mysql.result
        Update test case result.
     @ mysql-test/r/truncate.result
        Update test case result.
     @ mysql-test/suite/binlog/t/binlog_truncate_innodb.test
        As with other data modifying statements, TRUNCATE is still not
        possible in a transaction with isolation level READ COMMITTED
        or READ UNCOMMITED. It would be possible to implement so, but
        it is not worth the effort.
     @ mysql-test/suite/binlog/t/binlog_truncate_myisam.test
        Test under different binlog formats.
     @ mysql-test/suite/binlog/t/disabled.def
        Re-enable test case.
     @ mysql-test/t/truncate.test
        A metadata lock is now taken before the object is verified.
     @ sql/mysql_priv.h
        Rename functions.
     @ sql/sql_delete.cc
        Move truncation of a pre-locked table to its own function -- this
        is only used by repair. Also, move temporary table truncation to
        its own function.
        
        Acquire a exclusive metadata lock before accessing table metadata.
     @ sql/sql_parse.cc
        Rename function.
     @ sql/sql_table.cc
        Rename function.

    modified:
      mysql-test/extra/binlog_tests/binlog_truncate.test
      mysql-test/include/mix1.inc
      mysql-test/r/innodb_mysql.result
      mysql-test/r/truncate.result
      mysql-test/suite/binlog/r/binlog_truncate_innodb.result
      mysql-test/suite/binlog/r/binlog_truncate_myisam.result
      mysql-test/suite/binlog/t/binlog_truncate_innodb.test
      mysql-test/suite/binlog/t/binlog_truncate_myisam.test
      mysql-test/suite/binlog/t/disabled.def
      mysql-test/t/truncate.test
      sql/mysql_priv.h
      sql/sql_delete.cc
      sql/sql_parse.cc
      sql/sql_table.cc
=== modified file 'mysql-test/extra/binlog_tests/binlog_truncate.test'
--- a/mysql-test/extra/binlog_tests/binlog_truncate.test	2009-02-06 16:06:41 +0000
+++ b/mysql-test/extra/binlog_tests/binlog_truncate.test	2010-02-11 13:18:37 +0000
@@ -25,3 +25,43 @@ TRUNCATE TABLE t2;
 source include/show_binlog_events.inc;
 
 DROP TABLE t1,t2;
+
+--echo #
+--echo # Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+--echo #
+
+eval CREATE TABLE t1 (a INT) ENGINE=$engine;
+eval CREATE TABLE t2 (a INT) ENGINE=$engine;
+INSERT INTO t1 VALUES (1),(2);
+
+let $binlog_start = query_get_value("SHOW MASTER STATUS", Position, 1);
+if (`select length('$before_truncate') > 0`) {
+  eval $before_truncate;
+}
+
+--echo # Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+
+connect (truncate,localhost,root,,);
+--echo # Connection: truncate
+--send TRUNCATE TABLE t1
+
+connection default;
+--echo # Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COMMIT;
+
+connection truncate;
+--echo # Connection: truncate
+--reap
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM t2;
+
+connection default;
+--echo # Connection: default
+
+source include/show_binlog_events.inc;
+disconnect truncate;
+DROP TABLE t1,t2;

=== modified file 'mysql-test/include/mix1.inc'
--- a/mysql-test/include/mix1.inc	2009-12-08 07:39:49 +0000
+++ b/mysql-test/include/mix1.inc	2010-02-11 13:18:37 +0000
@@ -1351,6 +1351,13 @@ connection con1;
 SELECT * FROM t1;
 ROLLBACK;
 
+--echo # Switch to connection con2
+connection con2;
+ROLLBACK;
+
+--echo # Switch to connection con1
+connection con1;
+
 --echo # 2. test for serialized update:
 
 CREATE TABLE t2 (a INT);

=== modified file 'mysql-test/r/innodb_mysql.result'
--- a/mysql-test/r/innodb_mysql.result	2010-02-01 23:22:16 +0000
+++ b/mysql-test/r/innodb_mysql.result	2010-02-11 13:18:37 +0000
@@ -1590,6 +1590,9 @@ SELECT * FROM t1;
 a	b
 1	12
 ROLLBACK;
+# Switch to connection con2
+ROLLBACK;
+# Switch to connection con1
 # 2. test for serialized update:
 CREATE TABLE t2 (a INT);
 TRUNCATE t1;

=== modified file 'mysql-test/r/truncate.result'
--- a/mysql-test/r/truncate.result	2009-12-11 12:24:23 +0000
+++ b/mysql-test/r/truncate.result	2010-02-11 13:18:37 +0000
@@ -99,7 +99,7 @@ LOCK TABLE t1 WRITE;
 SELECT * FROM v1;
 ERROR HY000: Table 'v1' was not locked with LOCK TABLES
 TRUNCATE v1;
-ERROR 42S02: Table 'test.v1' doesn't exist
+ERROR HY000: Table 'v1' was not locked with LOCK TABLES
 SELECT * FROM v1;
 ERROR HY000: Table 'v1' was not locked with LOCK TABLES
 UNLOCK TABLES;
@@ -107,7 +107,7 @@ LOCK TABLE t1 WRITE, t2 WRITE;
 SELECT * FROM v1;
 ERROR HY000: Table 'v1' was not locked with LOCK TABLES
 TRUNCATE v1;
-ERROR 42S02: Table 'test.v1' doesn't exist
+ERROR HY000: Table 'v1' was not locked with LOCK TABLES
 SELECT * FROM v1;
 ERROR HY000: Table 'v1' was not locked with LOCK TABLES
 UNLOCK TABLES;
@@ -117,7 +117,7 @@ c1
 1
 3
 TRUNCATE v1;
-ERROR 42S02: Table 'test.v1' doesn't exist
+ERROR HY000: Table 'v1' was not locked with LOCK TABLES
 SELECT * FROM v1;
 c1
 1
@@ -129,7 +129,7 @@ c1
 1
 3
 TRUNCATE v1;
-ERROR 42S02: Table 'test.v1' doesn't exist
+ERROR HY000: Table 'v1' was not locked with LOCK TABLES
 SELECT * FROM v1;
 c1
 1

=== modified file 'mysql-test/suite/binlog/r/binlog_truncate_innodb.result'
--- a/mysql-test/suite/binlog/r/binlog_truncate_innodb.result	2009-02-06 16:06:41 +0000
+++ b/mysql-test/suite/binlog/r/binlog_truncate_innodb.result	2010-02-11 13:18:37 +0000
@@ -1,3 +1,5 @@
+SET BINLOG_FORMAT=ROW;
+RESET MASTER;
 CREATE TABLE t1 (a INT) ENGINE=InnoDB;
 CREATE TABLE t2 (a INT) ENGINE=InnoDB;
 INSERT INTO t2 VALUES (1),(2),(3);
@@ -9,6 +11,41 @@ Log_name	Pos	Event_type	Server_id	End_lo
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
 DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
 CREATE TABLE t1 (a INT) ENGINE=InnoDB;
 CREATE TABLE t2 (a INT) ENGINE=InnoDB;
 INSERT INTO t2 VALUES (1),(2),(3);
@@ -22,6 +59,42 @@ Log_name	Pos	Event_type	Server_id	End_lo
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
 DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
 CREATE TABLE t1 (a INT) ENGINE=InnoDB;
 CREATE TABLE t2 (a INT) ENGINE=InnoDB;
 INSERT INTO t2 VALUES (1),(2),(3);
@@ -35,6 +108,189 @@ Log_name	Pos	Event_type	Server_id	End_lo
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
 DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3);
+SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+**** Truncate of empty table shall be logged
+TRUNCATE TABLE t1;
+SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+TRUNCATE TABLE t2;
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
+DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3);
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+**** Truncate of empty table shall be logged
+TRUNCATE TABLE t1;
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+TRUNCATE TABLE t2;
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
+DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
+SET BINLOG_FORMAT=STATEMENT;
+RESET MASTER;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3);
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+**** Truncate of empty table shall be logged
+TRUNCATE TABLE t1;
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+TRUNCATE TABLE t2;
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
+DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t2 SELECT * FROM t1
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t2 SELECT * FROM t1
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
 CREATE TABLE t1 (a INT) ENGINE=InnoDB;
 CREATE TABLE t2 (a INT) ENGINE=InnoDB;
 INSERT INTO t2 VALUES (1),(2),(3);
@@ -48,6 +304,40 @@ Log_name	Pos	Event_type	Server_id	End_lo
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
 DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t2 SELECT * FROM t1
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t2 SELECT * FROM t1
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
 CREATE TABLE t1 (a INT) ENGINE=InnoDB;
 CREATE TABLE t2 (a INT) ENGINE=InnoDB;
 INSERT INTO t2 VALUES (1),(2),(3);
@@ -61,3 +351,38 @@ Log_name	Pos	Event_type	Server_id	End_lo
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
 DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t2 SELECT * FROM t1
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t2 SELECT * FROM t1
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
+SET BINLOG_FORMAT=DEFAULT;

=== modified file 'mysql-test/suite/binlog/r/binlog_truncate_myisam.result'
--- a/mysql-test/suite/binlog/r/binlog_truncate_myisam.result	2009-02-10 21:26:37 +0000
+++ b/mysql-test/suite/binlog/r/binlog_truncate_myisam.result	2010-02-11 13:18:37 +0000
@@ -1,3 +1,4 @@
+SET BINLOG_FORMAT=ROW;
 RESET MASTER;
 CREATE TABLE t1 (a INT) ENGINE=MyISAM;
 CREATE TABLE t2 (a INT) ENGINE=MyISAM;
@@ -10,3 +11,89 @@ Log_name	Pos	Event_type	Server_id	End_lo
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
 master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
 DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+CREATE TABLE t2 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1),(2);
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	COMMIT
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	COMMIT
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
+SET BINLOG_FORMAT=STATEMENT;
+RESET MASTER;
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+CREATE TABLE t2 (a INT) ENGINE=MyISAM;
+INSERT INTO t2 VALUES (1),(2),(3);
+**** Truncate of empty table shall be logged
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t2
+DROP TABLE t1,t2;
+#
+# Bug#42643: InnoDB does not support replication of TRUNCATE TABLE
+#
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+CREATE TABLE t2 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1),(2);
+# Connection: default
+BEGIN;
+INSERT INTO t2 SELECT * FROM t1;
+# Connection: truncate
+TRUNCATE TABLE t1;
+# Connection: default
+INSERT INTO t2 SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+COMMIT;
+# Connection: truncate
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+4
+# Connection: default
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t2 SELECT * FROM t1
+master-bin.000001	#	Query	#	#	COMMIT
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t2 SELECT * FROM t1
+master-bin.000001	#	Query	#	#	COMMIT
+master-bin.000001	#	Query	#	#	use `test`; TRUNCATE TABLE t1
+DROP TABLE t1,t2;
+SET BINLOG_FORMAT=DEFAULT;

=== modified file 'mysql-test/suite/binlog/t/binlog_truncate_innodb.test'
--- a/mysql-test/suite/binlog/t/binlog_truncate_innodb.test	2009-02-10 21:26:37 +0000
+++ b/mysql-test/suite/binlog/t/binlog_truncate_innodb.test	2010-02-11 13:18:37 +0000
@@ -1,21 +1,13 @@
 source include/have_log_bin.inc;
 source include/have_innodb.inc;
 
-# It is necessary to reset the master since otherwise the binlog test
-# might show the wrong binary log. The default for SHOW BINLOG EVENTS
-# is to show the first binary log, not the current one (which is
-# actually a better idea).
+let $engine = InnoDB;
 
+SET BINLOG_FORMAT=ROW;
 RESET MASTER;
 
-let $engine = InnoDB;
 source extra/binlog_tests/binlog_truncate.test;
 
-# Under transaction isolation level READ UNCOMMITTED and READ
-# COMMITTED, InnoDB does not permit statement-based replication of
-# row-deleting statement. In these cases, TRUNCATE TABLE should still
-# be replicated as a statement.
-
 let $before_truncate = SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
 source extra/binlog_tests/binlog_truncate.test;
 
@@ -27,3 +19,16 @@ source extra/binlog_tests/binlog_truncat
 
 let $before_truncate = SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
 source extra/binlog_tests/binlog_truncate.test;
+
+SET BINLOG_FORMAT=STATEMENT;
+RESET MASTER;
+
+source extra/binlog_tests/binlog_truncate.test;
+
+let $before_truncate = SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+source extra/binlog_tests/binlog_truncate.test;
+
+let $before_truncate = SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+source extra/binlog_tests/binlog_truncate.test;
+
+SET BINLOG_FORMAT=DEFAULT;

=== modified file 'mysql-test/suite/binlog/t/binlog_truncate_myisam.test'
--- a/mysql-test/suite/binlog/t/binlog_truncate_myisam.test	2009-02-10 21:26:37 +0000
+++ b/mysql-test/suite/binlog/t/binlog_truncate_myisam.test	2010-02-11 13:18:37 +0000
@@ -1,11 +1,15 @@
 source include/have_log_bin.inc;
 
-# It is necessary to reset the master since otherwise the binlog test
-# might show the wrong binary log. The default for SHOW BINLOG EVENTS
-# is to show the first binary log, not the current one (which is
-# actually a better idea).
+let $engine = MyISAM;
 
+SET BINLOG_FORMAT=ROW;
 RESET MASTER;
 
-let $engine = MyISAM;
 source extra/binlog_tests/binlog_truncate.test;
+
+SET BINLOG_FORMAT=STATEMENT;
+RESET MASTER;
+
+source extra/binlog_tests/binlog_truncate.test;
+
+SET BINLOG_FORMAT=DEFAULT;

=== modified file 'mysql-test/suite/binlog/t/disabled.def'
--- a/mysql-test/suite/binlog/t/disabled.def	2010-01-13 23:27:22 +0000
+++ b/mysql-test/suite/binlog/t/disabled.def	2010-02-11 13:18:37 +0000
@@ -9,6 +9,5 @@
 #  Do not use any TAB characters for whitespace.
 #
 ##############################################################################
-binlog_truncate_innodb	: BUG#42643 2009-02-06 mats Changes to InnoDB requires to complete fix for BUG#36763
 binlog_unsafe           : BUG#50312 2010-01-13 lsoares Warnings for unsafe sub-statement not returned to client
 

=== modified file 'mysql-test/t/truncate.test'
--- a/mysql-test/t/truncate.test	2009-12-11 12:24:23 +0000
+++ b/mysql-test/t/truncate.test	2010-02-11 13:18:37 +0000
@@ -102,7 +102,7 @@ SELECT * FROM v1;
 LOCK TABLE t1 WRITE;
 --error ER_TABLE_NOT_LOCKED
 SELECT * FROM v1;
---error ER_NO_SUCH_TABLE
+--error ER_TABLE_NOT_LOCKED
 TRUNCATE v1;
 --error ER_TABLE_NOT_LOCKED
 SELECT * FROM v1;
@@ -111,7 +111,7 @@ UNLOCK TABLES;
 LOCK TABLE t1 WRITE, t2 WRITE;
 --error ER_TABLE_NOT_LOCKED
 SELECT * FROM v1;
---error ER_NO_SUCH_TABLE
+--error ER_TABLE_NOT_LOCKED
 TRUNCATE v1;
 --error ER_TABLE_NOT_LOCKED
 SELECT * FROM v1;
@@ -119,14 +119,14 @@ UNLOCK TABLES;
 #
 LOCK TABLE v1 WRITE;
 SELECT * FROM v1;
---error ER_NO_SUCH_TABLE
+--error ER_TABLE_NOT_LOCKED
 TRUNCATE v1;
 SELECT * FROM v1;
 UNLOCK TABLES;
 #
 LOCK TABLE t1 WRITE, t2 WRITE, v1 WRITE;
 SELECT * FROM v1;
---error ER_NO_SUCH_TABLE
+--error ER_TABLE_NOT_LOCKED
 TRUNCATE v1;
 SELECT * FROM v1;
 UNLOCK TABLES;

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2010-02-08 20:19:55 +0000
+++ b/sql/mysql_priv.h	2010-02-11 13:18:37 +0000
@@ -1278,7 +1278,8 @@ int mysql_prepare_delete(THD *thd, TABLE
 bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
                   SQL_LIST *order, ha_rows rows, ulonglong options,
                   bool reset_auto_increment);
-bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
+bool mysql_truncate_table(THD *thd, TABLE_LIST *table_ref);
+bool mysql_truncate_locked_table(THD *thd, const char *db, const char *table);
 bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
 uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list,
                           bool tmp_table);

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2010-02-08 20:19:55 +0000
+++ b/sql/sql_delete.cc	2010-02-11 13:18:37 +0000
@@ -1074,19 +1074,69 @@ static bool mysql_truncate_by_delete(THD
 
 
 /*
-  Optimize delete of all rows by doing a full generate of the table
-  This will work even if the .ISM and .ISD tables are destroyed
+  Close and regenerate a temporary table.
 
-  dont_send_ok should be set if:
-  - We should always wants to generate the table (even if the table type
-    normally can't safely do this.
-  - We don't want an ok to be sent to the end user.
-  - We don't want to log the truncate command
-  - If we want to keep exclusive metadata lock on the table (obtained by
-    caller) on exit without errors.
+  @param  thd     Thread context.
+  @param  table   The temporary table.
+
+  @retval  FALSE  Success.
+  @retval  TRUE   Error.
 */
 
-bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
+static bool truncate_temporary_table(THD *thd, TABLE *table)
+{
+  bool error= TRUE;
+  TABLE_SHARE *share= table->s;
+  HA_CREATE_INFO create_info;
+  handlerton *table_type= table->s->db_type();
+  DBUG_ENTER("truncate_temporary_table");
+
+  memset(&create_info, 0, sizeof(create_info));
+
+  table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
+
+  /* Don't free share. */
+  close_temporary_table(thd, table, FALSE, FALSE);
+
+  ha_create_table(thd, share->normalized_path.str, share->db.str,
+                  share->table_name.str, &create_info, 1);
+
+  if (open_temporary_table(thd, share->path.str, share->db.str,
+                           share->table_name.str, 1))
+  {
+    error= FALSE;
+    thd->thread_specific_used= TRUE;
+  }
+  else
+    rm_temporary_table(table_type, share->path.str);
+
+  free_table_share(share);
+  my_free(table, MYF(0));
+
+  /* In RBR, the statement is not binlogged if the table is temporary. */
+  if (!error && !thd->is_current_stmt_binlog_format_row())
+    error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+
+  if (!error)
+    my_ok(thd);
+
+  DBUG_RETURN(error);
+}
+
+
+/*
+  Optimized delete of all rows by doing a full generate of the table.
+
+  @remark Will work even if the .ISM and .ISD tables are destroyed.
+
+  @param  thd         Thread context.
+  @param  table_ref   Reference to the table to be truncated.
+
+  @retval  FALSE  Success.
+  @retval  TRUE   Error.
+*/
+
+bool mysql_truncate_table(THD *thd, TABLE_LIST *table_ref)
 {
   HA_CREATE_INFO create_info;
   char path[FN_REFLEN + 1];
@@ -1094,133 +1144,121 @@ bool mysql_truncate(THD *thd, TABLE_LIST
   bool error= TRUE;
   uint path_length;
   /*
-    Is set if we're under LOCK TABLES, and used
-    to downgrade the exclusive lock after the
-    table was truncated.
+    Is set if we're under LOCK TABLES: used to downgrade the
+    exclusive lock after the table was truncated.
   */
   MDL_ticket *mdl_ticket= NULL;
   bool has_mdl_lock= FALSE;
-  bool is_temporary_table= false;
-  DBUG_ENTER("mysql_truncate");
-
-  bzero((char*) &create_info,sizeof(create_info));
+  enum legacy_db_type db_type;
+  handlerton *table_type;
+  DBUG_ENTER("mysql_truncate_table");
 
   /* Remove tables from the HANDLER's hash. */
-  mysql_ha_rm_tables(thd, table_list);
+  mysql_ha_rm_tables(thd, table_ref);
 
   /* If it is a temporary table, close and regenerate it */
-  if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
+  if ((table= find_temporary_table(thd, table_ref)))
   {
-    is_temporary_table= true;
-    handlerton *table_type= table->s->db_type();
-    TABLE_SHARE *share= table->s;
     /* Note that a temporary table cannot be partitioned */
-    if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
-      goto trunc_by_del;
+    if (ha_check_storage_engine_flag(table->s->db_type(), HTON_CAN_RECREATE))
+      error= truncate_temporary_table(thd, table);
+    else
+      error= mysql_truncate_by_delete(thd, table_ref);
 
-    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
+    DBUG_RETURN(error);
+  }
 
-    close_temporary_table(thd, table, 0, 0);    // Don't free share
-    ha_create_table(thd, share->normalized_path.str,
-                    share->db.str, share->table_name.str, &create_info, 1);
-    // We don't need to call invalidate() because this table is not in cache
-    if ((error= (int) !(open_temporary_table(thd, share->path.str,
-                                             share->db.str,
-					     share->table_name.str, 1))))
-      (void) rm_temporary_table(table_type, path);
-    else
-      thd->thread_specific_used= TRUE;
-    
-    free_table_share(share);
-    my_free((char*) table,MYF(0));
+  if (thd->locked_tables_mode)
+  {
+    if (!(table= find_table_for_mdl_upgrade(thd->open_tables, table_ref->db,
+                                            table_ref->table_name, FALSE)))
+      DBUG_RETURN(TRUE);
+  }
+  else
+  {
     /*
-      If we return here we will not have logged the truncation to the bin log
-      and we will not my_ok() to the client.
+      Even though we could use the previous execution branch here just as
+      well, we must not try to open the table: MySQL manual documents that
+      TRUNCATE can be used to repair a damaged table, i.e. a table that can
+      not be fully "opened". In particular MySQL manual says:
+
+      As long as the table format file tbl_name.frm is valid, the table can be
+      re-created as an empty table with TRUNCATE TABLE, even if the data or
+      index files have become corrupted.
     */
-    goto end;
+    MDL_request mdl_global_request, mdl_request;
+    MDL_request_list mdl_requests;
+
+    mdl_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
+    mdl_request.init(MDL_key::TABLE, table_ref->db, table_ref->table_name,
+                     MDL_EXCLUSIVE);
+    mdl_requests.push_front(&mdl_request);
+    mdl_requests.push_front(&mdl_global_request);
+
+    if (thd->mdl_context.acquire_locks(&mdl_requests))
+      DBUG_RETURN(TRUE);
   }
 
-  path_length= build_table_filename(path, sizeof(path) - 1, table_list->db,
-                                    table_list->table_name, reg_ext, 0);
+  path_length= build_table_filename(path, sizeof(path) - 1, table_ref->db,
+                                    table_ref->table_name, reg_ext, 0);
+
+  mysql_frm_type(thd, path, &db_type);
 
-  if (!dont_send_ok)
+  /* Type is unknown if the object is not found or is not a table. */
+  if (db_type == DB_TYPE_UNKNOWN)
   {
-    enum legacy_db_type table_type;
-    /*
-      FIXME: Code of TRUNCATE breaks the meta-data
-      locking protocol since it tries to find out the table storage
-      engine and therefore accesses table in some way without holding
-      any kind of meta-data lock.
-    */
-    mysql_frm_type(thd, path, &table_type);
-    if (table_type == DB_TYPE_UNKNOWN)
-    {
-      my_error(ER_NO_SUCH_TABLE, MYF(0),
-               table_list->db, table_list->table_name);
-      DBUG_RETURN(TRUE);
-    }
+    my_error(ER_NO_SUCH_TABLE, MYF(0), table_ref->db, table_ref->table_name);
+    DBUG_RETURN(TRUE);
+  }
+
 #ifdef WITH_PARTITION_STORAGE_ENGINE
+  /*
+    TODO: Add support for TRUNCATE PARTITION for NDB and other engines
+    supporting native partitioning
+  */
+  if (db_type != DB_TYPE_PARTITION_DB &&
+      thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION)
+  {
+    my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
+    DBUG_RETURN(TRUE);
+  }
+#endif
+
+  table_type= ha_resolve_by_legacy_type(thd, db_type);
+
+  if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE) ||
+      thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION)
+  {
     /*
-      TODO: Add support for TRUNCATE PARTITION for NDB and other engines
-      supporting native partitioning
+      If under LOCK TABLES mode, there is no reason to upgrade the
+      shared metadata lock as this session holds a write lock on the
+      data. This guarantees that no other transaction has access to
+      the table data. If not under LOCK TABLES mode, the exclusive
+      metadata lock is preserved. This behavior is important to
+      ensure serializability as InnoDB delete_all_rows implementation
+      aborts some granted locks.
     */
-    if (table_type != DB_TYPE_PARTITION_DB &&
-        thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION)
-    {
-      my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
-      DBUG_RETURN(TRUE);
-    }
-#endif
-    if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd,
-                                                                table_type),
-                                      HTON_CAN_RECREATE) ||
-        thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION)
-      goto trunc_by_del;
-
-
-    if (thd->locked_tables_mode)
-    {
-      if (!(table= find_table_for_mdl_upgrade(thd->open_tables, table_list->db,
-                                              table_list->table_name, FALSE)))
-        DBUG_RETURN(TRUE);
-      mdl_ticket= table->mdl_ticket;
-      if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
-        goto end;
-      close_all_tables_for_name(thd, table->s, FALSE);
-    }
-    else
-    {
-      MDL_request mdl_global_request, mdl_request;
-      MDL_request_list mdl_requests;
-      /*
-        Even though we could use the previous execution branch
-        here just as well, we must not try to open the table: 
-        MySQL manual documents that TRUNCATE can be used to 
-        repair a damaged table, i.e. a table that can not be
-        fully "opened". In particular MySQL manual says:
-
-        As long as the table format file tbl_name.frm  is valid,
-        the table can be re-created as an empty table with TRUNCATE
-        TABLE, even if the data or index files have become corrupted.
-      */
-
-      mdl_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
-      mdl_request.init(MDL_key::TABLE, table_list->db, table_list->table_name,
-                       MDL_EXCLUSIVE);
-      mdl_requests.push_front(&mdl_request);
-      mdl_requests.push_front(&mdl_global_request);
-
-      if (thd->mdl_context.acquire_locks(&mdl_requests))
-        DBUG_RETURN(TRUE);
-
-      has_mdl_lock= TRUE;
-      mysql_mutex_lock(&LOCK_open);
-      tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_list->db,
-                       table_list->table_name);
-      mysql_mutex_unlock(&LOCK_open);
-    }
+    error= mysql_truncate_by_delete(thd, table_ref);
+    DBUG_RETURN(error);
   }
 
+  if (thd->locked_tables_mode)
+  {
+    mdl_ticket= table->mdl_ticket;
+    if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+      goto end;
+    close_all_tables_for_name(thd, table->s, FALSE);
+  }
+  else
+  {
+    has_mdl_lock= TRUE;
+    mysql_mutex_lock(&LOCK_open);
+    tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_ref->db, table_ref->table_name);
+    mysql_mutex_unlock(&LOCK_open);
+  }
+
+  memset(&create_info, 0, sizeof(create_info));
+
   /*
     Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
     crashes, replacement works.  *(path + path_length - reg_ext_length)=
@@ -1228,38 +1266,78 @@ bool mysql_truncate(THD *thd, TABLE_LIST
   */
   path[path_length - reg_ext_length] = 0;
   mysql_mutex_lock(&LOCK_open);
-  error= ha_create_table(thd, path, table_list->db, table_list->table_name,
+  error= ha_create_table(thd, path, table_ref->db, table_ref->table_name,
                          &create_info, 1);
   mysql_mutex_unlock(&LOCK_open);
-  query_cache_invalidate3(thd, table_list, 0);
+  query_cache_invalidate3(thd, table_ref, 0);
 
 end:
-  if (!dont_send_ok)
-  {
-    if (thd->locked_tables_mode && thd->locked_tables_list.reopen_tables(thd))
+  if (thd->locked_tables_mode && thd->locked_tables_list.reopen_tables(thd))
       thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
-    /*
-      Even if we failed to reopen some tables,
-      the operation itself succeeded, write the binlog.
-    */
+
+  /*
+    Even if we failed to reopen some tables, the operation itself
+    succeeded, write the binlog.
+  */
+  if (!error)
+  {
+    /* In RBR, the statement is not binlogged if the table is temporary. */
+    error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
     if (!error)
-    {
-      /* In RBR, the statement is not binlogged if the table is temporary. */
-      if (!is_temporary_table || !thd->is_current_stmt_binlog_format_row())
-        error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
-      if (!error)
-        my_ok(thd);             // This should return record count
-    }
-    if (has_mdl_lock)
-      thd->mdl_context.release_transactional_locks();
-    if (mdl_ticket)
-      mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+      my_ok(thd);
   }
 
+  if (has_mdl_lock)
+    thd->mdl_context.release_transactional_locks();
+
+  if (mdl_ticket)
+    mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+
   DBUG_PRINT("exit", ("error: %d", error));
   DBUG_RETURN(error);
+}
+
+
+/*
+  Regenerate a metadata locked table.
+
+  @param  thd   Thread context.
+  @param  db    Name of the database to which the table belongs to.
+  @param  name  Table name.
+
+  @retval  FALSE  Success.
+  @retval  TRUE   Error.
+*/
+
+bool mysql_truncate_locked_table(THD *thd, const char *db, const char *table_name)
+{
+  bool error= TRUE;
+  HA_CREATE_INFO create_info;
+  char path[FN_REFLEN + 1];
+  DBUG_ENTER("mysql_truncate_locked_table");
+
+  /* There should be a exclusive metadata lock on the table. */
+  DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
+                                             MDL_EXCLUSIVE));
+
+  memset(&create_info, 0, sizeof(create_info));
+
+  /* Create a path to the table, but without a extension. */
+  build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
+
+  /* Attempt to reconstruct the table. */
+  mysql_mutex_lock(&LOCK_open);
+  error= ha_create_table(thd, path, db, table_name, &create_info, TRUE);
+  mysql_mutex_unlock(&LOCK_open);
+
+#ifdef HAVE_QUERY_CACHE
+  uint key_length;
+  char key[MAX_DBKEY_LENGTH];
+
+  key_length= (uint) (strmov(strmov(key, db) + 1, table_name) - key) + 1;
+  query_cache.invalidate(thd, key, key_length, FALSE);
+#endif
 
-trunc_by_del:
-  error= mysql_truncate_by_delete(thd, table_list);
   DBUG_RETURN(error);
 }
+

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-02-08 20:19:55 +0000
+++ b/sql/sql_parse.cc	2010-02-11 13:18:37 +0000
@@ -3074,7 +3074,7 @@ end_with_restore_list:
     }
     if (thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))
       goto error;
-    res= mysql_truncate(thd, first_table, 0);
+    res= mysql_truncate_table(thd, first_table);
     break;
   case SQLCOM_DELETE:
   {

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-02-06 10:28:06 +0000
+++ b/sql/sql_table.cc	2010-02-11 13:18:37 +0000
@@ -4497,7 +4497,7 @@ static int prepare_for_repair(THD *thd, 
 			     "Failed renaming data file");
     goto end;
   }
-  if (mysql_truncate(thd, table_list, 1))
+  if (mysql_truncate_locked_table(thd, table_list->db, table_list->table_name))
   {
     error= send_check_errmsg(thd, table_list, "repair",
 			     "Failed generating table from .frm file");


Attachment: [text/bzr-bundle] bzr/davi.arnaut@sun.com-20100211131837-gk596l5vorc6okhw.bundle
Thread
bzr commit into mysql-5.5-next-mr branch (davi:3090) Bug#42643Davi Arnaut11 Feb