diff options
author | Aleksey Midenkov <midenok@gmail.com> | 2023-01-18 16:52:10 +0300 |
---|---|---|
committer | Aleksey Midenkov <midenok@gmail.com> | 2023-01-26 17:15:20 +0300 |
commit | 7aadd088fda40b8fefc0def9a2494503f8bc31f7 (patch) | |
tree | 4843535099b925510d1187589de40f7afe838ed8 | |
parent | 2d5758af5a8ab43d200026efc510df26e4b58266 (diff) | |
download | mariadb-git-7aadd088fda40b8fefc0def9a2494503f8bc31f7.tar.gz |
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.
-rw-r--r-- | mysql-test/main/create_or_replace.result | 28 | ||||
-rw-r--r-- | mysql-test/main/create_or_replace.test | 22 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/foreign_key_not_windows.result | 43 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/foreign_key_not_windows.test | 47 | ||||
-rw-r--r-- | mysql-test/suite/versioning/r/foreign.result | 17 | ||||
-rw-r--r-- | mysql-test/suite/versioning/t/foreign.test | 6 | ||||
-rw-r--r-- | storage/innobase/dict/dict0dict.cc | 14 | ||||
-rw-r--r-- | storage/innobase/dict/dict0load.cc | 4 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 21 | ||||
-rw-r--r-- | storage/innobase/include/sql_funcs.h | 35 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.cc | 8 |
11 files changed, 222 insertions, 23 deletions
diff --git a/mysql-test/main/create_or_replace.result b/mysql-test/main/create_or_replace.result index 5eca9239de5..cb66af9480a 100644 --- a/mysql-test/main/create_or_replace.result +++ b/mysql-test/main/create_or_replace.result @@ -874,3 +874,31 @@ select * from t2; a unlock tables; drop tables t2, t1; +# +# MDEV-28933 CREATE OR REPLACE fails to recreate same constraint name +# +use test; +create table t (a int primary key) engine=innodb; +create or replace table u ( +a int primary key, +constraint c foreign key d (a) references t (a)) engine=innodb; +select * from information_schema.innodb_sys_foreign; +ID FOR_NAME REF_NAME N_COLS TYPE +test/c test/u test/t 1 0 +select * from information_schema.innodb_sys_foreign_cols; +ID FOR_COL_NAME REF_COL_NAME POS +test/c a a 0 +create or replace table u ( +a int primary key, +constraint c foreign key d (a) references t (a)) engine=innodb; +select * from information_schema.innodb_sys_foreign; +ID FOR_NAME REF_NAME N_COLS TYPE +test/c test/u test/t 1 0 +select * from information_schema.innodb_sys_foreign_cols; +ID FOR_COL_NAME REF_COL_NAME POS +test/c a a 0 +drop tables u, t; +select * from information_schema.innodb_sys_foreign; +ID FOR_NAME REF_NAME N_COLS TYPE +select * from information_schema.innodb_sys_foreign_cols; +ID FOR_COL_NAME REF_COL_NAME POS diff --git a/mysql-test/main/create_or_replace.test b/mysql-test/main/create_or_replace.test index b0593e2d1cb..1df8f3aa066 100644 --- a/mysql-test/main/create_or_replace.test +++ b/mysql-test/main/create_or_replace.test @@ -675,3 +675,25 @@ unlock tables; drop tables t2, t1; --enable_service_connection + +--echo # +--echo # MDEV-28933 CREATE OR REPLACE fails to recreate same constraint name +--echo # +use test; +create table t (a int primary key) engine=innodb; +create or replace table u ( + a int primary key, + constraint c foreign key d (a) references t (a)) engine=innodb; + +select * from information_schema.innodb_sys_foreign; +select * from information_schema.innodb_sys_foreign_cols; + +create or replace table u ( + a int primary key, + constraint c foreign key d (a) references t (a)) engine=innodb; + +select * from information_schema.innodb_sys_foreign; +select * from information_schema.innodb_sys_foreign_cols; +drop tables u, t; +select * from information_schema.innodb_sys_foreign; +select * from information_schema.innodb_sys_foreign_cols; diff --git a/mysql-test/suite/innodb/r/foreign_key_not_windows.result b/mysql-test/suite/innodb/r/foreign_key_not_windows.result index aaff06f8d68..02b2e3c29af 100644 --- a/mysql-test/suite/innodb/r/foreign_key_not_windows.result +++ b/mysql-test/suite/innodb/r/foreign_key_not_windows.result @@ -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 511 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 511 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=latin1 COLLATE=latin1_swedish_ci +use test; +drop database `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎`; diff --git a/mysql-test/suite/innodb/t/foreign_key_not_windows.test b/mysql-test/suite/innodb/t/foreign_key_not_windows.test index e5f42a0ddab..67e8935c660 100644 --- a/mysql-test/suite/innodb/t/foreign_key_not_windows.test +++ b/mysql-test/suite/innodb/t/foreign_key_not_windows.test @@ -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`; diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result index b17deba1c1e..45824b3800e 100644 --- a/mysql-test/suite/versioning/r/foreign.result +++ b/mysql-test/suite/versioning/r/foreign.result @@ -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; Warnings: diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test index c94cff540c6..c1c9523b75f 100644 --- a/mysql-test/suite/versioning/t/foreign.test +++ b/mysql-test/suite/versioning/t/foreign.test @@ -303,6 +303,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, @@ -313,6 +316,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; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index d652324e909..e630f752d23 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1652,7 +1652,9 @@ dict_table_rename_in_cache( table->name.m_name); dict_mem_foreign_table_name_lookup_set(foreign, FALSE); } - 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; @@ -1796,10 +1798,14 @@ 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); + } } } diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index cb81e4008df..f57f278a32f 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -3144,8 +3144,8 @@ loop: 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); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c9ab5059e15..7470d18d048 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5176,7 +5176,7 @@ normalize_table_name_c_low( db_ptr = ptr + 1; norm_len = db_len + name_len + sizeof "/"; - ut_a(norm_len < FN_REFLEN - 1); + ut_a(norm_len < FN_REFLEN); memcpy(norm_name, db_ptr, db_len); @@ -12342,6 +12342,7 @@ create_table_info_t::create_foreign_keys() if (fk->constraint_name.str) { ulint db_len; + const bool tmp= m_create_info->is_atomic_replace(); /* Catenate 'databasename/' to the constraint name specified by the user: we conceive the constraint as @@ -12351,13 +12352,17 @@ create_table_info_t::create_foreign_keys() 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) { diff --git a/storage/innobase/include/sql_funcs.h b/storage/innobase/include/sql_funcs.h index 307756196b1..1506a2a5a48 100644 --- a/storage/innobase/include/sql_funcs.h +++ b/storage/innobase/include/sql_funcs.h @@ -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 := id_len - 1; + 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; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 5cc86dac24a..22a302f5de1 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2709,6 +2709,14 @@ 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", + (fk == 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", + (fk == RENAME_FK) && new_is_tmp); err = que_eval_sql(info, rename_constraint_ids, trx); |