Handle null bits for record comparison in row events the same way as in handler::calculate_checksum(), forcing bits that can be undefined to 1. These bits are the trailing unused bits, as well as the first bit for tables not using HA_OPTION_PACK_RECORD. The csv storage engine leaves these bits at 0, while the row-based replication has them set to 1, which otherwise cause can't find record error. Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org> --- mysql-test/suite/rpl/r/rpl_csv.result | 13 +++++++ mysql-test/suite/rpl/t/rpl_csv.test | 16 ++++++++ sql/log_event_server.cc | 54 ++++++++++++++++++++++----- 3 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_csv.result create mode 100644 mysql-test/suite/rpl/t/rpl_csv.test diff --git a/mysql-test/suite/rpl/r/rpl_csv.result b/mysql-test/suite/rpl/r/rpl_csv.result new file mode 100644 index 00000000000..39b78186df3 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_csv.result @@ -0,0 +1,13 @@ +include/master-slave.inc +[connection master] +*** MDEV-35233: RBR does not work with CSV tables +CREATE TABLE t (a INT NOT NULL) ENGINE=CSV; +INSERT INTO t VALUES (1),(2); +DELETE FROM t where a=1; +connection slave; +SELECT * FROM t ORDER BY a; +a +2 +connection master; +DROP TABLE t; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_csv.test b/mysql-test/suite/rpl/t/rpl_csv.test new file mode 100644 index 00000000000..82f745d549e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_csv.test @@ -0,0 +1,16 @@ +--source include/have_csv.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--echo *** MDEV-35233: RBR does not work with CSV tables +CREATE TABLE t (a INT NOT NULL) ENGINE=CSV; +INSERT INTO t VALUES (1),(2); +DELETE FROM t where a=1; + +--sync_slave_with_master +SELECT * FROM t ORDER BY a; + +# Cleanup +--connection master +DROP TABLE t; +--source include/rpl_end.inc diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index 8b976ba5e14..d6617e8fb68 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -6646,6 +6646,46 @@ last_uniq_key(TABLE *table, uint keyno) return 1; } + +/* + We need to set the null bytes to ensure that the filler bit are + all set when returning. There are storage engines that just set + the necessary bits on the bytes and don't set the filler bits + correctly. +*/ +static void +normalize_null_bits(TABLE *table) +{ + if (table->s->null_bytes > 0) + { + DBUG_ASSERT(table->s->last_null_bit_pos < 8); + /* + Normalize any unused null bits. + + We need to set the highest (8 - last_null_bit_pos) bits to 1, except that + if last_null_bit_pos is 0 then there are no unused bits and we should set + no bits to 1. + + When N = last_null_bit_pos != 0, we can get a mask for this with + + 0xff << N = (0xff << 1) << (N-1) = 0xfe << (N-1) = 0xfe << ((N-1) & 7) + + And we can get a mask=0 for the case N = last_null_bit_pos = 0 with + + 0xfe << 7 = 0xfe << ((N-1) & 7) + + Thus we can set the desired bits in all cases by OR-ing with + (0xfe << ((N-1) & 7)), avoiding a conditional jump. + */ + table->record[0][table->s->null_bytes - 1]|= + (uchar)(0xfe << ((table->s->last_null_bit_pos - 1) & 7)); + /* Normalize the delete marker bit, if any. */ + table->record[0][0]|= + !(table->s->db_create_options & HA_OPTION_PACK_RECORD); + } +} + + /** Check if an error is a duplicate key error. @@ -7089,6 +7129,8 @@ static bool record_compare(TABLE *table, bool vers_from_plain= false) bool result= false; bool all_values_set= bitmap_is_set_all(&table->has_value_set); + normalize_null_bits(table); + /** Compare full record only if: - all fields were given values @@ -7552,6 +7594,8 @@ int Rows_log_event::find_row(rpl_group_info *rgi) // We can't use position() - try other methods. + normalize_null_bits(table); + /* Save copy of the record in table->record[1]. It might be needed later if linear search is used to find exact match. @@ -7588,16 +7632,6 @@ int Rows_log_event::find_row(rpl_group_info *rgi) DBUG_DUMP("key data", m_key, m_key_info->key_length); #endif - /* - We need to set the null bytes to ensure that the filler bit are - all set when returning. There are storage engines that just set - the necessary bits on the bytes and don't set the filler bits - correctly. - */ - if (table->s->null_bytes > 0) - table->record[0][table->s->null_bytes - 1]|= - 256U - (1U << table->s->last_null_bit_pos); - const enum ha_rkey_function find_flag= m_usable_key_parts == m_key_info->user_defined_key_parts ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT; -- 2.39.5
participants (1)
-
Kristian Nielsen