diff --git a/mysql-test/suite/innodb/r/innodb-index-online.result b/mysql-test/suite/innodb/r/innodb-index-online.result index 7f945ad60a6..b4b9ba9d421 100644 --- a/mysql-test/suite/innodb/r/innodb-index-online.result +++ b/mysql-test/suite/innodb/r/innodb-index-online.result @@ -308,6 +308,34 @@ SET DEBUG_SYNC = 'RESET'; SET DEBUG = ''; SET GLOBAL innodb_monitor_disable = module_ddl; DROP TABLE t1; +# Rollback delete-mark records after row_log_apply done and before index->is_committed() == true. +# But after row_log_apply done and before rollback, insert a non-duplicate row with NULL values. +# ddl shouldn't be aborted. +CREATE TABLE t1 (id int primary key, c1 int,c2 int); +INSERT INTO t1 VALUES (1,1,null); +INSERT INTO t1 VALUES (2,2,null); +SET DEBUG_SYNC = 'RESET'; +SET DEBUG_SYNC = 'row_log_apply_before SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC = 'row_log_apply_after WAIT_FOR s3'; +ALTER TABLE t1 ADD UNIQUE KEY uk1(c1,c2); +SET DEBUG_SYNC = 'now WAIT_FOR s1'; +BEGIN; +DELETE FROM t1 where id=1; +SET DEBUG_SYNC = 'now SIGNAL s2'; +insert into t1 values (3,1,null); +ROLLBACK; +SET DEBUG_SYNC = 'now SIGNAL s3'; +select id,c1,c2 from t1 force index(primary); +id c1 c2 +1 1 NULL +2 2 NULL +3 1 NULL +select id,c1,c2 from t1 force index(uk1); +id c1 c2 +1 1 NULL +3 1 NULL +2 2 NULL +drop table t1; SET GLOBAL DEBUG = ''; SET GLOBAL innodb_file_per_table = @global_innodb_file_per_table_orig; SET GLOBAL innodb_monitor_reset = default; diff --git a/mysql-test/suite/innodb/t/innodb-index-online.test b/mysql-test/suite/innodb/t/innodb-index-online.test index 6c2fc6d2355..6385f9565e2 100644 --- a/mysql-test/suite/innodb/t/innodb-index-online.test +++ b/mysql-test/suite/innodb/t/innodb-index-online.test @@ -405,6 +405,42 @@ SET GLOBAL innodb_monitor_disable = module_ddl; DROP TABLE t1; +--echo # Rollback delete-mark records after row_log_apply done and before index->is_committed() == true. +--echo # But after row_log_apply done and before rollback, insert a non-duplicate row with NULL values. +--echo # ddl shouldn't be aborted. +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection default; +CREATE TABLE t1 (id int primary key, c1 int,c2 int); +INSERT INTO t1 VALUES (1,1,null); +INSERT INTO t1 VALUES (2,2,null); +SET DEBUG_SYNC = 'RESET'; +SET DEBUG_SYNC = 'row_log_apply_before SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC = 'row_log_apply_after WAIT_FOR s3'; +--send ALTER TABLE t1 ADD UNIQUE KEY uk1(c1,c2) + +connection con1; +SET DEBUG_SYNC = 'now WAIT_FOR s1'; +BEGIN; +DELETE FROM t1 where id=1; +SET DEBUG_SYNC = 'now SIGNAL s2'; + +connection con2; +insert into t1 values (3,1,null); + +connection con1; +ROLLBACK; +SET DEBUG_SYNC = 'now SIGNAL s3'; + +connection default; +--reap +select id,c1,c2 from t1 force index(primary); +select id,c1,c2 from t1 force index(uk1); +drop table t1; +disconnect con1; +disconnect con2; +connection default; + # Check that all connections opened by test cases in this file are really # gone so execution of other tests won't be affected by their presence. --source include/wait_until_count_sessions.inc diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 98d9009c912..e895bf9f75e 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -679,8 +679,9 @@ try_again: << " at: " << rec_index_print(btr_cur_get_rec(btr_cur), index); } - if (btr_cur->up_match >= dict_index_get_n_unique(index) || - btr_cur->low_match >= dict_index_get_n_unique(index)) { + if ((btr_cur->up_match >= dict_index_get_n_unique(index) || + btr_cur->low_match >= dict_index_get_n_unique(index)) && + (!index->n_nullable || !dtuple_contains_null(entry))) { if (index->is_committed()) { ib::warn(ER_IB_MSG_1040) << "Record in index " << index->name << " was not found on rollback, and"