mirror of
https://github.com/MariaDB/server.git
synced 2025-01-27 01:04:19 +01:00
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.
This commit is contained in:
parent
c432c9ef19
commit
5bb31bc882
8 changed files with 121 additions and 11 deletions
|
@ -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;
|
||||||
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,
|
||||||
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,
|
||||||
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;
|
||||||
|
|
44
mysql-test/suite/innodb/r/fk_drop_alter.result
Normal file
44
mysql-test/suite/innodb/r/fk_drop_alter.result
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#
|
||||||
|
# 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;
|
35
mysql-test/suite/innodb/t/fk_drop_alter.test
Normal file
35
mysql-test/suite/innodb/t/fk_drop_alter.test
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
--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;
|
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(
|
||||||
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 @@ loop:
|
||||||
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 @@ loop:
|
||||||
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 @@ loop:
|
||||||
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:
|
||||||
|
|
Loading…
Add table
Reference in a new issue