mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
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 <monty@mariadb.org> Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
parent
b66d421d60
commit
9e7762e718
3 changed files with 72 additions and 10 deletions
13
mysql-test/suite/rpl/r/rpl_csv.result
Normal file
13
mysql-test/suite/rpl/r/rpl_csv.result
Normal file
|
@ -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
|
16
mysql-test/suite/rpl/t/rpl_csv.test
Normal file
16
mysql-test/suite/rpl/t/rpl_csv.test
Normal file
|
@ -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
|
|
@ -6641,6 +6641,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.
|
||||
|
||||
|
@ -7100,6 +7140,7 @@ static bool record_compare(TABLE *table, bool vers_from_plain= false)
|
|||
table->s->null_fields) == 0
|
||||
&& all_values_set)
|
||||
{
|
||||
normalize_null_bits(table);
|
||||
result= cmp_record(table, record[1]);
|
||||
goto record_compare_exit;
|
||||
}
|
||||
|
@ -7547,6 +7588,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.
|
||||
|
@ -7583,16 +7626,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;
|
||||
|
|
Loading…
Reference in a new issue