From 42f8d2f249ea4d0acc2fdd7c03b3ea9d44f92027 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Oct 2010 11:08:49 +0800 Subject: Bug#56226 Table map set to 0 after altering MyISAM table After ALTER TABLE which changed only table's metadata, row-based binlog sometimes got corrupted since the tablemap was unexpectedly set to 0 for subsequent updates to the same table. ALTER TABLE which changed only table's metadata always reset table_map_id for the table share to 0. Despite the fact that 0 is a valid value for table_map_id, this step caused problems as it could have created situation in which we had more than one table share with table_map_id equal 0. If more than one table with table_map_id are 0 were updated in the same statement, updates to these different tables were written into the same rows event. This caused slave server to crash. This bug happens only on 5.1. It doesn't affect 5.5+. This patch solves this problem by ensuring that ALTER TABLE statements which change metadata only never reset table_map_id to 0. To do this it changes reopen_table() to correctly use refreshed table_map_id value instead of using the old one/ resetting it. mysql-test/suite/rpl/r/rpl_alter.result: Add test for BUG#56226 mysql-test/suite/rpl/t/rpl_alter.test: Add test for BUG#56226 --- mysql-test/suite/rpl/r/rpl_alter.result | 20 +++++++++++ mysql-test/suite/rpl/t/rpl_alter.test | 59 +++++++++++++++++++++++++++++---- sql/sql_base.cc | 2 -- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_alter.result b/mysql-test/suite/rpl/r/rpl_alter.result index 6ef5ce3462a..cedb6854239 100644 --- a/mysql-test/suite/rpl/r/rpl_alter.result +++ b/mysql-test/suite/rpl/r/rpl_alter.result @@ -19,3 +19,23 @@ select * from mysqltest.t3; n 45 drop database mysqltest; + +# BUG#56226 Table map set to 0 after altering MyISAM table + +SET SESSION binlog_format='ROW'; +USE test; +CREATE TABLE t1 (a INT, b INT) ENGINE MyISAM; +CREATE TABLE t2 (a VARCHAR(255), b VARCHAR(255)) ENGINE MyISAM; +CREATE TRIGGER trg_t1ai +AFTER INSERT ON t1 FOR EACH ROW +BEGIN +INSERT INTO t2 (a) VALUES (NEW.a); +END;// +ALTER TABLE t1 CHANGE b c INT; +ALTER TABLE t2 CHANGE b c VARCHAR(255); + +INSERT INTO t1 (a) VALUES(2); +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 + +DROP TABLE t1, t2; diff --git a/mysql-test/suite/rpl/t/rpl_alter.test b/mysql-test/suite/rpl/t/rpl_alter.test index 576376a0264..bc42476244a 100644 --- a/mysql-test/suite/rpl/t/rpl_alter.test +++ b/mysql-test/suite/rpl/t/rpl_alter.test @@ -10,15 +10,62 @@ insert into mysqltest.t1 values (1,2); create table mysqltest.t2 (n int); insert into mysqltest.t2 values (45); rename table mysqltest.t2 to mysqltest.t3, mysqltest.t1 to mysqltest.t2; -save_master_pos; -connection slave; -sync_with_master; + +sync_slave_with_master; select * from mysqltest.t2; select * from mysqltest.t3; + connection master; drop database mysqltest; -save_master_pos; -connection slave; -sync_with_master; +sync_slave_with_master; + +--echo +--echo # BUG#56226 Table map set to 0 after altering MyISAM table +--echo +connection master; +SET SESSION binlog_format='ROW'; +USE test; + +CREATE TABLE t1 (a INT, b INT) ENGINE MyISAM; +CREATE TABLE t2 (a VARCHAR(255), b VARCHAR(255)) ENGINE MyISAM; + +--delimiter // +CREATE TRIGGER trg_t1ai + AFTER INSERT ON t1 FOR EACH ROW +BEGIN + INSERT INTO t2 (a) VALUES (NEW.a); +END;// +--delimiter ; + +ALTER TABLE t1 CHANGE b c INT; +ALTER TABLE t2 CHANGE b c VARCHAR(255); +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +--echo +INSERT INTO t1 (a) VALUES(2); +let _info= query_get_value(SHOW BINLOG EVENTS IN '$binlog_file' FROM $binlog_start, Info, 2); +# Table map id should not be 0. +if (`SELECT 'table_id: 0 (test.t1)' = '$_info'`) +{ + --echo test.t1's table map id is 0; + --die test.t1's table map id is 0; +} +let _info= query_get_value(SHOW BINLOG EVENTS IN '$binlog_file' FROM $binlog_start, Info, 3); +if (`SELECT 'table_id: 0 (test.t2)' = '$_info'`) +{ + --echo test.t2's table map id is 0; + --die test.t2's table map id is 0; +} + +let diff_table= test.t1; +source include/rpl_diff_tables.inc; +let diff_table= test.t2; +source include/rpl_diff_tables.inc; + +--echo +connection master; +DROP TABLE t1, t2; +source include/master-slave-end.inc; # End of 4.1 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c38526a6d0b..3766ff18293 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3082,8 +3082,6 @@ bool reopen_table(TABLE *table) tmp.maybe_null= table->maybe_null; tmp.status= table->status; - tmp.s->table_map_id= table->s->table_map_id; - /* Get state */ tmp.in_use= thd; tmp.reginfo.lock_type=table->reginfo.lock_type; -- cgit v1.2.1