diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index 236953795e673..ab9e7ec924fab 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -258,6 +258,7 @@ CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t2 (b INT PRIMARY KEY, FOREIGN KEY fk1 (b) REFERENCES t1 (a)) ENGINE=InnoDB; ALTER TABLE t2 DROP FOREIGN KEY fk1, DROP FOREIGN KEY fk1; +ERROR 42000: Can't DROP FOREIGN KEY `fk1`; check that it exists DROP TABLE t2, t1; CREATE TABLE t1 (f VARCHAR(256)) ENGINE=InnoDB; SET SESSION FOREIGN_KEY_CHECKS = OFF; @@ -1200,4 +1201,28 @@ set GLOBAL innodb_fast_shutdown=0; # restart ALTER TABLE t2 FORCE; DROP TABLE t2, t1, t3; +# +# MDEV-19194 ASAN use-after-poison in +# fk_prepare_copy_alter_table upon dropping FK +# +CREATE TABLE t1(f1 INT NOT NULL, KEY(f1))ENGINE=InnoDB; +CREATE TABLE t2(f1 INT NOT NULL, +FOREIGN KEY `f1`(f1) REFERENCES t1(f1))ENGINE=InnoDB; +ALTER TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY f1, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `f1`; check that it exists +Note 1091 Can't DROP FOREIGN KEY `f1`; check that it exists +DROP TABLE t2, t1; # End of 10.6 tests diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index e7761f3cf4bde..f52dacbb949c0 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -256,6 +256,7 @@ DROP TABLE t1; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t2 (b INT PRIMARY KEY, FOREIGN KEY fk1 (b) REFERENCES t1 (a)) ENGINE=InnoDB; +--error ER_CANT_DROP_FIELD_OR_KEY ALTER TABLE t2 DROP FOREIGN KEY fk1, DROP FOREIGN KEY fk1; DROP TABLE t2, t1; @@ -1271,4 +1272,22 @@ set GLOBAL innodb_fast_shutdown=0; ALTER TABLE t2 FORCE; DROP TABLE t2, t1, t3; +--echo # +--echo # MDEV-19194 ASAN use-after-poison in +--echo # fk_prepare_copy_alter_table upon dropping FK +--echo # +CREATE TABLE t1(f1 INT NOT NULL, KEY(f1))ENGINE=InnoDB; +CREATE TABLE t2(f1 INT NOT NULL, + FOREIGN KEY `f1`(f1) REFERENCES t1(f1))ENGINE=InnoDB; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ALTER TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t2 DROP FOREIGN KEY f1, ALGORITHM=COPY; +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +DROP TABLE t2, t1; + --echo # End of 10.6 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 549be4faf660b..26e13c9200778 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9012,6 +9012,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, { Alter_drop *drop; drop_it.rewind(); + List dropped_fk; while ((drop=drop_it++)) { switch (drop->type) { case Alter_drop::KEY: @@ -9041,7 +9042,18 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, { if (my_strcasecmp(system_charset_info, f_key->foreign_id->str, drop->name) == 0) + { + List_iterator check_it(dropped_fk); + LEX_CSTRING *dropped_name; + while ((dropped_name = check_it++)) + { + if (my_strcasecmp(system_charset_info, dropped_name->str, + f_key->foreign_id->str) == 0) + goto fk_not_found; + } + dropped_fk.push_back(f_key->foreign_id); goto fk_found; + } } goto fk_not_found; fk_found: @@ -9336,6 +9348,7 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, when a foreign key has the same table as child and parent. */ List_iterator fk_parent_key_it(fk_parent_key_list); + List keys_to_remove; while ((f_key= fk_parent_key_it++)) { @@ -9358,7 +9371,26 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, &table->s->db) == 0) && (lex_string_cmp(table_alias_charset, f_key->foreign_table, &table->s->table_name) == 0)) + { + keys_to_remove.push_back(f_key); + break; + } + } + } + + /* Remove the identified keys */ + List_iterator remove_it(keys_to_remove); + while ((f_key = remove_it++)) + { + fk_parent_key_it.rewind(); + FOREIGN_KEY_INFO *fk; + while ((fk= fk_parent_key_it++)) + { + if (fk == f_key) + { fk_parent_key_it.remove(); + break; + } } } @@ -9432,6 +9464,7 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, by this ALTER TABLE. */ List_iterator fk_key_it(fk_child_key_list); + keys_to_remove.empty(); while ((f_key= fk_key_it++)) { @@ -9444,7 +9477,26 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, if ((drop->type == Alter_drop::FOREIGN_KEY) && (my_strcasecmp(system_charset_info, f_key->foreign_id->str, drop->name) == 0)) + { + keys_to_remove.push_back(f_key); + break; + } + } + } + + /* Remove the identified keys */ + List_iterator remove_it2(keys_to_remove); + while ((f_key = remove_it2++)) + { + FOREIGN_KEY_INFO *fk; + fk_key_it.rewind(); + while ((fk= fk_key_it++)) + { + if (fk == f_key) + { fk_key_it.remove(); + break; + } } }