Bug #93838 | Not able to ALTER column with foreign key without some SQL_MODES | ||
---|---|---|---|
Submitted: | 7 Jan 2019 15:07 | Modified: | 19 May 2019 18:09 |
Reporter: | Przemyslaw Malkowski | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: DDL | Severity: | S3 (Non-critical) |
Version: | 5.7.23, 8.0.13 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[7 Jan 2019 15:07]
Przemyslaw Malkowski
[7 Jan 2019 15:42]
MySQL Verification Team
Thank you for the bug report. Please check the below note from the Manual: C:\dbs>c:\dbs\5.7\bin\mysql -uroot --port=3570 -p --prompt="mysql 5.7 > " Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3 Server version: 5.7.26-log Source distribution BUILD: 2018-DEC-12 Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql 5.7 > use test Database changed mysql 5.7 > create table a (id int primary key, name text ) ; create table b (id int primary key, fid int default null, foreign key (fid) references a(id)); Query OK, 0 rows affected (0.04 sec) Query OK, 0 rows affected (0.04 sec) mysql 5.7 > show create table b\G *************************** 1. row *************************** Table: b Create Table: CREATE TABLE `b` ( `id` int(11) NOT NULL, `fid` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fid` (`fid`), CONSTRAINT `b_ibfk_1` FOREIGN KEY (`fid`) REFERENCES `a` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html foreign_key_checks Note ...... Dropping an index required by a foreign key constraint is not permitted, even with foreign_key_checks=0. The foreign key constraint must be removed before dropping the index.
[7 Jan 2019 15:44]
MySQL Verification Team
C:\dbs>c:\dbs\5.7\bin\mysql -uroot --port=3570 -p --prompt="mysql 5.7 > " Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3 Server version: 5.7.26-log Source distribution BUILD: 2018-DEC-12 Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql 5.7 > use test Database changed mysql 5.7 > create table a (id int primary key, name text ) ; create table b (id int primary key, fid int default null, foreign key (fid) references a(id)); Query OK, 0 rows affected (0.04 sec) Query OK, 0 rows affected (0.04 sec) mysql 5.7 > show create table b; +-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | b | CREATE TABLE `b` ( `id` int(11) NOT NULL, `fid` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fid` (`fid`), CONSTRAINT `b_ibfk_1` FOREIGN KEY (`fid`) REFERENCES `a` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | +-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.01 sec) mysql 5.7 > show create table b\G *************************** 1. row *************************** Table: b Create Table: CREATE TABLE `b` ( `id` int(11) NOT NULL, `fid` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fid` (`fid`), CONSTRAINT `b_ibfk_1` FOREIGN KEY (`fid`) REFERENCES `a` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) mysql 5.7 > alter table b modify column fid int not null ; Query OK, 0 rows affected (0.08 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql 5.7 >
[7 Jan 2019 15:47]
MySQL Verification Team
C:\dbs>c:\dbs\8.0\bin\mysql -uroot --port=3580 -p --prompt="mysql 8.0 > " --default-character-set=utf8mb4 Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.15 Source distribution BUILD: 2018-DEC-11 Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql 8.0 > use test Database changed mysql 8.0 > create table a (id int primary key, name text ) ; create table b (id int primary key, fid int default null, foreign key (fid) references a(id)); Query OK, 0 rows affected (0.04 sec) Query OK, 0 rows affected (0.04 sec) mysql 8.0 > show create table b; +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | b | CREATE TABLE `b` ( `id` int(11) NOT NULL, `fid` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fid` (`fid`), CONSTRAINT `b_ibfk_1` FOREIGN KEY (`fid`) REFERENCES `a` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.01 sec) mysql 8.0 > alter table b modify column fid int not null ; Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql 8.0 >
[7 Jan 2019 15:51]
MySQL Verification Team
Could you please try version 8.0.13: C:\dbs>8.0\bin\mysql -uroot -p Enter password: ********** Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.13 MySQL Community Server - GPL Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use test Database changed mysql> create table a (id int primary key, name text ) ; create table b (id int primary key, fid int default null, foreign key (fid) references a(id)); Query OK, 0 rows affected (0.10 sec) Query OK, 0 rows affected (0.07 sec) mysql> Query OK, 0 rows affected (0.10 sec) mysql> alter table b modify column fid int not null ; Query OK, 0 rows affected (0.20 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql>
[7 Jan 2019 17:10]
MySQL Verification Team
Thank you for the bug report. C:\tmp\mysql-5.7.24>bin\mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.7.24 MySQL Community Server (GPL) Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> create database test; Query OK, 1 row affected (0.00 sec) mysql> use test Database changed mysql> create table a (id int primary key, name text ) ; create table b (id int primary key, fid int default null, foreign key (fid) references a(id)); Query OK, 0 rows affected (0.04 sec) Query OK, 0 rows affected (0.03 sec) mysql> set sql_mode=NO_ENGINE_SUBSTITUTION; Query OK, 0 rows affected, 1 warning (0.07 sec) mysql> alter table b modify column fid int not null ; ERROR 1832 (HY000): Cannot change column 'fid': used in a foreign key constraint 'b_ibfk_1' mysql> exit Bye C:\tmp\mysql-5.7.24>cd\ C:\>cd dbs C:\dbs>80c C:\dbs>c:\dbs\8.0\bin\mysql -uroot --port=3580 -p --prompt="mysql 8.0 > " --default-character-set=utf8mb4 Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.15 Source distribution BUILD: 2018-DEC-11 Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql 8.0 > create database t; Query OK, 1 row affected (0.02 sec) mysql 8.0 > use t Database changed mysql 8.0 > create table a (id int primary key, name text ) ; create table b (id int primary key, fid int default null, foreign key (fid) references a(id)); Query OK, 0 rows affected (0.05 sec) Query OK, 0 rows affected (0.04 sec) mysql 8.0 > set sql_mode=NO_ENGINE_SUBSTITUTION; Query OK, 0 rows affected (0.00 sec) mysql 8.0 > alter table b modify column fid int not null ; ERROR 1832 (HY000): Cannot change column 'fid': used in a foreign key constraint 'b_ibfk_1' mysql 8.0 >
[7 Jan 2019 17:19]
Przemyslaw Malkowski
Miguel, Regarding doc note: "Dropping an index required by a foreign key constraint is not permitted, even with foreign_key_checks=0. The foreign key constraint must be removed before dropping the index." I am not dropping any index. I am simply changing a minor column metadata property. The question is why it works in some SQL_MODE while it does not in other. Btw, same issue in 8.0.13: master [localhost:20314] {msandbox} (test) > select @@version,@@version_comment,@@sql_mode; +-----------+------------------------------+------------+ | @@version | @@version_comment | @@sql_mode | +-----------+------------------------------+------------+ | 8.0.13 | MySQL Community Server - GPL | | +-----------+------------------------------+------------+ 1 row in set (0.00 sec) master [localhost:20314] {msandbox} (test) > show create table a\G *************************** 1. row *************************** Table: a Create Table: CREATE TABLE `a` ( `id` int(11) NOT NULL, `name` text, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.01 sec) master [localhost:20314] {msandbox} (test) > show create table b\G *************************** 1. row *************************** Table: b Create Table: CREATE TABLE `b` ( `id` int(11) NOT NULL, `fid` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fid` (`fid`), CONSTRAINT `b_ibfk_1` FOREIGN KEY (`fid`) REFERENCES `a` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) master [localhost:20314] {msandbox} (test) > ALTER TABLE b MODIFY COLUMN fid INT NOT NULL; ERROR 1832 (HY000): Cannot change column 'fid': used in a foreign key constraint 'b_ibfk_1' --------------------------- master [localhost:20314] {msandbox} (test) > SET SQL_MODE=STRICT_TRANS_TABLES; Query OK, 0 rows affected, 1 warning (0.01 sec) master [localhost:20314] {msandbox} (test) > ALTER TABLE b MODIFY COLUMN fid INT NOT NULL; Query OK, 0 rows affected (0.12 sec) Records: 0 Duplicates: 0 Warnings: 0
[7 Jan 2019 18:39]
MySQL Verification Team
Indeed sorry I was confused and when re-read your instructions I got it, so now I verified it. Thanks.
[17 Apr 2019 19:09]
Dmitry Lenev
Posted by developer: Hello! The code works as designed in this case so this is not a code bug. Or documentation says that "13.1.9 ALTER TABLE Syntax" page of our documentation says (see https://dev.mysql.com/doc/refman/8.0/en/alter-table.html): "The server prohibits changes to foreign key columns that have the potential to cause loss of referential integrity. It also prohibits changes to the data type of such columns that may be unsafe. For example, changing VARCHAR(20) to VARCHAR(30) is permitted, but changing it to VARCHAR(1024) is not because that alters the number of length bytes required to store individual values. A workaround is to use ALTER TABLE ... DROP FOREIGN KEY before changing the column definition and ALTER TABLE ... ADD FOREIGN KEY afterward." The above applies to making nullable column non-nullable in non-strict mode because such operation will convert NULL values to some default non-null value, for which corresponding parent key value might be missing. At this point our code can't check this when such conversion occurs, so we have to prohibit such operations pessimistically. However, making nullable column non-nullable is OK in strict mode, since in such mode we don't convert NULLs to non-null values and return an error instead. So there is no chance that orphan child will be introduced by such ALTER TABLE. Let me demonstrate this with example (I have used 8.0 branch): CREATE TABLE parent (pk INT PRIMARY KEY); CREATE TABLE child (fk INT, FOREIGN KEY (fk) REFERENCES parent (pk)); INSERT INTO child VALUES (NULL); SET FOREIGN_KEY_CHECKS=1; SET SQL_MODE=''; # Pessimistically fails with ERROR HY000: Cannot change column 'fk': used in a foreign key constraint 'child_ibfk_1' ALTER TABLE child MODIFY fk INT NOT NULL; SET SQL_MODE='traditional'; # Starts changing table, detects NULL value and fails with "ERROR 22004: Invalid use of NULL value" ALTER TABLE child MODIFY fk INT NOT NULL; SET SQL_MODE=''; SET FOREIGN_KEY_CHECKS=0; # Will break referential integrity and create orphan as below SELECT confirms. ALTER TABLE child MODIFY fk INT NOT NULL; # Warnings: # Warning 1265 Data truncated for column 'fk' at row 1 SELECT * FROM child; # fk # 0 Having said above, I agree that this behavior is non-intuitive and our documentation could describe it more clearly/mention it explicitly. So I am changing category of this report to Documentation bug.
[19 May 2019 18:09]
Daniel Price
Posted by developer: The following information was added regarding changes to foreign key columns: "Changing a NULL column to NOT NULL in non-strict mode is prohibited to prevent converting NULL values to default non-NULL values, for which there are no corresponding values in the referenced table. The operation is permitted in strict mode, but an error is returned if any such conversion is required." Changes should appear online soon. https://dev.mysql.com/doc/refman/8.0/en/alter-table.html#alter-table-foreign-key Thank you for the bug report.