[MDEV-8697] Foreign key allowed between InnoDB and MyISAM if "set foreign_key_checks=0" Created: 2015-08-29  Updated: 2017-09-25  Resolved: 2017-09-25

Status: Closed
Project: MariaDB Server
Component/s: Data Definition - Alter Table
Affects Version/s: 10.0.20
Fix Version/s: N/A

Type: Bug Priority: Minor
Reporter: Nick Moore Assignee: Sergei Golubchik
Resolution: Not a Bug Votes: 0
Labels: upstream
Environment:

linux debian jessie



 Description   

Also reporting in MySQL: https://bugs.mysql.com/bug.php?id=78255

Putting foreign keys between InnoDB and MyISAM should be disallowed at schema-change time (the create table should fail) because MyISAM doesn't support foreign keys. But it is allowed if foreign keys checks are switched off.

Inserting rows then fails with "ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails" even if values are valid

This may seem like a perverse set of circumstances, but it happens quite easily when using Django South migrations.

See also: http://nick.zoic.org/sql/mysql-foreign-keys-between-innodb-and-myisam/

    MariaDB [test]> create table old_table ( id int(11) primary key ) engine=MyISAM;
 
    MariaDB [test]> create table new_table (
    ->     id int(11) primary key,
    ->     old_table_id int(11),
    ->     foreign key (old_table_id) references old_table (id)
    -> ) engine=InnoDB;
    ERROR 1005 (HY000): Can't create table `test`.`new_table` (errno: 150 "Foreign key constraint is incorrectly formed")
 
    MariaDB [test]> set foreign_key_checks=0;
    Query OK, 0 rows affected (0.00 sec)
 
    MariaDB [test]> create table new_table ( id int(11) primary key, old_table_id int(11), foreign key (old_table_id) references old_table (id) ) engine=InnoDB;
    Query OK, 0 rows affected (0.02 sec)
 
    MariaDB [test]> set foreign_key_checks=1;
    Query OK, 0 rows affected (0.00 sec)
 
    MariaDB [test]> insert into old_table values (1);
    Query OK, 1 row affected (0.00 sec)
 
    MariaDB [test]> insert into new_table values (1,1);
    ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`new_table`, CONSTRAINT `new_table_ibfk_1` FOREIGN KEY (`old_table_id`) REFERENCES `old_table` (`id`))



 Comments   
Comment by Elena Stepanova [ 2015-09-01 ]

I really don't see any problem at all here. Basically, what we have it:

  • one attempts to create the constraint;
  • server says that it's a bad idea;
  • one says "I know better, I want to do it anyway";
  • server does it upon the explicit request;
  • one attempts to insert the data – server says "I told you it was a bad idea".

So, if one insisted so much on creating the constraint upon table creation, why not to turn off foreign keys again upon inserting the data?

As a user, I would be rather unhappy if the server refused to create the table even after I specifically requested not to perform the foreign key check.

However, since upstream confirmed the bug report (for now), I will keep this one open as well, lets see what they come up with.

Comment by Nick Moore [ 2015-09-02 ]

G'day Elena,

I see what you're saying, but to my mind "set foreign_key_checks=0" is supposed to prevent the database from checking the data of the foreign keys, not the schema.

For example:

MariaDB [test]> set foreign_key_checks=0;
Query OK, 0 rows affected (0.00 sec)
 
MariaDB [test]> create table user_table (email char(255) primary key);   
Query OK, 0 rows affected (0.01 sec)
MariaDB [test]> create table prefs_table (id int(11) primary key, user int(11), foreign key (user) references user_table (email));
ERROR 1005 (HY000): Can't create table `test`.`prefs_table` (errno: 150 "Foreign key constraint is incorrectly formed")

On the other hand, it is also true that this doesn't always happen (in either MySQL or MariaDB):

MariaDB [test]> create table another_table (id int(11), other_id int(11), foreign key (other_id) references nonexistent_table (id));
Query OK, 0 rows affected (0.04 sec)

I'd argue that that shouldn't be allowed either, or at the very least it should throw a warning.

Mind you, the MySQL manual says that "Setting foreign_key_checks to 0 also affects data definition statements: DROP SCHEMA drops a schema even if it contains tables that have foreign keys that are referred to by tables outside the schema, and DROP TABLE drops tables that have foreign keys that are referred to by other tables." so perhaps I'm just plain wrong :-/.

PS: Congratulations on your greatly improved error messages for foreign key problems!

Comment by Sergei Golubchik [ 2017-09-25 ]

It's not a bug and foreign_key_checks=0 disables metadata checks too.

This is important when making and restoring backups — it allows to restore tables in any order, removing the need to do it in the dependency order.

Also, sometimes mysqldump creates a temporary MyISAM table that is later dropped — this is used when dumping a schema with views, because, otherwise, it'd need to understand dependencies and dump in the specific order (first tables, then some views, then views that use previously dumped views, etc).

Although, to my knowledge, mysqldump never needs to create a temporary MyISAM table when resolving foreign key dependencies, some other tools might.

So, foreign_key_checks=0 intentionally disables all metadata checks.

Generated at Thu Feb 08 07:29:06 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.