Skip to content

Commit 9e7762e

Browse files
committed
MDEV-35233: RBR does not work with CSV tables
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. Reviewed-by: Monty <[email protected]> Signed-off-by: Kristian Nielsen <[email protected]>
1 parent b66d421 commit 9e7762e

File tree

3 files changed

+72
-10
lines changed

3 files changed

+72
-10
lines changed

mysql-test/suite/rpl/r/rpl_csv.result

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
include/master-slave.inc
2+
[connection master]
3+
*** MDEV-35233: RBR does not work with CSV tables
4+
CREATE TABLE t (a INT NOT NULL) ENGINE=CSV;
5+
INSERT INTO t VALUES (1),(2);
6+
DELETE FROM t where a=1;
7+
connection slave;
8+
SELECT * FROM t ORDER BY a;
9+
a
10+
2
11+
connection master;
12+
DROP TABLE t;
13+
include/rpl_end.inc

mysql-test/suite/rpl/t/rpl_csv.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--source include/have_csv.inc
2+
--source include/have_binlog_format_row.inc
3+
--source include/master-slave.inc
4+
5+
--echo *** MDEV-35233: RBR does not work with CSV tables
6+
CREATE TABLE t (a INT NOT NULL) ENGINE=CSV;
7+
INSERT INTO t VALUES (1),(2);
8+
DELETE FROM t where a=1;
9+
10+
--sync_slave_with_master
11+
SELECT * FROM t ORDER BY a;
12+
13+
# Cleanup
14+
--connection master
15+
DROP TABLE t;
16+
--source include/rpl_end.inc

sql/log_event_server.cc

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6641,6 +6641,46 @@ last_uniq_key(TABLE *table, uint keyno)
66416641
return 1;
66426642
}
66436643

6644+
6645+
/*
6646+
We need to set the null bytes to ensure that the filler bit are
6647+
all set when returning. There are storage engines that just set
6648+
the necessary bits on the bytes and don't set the filler bits
6649+
correctly.
6650+
*/
6651+
static void
6652+
normalize_null_bits(TABLE *table)
6653+
{
6654+
if (table->s->null_bytes > 0)
6655+
{
6656+
DBUG_ASSERT(table->s->last_null_bit_pos < 8);
6657+
/*
6658+
Normalize any unused null bits.
6659+
6660+
We need to set the highest (8 - last_null_bit_pos) bits to 1, except that
6661+
if last_null_bit_pos is 0 then there are no unused bits and we should set
6662+
no bits to 1.
6663+
6664+
When N = last_null_bit_pos != 0, we can get a mask for this with
6665+
6666+
0xff << N = (0xff << 1) << (N-1) = 0xfe << (N-1) = 0xfe << ((N-1) & 7)
6667+
6668+
And we can get a mask=0 for the case N = last_null_bit_pos = 0 with
6669+
6670+
0xfe << 7 = 0xfe << ((N-1) & 7)
6671+
6672+
Thus we can set the desired bits in all cases by OR-ing with
6673+
(0xfe << ((N-1) & 7)), avoiding a conditional jump.
6674+
*/
6675+
table->record[0][table->s->null_bytes - 1]|=
6676+
(uchar)(0xfe << ((table->s->last_null_bit_pos - 1) & 7));
6677+
/* Normalize the delete marker bit, if any. */
6678+
table->record[0][0]|=
6679+
!(table->s->db_create_options & HA_OPTION_PACK_RECORD);
6680+
}
6681+
}
6682+
6683+
66446684
/**
66456685
Check if an error is a duplicate key error.
66466686
@@ -7100,6 +7140,7 @@ static bool record_compare(TABLE *table, bool vers_from_plain= false)
71007140
table->s->null_fields) == 0
71017141
&& all_values_set)
71027142
{
7143+
normalize_null_bits(table);
71037144
result= cmp_record(table, record[1]);
71047145
goto record_compare_exit;
71057146
}
@@ -7547,6 +7588,8 @@ int Rows_log_event::find_row(rpl_group_info *rgi)
75477588

75487589
// We can't use position() - try other methods.
75497590

7591+
normalize_null_bits(table);
7592+
75507593
/*
75517594
Save copy of the record in table->record[1]. It might be needed
75527595
later if linear search is used to find exact match.
@@ -7583,16 +7626,6 @@ int Rows_log_event::find_row(rpl_group_info *rgi)
75837626
DBUG_DUMP("key data", m_key, m_key_info->key_length);
75847627
#endif
75857628

7586-
/*
7587-
We need to set the null bytes to ensure that the filler bit are
7588-
all set when returning. There are storage engines that just set
7589-
the necessary bits on the bytes and don't set the filler bits
7590-
correctly.
7591-
*/
7592-
if (table->s->null_bytes > 0)
7593-
table->record[0][table->s->null_bytes - 1]|=
7594-
256U - (1U << table->s->last_null_bit_pos);
7595-
75967629
const enum ha_rkey_function find_flag=
75977630
m_usable_key_parts == m_key_info->user_defined_key_parts
75987631
? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT;

0 commit comments

Comments
 (0)