From fef8e27a79f7edbbfcfde2130fbe8fc290de6361 Mon Sep 17 00:00:00 2001 From: Timothy Smith <timothy.smith@sun.com> Date: Sun, 14 Dec 2008 12:29:59 -0700 Subject: [PATCH] Apply InnoDB snapshot innodb-5.1-ss2637, part 2. Fixes Bug #38839: auto increment does not work properly with InnoDB after update Detailed revision comments: r2609 | sunny | 2008-08-24 01:19:05 +0300 (Sun, 24 Aug 2008) | 12 lines branches/5.1: Fix for MySQL Bug#38839. Reset the statement level last value field in prebuilt. This field tracks the last value in an autoincrement interval. We use this value to check whether we need to update a table's AUTOINC counter, if the value written to a table is less than this value then we avoid updating the table's AUTOINC value in order to reduce mutex contention. If it's not reset (e.g., after a DELETE statement) then there is the possibility of missing updates to the table's AUTOINC counter resulting in a subsequent duplicate row error message under certain conditions (see the test case for details). Bug #38839 - auto increment does not work properly with InnoDB after update --- mysql-test/r/innodb-autoinc.result | 27 +++++++++++++++++++++++++++ mysql-test/t/innodb-autoinc.test | 21 +++++++++++++++++++++ storage/innobase/handler/ha_innodb.cc | 23 +++++++++++++++++------ 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index e000f910772..70cdc67f77e 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -169,3 +169,30 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`c1`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 DROP TABLE t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL, 1); +DELETE FROM t1 WHERE c1 = 1; +INSERT INTO t1 VALUES (2,1); +INSERT INTO t1 VALUES (NULL,8); +SELECT * FROM t1; +c1 c2 +2 1 +3 8 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL, 1); +DELETE FROM t1 WHERE c1 = 1; +INSERT INTO t1 VALUES (2,1), (NULL, 8); +INSERT INTO t1 VALUES (NULL,9); +SELECT * FROM t1; +c1 c2 +2 1 +3 8 +5 9 +DROP TABLE t1; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index aa464e42627..1c97364199b 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -139,3 +139,24 @@ SELECT c1 FROM t1; SHOW CREATE TABLE t1; DROP TABLE t1; +# +# Bug 38839 +# Reset the last value generated at end of statement +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL, 1); +DELETE FROM t1 WHERE c1 = 1; +INSERT INTO t1 VALUES (2,1); +INSERT INTO t1 VALUES (NULL,8); +SELECT * FROM t1; +DROP TABLE t1; +# Bug 38839 -- same as above but for multi value insert +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL, 1); +DELETE FROM t1 WHERE c1 = 1; +INSERT INTO t1 VALUES (2,1), (NULL, 8); +INSERT INTO t1 VALUES (NULL,9); +SELECT * FROM t1; +DROP TABLE t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8a8d9698ac1..682ba19aab9 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6429,15 +6429,26 @@ ha_innobase::extra( return(0); } +/********************************************************************** +Reset state of file to after 'open'. +This function is called after every statement for all tables used +by that statement. */ int ha_innobase::reset() { - if (prebuilt->blob_heap) { - row_mysql_prebuilt_free_blob_heap(prebuilt); - } - reset_template(prebuilt); - return 0; -} + if (prebuilt->blob_heap) { + row_mysql_prebuilt_free_blob_heap(prebuilt); + } + reset_template(prebuilt); + + /* TODO: This should really be reset in reset_template() but for now + it's safer to do it explicitly here. */ + + /* This is a statement level counter. */ + prebuilt->last_value = 0; + + return(0); +} /********************************************************************** MySQL calls this function at the start of each SQL statement inside LOCK -- 2.30.9