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;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0
ALTER TABLE tm1 DROP FOREIGN KEY fm1;
affected rows: 2
info: Records: 2 Duplicates: 0 Warnings: 0
ERROR 42000: Can't DROP FOREIGN KEY `fm1`; check that it exists
ALTER TABLE ti1 RENAME TO ti3;
affected rows: 0
ALTER TABLE tm1 RENAME TO tm3;
......
......@@ -1700,6 +1700,7 @@ ALTER TABLE ti1 DROP PRIMARY KEY;
ALTER TABLE tm1 DROP PRIMARY KEY;
ALTER TABLE ti1 DROP FOREIGN KEY fi1;
--error ER_CANT_DROP_FIELD_OR_KEY
ALTER TABLE tm1 DROP FOREIGN KEY fm1;
ALTER TABLE ti1 RENAME TO ti3;
......
......@@ -144,8 +144,10 @@ alter short drop default,
DROP INDEX utiny,
DROP INDEX ushort,
DROP PRIMARY KEY,
DROP FOREIGN KEY any_name,
DROP FOREIGN KEY IF EXISTS any_name,
ADD INDEX (auto);
Warnings:
Note 1091 Can't DROP FOREIGN KEY `any_name`; check that it exists
LOCK TABLES t1 WRITE;
ALTER TABLE t1
RENAME as t2,
......
......@@ -76,7 +76,7 @@ alter short drop default,
DROP INDEX utiny,
DROP INDEX ushort,
DROP PRIMARY KEY,
DROP FOREIGN KEY any_name,
DROP FOREIGN KEY IF EXISTS any_name,
ADD INDEX (auto);
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,
goto err;
case Alter_drop::FOREIGN_KEY:
// 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;
}
}
......
......@@ -4592,6 +4592,7 @@ dict_foreign_parse_drop_constraints(
const char* ptr1;
const char* id;
CHARSET_INFO* cs;
bool if_exists = false;
ut_a(trx->mysql_thd);
......@@ -4645,6 +4646,7 @@ dict_foreign_parse_drop_constraints(
ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
if (success) {
ptr = ptr1;
if_exists = true;
}
}
......@@ -4655,14 +4657,14 @@ dict_foreign_parse_drop_constraints(
goto syntax_error;
}
ut_a(*n < 1000);
(*constraints_to_drop)[*n] = id;
(*n)++;
if (std::find_if(table->foreign_set.begin(),
table->foreign_set.end(),
dict_foreign_matches_id(id))
== table->foreign_set.end()) {
table->foreign_set.end(),
dict_foreign_matches_id(id))
== table->foreign_set.end()) {
if (if_exists) {
goto loop;
}
if (!srv_read_only_mode) {
FILE* ef = dict_foreign_err_file;
......@@ -4684,6 +4686,9 @@ dict_foreign_parse_drop_constraints(
return(DB_CANNOT_DROP_CONSTRAINT);
}
ut_a(*n < 1000);
(*constraints_to_drop)[*n] = id;
(*n)++;
goto loop;
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