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 <kniel...@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

_______________________________________________
commits mailing list -- commits@lists.mariadb.org
To unsubscribe send an email to commits-le...@lists.mariadb.org

Reply via email to