Commit cf6c5176 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.
parent f1e1c133
......@@ -863,3 +863,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
......@@ -655,3 +655,25 @@ select * from t2;
unlock tables;
drop tables t2, t1;
--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;
......@@ -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
use test;
drop database `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎`;
......@@ -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`;
......@@ -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:
......
......@@ -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;
......
......@@ -1650,7 +1650,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;
......@@ -1794,10 +1796,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);
}
}
}
......
......@@ -3089,8 +3089,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);
......
......@@ -5250,7 +5250,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);
......@@ -12382,6 +12382,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
......@@ -12391,13 +12392,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) {
......
......@@ -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;
......
......@@ -2726,6 +2726,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);
......
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