summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/innodb.result23
-rw-r--r--mysql-test/t/innodb.test28
-rw-r--r--sql/ha_innodb.cc22
-rw-r--r--sql/ha_innodb.h2
-rw-r--r--sql/handler.h9
-rw-r--r--sql/sql_delete.cc22
6 files changed, 106 insertions, 0 deletions
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 69620d5d527..b2c78560562 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -2483,3 +2483,26 @@ delete t1 from t1,t2 where f1=f3 and f4='cc';
select * from t1;
f1 f2
drop table t1,t2;
+CREATE TABLE t1 (
+id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)
+) ENGINE=InnoDB;
+CREATE TABLE t2 (
+id INTEGER NOT NULL,
+FOREIGN KEY (id) REFERENCES t1 (id)
+) ENGINE=InnoDB;
+INSERT INTO t1 (id) VALUES (NULL);
+SELECT * FROM t1;
+id
+1
+TRUNCATE t1;
+INSERT INTO t1 (id) VALUES (NULL);
+SELECT * FROM t1;
+id
+1
+DELETE FROM t1;
+TRUNCATE t1;
+INSERT INTO t1 (id) VALUES (NULL);
+SELECT * FROM t1;
+id
+1
+DROP TABLE t2, t1;
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 8d51af4f22f..473a21c8242 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -1404,3 +1404,31 @@ insert into t1 values ('aa','bb'),('aa','cc');
delete t1 from t1,t2 where f1=f3 and f4='cc';
select * from t1;
drop table t1,t2;
+
+#
+# Test that the slow TRUNCATE implementation resets autoincrement columns
+# (bug #11946)
+#
+
+CREATE TABLE t1 (
+id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)
+) ENGINE=InnoDB;
+
+CREATE TABLE t2 (
+id INTEGER NOT NULL,
+FOREIGN KEY (id) REFERENCES t1 (id)
+) ENGINE=InnoDB;
+
+INSERT INTO t1 (id) VALUES (NULL);
+SELECT * FROM t1;
+TRUNCATE t1;
+INSERT INTO t1 (id) VALUES (NULL);
+SELECT * FROM t1;
+
+# continued from above; test that doing a slow TRUNCATE on a table with 0
+# rows resets autoincrement columns
+DELETE FROM t1;
+TRUNCATE t1;
+INSERT INTO t1 (id) VALUES (NULL);
+SELECT * FROM t1;
+DROP TABLE t2, t1;
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index bf781e9a5c2..cf91254fd12 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -6782,6 +6782,28 @@ ha_innobase::get_auto_increment()
return((ulonglong) nr);
}
+/* See comment in handler.h */
+int
+ha_innobase::reset_auto_increment()
+{
+ DBUG_ENTER("ha_innobase::reset_auto_increment");
+
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+ int error;
+
+ error = row_lock_table_autoinc_for_mysql(prebuilt);
+
+ if (error != DB_SUCCESS) {
+ error = convert_error_code_to_mysql(error, user_thd);
+
+ DBUG_RETURN(error);
+ }
+
+ dict_table_autoinc_initialize(prebuilt->table, 0);
+
+ DBUG_RETURN(0);
+}
+
/***********************************************************************
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
If there is no explicitly declared non-null unique key or a primary key, then
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 4817ab9b682..ec823487b30 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -173,6 +173,8 @@ class ha_innobase: public handler
enum thr_lock_type lock_type);
void init_table_handle_for_HANDLER();
ulonglong get_auto_increment();
+ int reset_auto_increment();
+
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
/*
ask handler about permission to cache table during query registration
diff --git a/sql/handler.h b/sql/handler.h
index ef45676207b..c28554618a6 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -650,6 +650,15 @@ public:
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
virtual ulonglong get_auto_increment();
virtual void restore_auto_increment();
+
+ /* This is called after TRUNCATE is emulated by doing a 'DELETE FROM t',
+ in which case we need a separate operation for resetting the table's
+ auto-increment counter. HA_ERR_WRONG_COMMAND is returned by storage
+ engines that have no need for this, i.e. those that can always do a
+ fast TRUNCATE. */
+ virtual int reset_auto_increment()
+ { return HA_ERR_WRONG_COMMAND; }
+
virtual void update_create_info(HA_CREATE_INFO *create_info) {}
/* admin commands - called from mysql_admin_table */
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 35183fc959b..f6fb5f2cf53 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -103,6 +103,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
free_underlaid_joins(thd, select_lex);
thd->row_count_func= 0;
send_ok(thd,0L);
+
+ /*
+ We don't need to call reset_auto_increment in this case, because
+ mysql_truncate always gives a NULL conds argument, hence we never
+ get here.
+ */
+
DBUG_RETURN(0); // Nothing to delete
}
@@ -226,6 +233,21 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
+ if ((error < 0) && (thd->lex->sql_command == SQLCOM_TRUNCATE))
+ {
+ /*
+ We're really doing a truncate and need to reset the table's
+ auto-increment counter.
+ */
+ int error2 = table->file->reset_auto_increment();
+
+ if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
+ {
+ table->file->print_error(error2, MYF(0));
+ error = 1;
+ }
+ }
+
cleanup:
/*
Invalidate the table in the query cache if something changed. This must