#At file:///home/thek/Development/cpp/mysqlbzr/mysql-5.1-bug37016/
2704 Kristofer Pettersson 2008-11-17
Bug#37016 TRUNCATE TABLE removes some rows but not all
TRUNCATE TABLE caused some rows to be deleted but not all if an error
occurred during row-by-row deletion.
The error was caused by a foreign key restriction imposed by InnoDB SE
but handled incorrectly by the server code. In stead of doing a rollback
in case of an error, an implicit commit was issued which caused the list
of on-going transactions to be cleared.
This patch fixes the problem by avoiding the implicit commit so that a
rollback can be performed instead.
modified:
mysql-test/r/innodb_mysql.result
mysql-test/t/innodb_mysql.test
sql/sql_delete.cc
per-file messages:
mysql-test/r/innodb_mysql.result
Added test case
mysql-test/t/innodb_mysql.test
Added test case
sql/sql_delete.cc
* Don't re-enable transactions if mysql_delete raised an error. If we do
we will clear the transaction list and won't be able to perform a rollback.
=== modified file 'mysql-test/r/innodb_mysql.result'
--- a/mysql-test/r/innodb_mysql.result 2008-11-03 17:46:47 +0000
+++ b/mysql-test/r/innodb_mysql.result 2008-11-17 11:33:48 +0000
@@ -1677,3 +1677,24 @@ select @@session.sql_log_bin, @@session.
CREATE TABLE t1 ( a INT ) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
DROP TABLE t1;
+#
+# Bug#37016 TRUNCATE TABLE removes some rows but not all
+#
+DROP TABLE IF EXISTS t1,t2;
+CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
+CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY
(t1_id) REFERENCES t1(id)) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+SELECT * FROM t1;
+id
+1
+2
+INSERT INTO t2 VALUES (10, 2);
+TRUNCATE TABLE t1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
(`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`t1_id`) REFERENCES `t1` (`id`))
+SELECT * FROM t1;
+id
+1
+2
+DROP TABLE t2;
+DROP TABLE t1;
=== modified file 'mysql-test/t/innodb_mysql.test'
--- a/mysql-test/t/innodb_mysql.test 2008-11-03 17:46:47 +0000
+++ b/mysql-test/t/innodb_mysql.test 2008-11-17 11:33:48 +0000
@@ -6,6 +6,7 @@
#
-- source include/have_innodb.inc
+
let $engine_type= InnoDB;
let $other_engine_type= MEMORY;
# InnoDB does support FOREIGN KEYFOREIGN KEYs
@@ -43,3 +44,21 @@ CREATE TABLE t1 ( a INT ) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
DROP TABLE t1;
+--echo #
+--echo # Bug#37016 TRUNCATE TABLE removes some rows but not all
+--echo #
+--disable_warnings
+DROP TABLE IF EXISTS t1,t2;
+--enable_warnings
+CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
+CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY
(t1_id) REFERENCES t1(id)) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+SELECT * FROM t1;
+INSERT INTO t2 VALUES (10, 2);
+--error ER_ROW_IS_REFERENCED_2
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t2;
+DROP TABLE t1;
+
=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc 2008-11-03 13:08:42 +0000
+++ b/sql/sql_delete.cc 2008-11-17 11:33:48 +0000
@@ -1065,7 +1065,10 @@ trunc_by_del:
thd->clear_current_stmt_binlog_row_based();
error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
HA_POS_ERROR, LL(0), TRUE);
- ha_enable_transaction(thd, TRUE);
+
+ if (!error)
+ ha_enable_transaction(thd, TRUE);
+
/*
Safety, in case the engine ignored ha_enable_transaction(FALSE)
above. Also clears thd->transaction.*.