Skip to content

Commit 601c971

Browse files
shlomi-noachdbussink
authored andcommitted
RENAME TABLE: 'preserve foreign key' behavior depends on existence of Vitess internal tables in statement (mysql#94)
* RENAME TABLE: 'preserve foreign key' behavior depends on existence of Vitess internal tables in statement Signed-off-by: Shlomi Noach <[email protected]>
1 parent 796047d commit 601c971

5 files changed

+88
-18
lines changed

mysql-test/r/rename_preserve_foreign_key_child.result

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ CONSTRAINT `new_child_parent_fk` FOREIGN KEY (parent_id) REFERENCES parent_table
2727
);
2828
insert into _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl select * from child_table;
2929
SET FOREIGN_KEY_CHECKS=1;
30-
SET rename_table_preserve_foreign_key=1;
3130
rename table child_table to _vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410, _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl to child_table, _vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410 to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
32-
SET rename_table_preserve_foreign_key=0;
3331
show create table child_table;
3432
Table Create Table
3533
child_table CREATE TABLE `child_table` (

mysql-test/r/rename_preserve_foreign_key_parent.result

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,47 @@ PRIMARY KEY (id)
2525
);
2626
insert into parent_table_new values (1, 7), (2, 7), (55, 7);
2727
SET FOREIGN_KEY_CHECKS=1;
28-
SET rename_table_preserve_foreign_key=1;
2928
rename table parent_table to parent_table_old, parent_table_new to parent_table;
30-
SET rename_table_preserve_foreign_key=0;
29+
show create table child_table;
30+
Table Create Table
31+
child_table CREATE TABLE `child_table` (
32+
`id` int NOT NULL,
33+
`parent_id` int DEFAULT NULL,
34+
PRIMARY KEY (`id`),
35+
KEY `parent_id_idx` (`parent_id`),
36+
CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `parent_table_old` (`id`)
37+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
38+
rename table parent_table to parent_table_new, parent_table_old to parent_table;
39+
show create table child_table;
40+
Table Create Table
41+
child_table CREATE TABLE `child_table` (
42+
`id` int NOT NULL,
43+
`parent_id` int DEFAULT NULL,
44+
PRIMARY KEY (`id`),
45+
KEY `parent_id_idx` (`parent_id`),
46+
CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `parent_table` (`id`)
47+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
48+
rename table parent_table to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
49+
show create table child_table;
50+
Table Create Table
51+
child_table CREATE TABLE `child_table` (
52+
`id` int NOT NULL,
53+
`parent_id` int DEFAULT NULL,
54+
PRIMARY KEY (`id`),
55+
KEY `parent_id_idx` (`parent_id`),
56+
CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `_84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl` (`id`)
57+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
58+
rename table _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl to parent_table;
59+
show create table child_table;
60+
Table Create Table
61+
child_table CREATE TABLE `child_table` (
62+
`id` int NOT NULL,
63+
`parent_id` int DEFAULT NULL,
64+
PRIMARY KEY (`id`),
65+
KEY `parent_id_idx` (`parent_id`),
66+
CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `parent_table` (`id`)
67+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
68+
rename table parent_table to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl, parent_table_new to parent_table;
3169
show create table child_table;
3270
Table Create Table
3371
child_table CREATE TABLE `child_table` (
@@ -44,15 +82,15 @@ id hint
4482
55 7
4583
delete from parent_table where id=1;
4684
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child_table`, CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `parent_table` (`id`))
47-
delete from parent_table_old where id=1;
85+
delete from _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl where id=1;
4886
insert into child_table values (14, 55);
4987
alter table child_table force;
5088
select id, hint from parent_table;
5189
id hint
5290
1 7
5391
2 7
5492
55 7
55-
delete from parent_table_old;
93+
delete from _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
5694
delete from parent_table where id=2;
5795
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child_table`, CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `parent_table` (`id`))
5896
drop table if exists _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl, _vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410, child_table, child_table_old, child_table_new;

mysql-test/t/rename_preserve_foreign_key_child.test

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ CREATE TABLE _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl (
4040
insert into _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl select * from child_table;
4141
# rename, preserving foreign key
4242
SET FOREIGN_KEY_CHECKS=1;
43-
SET rename_table_preserve_foreign_key=1;
4443
rename table child_table to _vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410, _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl to child_table, _vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410 to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
45-
SET rename_table_preserve_foreign_key=0;
4644
# child_table's foreign key definition should point to parent_table
4745
show create table child_table;
4846
select * from child_table;

mysql-test/t/rename_preserve_foreign_key_parent.test

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,34 @@ CREATE TABLE parent_table_new (
3636
PRIMARY KEY (id)
3737
);
3838
insert into parent_table_new values (1, 7), (2, 7), (55, 7);
39-
# rename, preserving foreign key
39+
# rename, using non-vitess names, expecting standard RENAME behavior
4040
SET FOREIGN_KEY_CHECKS=1;
41-
SET rename_table_preserve_foreign_key=1;
4241
rename table parent_table to parent_table_old, parent_table_new to parent_table;
43-
SET rename_table_preserve_foreign_key=0;
42+
show create table child_table;
43+
rename table parent_table to parent_table_new, parent_table_old to parent_table;
44+
show create table child_table;
45+
# rename, but only a single table named, expecting standard RENAME behavior
46+
rename table parent_table to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
47+
show create table child_table;
48+
rename table _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl to parent_table;
49+
show create table child_table;
50+
# rename, preserving foreign key
51+
rename table parent_table to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl, parent_table_new to parent_table;
4452
# child_table's foreign key definition should point to parent_table (formerly parent_table_new)
4553
show create table child_table;
4654
select id, hint from parent_table;
4755
# Verify that child's FK is now associated with the newly instated `parent_table`:
4856
--error ER_ROW_IS_REFERENCED_2
4957
delete from parent_table where id=1;
50-
# This should work, this table is no longer the parent of child_table
51-
delete from parent_table_old where id=1;
58+
# This should work, this table is no longer the parent of child_table, and also it is an internal table
59+
delete from _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl where id=1;
5260
# insert rows matching data only available in the new `parent_table`
5361
insert into child_table values (14, 55);
5462
# Rebuild child table. Foreign key should point to parent_table (the new one)
5563
alter table child_table force;
5664
select id, hint from parent_table;
5765
# This should work:
58-
delete from parent_table_old;
66+
delete from _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
5967
# This should error because of ON DELETE NO ACTION:
6068
--error ER_ROW_IS_REFERENCED_2
6169
delete from parent_table where id=2;

sql/sql_rename.cc

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ static bool do_rename(THD *thd, Table_ref *ren_table, const char *new_db,
553553
const char *new_table_name, const char *new_table_alias,
554554
bool *int_commit_done,
555555
std::set<handlerton *> *post_ddl_htons,
556-
Foreign_key_parents_invalidator *fk_invalidator) {
556+
Foreign_key_parents_invalidator *fk_invalidator, bool preserve_foreign_key) {
557557
const char *new_alias = new_table_name;
558558
const char *old_alias = ren_table->table_name;
559559

@@ -795,10 +795,10 @@ static bool do_rename(THD *thd, Table_ref *ren_table, const char *new_db,
795795
} else {
796796
// rename successful
797797
if (hton->flags & HTON_SUPPORTS_FOREIGN_KEYS) {
798-
// If 'OPTION_RENAME_TABLE_PRESERVE_FOREIGN_KEY' is set, then we explicitly don't want to run `adjust_fks_for_rename_table`,
798+
// If 'preserve_foreign_key' is set, then we explicitly don't want to run `adjust_fks_for_rename_table`,
799799
// because we want the foreign key child to point to the newly instated table, rather than follow
800800
// the old, renamed table.
801-
if (thd_test_options(thd, OPTION_RENAME_TABLE_PRESERVE_FOREIGN_KEY)) {
801+
if (preserve_foreign_key) {
802802
if (adjust_fks_for_rename_table_with_preserve_fk(thd, ren_table->db, old_alias, new_db, new_alias, hton)) {
803803
// adjust FKs failed
804804
cleanup_required = true;
@@ -953,11 +953,39 @@ static Table_ref *rename_tables(THD *thd, Table_ref *table_list,
953953

954954
DBUG_TRACE;
955955

956+
// PlanetScale patch: if _any_ table at all in this `RENAME` TABLE statement is an
957+
// internal Vitess table, then apply a "preserve foreign key" logic to the `RENAME`.
958+
// Also, there must be at least two renamed tables in this clause. Otherwise, again
959+
// this is treated just as a normal MySQL `RENAME`.
960+
// What we want to catch here are Vitess-specific `RENAME TABLE` statements that
961+
// should preserve the foreign key.
962+
bool preserve_foreign_key = false;
963+
int count_renames = 0;
964+
for (ren_table = table_list; ren_table; ren_table = new_table->next_local) {
965+
new_table = ren_table->next_local;
966+
{
967+
Table_name_inspector table_inspector(ren_table->table_name);
968+
if (table_inspector.skip_fk_checks()) {
969+
preserve_foreign_key = true;
970+
}
971+
}
972+
{
973+
Table_name_inspector table_inspector(new_table->table_name);
974+
if (table_inspector.skip_fk_checks()) {
975+
preserve_foreign_key = true;
976+
}
977+
}
978+
count_renames++;
979+
}
980+
if (count_renames < 2) {
981+
preserve_foreign_key = false;
982+
}
983+
956984
for (ren_table = table_list; ren_table; ren_table = new_table->next_local) {
957985
new_table = ren_table->next_local;
958986
if (do_rename(thd, ren_table, new_table->db, new_table->table_name,
959987
new_table->alias, int_commit_done, post_ddl_htons,
960-
fk_invalidator))
988+
fk_invalidator, preserve_foreign_key))
961989
return ren_table;
962990
}
963991
return nullptr;

0 commit comments

Comments
 (0)