Commit 3537e7cf authored by Aleksey Midenkov's avatar Aleksey Midenkov

MDEV-28933 CREATE OR REPLACE fails to recreate same constraint name

Use temporary constraint names for temporary tables. The constraints
are not added to cache (skipped in dict_table_rename_in_cache()).

The scheme for temporary constraint names is as follows:

    for old table: db_name/\xFFconstraint_name
    for new table: db_name/\xFF\xFFconstraint_name

normalize_table_name_c_low(): wrong comparison "less than FN_REFLEN -
1". Somewhere array of FN_REFLEN includes the trailing 0, somewhere
array of FN_REFLEN + 1 includes trailing 0, but nowhere array of
FN_REFLEN - 1 must include trailing 0.

Change from original MDEV-28933 fix:

As temporary FK is now required for any ALTER operation (especially
partitioning operations) row_rename_table_for_mysql() does FK rename
on both RENAME_FK and RENAME_ALTER_COPY (see do_rename_fk).
parent 6b1ebb7d
......@@ -11,7 +11,7 @@ set binlog_alter_two_phase = ON;
create table t1 (f1 int primary key) engine=InnoDB;
create table t2 (f1 int primary key, constraint c1 foreign key (f1) references t1(f1)) engine=innodb;
alter table t2 add constraint c1 foreign key (f1) references t1(f1);
ERROR HY000: Can't create table `test`.`t2` (errno: 121 "Duplicate key on write or update")
ERROR HY000: Duplicate ALTER TABLE constraint name '???'
drop table t2, t1;
select @@gtid_binlog_state;
@@gtid_binlog_state
......
......@@ -21,7 +21,7 @@ set binlog_alter_two_phase = ON;
create table t1 (f1 int primary key) engine=InnoDB;
create table t2 (f1 int primary key, constraint c1 foreign key (f1) references t1(f1)) engine=innodb;
--error ER_CANT_CREATE_TABLE
--error ER_DUP_CONSTRAINT_NAME
alter table t2 add constraint c1 foreign key (f1) references t1(f1);
drop table t2, t1;
......
......@@ -6,7 +6,7 @@ create table t2(a int, b int, key(a),key(b))engine=innodb;
alter table t2 add constraint b foreign key (b) references t1(a);
alter table t1 add constraint b1 foreign key (b) references t2(a);
alter table t2 add constraint b1 foreign key (b) references t1(a);
ERROR HY000: Can't create table `test`.`t2` (errno: 121 "Duplicate key on write or update")
ERROR HY000: Duplicate ALTER TABLE constraint name '???'
alter table t2 drop foreign key b;
alter table t1 drop foreign key b1;
drop table t2;
......
......@@ -11,7 +11,7 @@ ERROR HY000: Can't create table `test`.`t2` (errno: 150 "Foreign key constraint
create table t2 (f1 int primary key,
constraint c1 foreign key (f1) references t1(f1)) engine=innodb;
alter table t2 add constraint c1 foreign key (f1) references t1(f1);
ERROR HY000: Can't create table `test`.`t2` (errno: 121 "Duplicate key on write or update")
ERROR HY000: Duplicate ALTER TABLE constraint name '???'
set foreign_key_checks = 0;
alter table t2 add constraint c1 foreign key (f1) references t1(f1);
ERROR HY000: Duplicate FOREIGN KEY constraint name 'test/c1'
......@@ -210,7 +210,7 @@ CONSTRAINT t2_ibfk_1 FOREIGN KEY (a) REFERENCES t1(a)) ENGINE=InnoDB;
CREATE TABLE best.t2 (a INT PRIMARY KEY, b TEXT, FULLTEXT INDEX(b),
FOREIGN KEY (a) REFERENCES test.t1(a)) ENGINE=InnoDB;
RENAME TABLE best.t2 TO test.t2;
ERROR 42S01: Table 't2' already exists
ERROR HY000: Duplicate ALTER TABLE constraint name '???'
SHOW CREATE TABLE best.t2;
Table Create Table
t2 CREATE TABLE `t2` (
......
......@@ -6,11 +6,20 @@ CREATE DATABASE `d255`;
CREATE TABLE `d255`.`d255`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
ERROR HY000: Long database name and identifier for object resulted in path length exceeding 512 characters. Path: './@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023/@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@
CREATE OR REPLACE TABLE `d255`.`d255`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
ERROR HY000: Long database name and identifier for object resulted in path length exceeding 512 characters. Path: './@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023/@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@
CREATE TABLE `d255`.`_##################################################`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
ERROR HY000: Long database name and identifier for object resulted in path length exceeding 512 characters. Path: './@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023/_@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023
CREATE OR REPLACE TABLE `d255`.`_##################################################`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
ERROR HY000: Long database name and identifier for object resulted in path length exceeding 512 characters. Path: './@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023/_@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023
CREATE TABLE `d255`.`##################################################`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
CREATE OR REPLACE TABLE `d255`.`d245`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
DROP TABLE `d255`.`d245`;
#
# MDEV-29258 Failing assertion for name length on RENAME TABLE
#
......@@ -29,3 +38,37 @@ RENAME TABLE `d255`.u TO u;
DROP TABLE u;
DROP DATABASE `d255`;
# End of 10.3 tests
#
# MDEV-28933 CREATE OR REPLACE fails to recreate same constraint name
#
set names utf8;
create database `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎`;
use `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎`;
create table t (a int primary key) engine=innodb;
create table u (
a int primary key,
constraint `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎` foreign key d (a) references t (a)) engine=innodb;
select * from information_schema.innodb_sys_foreign;
ID FOR_NAME REF_NAME N_COLS TYPE
@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@27 @274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@27 @274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@27 1 0
select * from information_schema.innodb_sys_foreign_cols;
ID FOR_COL_NAME REF_COL_NAME POS
@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@27 a a 0
create or replace table u (
a int primary key,
constraint `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎` foreign key d (a) references t (a)) engine=innodb;
select * from information_schema.innodb_sys_foreign;
ID FOR_NAME REF_NAME N_COLS TYPE
@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@27 @274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@27 @274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@27 1 0
select * from information_schema.innodb_sys_foreign_cols;
ID FOR_COL_NAME REF_COL_NAME POS
@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@27 a a 0
show create table u;
Table Create Table
u CREATE TABLE `u` (
`a` int(11) NOT NULL,
PRIMARY KEY (`a`),
CONSTRAINT `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎` FOREIGN KEY (`a`) REFERENCES `t` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
use test;
drop database `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎`;
......@@ -509,7 +509,7 @@ t4 CREATE TABLE `t4` (
CONSTRAINT `dc` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
alter table t3 add constraint dc foreign key (a) references t1(a);
ERROR HY000: Can't create table `test`.`t3` (errno: 121 "Duplicate key on write or update")
ERROR HY000: Duplicate ALTER TABLE constraint name '???'
SET FOREIGN_KEY_CHECKS=0;
alter table t3 add constraint dc foreign key (a) references t1(a);
ERROR HY000: Failed to add the foreign key constraint 'test/dc' to system tables
......
......@@ -10,7 +10,7 @@ create table t2(a int, b int, key(a),key(b))engine=innodb;
alter table t2 add constraint b foreign key (b) references t1(a);
alter table t1 add constraint b1 foreign key (b) references t2(a);
--error ER_CANT_CREATE_TABLE
--error ER_DUP_CONSTRAINT_NAME
alter table t2 add constraint b1 foreign key (b) references t1(a);
alter table t2 drop foreign key b;
......
......@@ -17,7 +17,7 @@ constraint c1 foreign key (f1) references t1(f1)) engine=InnoDB;
create table t2 (f1 int primary key,
constraint c1 foreign key (f1) references t1(f1)) engine=innodb;
--error ER_CANT_CREATE_TABLE
--error ER_DUP_CONSTRAINT_NAME
alter table t2 add constraint c1 foreign key (f1) references t1(f1);
set foreign_key_checks = 0;
......@@ -195,7 +195,7 @@ CONSTRAINT t2_ibfk_1 FOREIGN KEY (a) REFERENCES t1(a)) ENGINE=InnoDB;
CREATE TABLE best.t2 (a INT PRIMARY KEY, b TEXT, FULLTEXT INDEX(b),
FOREIGN KEY (a) REFERENCES test.t1(a)) ENGINE=InnoDB;
--replace_regex /Table '.*t2'/Table 't2'/
--error ER_TABLE_EXISTS_ERROR
--error ER_DUP_CONSTRAINT_NAME
RENAME TABLE best.t2 TO test.t2;
SHOW CREATE TABLE best.t2;
DROP DATABASE best;
......
......@@ -25,20 +25,43 @@ CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
# corresponding to the 51 characters below: 5*51=255.
let $d255=###################################################;
let $d250=##################################################;
let $d245=#####################;
# FIXME: MDEV-29258
# let $d245=#################################################;
--replace_result $d255 d255
eval CREATE DATABASE `$d255`;
--replace_result $d255 d255
--error ER_IDENT_CAUSES_TOO_LONG_PATH
eval CREATE TABLE `$d255`.`$d255`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
--replace_result $d255 d255
--error ER_IDENT_CAUSES_TOO_LONG_PATH
eval CREATE OR REPLACE TABLE `$d255`.`$d255`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
--replace_result $d255 d255
--error ER_IDENT_CAUSES_TOO_LONG_PATH
eval CREATE TABLE `$d255`.`_$d250`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
--replace_result $d255 d255
--error ER_IDENT_CAUSES_TOO_LONG_PATH
eval CREATE OR REPLACE TABLE `$d255`.`_$d250`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
--replace_result $d255 d255
eval CREATE TABLE `$d255`.`$d250`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
--replace_result $d255 d255 $d245 d245
eval CREATE OR REPLACE TABLE `$d255`.`$d245`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
--replace_result $d255 d255 $d245 d245
eval DROP TABLE `$d255`.`$d245`;
--echo #
--echo # MDEV-29258 Failing assertion for name length on RENAME TABLE
--echo #
......@@ -53,7 +76,6 @@ eval DROP TABLE `$d255`.`$d250`;
eval RENAME TABLE `$d255`.`$d245` TO `$d255`.`$d250`;
--replace_result $d250 d250 $d255 d255
eval RENAME TABLE `$d255`.`$d250` TO a;
--replace_result $d255 d255
DROP TABLE a,t;
--echo #
......@@ -75,3 +97,26 @@ DROP TABLE u;
eval DROP DATABASE `$d255`;
--echo # End of 10.3 tests
--echo #
--echo # MDEV-28933 CREATE OR REPLACE fails to recreate same constraint name
--echo #
set names utf8;
let $d= `select repeat('❎', 45)`;
let $t= `select repeat('❎', 64)`;
eval create database `$d`;
eval use `$d`;
create table t (a int primary key) engine=innodb;
eval create table u (
a int primary key,
constraint `$t` foreign key d (a) references t (a)) engine=innodb;
select * from information_schema.innodb_sys_foreign;
select * from information_schema.innodb_sys_foreign_cols;
eval create or replace table u (
a int primary key,
constraint `$t` foreign key d (a) references t (a)) engine=innodb;
select * from information_schema.innodb_sys_foreign;
select * from information_schema.innodb_sys_foreign_cols;
show create table u;
use test;
eval drop database `$d`;
......@@ -221,7 +221,7 @@ show create table t4;
# Embedded server doesn't chdir to data directory
--replace_result $MYSQLD_DATADIR ./ master-data/ ''
# a foreign key 'test/dc' already exists
--error ER_CANT_CREATE_TABLE
--error ER_DUP_CONSTRAINT_NAME
alter table t3 add constraint dc foreign key (a) references t1(a);
SET FOREIGN_KEY_CHECKS=0;
--error ER_FK_FAIL_ADD_SYSTEM
......
......@@ -15,7 +15,7 @@ ERROR HY000: Can't create table `test`.`t2` (errno: 150 "Foreign key constraint
create table t2 (f1 int primary key,
constraint c1 foreign key (f1) references t1(f1)) engine=innodb;
alter table t2 add constraint c1 foreign key (f1) references t1(f1);
ERROR HY000: Can't create table `test`.`t2` (errno: 121 "Duplicate key on write or update")
ERROR HY000: Duplicate ALTER TABLE constraint name '???'
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
......
......@@ -22,7 +22,7 @@ constraint c1 foreign key (f1) references t1(f1)) engine=InnoDB;
create table t2 (f1 int primary key,
constraint c1 foreign key (f1) references t1(f1)) engine=innodb;
--error ER_CANT_CREATE_TABLE
--error ER_DUP_CONSTRAINT_NAME
alter table t2 add constraint c1 foreign key (f1) references t1(f1);
--source include/show_binlog_events.inc
......
......@@ -263,6 +263,13 @@ constraint `fk_child_parent`
on delete cascade
on update cascade
) engine = innodb with system versioning;
select * from information_schema.innodb_sys_foreign;
ID FOR_NAME REF_NAME N_COLS TYPE
test/fk_child_parent test/child test/parent 2 5
select * from information_schema.innodb_sys_foreign_cols;
ID FOR_COL_NAME REF_COL_NAME POS
test/fk_child_parent parent_id id 0
test/fk_child_parent parent_value value 1
create or replace table subchild (
id int not null auto_increment primary key,
parent_id smallint unsigned not null,
......@@ -272,6 +279,16 @@ constraint `fk_subchild_child_parent`
on delete cascade
on update cascade
) engine=innodb;
select * from information_schema.innodb_sys_foreign;
ID FOR_NAME REF_NAME N_COLS TYPE
test/fk_child_parent test/child test/parent 2 5
test/fk_subchild_child_parent test/subchild test/child 2 5
select * from information_schema.innodb_sys_foreign_cols;
ID FOR_COL_NAME REF_COL_NAME POS
test/fk_child_parent parent_id id 0
test/fk_child_parent parent_value value 1
test/fk_subchild_child_parent parent_id parent_id 0
test/fk_subchild_child_parent parent_value parent_value 1
insert into parent (value) values (23);
select id, value from parent into @id, @value;
insert into child values (default, @id, @value);
......
......@@ -304,6 +304,9 @@ eval create or replace table child (
on update cascade
) engine = innodb with system versioning;
select * from information_schema.innodb_sys_foreign;
select * from information_schema.innodb_sys_foreign_cols;
create or replace table subchild (
id int not null auto_increment primary key,
parent_id smallint unsigned not null,
......@@ -314,6 +317,9 @@ create or replace table subchild (
on update cascade
) engine=innodb;
select * from information_schema.innodb_sys_foreign;
select * from information_schema.innodb_sys_foreign_cols;
insert into parent (value) values (23);
--enable_prepare_warnings
select id, value from parent into @id, @value;
......
......@@ -586,7 +586,7 @@ class Identifier_chain2
size_t make_sep_name_opt_casedn(char *dst, size_t dst_size,
int sep, bool casedn) const
{
DBUG_ASSERT(m_name[0].length + m_name[1].length + 2 < FN_REFLEN - 1);
DBUG_ASSERT(m_name[0].length + m_name[1].length + 2 < FN_REFLEN);
return casedn ? make_sep_name_casedn(dst, dst_size, sep) :
make_sep_name(dst, dst_size, sep);
}
......
......@@ -5336,6 +5336,12 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
if (error == HA_ERR_WRONG_COMMAND)
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
if (error == HA_ERR_FOREIGN_DUPLICATE_KEY)
/*
TODO: constraint name is not known because rename_constraint_ids
does not supply it in row_rename_table_for_mysql()
*/
my_error(ER_DUP_CONSTRAINT_NAME, MYF(0), "ALTER TABLE", "???");
else if (error == ENOTDIR)
my_error(ER_BAD_DB_ERROR, MYF(0), new_db->str);
else if (error)
......
......@@ -1617,7 +1617,8 @@ dict_table_rename_in_cache(
foreign->heap, table->name.m_name);
foreign->foreign_table_name_lookup_set();
if (strchr(foreign->id, '/')) {
const bool tmp_id = (strchr(foreign->id, '\xFF') != NULL);
if (!tmp_id && strchr(foreign->id, '/')) {
/* This is a >= 4.0.18 format id */
ulint db_len;
......@@ -1761,10 +1762,17 @@ dict_table_rename_in_cache(
}
table->foreign_set.erase(it);
fk_set.insert(foreign);
if (foreign->referenced_table) {
foreign->referenced_table->referenced_set.insert(foreign);
if (!tmp_id) {
fk_set.insert(foreign);
if (foreign->referenced_table) {
foreign->referenced_table
->referenced_set.insert(foreign);
}
} else {
/* foreign was not added to cache, free it */
dict_foreign_free(foreign);
}
}
......
......@@ -3163,8 +3163,8 @@ dict_load_foreigns(
rec, DICT_FLD__SYS_FOREIGN_FOR_NAME__ID, &len);
/* Copy the string because the page may be modified or evicted
after mtr.commit() below. */
char fk_id[MAX_TABLE_NAME_LEN + NAME_LEN];
after mtr.commit() below (-2 is for \xFF\xFF in tmp constraints). */
char fk_id[MAX_TABLE_NAME_LEN + NAME_LEN - 2];
err = DB_SUCCESS;
if (UNIV_LIKELY(len < sizeof fk_id)) {
memcpy(fk_id, field, len);
......
......@@ -5297,7 +5297,8 @@ create_table_info_t::create_table_info_t(
m_create_info(create_info),
m_table(NULL),
m_innodb_file_per_table(file_per_table),
m_creating_stub(thd_ddl_options(thd)->import_tablespace())
m_creating_stub(thd_ddl_options(thd)->import_tablespace()),
alter_table(NULL)
{
m_table_name[0]= '\0';
m_remote_path[0]= '\0';
......@@ -12258,7 +12259,6 @@ create_table_info_t::create_foreign_keys()
LEX_CSTRING name= {m_table_name, strlen(m_table_name)};
if (sqlcom == SQLCOM_ALTER_TABLE) {
dict_table_t* alter_table;
mem_heap_t* heap = mem_heap_create(10000);
LEX_CSTRING table_name = m_form->s->table_name;
CHARSET_INFO* to_cs = &my_charset_filename;
......@@ -12313,6 +12313,15 @@ create_table_info_t::create_foreign_keys()
alter_table);
}
/*
alter_table == NULL might be by the following reasons:
1. tmp_table;
2. is_partition(m_table_name);
3. Engine changed from non-InnoDB, so no original table in InnoDB;
4. Anything else?
*/
*innobase_convert_name(create_name, sizeof create_name,
n, strlen(n), m_thd) = '\0';
mem_heap_free(heap);
......@@ -12474,6 +12483,7 @@ create_table_info_t::create_foreign_key(
if (fk->constraint_name.str) {
ulint db_len;
const bool tmp= alter_table;
/* Catenate 'databasename/' to the constraint name
specified by the user: we conceive the constraint as
......@@ -12483,13 +12493,17 @@ create_table_info_t::create_foreign_key(
db_len = dict_get_db_name_len(table->name.m_name);
foreign->id = static_cast<char*>(mem_heap_alloc(
foreign->heap,
db_len + fk->constraint_name.length + 2));
memcpy(foreign->id, table->name.m_name, db_len);
foreign->id[db_len] = '/';
strcpy(foreign->id + db_len + 1,
fk->constraint_name.str);
foreign->heap, (tmp ? 3 : 2)
+ db_len + fk->constraint_name.length));
char *pos = foreign->id;
memcpy(pos, table->name.m_name, db_len);
pos += db_len;
*(pos++) = '/';
if (tmp) {
*(pos++) = '\xFF';
}
strcpy(pos, fk->constraint_name.str);
}
if (foreign->id == NULL) {
......
......@@ -780,6 +780,7 @@ class create_table_info_t
/** Whether we are creating a stub table for importing. */
const bool m_creating_stub;
dict_table_t* alter_table;
};
/**
......
......@@ -32,12 +32,15 @@ R"===(PROCEDURE RENAME_CONSTRAINT_IDS () IS
gen_constr_prefix CHAR;
new_db_name CHAR;
foreign_id CHAR;
foreign_id2 CHAR;
constr_name CHAR;
new_foreign_id CHAR;
old_db_name_len INT;
old_t_name_len INT;
new_db_name_len INT;
id_len INT;
offset INT;
offset2 INT;
constr_name_len INT;
found INT;
BEGIN
found := 1;
......@@ -45,7 +48,6 @@ R"===(PROCEDURE RENAME_CONSTRAINT_IDS () IS
new_db_name_len := INSTR(:new_table_name, '/') - 1;
new_db_name := SUBSTR(:new_table_name, 0,
new_db_name_len);
old_t_name_len := LENGTH(:old_table_name);
gen_constr_prefix := CONCAT(:old_table_name_utf8,
'_ibfk_');
WHILE found = 1 LOOP
......@@ -62,6 +64,18 @@ R"===(PROCEDURE RENAME_CONSTRAINT_IDS () IS
SET FOR_NAME = :new_table_name
WHERE ID = foreign_id;
id_len := LENGTH(foreign_id);
foreign_id2 := foreign_id;
offset := INSTR(foreign_id, ')===" "\xFF" R"===(');
IF (SUBSTR(foreign_id, offset, 1) = ')===" "\xFF" R"===(') THEN
offset2 := offset + 1;
ELSE
offset2 := offset;
END IF;
IF (:old_is_tmp > 0 AND offset > 0) THEN
foreign_id := CONCAT(SUBSTR(foreign_id2, 0, offset - 1),
SUBSTR(foreign_id2, offset2, id_len - offset2));
id_len := LENGTH(foreign_id);
END IF;
IF (INSTR(foreign_id, '/') > 0) THEN
IF (INSTR(foreign_id,
gen_constr_prefix) > 0)
......@@ -71,17 +85,22 @@ R"===(PROCEDURE RENAME_CONSTRAINT_IDS () IS
CONCAT(:new_table_utf8,
SUBSTR(foreign_id, offset, id_len - offset));
ELSE
new_foreign_id :=
CONCAT(new_db_name,
SUBSTR(foreign_id, old_db_name_len,
id_len - old_db_name_len));
constr_name_len := id_len - old_db_name_len;
constr_name := SUBSTR(foreign_id, old_db_name_len,
constr_name_len);
IF (:new_is_tmp > 0) THEN
new_foreign_id := CONCAT(new_db_name, ')===" "/\xFF\xFF" R"===(',
SUBSTR(constr_name, 1, constr_name_len - 1));
ELSE
new_foreign_id := CONCAT(new_db_name, constr_name);
END IF;
END IF;
UPDATE SYS_FOREIGN
SET ID = new_foreign_id
WHERE ID = foreign_id;
WHERE ID = foreign_id2;
UPDATE SYS_FOREIGN_COLS
SET ID = new_foreign_id
WHERE ID = foreign_id;
WHERE ID = foreign_id2;
END IF;
END IF;
END LOOP;
......
......@@ -2681,6 +2681,7 @@ row_rename_table_for_mysql(
char new_table_name[MAX_TABLE_NAME_LEN + 1];
char old_table_utf8[MAX_TABLE_NAME_LEN + 1];
uint errors = 0;
const bool do_rename_fk = (fk == RENAME_FK || fk == RENAME_ALTER_COPY);
strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
old_table_utf8[MAX_TABLE_NAME_LEN] = '\0';
......@@ -2720,8 +2721,22 @@ row_rename_table_for_mysql(
}
pars_info_add_str_literal(info, "new_table_utf8", new_table_name);
/* Old foreign ID for temporary constraint was written like this:
db_name/\xFFconstraint_name */
pars_info_add_int4_literal(info, "old_is_tmp",
do_rename_fk && old_is_tmp);
/* New foreign ID for temporary constraint is written like this:
db_name/\xFF\xFFconstraint_name */
pars_info_add_int4_literal(info, "new_is_tmp",
do_rename_fk && new_is_tmp);
err = que_eval_sql(info, rename_constraint_ids, trx);
/*
Higher layer should throw not ER_TABLE_EXISTS_ERROR but
ER_ERROR_ON_RENAME with explanation about foreign keys.
*/
if (err == DB_DUPLICATE_KEY)
err = DB_FOREIGN_DUPLICATE_KEY;
} else if (n_constraints_to_drop > 0) {
/* Drop some constraints of tmp tables. */
......
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