From fa31a9950babd887086c20419669b484d813f501 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Aug 2005 11:00:20 +0300 Subject: [PATCH] Fix bug #11946, truncate not always resetting the auto-increment counter in InnoDB tables. mysql-test/r/innodb.result: New tests. mysql-test/t/innodb.test: New tests. sql/ha_innodb.cc: Add reset_auto_increment. sql/ha_innodb.h: Add reset_auto_increment. sql/handler.h: Add reset_auto_increment. sql/sql_delete.cc: Call handler->reset_auto_increment when needed. --- mysql-test/r/innodb.result | 23 +++++++++++++++++++++++ mysql-test/t/innodb.test | 28 ++++++++++++++++++++++++++++ sql/ha_innodb.cc | 22 ++++++++++++++++++++++ sql/ha_innodb.h | 2 ++ sql/handler.h | 9 +++++++++ sql/sql_delete.cc | 22 ++++++++++++++++++++++ 6 files changed, 106 insertions(+) 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