mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
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.
This commit is contained in:
parent
c78623fa10
commit
fa31a9950b
6 changed files with 106 additions and 0 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue