Commit b489c89f authored by Luis Soares's avatar Luis Soares

BUG#11766865: 60091: RBR + NO PK + UPDATE NULL VALUE --> SLAVE BREAK WITH ERROR HA_ERR_END_OF_

  
The slave was not able to find the correct row in the innodb
table, because the row fetched from the innodb table would not
match the before image. This happened because the (don't care)
bytes in the NULLed fields would change once the row was stored
in the storage engine (from zero to the default value). This
would make bulk memory comparison (using memcmp) to fail.
  
We fix this by taking a preventing measure and avoiding memcmp
for tables that contain nullable fields. Therefore, we protect
the slave search routine from engines that return arbitrary
values for don't care bytes (in the nulled fields). Instead, the
slave thread will only check null_bits and those fields that are
not set to NULL when comparing the before image against the
storage engine row.

mysql-test/extra/rpl_tests/rpl_record_compare.test:
  Added test case to the include file so that this is tested 
  with more than one engine.
mysql-test/suite/rpl/r/rpl_row_rec_comp_innodb.result:
  Result update.
mysql-test/suite/rpl/r/rpl_row_rec_comp_myisam.result:
  Result update.
mysql-test/suite/rpl/t/rpl_row_rec_comp_myisam.test:
  Moved the include file last, so that the result from
  BUG#11766865 is not intermixed with the result for
  BUG#11760454.
sql/log_event.cc:
  Skips memory comparison if the table has nullable 
  columns and compares only non-nulled fields in the
  field comparison loop.
parent 378091e4
......@@ -62,4 +62,24 @@ UPDATE t1 SET c1= 0;
DROP TABLE t1;
-- sync_slave_with_master
#
# BUG#11766865: 60091: RBR + NO PK + UPDATE NULL VALUE --> SLAVE BREAK WITH ERROR HA_ERR_END_OF_
#
--connection master
--source include/rpl_reset.inc
--connection master
--eval CREATE TABLE t1 (c1 int(11) NOT NULL, c2 int(11) NOT NULL, c3 int(11) DEFAULT '-1') ENGINE=$engine DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES (1,2,NULL);
UPDATE t1 SET c1=1, c2=2, c3=-1 WHERE c1=1 AND c2=2 AND ISNULL(c3);
--sync_slave_with_master
--let $diff_tables=master:test.t1, slave:test.t1
--source include/diff_tables.inc
--connection master
DROP TABLE t1;
--sync_slave_with_master
......@@ -25,4 +25,10 @@ INSERT INTO t1(c1) VALUES (NULL);
UPDATE t1 SET c1= 0;
include/diff_tables.inc [master:t1, slave:t1]
DROP TABLE t1;
include/rpl_reset.inc
CREATE TABLE t1 (c1 int(11) NOT NULL, c2 int(11) NOT NULL, c3 int(11) DEFAULT '-1') ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO t1 VALUES (1,2,NULL);
UPDATE t1 SET c1=1, c2=2, c3=-1 WHERE c1=1 AND c2=2 AND ISNULL(c3);
include/diff_tables.inc [master:test.t1, slave:test.t1]
DROP TABLE t1;
include/rpl_end.inc
include/master-slave.inc
[connection master]
## coverage purposes - Field_bits
## 1 X bit + 2 Null bits + 5 bits => last_null_bit_pos==0
include/rpl_reset.inc
CREATE TABLE t1 (c1 bigint(20) DEFAULT 0, c2 bit(5)) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1(c1,c2) VALUES (10, b'1');
INSERT INTO t1(c1,c2) VALUES (NULL, b'1');
UPDATE t1 SET c1= 0;
include/diff_tables.inc [master:t1, slave:t1]
DROP TABLE t1;
## case #1 - last_null_bit_pos==0 in record_compare without X bit
include/rpl_reset.inc
CREATE TABLE t1 (c1 bigint(20) DEFAULT 0, c2 bigint(20) DEFAULT 0, c3 bigint(20) DEFAULT 0, c4 varchar(1) DEFAULT '', c5 bigint(20) DEFAULT 0, c6 bigint(20) DEFAULT 0, c7 bigint(20) DEFAULT 0, c8 bigint(20) DEFAULT 0) ENGINE=MyISAM DEFAULT CHARSET=latin1;
......@@ -25,13 +34,10 @@ INSERT INTO t1(c1) VALUES (NULL);
UPDATE t1 SET c1= 0;
include/diff_tables.inc [master:t1, slave:t1]
DROP TABLE t1;
## coverage purposes - Field_bits
## 1 X bit + 2 Null bits + 5 bits => last_null_bit_pos==0
include/rpl_reset.inc
CREATE TABLE t1 (c1 bigint(20) DEFAULT 0, c2 bit(5)) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1(c1,c2) VALUES (10, b'1');
INSERT INTO t1(c1,c2) VALUES (NULL, b'1');
UPDATE t1 SET c1= 0;
include/diff_tables.inc [master:t1, slave:t1]
CREATE TABLE t1 (c1 int(11) NOT NULL, c2 int(11) NOT NULL, c3 int(11) DEFAULT '-1') ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1 VALUES (1,2,NULL);
UPDATE t1 SET c1=1, c2=2, c3=-1 WHERE c1=1 AND c2=2 AND ISNULL(c3);
include/diff_tables.inc [master:test.t1, slave:test.t1]
DROP TABLE t1;
include/rpl_end.inc
-- source include/have_binlog_format_row.inc
-- source include/master-slave.inc
-- let $engine= MyISAM
#
# BUG#52868 Wrong handling of NULL value during update, replication out of sync
#
-- let $engine= MyISAM
-- source extra/rpl_tests/rpl_record_compare.test
-- echo ## coverage purposes - Field_bits
-- echo ## 1 X bit + 2 Null bits + 5 bits => last_null_bit_pos==0
......@@ -28,4 +27,7 @@ UPDATE t1 SET c1= 0;
-- connection master
DROP TABLE t1;
-- sync_slave_with_master
-- source extra/rpl_tests/rpl_record_compare.test
--source include/rpl_end.inc
......@@ -8888,7 +8888,19 @@ static bool record_compare(TABLE *table)
}
}
if (table->s->blob_fields + table->s->varchar_fields == 0)
/**
Compare full record only if:
- there are no blob fields (otherwise we would also need
to compare blobs contents as well);
- there are no varchar fields (otherwise we would also need
to compare varchar contents as well);
- there are no null fields, otherwise NULLed fields
contents (i.e., the don't care bytes) may show arbitrary
values, depending on how each engine handles internally.
*/
if ((table->s->blob_fields +
table->s->varchar_fields +
table->s->null_fields) == 0)
{
result= cmp_record(table,record[1]);
goto record_compare_exit;
......@@ -8903,13 +8915,22 @@ static bool record_compare(TABLE *table)
goto record_compare_exit;
}
/* Compare updated fields */
/* Compare fields */
for (Field **ptr=table->field ; *ptr ; ptr++)
{
if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
/**
We only compare field contents that are not null.
NULL fields (i.e., their null bits) were compared
earlier.
*/
if (!(*(ptr))->is_null())
{
result= TRUE;
goto record_compare_exit;
if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
{
result= TRUE;
goto record_compare_exit;
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment