diff --git a/mysql-test/suite/parts/r/mdev_40995.result b/mysql-test/suite/parts/r/mdev_40995.result new file mode 100644 index 0000000000000..f187b37412ddf --- /dev/null +++ b/mysql-test/suite/parts/r/mdev_40995.result @@ -0,0 +1,28 @@ +# +# MDEV-40995 concurrent INSERT ... SELECT on a partitioned InnoDB table +# can leave the table-level AUTO_INCREMENT counter behind MAX(pk) +# +CREATE TABLE t1 ( +id INT AUTO_INCREMENT, +pk2 INT NOT NULL, +a INT, +PRIMARY KEY (id, pk2), +UNIQUE KEY (a, pk2) +) ENGINE=InnoDB PARTITION BY HASH(pk2) PARTITIONS 2; +INSERT INTO t1 (pk2, a) VALUES (1, 10), (1, 100), (1, 110); +connect con1,localhost,root,,; +connect con2,localhost,root,,; +connection con1; +SET DEBUG_SYNC = 'ha_partition_get_auto_increment_after_reservation SIGNAL start_t2 WAIT_FOR t2_done EXECUTE 1'; +INSERT INTO t1 (pk2, a) SELECT pk2, a+10 FROM t1 WHERE pk2=1 ORDER BY a;; +connection con2; +SET DEBUG_SYNC = 'now WAIT_FOR start_t2'; +INSERT INTO t1 (pk2, a) VALUES (2, 200); +SET DEBUG_SYNC = 'now SIGNAL t2_done'; +connection con1; +ERROR 23000: Duplicate entry '110-1' for key 'a' +connection default; +INSERT INTO t1 (pk2, a) VALUES (2, 300); +INSERT INTO t1 (pk2, a) VALUES (2, 400); +DROP TABLE t1; +SET DEBUG_SYNC = 'RESET'; diff --git a/mysql-test/suite/parts/t/mdev_40995-master.opt b/mysql-test/suite/parts/t/mdev_40995-master.opt new file mode 100644 index 0000000000000..571c7877f11a3 --- /dev/null +++ b/mysql-test/suite/parts/t/mdev_40995-master.opt @@ -0,0 +1 @@ +--innodb-autoinc-lock-mode=2 diff --git a/mysql-test/suite/parts/t/mdev_40995.test b/mysql-test/suite/parts/t/mdev_40995.test new file mode 100644 index 0000000000000..d00ad9e032d61 --- /dev/null +++ b/mysql-test/suite/parts/t/mdev_40995.test @@ -0,0 +1,41 @@ +--source include/have_debug_sync.inc +--source include/have_partition.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV-40995 concurrent INSERT ... SELECT on a partitioned InnoDB table +--echo # can leave the table-level AUTO_INCREMENT counter behind MAX(pk) +--echo # + +CREATE TABLE t1 ( + id INT AUTO_INCREMENT, + pk2 INT NOT NULL, + a INT, + PRIMARY KEY (id, pk2), + UNIQUE KEY (a, pk2) +) ENGINE=InnoDB PARTITION BY HASH(pk2) PARTITIONS 2; + +INSERT INTO t1 (pk2, a) VALUES (1, 10), (1, 100), (1, 110); + +--connect (con1,localhost,root,,) +--connect (con2,localhost,root,,) + +--connection con1 +SET DEBUG_SYNC = 'ha_partition_get_auto_increment_after_reservation SIGNAL start_t2 WAIT_FOR t2_done EXECUTE 1'; +--send INSERT INTO t1 (pk2, a) SELECT pk2, a+10 FROM t1 WHERE pk2=1 ORDER BY a; + +--connection con2 +SET DEBUG_SYNC = 'now WAIT_FOR start_t2'; +INSERT INTO t1 (pk2, a) VALUES (2, 200); +SET DEBUG_SYNC = 'now SIGNAL t2_done'; + +--connection con1 +--error ER_DUP_ENTRY +--reap + +--connection default +INSERT INTO t1 (pk2, a) VALUES (2, 300); +INSERT INTO t1 (pk2, a) VALUES (2, 400); + +DROP TABLE t1; +SET DEBUG_SYNC = 'RESET'; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index e1e04c359211b..47dcee1eab13b 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -11107,6 +11107,7 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment, part_share->next_auto_inc_val+= nb_desired_values * increment; unlock_auto_increment(); + DEBUG_SYNC(ha_thd(), "ha_partition_get_auto_increment_after_reservation"); DBUG_PRINT("info", ("*first_value: %lu", (ulong) *first_value)); *nb_reserved_values= nb_desired_values; } @@ -11139,7 +11140,8 @@ void ha_partition::release_auto_increment() we can lower the reserved value. */ if (next_insert_id < next_auto_inc_val && - auto_inc_interval_for_cur_row.maximum() >= next_auto_inc_val) + auto_inc_interval_for_cur_row.maximum() >= next_auto_inc_val && + next_insert_id >= auto_inc_interval_for_cur_row.minimum()) { THD *thd= ha_thd(); /*