MDEV-22230 : Unexpected ER_ERROR_ON_RENAME upon DROP non-existing FOREIGN KEY

mysql_prepare_alter_table(): Alter table should check whether
foreign key exists when it expected to exists and
report the error in early stage

dict_foreign_parse_drop_constraints(): Don't throw error if the
foreign key constraints doesn't exist when if exists is given
in the statement.
parent c432c9ef
...@@ -1998,8 +1998,7 @@ ALTER TABLE ti1 DROP FOREIGN KEY fi1; ...@@ -1998,8 +1998,7 @@ ALTER TABLE ti1 DROP FOREIGN KEY fi1;
affected rows: 0 affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0 info: Records: 0 Duplicates: 0 Warnings: 0
ALTER TABLE tm1 DROP FOREIGN KEY fm1; ALTER TABLE tm1 DROP FOREIGN KEY fm1;
affected rows: 2 ERROR 42000: Can't DROP FOREIGN KEY `fm1`; check that it exists
info: Records: 2 Duplicates: 0 Warnings: 0
ALTER TABLE ti1 RENAME TO ti3; ALTER TABLE ti1 RENAME TO ti3;
affected rows: 0 affected rows: 0
ALTER TABLE tm1 RENAME TO tm3; ALTER TABLE tm1 RENAME TO tm3;
......
...@@ -1700,6 +1700,7 @@ ALTER TABLE ti1 DROP PRIMARY KEY; ...@@ -1700,6 +1700,7 @@ ALTER TABLE ti1 DROP PRIMARY KEY;
ALTER TABLE tm1 DROP PRIMARY KEY; ALTER TABLE tm1 DROP PRIMARY KEY;
ALTER TABLE ti1 DROP FOREIGN KEY fi1; ALTER TABLE ti1 DROP FOREIGN KEY fi1;
--error ER_CANT_DROP_FIELD_OR_KEY
ALTER TABLE tm1 DROP FOREIGN KEY fm1; ALTER TABLE tm1 DROP FOREIGN KEY fm1;
ALTER TABLE ti1 RENAME TO ti3; ALTER TABLE ti1 RENAME TO ti3;
......
...@@ -144,8 +144,10 @@ alter short drop default, ...@@ -144,8 +144,10 @@ alter short drop default,
DROP INDEX utiny, DROP INDEX utiny,
DROP INDEX ushort, DROP INDEX ushort,
DROP PRIMARY KEY, DROP PRIMARY KEY,
DROP FOREIGN KEY any_name, DROP FOREIGN KEY IF EXISTS any_name,
ADD INDEX (auto); ADD INDEX (auto);
Warnings:
Note 1091 Can't DROP FOREIGN KEY `any_name`; check that it exists
LOCK TABLES t1 WRITE; LOCK TABLES t1 WRITE;
ALTER TABLE t1 ALTER TABLE t1
RENAME as t2, RENAME as t2,
......
...@@ -76,7 +76,7 @@ alter short drop default, ...@@ -76,7 +76,7 @@ alter short drop default,
DROP INDEX utiny, DROP INDEX utiny,
DROP INDEX ushort, DROP INDEX ushort,
DROP PRIMARY KEY, DROP PRIMARY KEY,
DROP FOREIGN KEY any_name, DROP FOREIGN KEY IF EXISTS any_name,
ADD INDEX (auto); ADD INDEX (auto);
LOCK TABLES t1 WRITE; LOCK TABLES t1 WRITE;
......
#
# MDEV-22230 : Unexpected ER_ERROR_ON_RENAME upon DROP
# non-existing FOREIGN KEY
#
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP FOREIGN KEY x, ALGORITHM=COPY;
ERROR 42000: Can't DROP FOREIGN KEY `x`; check that it exists
ALTER TABLE t1 DROP FOREIGN KEY x, ALGORITHM=INPLACE;
ERROR 42000: Can't DROP FOREIGN KEY `x`; check that it exists
DROP TABLE t1;
CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB;
CREATE TABLE t2 (a INT, FOREIGN KEY fk_id (a) REFERENCES t1(a))ENGINE=InnoDB;
CREATE TABLE t3 (a INT, FOREIGN KEY fk_1 (a) REFERENCES t1(a))ENGINE=InnoDB;
ALTER TABLE t3 DROP FOREIGN KEY IF EXISTS fk_id;
Warnings:
Note 1091 Can't DROP FOREIGN KEY `fk_id`; check that it exists
DROP TABLE t3, t2;
ALTER TABLE t1 MODIFY COLUMN a VARCHAR(2), DROP FOREIGN KEY IF EXISTS x;
Warnings:
Note 1091 Can't DROP FOREIGN KEY `x`; check that it exists
DROP TABLE t1;
CREATE DATABASE best;
CREATE TABLE best.t1(f1 INT, KEY(f1))ENGINE=InnoDB;
CREATE TABLE best.t2(f1 INT, FOREIGN KEY foo(f1) REFERENCES t1(f1))ENGINE=InnoDB;
CREATE TABLE t1(f1 INT, KEY(f1))ENGINE=InnoDB;
CREATE TABLE t2(f1 INT, FOREIGN KEY foo(f1) REFERENCES t1(f1))ENGINE=InnoDB;
ALTER TABLE t2 DROP FOREIGN KEY foo;
ALTER TABLE t2 DROP FOREIGN KEY foo;
ERROR 42000: Can't DROP FOREIGN KEY `foo`; check that it exists
ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS foo;
Warnings:
Note 1091 Can't DROP FOREIGN KEY `foo`; check that it exists
SHOW CREATE TABLE best.t2;
Table Create Table
t2 CREATE TABLE `t2` (
`f1` int(11) DEFAULT NULL,
KEY `foo` (`f1`),
CONSTRAINT `foo` FOREIGN KEY (`f1`) REFERENCES `t1` (`f1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
ID FOR_NAME REF_NAME N_COLS TYPE
best/foo best/t2 best/t1 1 0
DROP TABLE best.t2, best.t1, t2, t1;
DROP DATABASE best;
--source include/have_innodb.inc
--echo #
--echo # MDEV-22230 : Unexpected ER_ERROR_ON_RENAME upon DROP
--echo # non-existing FOREIGN KEY
--echo #
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
--error ER_CANT_DROP_FIELD_OR_KEY
ALTER TABLE t1 DROP FOREIGN KEY x, ALGORITHM=COPY;
--error ER_CANT_DROP_FIELD_OR_KEY
ALTER TABLE t1 DROP FOREIGN KEY x, ALGORITHM=INPLACE;
# Cleanup
DROP TABLE t1;
CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB;
CREATE TABLE t2 (a INT, FOREIGN KEY fk_id (a) REFERENCES t1(a))ENGINE=InnoDB;
CREATE TABLE t3 (a INT, FOREIGN KEY fk_1 (a) REFERENCES t1(a))ENGINE=InnoDB;
ALTER TABLE t3 DROP FOREIGN KEY IF EXISTS fk_id;
DROP TABLE t3, t2;
ALTER TABLE t1 MODIFY COLUMN a VARCHAR(2), DROP FOREIGN KEY IF EXISTS x;
DROP TABLE t1;
CREATE DATABASE best;
CREATE TABLE best.t1(f1 INT, KEY(f1))ENGINE=InnoDB;
CREATE TABLE best.t2(f1 INT, FOREIGN KEY foo(f1) REFERENCES t1(f1))ENGINE=InnoDB;
CREATE TABLE t1(f1 INT, KEY(f1))ENGINE=InnoDB;
CREATE TABLE t2(f1 INT, FOREIGN KEY foo(f1) REFERENCES t1(f1))ENGINE=InnoDB;
ALTER TABLE t2 DROP FOREIGN KEY foo;
--error ER_CANT_DROP_FIELD_OR_KEY
ALTER TABLE t2 DROP FOREIGN KEY foo;
ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS foo;
SHOW CREATE TABLE best.t2;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
DROP TABLE best.t2, best.t1, t2, t1;
DROP DATABASE best;
...@@ -9056,6 +9056,30 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, ...@@ -9056,6 +9056,30 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
goto err; goto err;
case Alter_drop::FOREIGN_KEY: case Alter_drop::FOREIGN_KEY:
// Leave the DROP FOREIGN KEY names in the alter_info->drop_list. // Leave the DROP FOREIGN KEY names in the alter_info->drop_list.
/* If this is DROP FOREIGN KEY without IF EXIST,
we can now check does it exists and if not report a error. */
if (!drop->drop_if_exists)
{
List <FOREIGN_KEY_INFO> fk_child_key_list;
table->file->get_foreign_key_list(thd, &fk_child_key_list);
if (fk_child_key_list.is_empty())
{
fk_not_found:
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->type_name(),
drop->name);
goto err;
}
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
while (FOREIGN_KEY_INFO *f_key= fk_key_it++)
{
if (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
drop->name) == 0)
goto fk_found;
}
goto fk_not_found;
fk_found:
break;
}
break; break;
} }
} }
......
...@@ -4592,6 +4592,7 @@ dict_foreign_parse_drop_constraints( ...@@ -4592,6 +4592,7 @@ dict_foreign_parse_drop_constraints(
const char* ptr1; const char* ptr1;
const char* id; const char* id;
CHARSET_INFO* cs; CHARSET_INFO* cs;
bool if_exists = false;
ut_a(trx->mysql_thd); ut_a(trx->mysql_thd);
...@@ -4645,6 +4646,7 @@ dict_foreign_parse_drop_constraints( ...@@ -4645,6 +4646,7 @@ dict_foreign_parse_drop_constraints(
ptr1 = dict_accept(cs, ptr1, "EXISTS", &success); ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
if (success) { if (success) {
ptr = ptr1; ptr = ptr1;
if_exists = true;
} }
} }
...@@ -4655,14 +4657,14 @@ dict_foreign_parse_drop_constraints( ...@@ -4655,14 +4657,14 @@ dict_foreign_parse_drop_constraints(
goto syntax_error; goto syntax_error;
} }
ut_a(*n < 1000);
(*constraints_to_drop)[*n] = id;
(*n)++;
if (std::find_if(table->foreign_set.begin(), if (std::find_if(table->foreign_set.begin(),
table->foreign_set.end(), table->foreign_set.end(),
dict_foreign_matches_id(id)) dict_foreign_matches_id(id))
== table->foreign_set.end()) { == table->foreign_set.end()) {
if (if_exists) {
goto loop;
}
if (!srv_read_only_mode) { if (!srv_read_only_mode) {
FILE* ef = dict_foreign_err_file; FILE* ef = dict_foreign_err_file;
...@@ -4684,6 +4686,9 @@ dict_foreign_parse_drop_constraints( ...@@ -4684,6 +4686,9 @@ dict_foreign_parse_drop_constraints(
return(DB_CANNOT_DROP_CONSTRAINT); return(DB_CANNOT_DROP_CONSTRAINT);
} }
ut_a(*n < 1000);
(*constraints_to_drop)[*n] = id;
(*n)++;
goto loop; goto loop;
syntax_error: syntax_error:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment