#At file:///home/lsoares/Workspace/bzr/work/bugfixing/47200/mysql-next-bugfixing/ based on revid:luis.soares@stripped
2813 Luis Soares 2009-09-10
BUG#47200: RBR: Absence of PK on slave leads to slave stop.
If the same table is declared with a PK on the master but without
the PK on the slave, row based replication may break. This is
noticed for InnoDB engine, which provides HA_PARTIAL_COLUMN_READ,
but it may also fail with other engines providing the same
flag. The failure happens when searching the row on the slave to
be updated.
When the slave thread performs a scan (table or index), the
search procedure is basically fetching rows from slave engine and
comparing them against the row in the event before image. If the
engine provides HA_PARTIAL_COLUMN_READ, then a memory comparison
is performed for both rows, otherwise, a column by column (for
only those marked in the read_set) comparison is done. There can
be two problems with this:
First, engine does not honor HA_PARTIAL_COLUMN_READ for some
cases. When fetching the row from the slave engine, and although
it provides HA_PARTIAL_COLUMN_READ, the table->read_set (which
marks only the columns as in the master PK) is ignored. Thence,
the engine returns the full row instead of only the columns
needed for comparison. In this case, the comparison will fail.
Second, when the RBR event row is unpacked it is filled with
default values for the missing columns. So, it can be the case
the event before image is filled with default values, on the
slave at unpack time. Consequently, when searching the record,
and even if the engine honors HA_PARTIAL_COLUMN_READ, the slave
will fail comparison - it will do a memory comparison of row with
PK + default values against a row with only the PK.
This patch fixes this issue by removing the part of the
comparison that takes into account the HA_PARTIAL_COLUMN_READ. In
such cases it performs a column by column comparison (for those
marked in the read_set).
modified:
mysql-test/suite/rpl/r/rpl_row_record_find_innodb.result
mysql-test/suite/rpl/t/rpl_row_record_find_innodb.test
sql/log_event.cc
sql/log_event_old.cc
=== modified file 'mysql-test/suite/rpl/r/rpl_row_record_find_innodb.result'
--- a/mysql-test/suite/rpl/r/rpl_row_record_find_innodb.result 2009-04-29 16:48:59 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_record_find_innodb.result 2009-09-10 09:37:43 +0000
@@ -826,3 +826,15 @@ DELETE FROM t WHERE c1 = 8;
DELETE FROM t;
Comparing tables master:test.t and slave:test.t
DROP TABLE t;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t (c1 int, c2 char(1), c3 char(1),
+c4 char(1), primary key(c1,c3)) engine=
+InnoDB;
+SET SQL_LOG_BIN=1;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t (c1 int, c2 char(1), c3 char(1),
+c4 char(1)) engine= InnoDB;
+SET SQL_LOG_BIN=1;
+INSERT INTO t VALUES (1, '2', '3', '4' );
+UPDATE t SET c4 = '7';
+DROP TABLE t;
=== modified file 'mysql-test/suite/rpl/t/rpl_row_record_find_innodb.test'
--- a/mysql-test/suite/rpl/t/rpl_row_record_find_innodb.test 2009-04-29 16:48:59 +0000
+++ b/mysql-test/suite/rpl/t/rpl_row_record_find_innodb.test 2009-09-10 09:37:43 +0000
@@ -44,3 +44,35 @@ let $master_engine= MyISAM;
let $slave_engine= InnoDB;
-- source extra/rpl_tests/rpl_row_record_find.test
+
+#
+# BUG#47200: RBR: Absence of PK on slave leads to slave stop.
+#
+
+-- connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t (c1 int, c2 char(1), c3 char(1),
+ c4 char(1), primary key(c1,c3)) engine=
+InnoDB;
+SET SQL_LOG_BIN=1;
+
+-- connection slave
+SET SQL_LOG_BIN=0;
+CREATE TABLE t (c1 int, c2 char(1), c3 char(1),
+ c4 char(1)) engine= InnoDB;
+SET SQL_LOG_BIN=1;
+
+-- connection master
+INSERT INTO t VALUES (1, '2', '3', '4' );
+
+-- sync_slave_with_master
+
+-- connection master
+UPDATE t SET c4 = '7';
+
+-- sync_slave_with_master
+-- connection master
+
+DROP TABLE t;
+
+-- sync_slave_with_master
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2009-08-13 14:29:55 +0000
+++ b/sql/log_event.cc 2009-09-10 09:37:43 +0000
@@ -8735,16 +8735,14 @@ static bool record_compare(TABLE *table,
ii) all columns were read or the slave SE provides partial reads
*/
if ((table->s->blob_fields + table->s->varchar_fields == 0) &&
- (bitmap_is_set_all(cols_in_readset) ||
- (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)))
+ (bitmap_is_set_all(cols_in_readset)))
{
result= cmp_record(table,record[1]);
goto record_compare_exit;
}
/* Compare null bits only if all fields were read or slave SE has partial reads */
- if ((bitmap_is_set_all(cols_in_readset) ||
- (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)) &&
+ if ((bitmap_is_set_all(cols_in_readset)) &&
memcmp(table->null_flags,
table->null_flags+table->s->rec_buff_length,
table->s->null_bytes))
=== modified file 'sql/log_event_old.cc'
--- a/sql/log_event_old.cc 2009-08-13 14:29:55 +0000
+++ b/sql/log_event_old.cc 2009-09-10 09:37:43 +0000
@@ -320,16 +320,14 @@ static bool record_compare(TABLE *table,
ii) all columns were read or the slave SE provides partial reads
*/
if ((table->s->blob_fields + table->s->varchar_fields == 0) &&
- (bitmap_is_set_all(cols_in_readset) ||
- (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)))
+ (bitmap_is_set_all(cols_in_readset)))
{
result= cmp_record(table,record[1]);
goto record_compare_exit;
}
/* Compare null bits only if all fields were read or slave SE has partial reads */
- if ((bitmap_is_set_all(cols_in_readset) ||
- (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)) &&
+ if ((bitmap_is_set_all(cols_in_readset)) &&
memcmp(table->null_flags,
table->null_flags+table->s->rec_buff_length,
table->s->null_bytes))
Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20090910093743-d0o4ml1vl2cknppi.bundle