Major bug in MySQL 8.x? -- foreign keys - mysql

While retrieving foreign keys information from MySQL (for a code generator) I noticed this strange behavior. It looks like a major bug in MySQL 8.x. When I create a foreign key using REFERENCES the engine does not enforce it. For example:
create table p (
id int primary key not null
) engine=innodb;
create table q (
pid int references p (id)
) engine=innodb;
insert into q (pid) values (123); -- succeeds (!)
See example at DB Fiddle.
However, if I create the foreign key typing FOREIGN KEY (col) REFERENCES table (col) it works properly:
create table p (
id int primary key not null
) engine=innodb;
create table r (
pid int,
foreign key (pid) references p (id)
) engine=innodb;
insert into r (pid) values (456); -- fails, as expected
See running example at DB Fiddle.
If this is a bona fide major bug in MySQL, is there any way of disabling the bad syntax?
Note: I just verified that MariaDB presented the same bug until 10.4, but it seems it's fixed in 10.5.

Not fixed in MySQL. It permits legal SQL syntax, but MySQL does not save the constraint when using the column-level foreign key syntax.
This was reported as a bug in 2005, and closed with a "won't fix" message.
https://bugs.mysql.com/bug.php?id=13301
https://dev.mysql.com/doc/refman/8.0/en/ansi-diff-foreign-keys.html says:
MySQL parses but ignores “inline REFERENCES specifications” (as defined in the SQL standard) where the references are defined as part of the column specification. MySQL accepts REFERENCES clauses only when specified as part of a separate FOREIGN KEY specification. For storage engines that do not support foreign keys (such as MyISAM), MySQL Server parses and ignores foreign key specifications.
There is no way to disable the unsupported syntax, or even to make it return an error or a warning.

Related

purpose of declaring foreign keys in mysql MyISAM engine

I just came to know that mysql MyISAM engine doesn't support foreign keys.But i have seen several example of declaring foreign keys like below :
CREATE TABLE Orders (
OrderID int NOT NULL,
OrderNumber int NOT NULL,
PersonID int,
PRIMARY KEY (OrderID),
FOREIGN KEY (PersonID) REFERENCES Persons(PersonID)
);
As foreign keys are not supported we would not get the benefits like on update and on delete in MyISAM engine.My question is then why we are declaring a field as foreign key in MyISAM engine ?
There is no point of declaring foreign keys with the myisam table type, since this functionality does not exist there. Mysql can parse the foreign key syntax for the myisam table type (meaning no error message will be raised if it encounters an fk definition), making migration from other database products or table engines easier because you do not have to edit the create table statements to remove them.

Separate FOREIGN KEY declaration fails

The following CREATE TABLE statement (simplified on purpose)
works well on current Mysql 5.1 / INNODB:
CREATE TABLE Employee (
id INT NOT NULL PRIMARY KEY
,boss INT REFERENCES Employee
)
Now I try to create the FOREIGN KEY separately (after executing DROP TABLE Employee):
CREATE TABLE Employee (
id INT NOT NULL PRIMARY KEY
, boss INT
,CONSTRAINT _FK_boss FOREIGN KEY(boss) REFERENCES Employee
)
This time table creation fails with message
"Cannot add foreign key constraint".
BTW: I already did a DROP/CREATE DATABASE ..., tinkered with the constraint identifier name with no success at all. Adding an explicit "Engine innodb" does not help either. My original schema has two distinct 1:n related tables exhibiting identical behavior.
As far as I understand
http://dev.mysql.com/doc/refman/5.1/en/create-table.html the syntax is alright.
The first example did not work. If you run SHOW CREATE TABLE, you'll see the constraint is not there.
MySQL parses inline foreign key declarations, but InnoDB ignores them. InnoDB supports only table-level constraints. And InnoDB requires the column to be declared explicitly, even though standard SQL says it's optional.
This is an artifact of MySQL's pluggable storage engine architecture. Both the storage-independent layer of MySQL and each individual storage-engine layer has their own SQL parser, and they may not agree on how much of the standard language they support. Another example is CHECK constraints, which are parsed by MySQL, but ignored by all storage engines (so far).
Foreign key constraints require the column; it's not optional. This statement will allow the declaration to succeed.
CREATE TABLE Employee (
id INT NOT NULL PRIMARY KEY
, boss INT
,CONSTRAINT _FK_boss FOREIGN KEY(boss) REFERENCES Employee (id)
);

Foreign keys on create table doesn't get created

Executing my code didn't cause errors and didn't create the expected keys on this server:
create table table1 (
id int not null auto_increment primary key,
name varchar(10) not null default ''
) engine=innodb;
create table table2 (
id int not null auto_increment primary key,
idTable1 int null references table1(id) on delete cascade
) engine=innodb;
I've seen some declaring the constraints as:
columnName int not null, foreign key (columnName) references table1(id) on delete cascade
but I think I've already used the previous syntax before and it worked on a different server. I just can't remember for sure.
Have you seen this before? Am I wrong in assuming my syntax would work as it works on MSSQL? If so, why this doesn't cause an error to be thrown?
Edit.:
InnoDB is enabled and set to default with SET storage_engine=INNODB; before running the queries to make sure.
Keys added with the second syntax example work. Keys added with alter table work also.
MySQL doesn't support column level Foreign key constraint addition to the CREATE syntax.
It has to be table level.
Furthermore, MySQL does not recognize or support “inline REFERENCES
specifications” (as defined in the SQL standard) where the references
are defined as part of the column specification. MySQL accepts
REFERENCES clauses only when specified as part of a separate FOREIGN
KEY specification. For storage engines that do not support foreign
keys (such as MyISAM), MySQL Server parses and ignores foreign key
specifications.
Further reading: here

I am getting an error trying to create table in phpmyadmin

I am trying to run the following:
CREATE TABLE IF NOT EXISTS table_name (
user_id int(11) NOT NULL,
other_id int(11) NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (other_id) REFERENCES other_table(id),
PRIMARY KEY (user_id, other_id)
);
and getting the following error:
#1005 - Can't create table 'database_name.table_name' (errno: 150)
am I doing something wrong? This works fine just running it in another environment rather than phpmyadmin sql environment.
Take a look at this SO question.
Note the correct answer. Check column types They need to match. May be your problem.
In general, Here is the authoritative guide to FK in Mysql.
In addition to SHOW ERRORS, in the event of a foreign key error
involving InnoDB tables (usually Error 150 in the MySQL Server), you
can obtain a detailed explanation of the most recent InnoDB foreign
key error by checking the output of SHOW ENGINE INNODB STATUS.
EDIT: Incorporating comments
Table on PHPMyAdmin were defaulting to MyISAM. On Local they were defaulting to to InnoDB. MyISAM does not support FK. This does not fully explain the difference, as based on MySql Documentation, It should just work, without creating the FK's. ( Perhaps a settings issue or Older Version Issue)
Does users and other_table exist?
You can't have the foreign key references to non-existant tables.
You can add the references afterwards with alter table.
DROP TABLE IF EXISTS `table_name`;
CREATE TABLE IF NOT EXISTS table_name (
user_id int(11) NOT NULL,
other_id int(11) NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (other_id) REFERENCES other_table(id),
PRIMARY KEY (user_id, other_id)
);

Failure in using alter table to add partition

I have a table having structure as below:
CREATE TABLE `child_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`value` int,
`ref_id` int,
PRIMARY KEY (`id`),
KEY `ref_id` (`ref_id`),
CONSTRAINT `FK4E9BF08E940F8C98` FOREIGN KEY (`ref_id`) REFERENCES `parent_table` (`id`) ON DELETE CASCADE
)
When running statement to add partition, it fails and show the error:
ERROR 1217: Cannot delete or update a parent row: a foreign key constraint fails
SQL Statement:
ALTER TABLE `learning`.`child_table` PARTITION BY HASH(ref_id) PARTITIONS 10
So I remove the foreign constraint with parent_table, then run again. It still fails and show the same error.
Did I do anything wrong?
I know this is an old question, but for people that fall here from looking for this problem, since its the first Google result:
MySQL does not support foreign keys on partitioned tables.
From the manual
Foreign keys not supported for partitioned InnoDB tables. Partitioned tables using the InnoDB storage engine do not support foreign keys. More specifically, this means that the following two statements are true:
No definition of an InnoDB table employing user-defined partitioning may contain foreign key references; no InnoDB table whose definition contains foreign key references may be partitioned.
No InnoDB table definition may contain a foreign key reference to a user-partitioned table; no InnoDB table with user-defined partitioning may contain columns referenced by foreign keys.
The error is referring to a foreign key on another table that references child_table. You need to find and remove the foreign key from that table, not necessarily child_table. You could also try running SET foreign_key_checks = 0 first.