Commit fa31a995 authored by unknown's avatar unknown

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.
parent c78623fa
...@@ -2483,3 +2483,26 @@ delete t1 from t1,t2 where f1=f3 and f4='cc'; ...@@ -2483,3 +2483,26 @@ delete t1 from t1,t2 where f1=f3 and f4='cc';
select * from t1; select * from t1;
f1 f2 f1 f2
drop table t1,t2; 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;
...@@ -1404,3 +1404,31 @@ insert into t1 values ('aa','bb'),('aa','cc'); ...@@ -1404,3 +1404,31 @@ insert into t1 values ('aa','bb'),('aa','cc');
delete t1 from t1,t2 where f1=f3 and f4='cc'; delete t1 from t1,t2 where f1=f3 and f4='cc';
select * from t1; select * from t1;
drop table t1,t2; 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;
...@@ -6782,6 +6782,28 @@ ha_innobase::get_auto_increment() ...@@ -6782,6 +6782,28 @@ ha_innobase::get_auto_increment()
return((ulonglong) nr); 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. 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 If there is no explicitly declared non-null unique key or a primary key, then
......
...@@ -173,6 +173,8 @@ class ha_innobase: public handler ...@@ -173,6 +173,8 @@ class ha_innobase: public handler
enum thr_lock_type lock_type); enum thr_lock_type lock_type);
void init_table_handle_for_HANDLER(); void init_table_handle_for_HANDLER();
ulonglong get_auto_increment(); ulonglong get_auto_increment();
int reset_auto_increment();
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; } uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
/* /*
ask handler about permission to cache table during query registration ask handler about permission to cache table during query registration
......
...@@ -650,6 +650,15 @@ public: ...@@ -650,6 +650,15 @@ public:
{ return (my_errno=HA_ERR_WRONG_COMMAND); } { return (my_errno=HA_ERR_WRONG_COMMAND); }
virtual ulonglong get_auto_increment(); virtual ulonglong get_auto_increment();
virtual void restore_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) {} virtual void update_create_info(HA_CREATE_INFO *create_info) {}
/* admin commands - called from mysql_admin_table */ /* admin commands - called from mysql_admin_table */
......
...@@ -103,6 +103,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -103,6 +103,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
thd->row_count_func= 0; thd->row_count_func= 0;
send_ok(thd,0L); 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 DBUG_RETURN(0); // Nothing to delete
} }
...@@ -226,6 +233,21 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -226,6 +233,21 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (options & OPTION_QUICK) if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL); (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: cleanup:
/* /*
Invalidate the table in the query cache if something changed. This must Invalidate the table in the query cache if something changed. This must
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment