Skip to content

Commit eb1f21f

Browse files
author
gshchepa/uchum@gleb.loc
committed
Fixed bug #27954.
This bug affects multi-row INSERT ... ON DUPLICATE into table with PRIMARY KEY of AUTO_INCREMENT field and some additional UNIQUE indices. If the first row in multi-row INSERT contains duplicated values of UNIQUE indices, then following rows of multi-row INSERT (with either duplicated or unique key field values) may me applied to _arbitrary_ records of table as updates. This bug was introduced in 5.0. Related code was widely rewritten in 5.1, and 5.1 is already free of this problem. 4.1 was not affected too. When updating the row during INSERT ON DUPLICATE KEY UPDATE, we called restore_auto_increment(), which set next_insert_id back to 0, but we forgot to set clear_next_insert_id back to 0. restore_auto_increment() function has been fixed.
1 parent 2cf753a commit eb1f21f

File tree

4 files changed

+50
-0
lines changed

4 files changed

+50
-0
lines changed

mysql-test/r/insert_update.result

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,25 @@ id f1
336336
0 test1
337337
DROP TABLE t1;
338338
SET SQL_MODE='';
339+
CREATE TABLE t1 (
340+
id INT AUTO_INCREMENT PRIMARY KEY,
341+
c1 CHAR(1) UNIQUE KEY,
342+
cnt INT DEFAULT 1
343+
);
344+
INSERT INTO t1 (c1) VALUES ('A'), ('B'), ('C');
345+
SELECT * FROM t1;
346+
id c1 cnt
347+
1 A 1
348+
2 B 1
349+
3 C 1
350+
INSERT INTO t1 (c1) VALUES ('A'), ('X'), ('Y'), ('Z')
351+
ON DUPLICATE KEY UPDATE cnt=cnt+1;
352+
SELECT * FROM t1;
353+
id c1 cnt
354+
1 A 2
355+
2 B 1
356+
3 C 1
357+
4 X 1
358+
5 Y 1
359+
6 Z 1
360+
DROP TABLE t1;

mysql-test/t/insert_update.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,20 @@ REPLACE INTO t1 VALUES (0,"test1",null);
247247
SELECT id, f1 FROM t1;
248248
DROP TABLE t1;
249249
SET SQL_MODE='';
250+
251+
#
252+
# Bug#27954: multi-row INSERT ... ON DUPLICATE with duplicated
253+
# row at the first place into table with AUTO_INCREMENT and
254+
# additional UNIQUE key.
255+
#
256+
CREATE TABLE t1 (
257+
id INT AUTO_INCREMENT PRIMARY KEY,
258+
c1 CHAR(1) UNIQUE KEY,
259+
cnt INT DEFAULT 1
260+
);
261+
INSERT INTO t1 (c1) VALUES ('A'), ('B'), ('C');
262+
SELECT * FROM t1;
263+
INSERT INTO t1 (c1) VALUES ('A'), ('X'), ('Y'), ('Z')
264+
ON DUPLICATE KEY UPDATE cnt=cnt+1;
265+
SELECT * FROM t1;
266+
DROP TABLE t1;

sql/handler.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,7 +1685,14 @@ void handler::restore_auto_increment()
16851685
{
16861686
THD *thd= table->in_use;
16871687
if (thd->next_insert_id)
1688+
{
16881689
thd->next_insert_id= thd->prev_insert_id;
1690+
if (thd->next_insert_id == 0)
1691+
{
1692+
/* we didn't generate a value, engine will be called again */
1693+
thd->clear_next_insert_id= 0;
1694+
}
1695+
}
16891696
}
16901697

16911698

sql/sql_class.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,10 @@ class THD :public Statement,
14311431
*/
14321432
bool insert_id_used;
14331433

1434+
/*
1435+
clear_next_insert_id is set if engine was called at least once
1436+
for this statement to generate auto_increment value.
1437+
*/
14341438
bool clear_next_insert_id;
14351439
/* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
14361440
bool substitute_null_with_insert_id;

0 commit comments

Comments
 (0)