diff --git a/mysql-test/suite/versioning/r/rpl.result b/mysql-test/suite/versioning/r/rpl.result index a6fa6b3fca7..17372c63e99 100644 --- a/mysql-test/suite/versioning/r/rpl.result +++ b/mysql-test/suite/versioning/r/rpl.result @@ -164,4 +164,28 @@ update t1 set i = 0; connection slave; connection master; drop table t1; +# check versioned -> versioned replication without any keys on duplicate records +connection master; +create table t1 (a INT) with system versioning; +insert into t1 values (1); +insert into t1 values (1); +delete from t1; +connection slave; +include/diff_tables.inc [master:test.t1,slave:test.t1] +connection master; +drop table t1; +connection slave; +# check unversioned -> versioned replication with non-unique keys on duplicate records +connection master; +set statement sql_log_bin=0 for create table t1 (a INT NOT NULL, b INT, INDEX(a,b)); +connection slave; +set statement sql_log_bin=0 for create table t1 (a INT NOT NULL, b INT, INDEX(a,b)) with system versioning; +connection master; +insert into t1 values (1,1); +insert into t1 values (1,1); +delete from t1; +connection slave; +include/diff_tables.inc [master:test.t1,slave:test.t1] +connection master; +drop table t1; include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl.test b/mysql-test/suite/versioning/t/rpl.test index b5be68feece..7d78b60e6fa 100644 --- a/mysql-test/suite/versioning/t/rpl.test +++ b/mysql-test/suite/versioning/t/rpl.test @@ -133,4 +133,38 @@ sync_slave_with_master; connection master; drop table t1; + +# +# MDEV-30430: Enabling system versioning on tables without primary key breaks replication +# Note that bugs are only present with row binlog format +# +--echo # check versioned -> versioned replication without any keys on duplicate records +connection master; +create table t1 (a INT) with system versioning; +insert into t1 values (1); +insert into t1 values (1); +delete from t1; +sync_slave_with_master; +--let $diff_tables= master:test.t1,slave:test.t1 +--source include/diff_tables.inc +connection master; +drop table t1; +sync_slave_with_master; + +--echo # check unversioned -> versioned replication with non-unique keys on duplicate records +connection master; +set statement sql_log_bin=0 for create table t1 (a INT NOT NULL, b INT, INDEX(a,b)); +connection slave; +set statement sql_log_bin=0 for create table t1 (a INT NOT NULL, b INT, INDEX(a,b)) with system versioning; +connection master; +insert into t1 values (1,1); +insert into t1 values (1,1); +delete from t1; +sync_slave_with_master; +--let $diff_tables= master:test.t1,slave:test.t1 +--source include/diff_tables.inc + +connection master; +drop table t1; + --source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index 14cdf880d62..74b39dcadef 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -13873,7 +13873,7 @@ uint8 Write_rows_log_event::get_trg_event_map() Returns TRUE if different. */ -static bool record_compare(TABLE *table) +static bool record_compare(TABLE *table, bool vers_from_plain= false) { bool result= FALSE; /** @@ -13906,10 +13906,19 @@ static bool record_compare(TABLE *table) /* Compare fields */ for (Field **ptr=table->field ; *ptr ; ptr++) { - if (table->versioned() && (*ptr)->vers_sys_field()) - { + /* + If the table is versioned, don't compare using the version if there is a + primary key. If there isn't a primary key, we need the version to + identify the correct record if there are duplicate rows in the data set. + However, if the primary server is unversioned (vers_from_plain is true), + then we implicitly use row_end as the primary key on our side. This is + because the implicit row_end value will be set to the maximum value for + the latest row update (which is what we care about). + */ + if (table->versioned() && (*ptr)->vers_sys_field() && + (table->s->primary_key < MAX_KEY || + (vers_from_plain && table->vers_start_field() == (*ptr)))) continue; - } /** We only compare field contents that are not null. NULL fields (i.e., their null bits) were compared @@ -14306,7 +14315,7 @@ int Rows_log_event::find_row(rpl_group_info *rgi) /* We use this to test that the correct key is used in test cases. */ DBUG_EXECUTE_IF("slave_crash_if_index_scan", abort();); - while (record_compare(table)) + while (record_compare(table, m_vers_from_plain)) { while ((error= table->file->ha_index_next(table->record[0]))) { @@ -14359,7 +14368,7 @@ int Rows_log_event::find_row(rpl_group_info *rgi) goto end; } } - while (record_compare(table)); + while (record_compare(table, m_vers_from_plain)); /* Note: above record_compare will take into account all record fields