List:Commits« Previous MessageNext Message »
From:Luis Soares Date:January 21 2010 5:20pm
Subject:bzr commit into mysql-5.1-bugteam branch (luis.soares:3320) Bug#49481
View as plain text  
#At file:///home/lsoares/Workspace/bzr/work/bugfixing/49482/mysql-5.1-bugteam/ based on revid:luis.soares@stripped

 3320 Luis Soares	2010-01-21
      BUG#49481: RBR: MyISAM and bit fields may cause slave to stop on delete: 
      cant find record
      
      Some engines return data for the record. Despite the fact that
      the null bit is set for some fields, their old value may still in
      the row. This can happen when unpacking an AI from the binlog on
      top of a previous record in which a field is set to NULL, which
      previously contained a value. Ultimately, this may cause the
      comparison of records to fail when the slave is doing an index or
      range scan.
      
      We fix this by deploying a call to reset() for each field that is
      set to null while unpacking a row from the binary log.
      Furthermore, we also add mixed mode test case to cover the
      scenario where updating and setting a field to null through a
      Query event and later searching it through a rows event will
      succeed.
      
      Finally, we also change the reset() method, from Field_bit class,
      so that it takes into account bits stored among the null bits and
      not only the ones stored in the record.
     @ mysql-test/suite/rpl/t/rpl_set_null_innodb.test
        InnoDB test.
     @ mysql-test/suite/rpl/t/rpl_set_null_myisam.test
        MyISAM test.
     @ mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test
        NDB test.
     @ sql/field.h
        Changed reset so that it also clears the bits
        among the null_bits for the Field_bit class.
     @ sql/rpl_record.cc
        Resetting field after setting it to null when unpacking
        row.

    added:
      mysql-test/extra/rpl_tests/rpl_set_null.test
      mysql-test/suite/rpl/r/rpl_set_null_innodb.result
      mysql-test/suite/rpl/r/rpl_set_null_myisam.result
      mysql-test/suite/rpl/t/rpl_set_null_innodb.test
      mysql-test/suite/rpl/t/rpl_set_null_myisam.test
      mysql-test/suite/rpl_ndb/r/rpl_ndb_set_null.result
      mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test
    modified:
      sql/field.h
      sql/rpl_record.cc
=== added file 'mysql-test/extra/rpl_tests/rpl_set_null.test'
--- a/mysql-test/extra/rpl_tests/rpl_set_null.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_set_null.test	2010-01-21 17:20:24 +0000
@@ -0,0 +1,86 @@
+# Both of the following tests check that comparison of binlog BI
+# against SE record will not fail due to remains from previous values
+# in the SE record (before a given field was set to null).
+#
+# In MIXED mode:
+# - Insert and update are executed as statements
+# - Delete is executed as a row event
+# - Assertion: checks that comparison will not fail because the update
+#              statement will clear the record contents for the nulled
+#              field. If data was not cleared, some engines may keep
+#              the value and return it later as garbage - despite the
+#              fact that field is null. This may cause slave to
+#              falsely fail in the comparison (memcmp would fail
+#              because of "garbage" in record data).
+#
+# In ROW mode:
+# - Insert, update and delete are executed as row events.
+# - Assertion: checks that comparison will not fail because the update
+#              rows event will clear the record contents before
+#              feeding the new value to the SE. This protects against
+#              SEs that do not clear record contents when storing
+#              nulled fields. If the engine did not clear the data it
+#              would cause slave to falsely fail in the comparison
+#              (memcmp would fail because of "garbage" in record
+#              data). This scenario is pretty much the same described
+#              above in MIXED mode, but checks different execution
+#              path in the slave.
+
+# BUG#49481: RBR: MyISAM and bit fields may cause slave to stop on
+#  delete cant find record
+
+-- source include/master-slave-reset.inc
+
+-- connection master
+-- eval CREATE TABLE t1 (c1 BIT, c2 INT) Engine=$engine
+INSERT INTO `t1` VALUES ( 1, 1 );
+UPDATE t1 SET c1=NULL where c2=1;
+-- sync_slave_with_master
+
+-- let $diff_table_1=master:test.t1
+-- let $diff_table_2=slave:test.t1
+-- source include/diff_tables.inc
+
+-- connection master
+# triggers switch to row mode when on mixed 
+DELETE FROM t1 WHERE c2=1 LIMIT 1;
+-- sync_slave_with_master
+
+-- let $diff_table_1=master:test.t1
+-- let $diff_table_2=slave:test.t1
+-- source include/diff_tables.inc
+
+-- connection master
+DROP TABLE t1;
+-- sync_slave_with_master
+
+-- source include/master-slave-reset.inc
+
+-- connection master
+
+# BUG#49482: RBR: Replication may break on deletes when MyISAM tables
+#  + char field are used
+
+-- eval CREATE TABLE t1 (c1 CHAR) Engine=$engine
+
+INSERT INTO t1 ( c1 ) VALUES ( 'w' ) ;
+SELECT * FROM t1;
+UPDATE t1 SET c1=NULL WHERE c1='w';
+-- sync_slave_with_master
+
+-- let $diff_table_1=master:test.t1
+-- let $diff_table_2=slave:test.t1
+-- source include/diff_tables.inc
+
+-- connection master
+# triggers switch to row mode when on mixed 
+DELETE FROM t1 LIMIT 2;
+-- sync_slave_with_master
+
+-- let $diff_table_1=master:test.t1
+-- let $diff_table_2=slave:test.t1
+-- source include/diff_tables.inc
+
+-- connection master
+DROP TABLE t1;
+-- sync_slave_with_master

=== added file 'mysql-test/suite/rpl/r/rpl_set_null_innodb.result'
--- a/mysql-test/suite/rpl/r/rpl_set_null_innodb.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_set_null_innodb.result	2010-01-21 17:20:24 +0000
@@ -0,0 +1,35 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1 (c1 BIT, c2 INT) Engine=InnoDB;
+INSERT INTO `t1` VALUES ( 1, 1 );
+UPDATE t1 SET c1=NULL where c2=1;
+Comparing tables master:test.t1 and slave:test.t1
+DELETE FROM t1 WHERE c2=1 LIMIT 1;
+Comparing tables master:test.t1 and slave:test.t1
+DROP TABLE t1;
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1 (c1 CHAR) Engine=InnoDB;
+INSERT INTO t1 ( c1 ) VALUES ( 'w' ) ;
+SELECT * FROM t1;
+c1
+w
+UPDATE t1 SET c1=NULL WHERE c1='w';
+Comparing tables master:test.t1 and slave:test.t1
+DELETE FROM t1 LIMIT 2;
+Comparing tables master:test.t1 and slave:test.t1
+DROP TABLE t1;

=== added file 'mysql-test/suite/rpl/r/rpl_set_null_myisam.result'
--- a/mysql-test/suite/rpl/r/rpl_set_null_myisam.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_set_null_myisam.result	2010-01-21 17:20:24 +0000
@@ -0,0 +1,35 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1 (c1 BIT, c2 INT) Engine=MyISAM;
+INSERT INTO `t1` VALUES ( 1, 1 );
+UPDATE t1 SET c1=NULL where c2=1;
+Comparing tables master:test.t1 and slave:test.t1
+DELETE FROM t1 WHERE c2=1 LIMIT 1;
+Comparing tables master:test.t1 and slave:test.t1
+DROP TABLE t1;
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1 (c1 CHAR) Engine=MyISAM;
+INSERT INTO t1 ( c1 ) VALUES ( 'w' ) ;
+SELECT * FROM t1;
+c1
+w
+UPDATE t1 SET c1=NULL WHERE c1='w';
+Comparing tables master:test.t1 and slave:test.t1
+DELETE FROM t1 LIMIT 2;
+Comparing tables master:test.t1 and slave:test.t1
+DROP TABLE t1;

=== added file 'mysql-test/suite/rpl/t/rpl_set_null_innodb.test'
--- a/mysql-test/suite/rpl/t/rpl_set_null_innodb.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_set_null_innodb.test	2010-01-21 17:20:24 +0000
@@ -0,0 +1,6 @@
+-- source include/have_binlog_format_mixed_or_row.inc
+-- source include/master-slave.inc
+-- source include/have_innodb.inc
+
+-- let $engine= InnoDB
+-- source extra/rpl_tests/rpl_set_null.test

=== added file 'mysql-test/suite/rpl/t/rpl_set_null_myisam.test'
--- a/mysql-test/suite/rpl/t/rpl_set_null_myisam.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_set_null_myisam.test	2010-01-21 17:20:24 +0000
@@ -0,0 +1,5 @@
+-- source include/have_binlog_format_mixed_or_row.inc
+-- source include/master-slave.inc
+
+-- let $engine= MyISAM
+-- source extra/rpl_tests/rpl_set_null.test

=== added file 'mysql-test/suite/rpl_ndb/r/rpl_ndb_set_null.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_set_null.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_set_null.result	2010-01-21 17:20:24 +0000
@@ -0,0 +1,35 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1 (c1 BIT, c2 INT) Engine=NDB;
+INSERT INTO `t1` VALUES ( 1, 1 );
+UPDATE t1 SET c1=NULL where c2=1;
+Comparing tables master:test.t1 and slave:test.t1
+DELETE FROM t1 WHERE c2=1 LIMIT 1;
+Comparing tables master:test.t1 and slave:test.t1
+DROP TABLE t1;
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1 (c1 CHAR) Engine=NDB;
+INSERT INTO t1 ( c1 ) VALUES ( 'w' ) ;
+SELECT * FROM t1;
+c1
+w
+UPDATE t1 SET c1=NULL WHERE c1='w';
+Comparing tables master:test.t1 and slave:test.t1
+DELETE FROM t1 LIMIT 2;
+Comparing tables master:test.t1 and slave:test.t1
+DROP TABLE t1;

=== added file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test	2010-01-21 17:20:24 +0000
@@ -0,0 +1,6 @@
+-- source include/have_ndb.inc
+-- source include/have_binlog_format_mixed_or_row.inc
+-- source include/ndb_master-slave.inc
+
+-- let $engine= NDB
+-- source extra/rpl_tests/rpl_set_null.test

=== modified file 'sql/field.h'
--- a/sql/field.h	2009-12-08 09:26:11 +0000
+++ b/sql/field.h	2010-01-21 17:20:24 +0000
@@ -1926,7 +1926,12 @@ public:
   uint32 max_display_length() { return field_length; }
   uint size_of() const { return sizeof(*this); }
   Item_result result_type () const { return INT_RESULT; }
-  int reset(void) { bzero(ptr, bytes_in_rec); return 0; }
+  int reset(void) { 
+    bzero(ptr, bytes_in_rec); 
+    if (bit_ptr && (bit_len > 0))  // reset odd bits among null bits
+      clr_rec_bits(bit_ptr, bit_ofs, bit_len);
+    return 0; 
+  }
   int store(const char *to, uint length, CHARSET_INFO *charset);
   int store(double nr);
   int store(longlong nr, bool unsigned_val);

=== modified file 'sql/rpl_record.cc'
--- a/sql/rpl_record.cc	2009-10-22 00:15:45 +0000
+++ b/sql/rpl_record.cc	2010-01-21 17:20:24 +0000
@@ -231,6 +231,17 @@ unpack_row(Relay_log_info const *rli,
         {
           DBUG_PRINT("debug", ("Was NULL; null mask: 0x%x; null bits: 0x%x",
                                null_mask, null_bits));
+          /** 
+            Calling reset just in case one is unpacking on top a 
+            record with data. 
+
+            This could probably go into set_null() but doing so, 
+            (i) triggers assertion in other parts of the code at 
+            the moment; (ii) it would make us reset the field,
+            always when setting null, which right now doesn't seem 
+            needed anywhere else except here.
+           */
+          f->reset();
           f->set_null();
         }
         else


Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20100121172024-0lii1rp5mqqcrjo6.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (luis.soares:3320) Bug#49481Luis Soares21 Jan
  • Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:3320)Bug#49481Alfranio Correia22 Jan