diff options
author | Luis Soares <luis.soares@sun.com> | 2010-01-26 08:55:22 +0000 |
---|---|---|
committer | Luis Soares <luis.soares@sun.com> | 2010-01-26 08:55:22 +0000 |
commit | b9d94d2a09eb215256990c4a02208f698407e7c8 (patch) | |
tree | d08a1a654cc33156dd9f60ed64d5992a7ab9fb28 | |
parent | 93dda2c670931ec8337fd75800a5dae2a757be50 (diff) | |
parent | 04ac86e366b8c95ebeb2ef2cbb7757724124a78d (diff) | |
download | mariadb-git-b9d94d2a09eb215256990c4a02208f698407e7c8.tar.gz |
automerge: mysql-5.1-bugteam branch --> mysql-5.1-bugteam latest
NOTE: added TODO to the comments requested by reviewer during this
merge.
-rw-r--r-- | mysql-test/extra/rpl_tests/rpl_set_null.test | 86 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_set_null_innodb.result | 35 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_set_null_myisam.result | 35 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_set_null_innodb.test | 6 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_set_null_myisam.test | 5 | ||||
-rw-r--r-- | mysql-test/suite/rpl_ndb/r/rpl_ndb_set_null.result | 35 | ||||
-rw-r--r-- | mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test | 6 | ||||
-rw-r--r-- | sql/field.h | 7 | ||||
-rw-r--r-- | sql/rpl_record.cc | 16 |
9 files changed, 230 insertions, 1 deletions
diff --git a/mysql-test/extra/rpl_tests/rpl_set_null.test b/mysql-test/extra/rpl_tests/rpl_set_null.test new file mode 100644 index 00000000000..f2aba089279 --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_set_null.test @@ -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 diff --git a/mysql-test/suite/rpl/r/rpl_set_null_innodb.result b/mysql-test/suite/rpl/r/rpl_set_null_innodb.result new file mode 100644 index 00000000000..41600a5fe1b --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_set_null_innodb.result @@ -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; diff --git a/mysql-test/suite/rpl/r/rpl_set_null_myisam.result b/mysql-test/suite/rpl/r/rpl_set_null_myisam.result new file mode 100644 index 00000000000..cbd7010664a --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_set_null_myisam.result @@ -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; diff --git a/mysql-test/suite/rpl/t/rpl_set_null_innodb.test b/mysql-test/suite/rpl/t/rpl_set_null_innodb.test new file mode 100644 index 00000000000..dba79b78fa1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_set_null_innodb.test @@ -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 diff --git a/mysql-test/suite/rpl/t/rpl_set_null_myisam.test b/mysql-test/suite/rpl/t/rpl_set_null_myisam.test new file mode 100644 index 00000000000..7b433071553 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_set_null_myisam.test @@ -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 diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_set_null.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_set_null.result new file mode 100644 index 00000000000..473cd63169c --- /dev/null +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_set_null.result @@ -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; diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test new file mode 100644 index 00000000000..454807d9591 --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_set_null.test @@ -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 diff --git a/sql/field.h b/sql/field.h index ae074cc1a30..55604193687 100644 --- a/sql/field.h +++ b/sql/field.h @@ -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); diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 8e80620dd2c..1a48d0e3b0e 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -231,6 +231,22 @@ 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. + + TODO: maybe in the future we should consider moving + the reset to make it part of set_null. But then + the assertions triggered need to be + addressed/revisited. + */ + f->reset(); f->set_null(); } else |