Commit e40dbfa8 authored by unknown's avatar unknown

Bug#18436 (RBR: Replication to partition engine triggers assertion on slave side):

Partial fix for resolving the problem. Swapping contents of record[0]
and record[1] since this is what some storage engines expect.


sql/handler.cc:
  Adding assertion to get early failure.
sql/log_event.cc:
  Correcting code so that new record is passed in record[0] and
  old record is passed in record[1] when calling update_row().
mysql-test/r/rpl_row_basic_8partition.result:
  New BitKeeper file ``mysql-test/r/rpl_row_basic_8partition.result''
mysql-test/t/rpl_row_basic_8partition.test:
  New BitKeeper file ``mysql-test/t/rpl_row_basic_8partition.test''
parent dfa9a764
This diff is collapsed.
############################################################
# Author: MATZ #
# Date: 2006-03-22 #
# Purpose: See if replication of partition tables work #
# Most of this test is copied from the rpl_xxx2yyy tests, #
# but here we just test some simple basic replication of #
# partition tables with same engine (MyISAM) in both ends. #
############################################################
--source include/master-slave.inc
connection master;
--disable_warnings
DROP TABLE IF EXISTS t1;
SET BINLOG_FORMAT=ROW;
--echo **** Partition RANGE testing ****
# Create table that is partitioned by range on year i.e. year(t) and
# replicate basice operations such at insert, update delete between 2
# different storage engines Alter table and ensure table is handled
# Correctly on the slave
# Note that the storage engine should not be explicit: the default
# storage engine is used on master and slave.
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE)
PARTITION BY RANGE (YEAR(t))
(PARTITION p0 VALUES LESS THAN (1901),
PARTITION p1 VALUES LESS THAN (1946),
PARTITION p2 VALUES LESS THAN (1966),
PARTITION p3 VALUES LESS THAN (1986),
PARTITION p4 VALUES LESS THAN (2005),
PARTITION p5 VALUES LESS THAN MAXVALUE);
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave --
sync_slave_with_master;
SHOW CREATE TABLE t1;
--source include/rpl_multi_engine3.inc
connection master;
# Check that simple Alter statements are replicated correctly
ALTER TABLE t1 MODIFY vc TEXT;
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
# Perform basic operation on master and ensure replicated correctly
--source include/rpl_multi_engine3.inc
connection master;
DROP TABLE IF EXISTS t1;
########################################################
--echo **** Partition LIST testing ****
# Create table that is partitioned by list on id i.e. (2,4). Pretend
# that we missed one and alter to add. Then replicate basice
# operations such at insert, update delete between 2 different storage
# engines Alter table and ensure table is handled Correctly on the
# slave.
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE)
PARTITION BY LIST(id)
(PARTITION p0 VALUES IN (2, 4),
PARTITION p1 VALUES IN (42, 142),
PARTITION p2 VALUES IN (412));
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
# Perform basic operation on master and ensure replicated correctly
--source include/rpl_multi_engine3.inc
connection master;
# Check that simple Alter statements are replicated correctly ---
ALTER TABLE t1 MODIFY vc TEXT;
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
# Perform basic operation on master and ensure replicated correctly
--source include/rpl_multi_engine3.inc
connection master;
DROP TABLE IF EXISTS t1;
########################################################
--echo **** Partition HASH testing ****
# Create table that is partitioned by hash on year i.e. YEAR(t). Then
# replicate basice operations such at insert, update delete between 2
# different storage engines Alter table and ensure table is handled
# Correctly on the slave
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE)
PARTITION BY HASH( YEAR(t) )
PARTITIONS 4;
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--source include/rpl_multi_engine3.inc
# Check that simple Alter statements are replicated correctly
ALTER TABLE t1 MODIFY vc TEXT;
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--source include/rpl_multi_engine3.inc
connection master;
DROP TABLE IF EXISTS t1;
########################################################
# This part does not work
--disable_parsing
--echo **** Partition by KEY ****
# Create table that is partitioned by key on id with 4 parts. Then
# replicate basice operations such at insert, update delete between 2
# different storage engines Alter table and ensure table is handled
# Correctly on the slave
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE,PRIMARY KEY(id))
PARTITION BY KEY()
PARTITIONS 4;
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--source include/rpl_multi_engine3.inc
connection master;
# Check that simple Alter statements are replicated correctly
ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY(id, total);
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--source include/rpl_multi_engine3.inc
connection master;
# Check that simple Alter statements are replicated correctly
ALTER TABLE t1 MODIFY vc TEXT;
--echo --- On master ---
SHOW CREATE TABLE t1;
--echo --- On slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--source include/rpl_multi_engine3.inc
DROP TABLE IF EXISTS t1;
--enable_parsing
# End of 5.1 test case
...@@ -3296,6 +3296,13 @@ int handler::ha_write_row(byte *buf) ...@@ -3296,6 +3296,13 @@ int handler::ha_write_row(byte *buf)
int handler::ha_update_row(const byte *old_data, byte *new_data) int handler::ha_update_row(const byte *old_data, byte *new_data)
{ {
int error; int error;
/*
Some storage engines require that the new record is in record[0]
(and the old record is in record[1]).
*/
DBUG_ASSERT(new_data == table->record[0]);
if (unlikely(error= update_row(old_data, new_data))) if (unlikely(error= update_row(old_data, new_data)))
return error; return error;
#ifdef HAVE_ROW_BASED_REPLICATION #ifdef HAVE_ROW_BASED_REPLICATION
......
...@@ -6402,7 +6402,7 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6402,7 +6402,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
table->record[0] if the engine allows it. We first compute a table->record[0] if the engine allows it. We first compute a
row reference using the position() member function (it will be row reference using the position() member function (it will be
stored in table->file->ref) and the use rnd_pos() to position stored in table->file->ref) and the use rnd_pos() to position
the "cursor" at the correct row. the "cursor" (i.e., record[0] in this case) at the correct row.
*/ */
table->file->position(table->record[0]); table->file->position(table->record[0]);
DBUG_RETURN(table->file->rnd_pos(table->record[0], table->file->ref)); DBUG_RETURN(table->file->rnd_pos(table->record[0], table->file->ref));
...@@ -6797,19 +6797,25 @@ int Update_rows_log_event::do_exec_row(TABLE *table) ...@@ -6797,19 +6797,25 @@ int Update_rows_log_event::do_exec_row(TABLE *table)
return error; return error;
/* /*
This is only a precaution to make sure that the call to We have to ensure that the new record (i.e., the after image) is
ha_update_row is using record[1]. in record[0] and the old record (i.e., the before image) is in
record[1]. This since some storage engines require this (for
example, the partition engine).
If this is not needed/required, then we could use m_after_image in Since find_and_fetch_row() puts the fetched record (i.e., the old
that call instead. record) in record[0], we have to move it out of the way and into
record[1]. After that, we can put the new record (i.e., the after
image) into record[0].
*/ */
bmove_align(table->record[1], m_after_image,(size_t) table->s->reclength); bmove_align(table->record[1], table->record[0], table->s->reclength);
bmove_align(table->record[0], m_after_image, table->s->reclength);
/* /*
Now we should have the right row to update. The record that has Now we should have the right row to update. The old row (the one
been fetched is guaranteed to be in record[0], so we use that. we're looking for) has to be in record[1] and the new row has to
be in record[0] for all storage engines to work correctly.
*/ */
error= table->file->ha_update_row(table->record[0], table->record[1]); error= table->file->ha_update_row(table->record[1], table->record[0]);
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment