From 5983038a669f582ae256e774026e9a91dd0667d1 Mon Sep 17 00:00:00 2001 From: "gshchepa/uchum@gshchepa.loc" <> Date: Thu, 26 Apr 2007 02:01:23 +0500 Subject: [PATCH] Fixed bug #27650: INSERT into InnoDB table may cause "ERROR 1062 (23000): Duplicate entry..." errors or lost records after multi-row INSERT of the form: "INSERT INTO t (id...) VALUES (NULL...) ON DUPLICATE KEY UPDATE id=VALUES(id)", where "id" is an AUTO_INCREMENT column. It happens because InnoDB handler forgets to save next insert id after updating of auto_increment column with new values. As result of that last insert id stored inside InnoDB dictionary tables differs from it's cached thd->next_insert_id value. --- mysql-test/r/innodb_mysql.result | 39 ++++++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 47 ++++++++++++++++++++++++++++++++ sql/ha_innodb.cc | 2 ++ 3 files changed, 88 insertions(+) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 298fc58ffcb..88428840a82 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -446,4 +446,43 @@ a 2 5 drop table t1; +create table t1( +id int auto_increment, +c char(1) not null, +counter int not null default 1, +primary key (id), +unique key (c) +) engine=innodb; +insert into t1 (id, c) values +(NULL, 'a'), +(NULL, 'a') +on duplicate key update id = values(id), counter = counter + 1; +select * from t1; +id c counter +2 a 2 +insert into t1 (id, c) values +(NULL, 'b') +on duplicate key update id = values(id), counter = counter + 1; +select * from t1; +id c counter +2 a 2 +3 b 1 +truncate table t1; +insert into t1 (id, c) values (NULL, 'a'); +select * from t1; +id c counter +1 a 1 +insert into t1 (id, c) values (NULL, 'b'), (NULL, 'b') +on duplicate key update id = values(id), c = values(c), counter = counter + 1; +select * from t1; +id c counter +1 a 1 +3 b 2 +insert into t1 (id, c) values (NULL, 'a') +on duplicate key update id = values(id), c = values(c), counter = counter + 1; +select * from t1; +id c counter +3 b 2 +4 a 2 +drop table t1; End of 5.0 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index c351891d205..c2521656a9c 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -412,4 +412,51 @@ DROP TABLE t1; --source include/innodb_rollback_on_timeout.inc + +-- source include/have_innodb.inc + +# +# Bug #27650: INSERT fails after multi-row INSERT of the form: +# INSERT INTO t (id...) VALUES (NULL...) ON DUPLICATE KEY UPDATE id=VALUES(id) +# + +create table t1( +id int auto_increment, +c char(1) not null, +counter int not null default 1, +primary key (id), +unique key (c) +) engine=innodb; + +insert into t1 (id, c) values +(NULL, 'a'), +(NULL, 'a') +on duplicate key update id = values(id), counter = counter + 1; + +select * from t1; + +insert into t1 (id, c) values +(NULL, 'b') +on duplicate key update id = values(id), counter = counter + 1; + +select * from t1; + +truncate table t1; + +insert into t1 (id, c) values (NULL, 'a'); + +select * from t1; + +insert into t1 (id, c) values (NULL, 'b'), (NULL, 'b') +on duplicate key update id = values(id), c = values(c), counter = counter + 1; + +select * from t1; + +insert into t1 (id, c) values (NULL, 'a') +on duplicate key update id = values(id), c = values(c), counter = counter + 1; + +select * from t1; + +drop table t1; + --echo End of 5.0 tests diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 217f59d4b7e..808c3bcd41d 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3299,6 +3299,8 @@ no_commit: if (error == DB_DUPLICATE_KEY && auto_inc_used && (user_thd->lex->sql_command == SQLCOM_REPLACE || user_thd->lex->sql_command == SQLCOM_REPLACE_SELECT + || (user_thd->lex->sql_command == SQLCOM_INSERT + && user_thd->lex->duplicates == DUP_UPDATE) || (user_thd->lex->sql_command == SQLCOM_LOAD && user_thd->lex->duplicates == DUP_REPLACE))) {