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