List:Commits« Previous MessageNext Message »
From:Luis Soares Date:February 24 2010 7:01pm
Subject:bzr commit into mysql-5.1-bugteam branch (luis.soares:3341) Bug#51251
View as plain text  
#At file:///home/lsoares/Workspace/bzr/work/bugfixing/51251/mysql-5.1-bugteam/ based on revid:joro@stripped

 3341 Luis Soares	2010-02-24
      BUG#51251: Wrong binlogging in case of TRUNCATE <temporary InnoDB table>
      
      For temporary tables that are created with an engine that does
      not provide the HTON_CAN_RECREATE, the truncate operation is
      performed resorting to the optimized handler::ha_delete_all_rows
      method. However, this means that the truncate will share
      execution path, from mysql_delete, with truncate on regular
      tables and other delete operations. As a consequence the truncate
      operation, for the temporary table is logged, even if in row mode
      because there is no distinction between this and the other delete
      operations at binlogging time.
      
      We fix this by checking if: (i) the binlog format, when the
      truncate operation was issued, is ROW; (ii) if the operation is a
      truncate; and (iii) if the table is a temporary table; before
      writing to the binary log. If all three conditions are met, we
      skip writing to the binlog. A side effect of this fix is that we
      limit the scope of setting and resetting the
      current_stmt_binlog_row_based. Now we just set and reset it
      inside mysql_delete in the boundaries of the
      handler::ha_write_row loop. This way we have access to
      thd->current_stmt_binlog_row_based real value inside
      mysql_delete.
     @ mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
        Updated result for spurious truncate table.
     @ mysql-test/suite/binlog/t/binlog_row_innodb_truncate.test
        Test case.
     @ sql/sql_delete.cc
        Added check in mysql_delete before writing the TRUNCATE statement
        to the binary log. Additionally, removed the set/reset of
        current_stmt_binlog_row_based so that it happens just in the 
        boundaries of the handler::ha_write_row loop inside mysql_delete.

    added:
      mysql-test/suite/binlog/r/binlog_row_innodb_truncate.result
      mysql-test/suite/binlog/t/binlog_row_innodb_truncate.test
    modified:
      mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
      sql/sql_delete.cc
=== added file 'mysql-test/suite/binlog/r/binlog_row_innodb_truncate.result'
--- a/mysql-test/suite/binlog/r/binlog_row_innodb_truncate.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_innodb_truncate.result	2010-02-24 19:01:53 +0000
@@ -0,0 +1,28 @@
+CREATE TABLE t1 ( c1 int , primary key (c1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TEMPORARY TABLE IF NOT EXISTS  t2 LIKE t1;
+TRUNCATE TABLE t2;
+DROP TABLE t1;
+###############################################
+### assertion: No event for '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`; CREATE TABLE t1 ( c1 int , primary key (c1)) ENGINE=InnoDB
+master-bin.000001	#	Query	#	#	BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t1)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Xid	#	#	COMMIT /* XID */
+master-bin.000001	#	Query	#	#	use `test`; DROP TABLE t1
+###############################################
+RESET MASTER;
+CREATE TEMPORARY TABLE t1 (c1 int) Engine=InnoDB;
+INSERT INTO t1 VALUES (1), (2), (3);
+TRUNCATE t1;
+DROP TEMPORARY TABLE t1;
+###############################################
+### assertion: No event for 'TRUNCATE TABLE t1'
+###############################################
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+###############################################

=== modified file 'mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result'
--- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result	2010-01-22 09:38:21 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result	2010-02-24 19:01:53 +0000
@@ -413,7 +413,6 @@ master-bin.000001	#	Query	#	#	BEGIN
 master-bin.000001	#	Table_map	#	#	table_id: # (test.t1)
 master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
 master-bin.000001	#	Query	#	#	COMMIT
-master-bin.000001	#	Query	#	#	use `test`; TRUNCATE table t2
 master-bin.000001	#	Query	#	#	BEGIN
 master-bin.000001	#	Table_map	#	#	table_id: # (test.t1)
 master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F

=== added file 'mysql-test/suite/binlog/t/binlog_row_innodb_truncate.test'
--- a/mysql-test/suite/binlog/t/binlog_row_innodb_truncate.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_row_innodb_truncate.test	2010-02-24 19:01:53 +0000
@@ -0,0 +1,37 @@
+-- source include/have_binlog_format_row.inc
+-- source include/have_innodb.inc
+
+#
+# BUG#51251
+#
+# The test case checks if truncating a temporary table created with
+# engine InnoDB will not cause the truncate statement to be binlogged.
+
+# Before patch for BUG#51251, the TRUNCATE statements below would be
+# binlogged, which would cause the slave to fail with "table does not
+# exist".
+
+CREATE TABLE t1 ( c1 int , primary key (c1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TEMPORARY TABLE IF NOT EXISTS  t2 LIKE t1;
+TRUNCATE TABLE t2;
+DROP TABLE t1;
+
+-- echo ###############################################
+-- echo ### assertion: No event for 'TRUNCATE TABLE t2'
+-- echo ###############################################
+-- source include/show_binlog_events.inc
+-- echo ###############################################
+
+RESET MASTER;
+
+CREATE TEMPORARY TABLE t1 (c1 int) Engine=InnoDB;
+INSERT INTO t1 VALUES (1), (2), (3);
+TRUNCATE t1;
+DROP TEMPORARY TABLE t1;
+
+-- echo ###############################################
+-- echo ### assertion: No event for 'TRUNCATE TABLE t1'
+-- echo ###############################################
+-- source include/show_binlog_events.inc
+-- echo ###############################################

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2010-01-24 07:03:23 +0000
+++ b/sql/sql_delete.cc	2010-02-24 19:01:53 +0000
@@ -50,6 +50,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
   SELECT_LEX   *select_lex= &thd->lex->select_lex;
   THD::killed_state killed_status= THD::NOT_KILLED;
   DBUG_ENTER("mysql_delete");
+  bool save_binlog_row_based;
 
   THD::enum_binlog_query_type query_type=
     thd->lex->sql_command == SQLCOM_TRUNCATE ?
@@ -293,6 +294,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *
 
   table->mark_columns_needed_for_delete();
 
+  save_binlog_row_based= thd->current_stmt_binlog_row_based;
+  if (thd->lex->sql_command == SQLCOM_TRUNCATE &&
+      thd->current_stmt_binlog_row_based)
+    thd->clear_current_stmt_binlog_row_based();
+
   while (!(error=info.read_record(&info)) && !thd->killed &&
 	 ! thd->is_error())
   {
@@ -342,6 +348,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
     else
       table->file->unlock_row();  // Row failed selection, release lock on it
   }
+  thd->current_stmt_binlog_row_based= save_binlog_row_based;
   killed_status= thd->killed;
   if (killed_status != THD::NOT_KILLED || thd->is_error())
     error= 1;					// Aborted
@@ -390,7 +397,10 @@ cleanup:
   /* See similar binlogging code in sql_update.cc, for comments */
   if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
   {
-    if (mysql_bin_log.is_open())
+    if (mysql_bin_log.is_open() &&
+        !(thd->lex->sql_command == SQLCOM_TRUNCATE &&
+          thd->current_stmt_binlog_row_based &&
+          find_temporary_table(thd, table_list)))
     {
       bool const is_trans=
         thd->lex->sql_command == SQLCOM_TRUNCATE ?
@@ -1059,15 +1069,13 @@ bool multi_delete::send_eof()
 
 static bool mysql_truncate_by_delete(THD *thd, TABLE_LIST *table_list)
 {
-  bool error, save_binlog_row_based= thd->current_stmt_binlog_row_based;
+  bool error;
   DBUG_ENTER("mysql_truncate_by_delete");
   table_list->lock_type= TL_WRITE;
   mysql_init_select(thd->lex);
-  thd->clear_current_stmt_binlog_row_based();
   error= mysql_delete(thd, table_list, NULL, NULL, HA_POS_ERROR, LL(0), TRUE);
   ha_autocommit_or_rollback(thd, error);
   end_trans(thd, error ? ROLLBACK : COMMIT);
-  thd->current_stmt_binlog_row_based= save_binlog_row_based;
   DBUG_RETURN(error);
 }
 


Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20100224190153-k0bpdx9abe88uoo2.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (luis.soares:3341) Bug#51251Luis Soares24 Feb
Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:3341)Bug#51251Luís Soares24 Feb
  • Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:3341)Bug#51251Luís Soares26 Feb