Bug #89018 MySQL creates foreign key constraint when index in parent table is missing
Submitted: 21 Dec 2017 18:17 Modified: 19 May 2019 14:10
Reporter: Power Gamer Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: DDL Severity:S3 (Non-critical)
Version:5.7.17, 5.7.20, 5.6.38 OS:Windows
Assigned to: CPU Architecture:Any
Tags: foreign key, INDEX

[21 Dec 2017 18:17] Power Gamer
Description:
A quote from https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html :
InnoDB permits a foreign key to reference any column or group of columns. However, in the referenced table, there must be an index where the referenced columns are listed as the first columns in the same order. 

The restriction above is NOT enforced in some cases (see examples under the "How to repeat" section).

How to repeat:
-- Example 1 - indexes on columns a and b are not unique.
DROP TABLE IF EXISTS tbl2;
DROP TABLE IF EXISTS tbl1;
CREATE TABLE tbl1(a INT NOT NULL, b INT NOT NULL) ENGINE=InnoDB;
CREATE INDEX a_idx ON tbl1(a);
CREATE INDEX b_idx ON tbl1(b);
CREATE TABLE tbl2(aa INT NOT NULL, bb INT NOT NULL, CONSTRAINT fk FOREIGN KEY(aa, bb) REFERENCES tbl1(a, b)) ENGINE=InnoDB;
-- SQL Error (1215): Cannot add foreign key constraint
-- Correct! Table tbl1 does not have a composite index for columns (a, b).

-- Same as 1st example but both indexes are unique.
DROP TABLE IF EXISTS tbl2;
DROP TABLE IF EXISTS tbl1;
CREATE TABLE tbl1(a INT NOT NULL, b INT NOT NULL) ENGINE=InnoDB;
CREATE UNIQUE INDEX a_idx ON tbl1(a);
CREATE UNIQUE INDEX b_idx ON tbl1(b);
CREATE TABLE tbl2(aa INT NOT NULL, bb INT NOT NULL, CONSTRAINT fk FOREIGN KEY(aa, bb) REFERENCES tbl1(a, b)) ENGINE=InnoDB;
-- SQL Error (1215): Cannot add foreign key constraint
-- Correct! Table tbl1 does not have a composite index for columns (a, b).

-- Same as 1st example but only index on column a is unique.
DROP TABLE IF EXISTS tbl2;
DROP TABLE IF EXISTS tbl1;
CREATE TABLE tbl1(a INT NOT NULL, b INT NOT NULL) ENGINE=InnoDB;
CREATE UNIQUE INDEX a_idx ON tbl1(a);
CREATE INDEX b_idx ON tbl1(b);
CREATE TABLE tbl2(aa INT NOT NULL, bb INT NOT NULL, CONSTRAINT fk FOREIGN KEY(aa, bb) REFERENCES tbl1(a, b)) ENGINE=InnoDB;
-- SQL Error (1215): Cannot add foreign key constraint
-- Correct! Table tbl1 does not have a composite index for columns (a, b).

-- Same as 1st example but only index on column b is unique.
DROP TABLE IF EXISTS tbl2;
DROP TABLE IF EXISTS tbl1;
CREATE TABLE tbl1(a INT NOT NULL, b INT NOT NULL) ENGINE=InnoDB;
CREATE INDEX a_idx ON tbl1(a);
CREATE UNIQUE INDEX b_idx ON tbl1(b);
CREATE TABLE tbl2(aa INT NOT NULL, bb INT NOT NULL, CONSTRAINT fk FOREIGN KEY(aa, bb) REFERENCES tbl1(a, b)) ENGINE=InnoDB;
-- Table tbl1 still does not have a composite index for columns (a, b).
-- Yet, there are no errors and the table tbl2 with foreign key constraint is created successfully!
-- This is wrong - should have been the same error as in previous examples according to the restriction quoted from documentation above.

Suggested fix:
MySQL should not allow creation of foreign key constraints that do not follow documented restriction of having proper index in parent table and return error for last example.
[22 Dec 2017 10:02] MySQL Verification Team
Hello!

Thank you for the report and test case.

Thanks,
Umesh
[19 May 2019 14:10] Daniel Price
Posted by developer:
 
The referenced documentation was revised as follows:

https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html

"InnoDB permits a foreign key to reference any index column or group of
columns. However, in the referenced table, there must be an index where
the referenced columns are the first columns in the same order. Hidden
columns that InnoDB adds to an index are also considered."

Thank you for the bug report.