diff --git a/mysql-test/suite/innodb/r/autoinc_debug.result b/mysql-test/suite/innodb/r/autoinc_debug.result new file mode 100644 index 00000000000..eb9dfc2a028 --- /dev/null +++ b/mysql-test/suite/innodb/r/autoinc_debug.result @@ -0,0 +1,100 @@ +CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB; +# SETTING auto_increment_increment IN CONNECTION DEFAULT +SET AUTO_INCREMENT_INCREMENT = 1; +INSERT INTO t1 VALUES(NULL); +SELECT * FROM t1; +id +1 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 +# SETTING auto_increment_increment IN CONNECTION1 +SET AUTO_INCREMENT_INCREMENT = 2; +SET DEBUG_SYNC= 'ib_after_row_insert SIGNAL opened WAIT_FOR flushed1'; +INSERT INTO t1 VALUES(NULL); +connect con1, localhost, root,,; +SET AUTO_INCREMENT_INCREMENT = 2; +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'ib_after_row_insert_step SIGNAL flushed1 WAIT_FOR opened1'; +insert into t1 values(NULL); +connection default; +SELECT * FROM t1; +id +1 +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 +SET DEBUG_SYNC= 'now SIGNAL opened1'; +connection con1; +SELECT * FROM t1; +id +1 +3 +5 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 +connection default; +disconnect con1; +DROP TABLE t1; +CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB; +# SETTING auto_increment_increment IN CONNECTION DEFAULT +SET AUTO_INCREMENT_INCREMENT = 1; +INSERT INTO t1 VALUES(NULL); +SELECT * FROM t1; +id +1 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 +SET DEBUG_SYNC = 'now SIGNAL flushed'; +connect con1, localhost, root,,; +# SETTING auto_increment_increment in connection1 +SET AUTO_INCREMENT_INCREMENT = 2; +SET DEBUG_SYNC= 'now WAIT_FOR flushed'; +SET DEBUG_SYNC= 'ib_after_row_insert SIGNAL opened WAIT_FOR flushed1'; +INSERT INTO t1 values(NULL); +connection default; +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'ib_after_row_insert_step SIGNAL flushed1 WAIT_FOR opened1'; +INSERT INTO t1 VALUES(NULL); +connection con1; +SELECT * FROM t1; +id +1 +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 +SET DEBUG_SYNC= 'now SIGNAL opened1'; +disconnect con1; +connection default; +SELECT * FROM t1; +id +1 +3 +5 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 +DROP TABLE t1; +SET DEBUG_SYNC='RESET'; diff --git a/mysql-test/suite/innodb/t/autoinc_debug.test b/mysql-test/suite/innodb/t/autoinc_debug.test new file mode 100644 index 00000000000..2e662565490 --- /dev/null +++ b/mysql-test/suite/innodb/t/autoinc_debug.test @@ -0,0 +1,85 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/not_embedded.inc + +# Two parallel connection with autoinc column after restart. + +CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB; + +--echo # SETTING auto_increment_increment IN CONNECTION DEFAULT +SET AUTO_INCREMENT_INCREMENT = 1; +INSERT INTO t1 VALUES(NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; + +--source include/restart_mysqld.inc + +--echo # SETTING auto_increment_increment IN CONNECTION1 +SET AUTO_INCREMENT_INCREMENT = 2; + +SET DEBUG_SYNC= 'ib_after_row_insert SIGNAL opened WAIT_FOR flushed1'; + +SEND INSERT INTO t1 VALUES(NULL); + +connect(con1, localhost, root,,); +SET AUTO_INCREMENT_INCREMENT = 2; +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'ib_after_row_insert_step SIGNAL flushed1 WAIT_FOR opened1'; +send insert into t1 values(NULL); + +connection default; +reap; +SELECT * FROM t1; +SHOW CREATE TABLE t1; +SET DEBUG_SYNC= 'now SIGNAL opened1'; + +connection con1; +reap; +SELECT * FROM t1; +SHOW CREATE TABLE t1; +connection default; +disconnect con1; + +DROP TABLE t1; + +# Two parallel connection with autoinc column without restart. + +CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB; + +--echo # SETTING auto_increment_increment IN CONNECTION DEFAULT +SET AUTO_INCREMENT_INCREMENT = 1; +INSERT INTO t1 VALUES(NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +SET DEBUG_SYNC = 'now SIGNAL flushed'; + +connect(con1, localhost, root,,); + +--echo # SETTING auto_increment_increment in connection1 +SET AUTO_INCREMENT_INCREMENT = 2; + +SET DEBUG_SYNC= 'now WAIT_FOR flushed'; +SET DEBUG_SYNC= 'ib_after_row_insert SIGNAL opened WAIT_FOR flushed1'; + +send INSERT INTO t1 values(NULL); + +connection default; + +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'ib_after_row_insert_step SIGNAL flushed1 WAIT_FOR opened1'; + +send INSERT INTO t1 VALUES(NULL); + +connection con1; +reap; +SELECT * FROM t1; +SHOW CREATE TABLE t1; +SET DEBUG_SYNC= 'now SIGNAL opened1'; +disconnect con1; + +connection default; +reap; +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +SET DEBUG_SYNC='RESET'; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 5d8ff4ff493..6dc625a30d7 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -17667,6 +17667,37 @@ ha_innobase::get_auto_increment( whether we update the table autoinc counter or not. */ ulonglong col_max_value = innobase_get_int_col_max_value(table->next_number_field); + /** The following logic is needed to avoid duplicate key error + for autoincrement column. + + (1) InnoDB gives the current autoincrement value with respect + to increment and offset value. + + (2) Basically it does compute_next_insert_id() logic inside InnoDB + to avoid the current auto increment value changed by handler layer. + + (3) It is restricted only for insert operations. */ + + if (increment > 1 && thd_sql_command(m_user_thd) != SQLCOM_ALTER_TABLE + && autoinc < col_max_value) { + + ulonglong prev_auto_inc = autoinc; + + autoinc = ((autoinc - 1) + increment - offset)/ increment; + + autoinc = autoinc * increment + offset; + + /* If autoinc exceeds the col_max_value then reset + to old autoinc value. Because in case of non-strict + sql mode, boundary value is not considered as error. */ + + if (autoinc >= col_max_value) { + autoinc = prev_auto_inc; + } + + ut_ad(autoinc > 0); + } + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index b92794138cc..d34b42e50ba 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1505,6 +1505,8 @@ run_again: row_ins_step(thr); + DEBUG_SYNC_C("ib_after_row_insert_step"); + err = trx->error_state; if (err != DB_SUCCESS) {