diff options
-rw-r--r-- | mysql-test/suite/innodb/r/alter_primary_key.result | 26 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/alter_primary_key.test | 34 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 10 |
3 files changed, 68 insertions, 2 deletions
diff --git a/mysql-test/suite/innodb/r/alter_primary_key.result b/mysql-test/suite/innodb/r/alter_primary_key.result new file mode 100644 index 00000000000..afe687871f3 --- /dev/null +++ b/mysql-test/suite/innodb/r/alter_primary_key.result @@ -0,0 +1,26 @@ +# +# MDEV-23244 ALTER TABLE…ADD PRIMARY KEY fails to flag +# duplicate key error from concurrent DML +# +CREATE TABLE t0 (pk INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1 (c CHAR(2) NOT NULL) ENGINE=InnoDB; +connect con1,localhost,root,,; +BEGIN; +INSERT INTO t0 VALUES(1); +connection default; +SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL dml WAIT_FOR dml_done'; +ALTER TABLE t1 ADD PRIMARY KEY(c(1)); +connection con1; +SET DEBUG_SYNC='now WAIT_FOR dml'; +INSERT INTO t1 VALUES ('ab'),('ac'); +COMMIT; +SET DEBUG_SYNC='now SIGNAL dml_done'; +disconnect con1; +connection default; +ERROR 23000: Duplicate entry 'a' for key 'PRIMARY' +SET DEBUG_SYNC='RESET'; +SELECT * FROM t1; +c +ab +ac +DROP TABLE t0,t1; diff --git a/mysql-test/suite/innodb/t/alter_primary_key.test b/mysql-test/suite/innodb/t/alter_primary_key.test new file mode 100644 index 00000000000..4edc0cc023e --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_primary_key.test @@ -0,0 +1,34 @@ +--source innodb_default_row_format.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--echo # +--echo # MDEV-23244 ALTER TABLE…ADD PRIMARY KEY fails to flag +--echo # duplicate key error from concurrent DML +--echo # + +CREATE TABLE t0 (pk INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1 (c CHAR(2) NOT NULL) ENGINE=InnoDB; + +connect (con1,localhost,root,,); +BEGIN; +INSERT INTO t0 VALUES(1); + +connection default; +SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL dml WAIT_FOR dml_done'; +send ALTER TABLE t1 ADD PRIMARY KEY(c(1)); + +connection con1; +SET DEBUG_SYNC='now WAIT_FOR dml'; +INSERT INTO t1 VALUES ('ab'),('ac'); +COMMIT; +SET DEBUG_SYNC='now SIGNAL dml_done'; +disconnect con1; + +connection default; +--error ER_DUP_ENTRY +reap; +SET DEBUG_SYNC='RESET'; + +SELECT * FROM t1; +DROP TABLE t0,t1; diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index d6596d586ab..13649777419 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -2241,8 +2241,14 @@ row_ins_duplicate_online( return(DB_SUCCESS); } - if (fields == n_uniq + 2) { - /* rec is an exact match of entry. */ + ulint trx_id_len; + + if (fields == n_uniq + 2 + && memcmp(rec_get_nth_field(rec, offsets, n_uniq, &trx_id_len), + reset_trx_id, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)) { + ut_ad(trx_id_len == DATA_TRX_ID_LEN); + /* rec is an exact match of entry, and DB_TRX_ID belongs + to a transaction that started after our ALTER TABLE. */ return(DB_SUCCESS_LOCKED_REC); } |