Bug #37538 | how to orphan a foreign key in InnoDB by using a compound statement | ||
---|---|---|---|
Submitted: | 20 Jun 2008 3:22 | Modified: | 15 Jul 2008 14:29 |
Reporter: | Ben Krug | Email Updates: | |
Status: | Won't fix | Impact on me: | |
Category: | MySQL Server: InnoDB storage engine | Severity: | S3 (Non-critical) |
Version: | 5.0.50, 5.0.60 | OS: | Any |
Assigned to: | Vasil Dimov | CPU Architecture: | Any |
Tags: | foreign key, innodb, workbench |
[20 Jun 2008 3:22]
Ben Krug
[20 Jun 2008 4:09]
Valeriy Kravchuk
Verified just as described with 5.0.60.
[20 Jun 2008 4:17]
Valeriy Kravchuk
5.1 is also affected, but in a different way: C:\Program Files\MySQL\MySQL Server 5.0\bin>mysql -uroot -proot -P3310 test Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 7 Server version: 5.1.25-rc-community MySQL Community Server (GPL) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> DROP DATABASE if exists `aac_test`; Query OK, 0 rows affected, 1 warning (0.05 sec) mysql> mysql> CREATE DATABASE IF NOT EXISTS `aac_test` -> CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 1 row affected (0.00 sec) mysql> USE `aac_test`; Database changed mysql> mysql> DROP TABLE IF EXISTS `aac_test`.`exam`; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> CREATE TABLE `aac_test`.`exam` ( -> `id` BIGINT(19) NOT NULL AUTO_INCREMENT, -> PRIMARY KEY (`id`) -> ) -> ENGINE = INNODB -> CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.08 sec) mysql> mysql> DROP TABLE IF EXISTS `aac_test`.`exam_time`; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> CREATE TABLE `aac_test`.`exam_time` ( -> `id` BIGINT(19) NOT NULL AUTO_INCREMENT, -> `exam_id` BIGINT(19) NULL, -> PRIMARY KEY (`id`), -> CONSTRAINT FOREIGN KEY `FK_exam_time_exam` (`exam_id`) -> REFERENCES `aac_test`.`exam` (`id`) -> ON DELETE CASCADE -> ON UPDATE NO ACTION -> ) -> ENGINE = INNODB -> CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.08 sec) mysql> ALTER TABLE `exam_time` CHANGE COLUMN `exam_id` `examId` BIGINT(19) NULL DEFAULT NULL; Query OK, 0 rows affected (0.09 sec) Records: 0 Duplicates: 0 Warnings: 0 So, ALTER TABLE works. But look at the result: mysql> show create table exam_time\G *************************** 1. row *************************** Table: exam_time Create Table: CREATE TABLE `exam_time` ( `id` bigint(19) NOT NULL AUTO_INCREMENT, `examId` bigint(19) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_exam_time_exam` (`examId`), CONSTRAINT `exam_time_ibfk_1` FOREIGN KEY (`exam_id`) REFERENCES `exam` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.03 sec) Column name is FOREIGN KEY definition is NOT changed...
[20 Jun 2008 17:01]
Ken Jacobs
This is related to bug http://bugs.mysql.com/bug.php?id=21704.
[23 Jun 2008 13:37]
Heikki Tuuri
Hi! Dropping a foreign key should succeed in 5.1.xx and 6.0.x with Vasil's patch to: Bug "#18942 DROP DATABASE does not drop an orphan FOREIGN KEY constraint" http://bugs.mysql.com/bug.php?id=18942. Assigning this bug to Vasil. Vasil, please check if DROP DATABASE drops the constraint in 5.1.2x. The fact that RENAME COLUMN causes problems to InnoDB's foreign keys is known from the bug report Ken mentioned. But I do not understand why the behavior in this bug report is as reported. Vasil, please investigate. Regards, Heikki
[24 Jun 2008 9:27]
Vasil Dimov
Ben, what version of MySQL did you use to get the "DROP DATABASE does not wipe orphan FKs"? The fix for Bug#18942 has not been committed into 5.0. I confirm that DROP DATABASE wipes the orphan FKs in 5.1.27-r2662. Otherwise this seems to be the same as Bug#21704.
[24 Jun 2008 16:17]
Heikki Tuuri
Marked as duplicate of http://bugs.mysql.com/bug.php?id=21704
[24 Jun 2008 17:17]
Ben Krug
This is not a duplicate of 21704, although it's related to it. The new aspect here is that this is a new way to rename the affected column without error, which then leads to 21704. Simply trying to rename the field will return an error. But an additional change clause to the ALTER TABLE statement allows it to be processed without error, thus leading to 21704. The bug is that the compound statement is allowed to execute without error. However, that said, fixing 21704 means that this bug is no longer a bug, as then it will be OK for the field to be renamed. BTW to answer Vasil, yes, I used 5.0 when I first tested this bug.
[25 Jun 2008 8:32]
Vasil Dimov
Ok, this is not a duplicate. The bug is that ALTER TABLE `exam_time` CHANGE COLUMN `exam_id` `examId` BIGINT(19) NULL DEFAULT NULL ,RENAME TO `examTime` ; does not return an error, just like ALTER TABLE `exam_time` CHANGE COLUMN `exam_id` `examId` BIGINT(19) NULL DEFAULT NULL; does. The first statement should also return an error.
[7 Jul 2008 12:01]
Vasil Dimov
Here is some analysis why one of the statements fails and the other one succeeds. On a fresh database execute these: CREATE DATABASE `aac_test` CHARACTER SET utf8 COLLATE utf8_general_ci; USE `aac_test`; CREATE TABLE `exam` ( `id` BIGINT(19) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE TABLE `exam_time` ( `id` BIGINT(19) NOT NULL AUTO_INCREMENT, `exam_id` BIGINT(19) NULL, PRIMARY KEY (`id`), CONSTRAINT FOREIGN KEY `FK_exam_time_exam` (`exam_id`) REFERENCES `aac_test`.`exam` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION ) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci; After this: 1. ALTER TABLE exam_time CHANGE COLUMN exam_id examId BIGINT(19) NULL DEFAULT NULL; fails because the following code path is executed: in mysql_alter_table(): rename exam_time -> #sql2-543d-2 (ok) rename #sql-543d_2 -> exam_time (error) sql_table.cc:3935 row_rename_table_for_mysql(#sql-543d_2 -> exam_time) dict_load_foreigns(exam_time) (error) dict_load_foreign(exam_time_ibfk_1) (error) dict_foreign_add_to_cache(exam_time_ibfk_1) (error) dict0dict.c:2329 dict_foreign_find_index(table=exam_time, column=exam_id) (NULL) // cannot find a matching index, the index is on column // examId, FK on column exam_id 2. ALTER TABLE exam_time CHANGE COLUMN exam_id examId BIGINT(19) NULL DEFAULT NULL, RENAME TO examTime; succeeds because: rename exam_time -> #sql2-9baf-2 (ok) rename #sql-9baf_2 -> examTime (ok) sql_table.cc:3935 row_rename_table_for_mysql(#sql-9baf_2 -> examTime) row0mysql.c:3880 dict_load_foreigns(examTime) (success) // The system table SYS_FOREIGN does not contan any // rows for the table examTime, i.e. no FK associated with // the table examTime So dict_load_foreigns() returns success if there are no FKs associated with the given table, but returns an error if there is a FK but it cannot be loaded.
[7 Jul 2008 12:54]
Heikki Tuuri
Vasil, thank you for an intelligent analysis. Can you write a function that checks if the RENAME has renamed also a column, and make InnoDB RENAME it in SYS_FOREIGN and associated memory structures like dict_col_t? Or maybe easier to block the RENAME? I understand the bug is only in 5.0? We cannot endanger the stability of 5.0 with a complex patch like this. --Heikki
[8 Jul 2008 13:02]
Vasil Dimov
Looks like any fix for this is too risky for 5.0. In 5.1 both ALTER statements succeed leaving inconsistent results like: CREATE TABLE `examTime` ( `id` bigint(19) NOT NULL AUTO_INCREMENT, `examId` bigint(19) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_exam_time_exam` (`examId`), CONSTRAINT `examTime_ibfk_1` FOREIGN KEY (`exam_id`) REFERENCES `exam` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8; which would cause problems with mysqldump & restore
[15 Jul 2008 14:29]
Vasil Dimov
Setting to "Won't fix" as the fix is too risky for 5.0. I have opened Bug#38139 to handle this in 5.1.