#At file:///home/lsoares/Workspace/bzr/work/bugfixing/51251/mysql-5.1-bugteam/ based on revid:joro@stripped
3341 Luis Soares 2010-02-19
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.
@ 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/mysql_priv.h
Added parameter in mysql_delete interface.
@ sql/sql_delete.cc
Added check in mysql_delete before writing the TRUNCATE statement
to the binary log.
@ sql/sql_parse.cc
Added value for the new parameter in 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/mysql_priv.h
sql/sql_delete.cc
sql/sql_parse.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-19 00:22:18 +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-19 00:22:18 +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-19 00:22:18 +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/mysql_priv.h'
--- a/sql/mysql_priv.h 2010-02-09 10:30:50 +0000
+++ b/sql/mysql_priv.h 2010-02-19 00:22:18 +0000
@@ -1277,7 +1277,7 @@ void prepare_triggers_for_insert_stmt(TA
int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
SQL_LIST *order, ha_rows rows, ulonglong options,
- bool reset_auto_increment);
+ bool reset_auto_increment, bool saved_binlog_format_row);
bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
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,
=== 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-19 00:22:18 +0000
@@ -34,7 +34,7 @@
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
SQL_LIST *order, ha_rows limit, ulonglong options,
- bool reset_auto_increment)
+ bool reset_auto_increment, bool save_binlog_row_based)
{
bool will_batch;
int error, loc_error;
@@ -390,7 +390,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 &&
+ save_binlog_row_based &&
+ find_temporary_table(thd, table_list)))
{
bool const is_trans=
thd->lex->sql_command == SQLCOM_TRUNCATE ?
@@ -1064,7 +1067,7 @@ static bool mysql_truncate_by_delete(THD
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);
+ error= mysql_delete(thd, table_list, NULL, NULL, HA_POS_ERROR, LL(0), TRUE, save_binlog_row_based);
ha_autocommit_or_rollback(thd, error);
end_trans(thd, error ? ROLLBACK : COMMIT);
thd->current_stmt_binlog_row_based= save_binlog_row_based;
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2010-02-05 17:01:09 +0000
+++ b/sql/sql_parse.cc 2010-02-19 00:22:18 +0000
@@ -3309,7 +3309,7 @@ end_with_restore_list:
res = mysql_delete(thd, all_tables, select_lex->where,
&select_lex->order_list,
unit->select_limit_cnt, select_lex->options,
- FALSE);
+ FALSE, thd->current_stmt_binlog_row_based);
break;
}
case SQLCOM_DELETE_MULTI:
Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20100219002218-g5o5uz2jgw1qcxmn.bundle