Skip to content

Commit

Permalink
RENAME TABLE: 'preserve foreign key' behavior depends on existence of…
Browse files Browse the repository at this point in the history
… 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 <2607934+shlomi-noach@users.noreply.github.com>
  • Loading branch information
shlomi-noach authored and dbussink committed Dec 11, 2023
1 parent c5d9391 commit c2f1344
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 18 deletions.
2 changes: 0 additions & 2 deletions mysql-test/r/rename_preserve_foreign_key_child.result
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ CONSTRAINT `new_child_parent_fk` FOREIGN KEY (parent_id) REFERENCES parent_table
);
insert into _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl select * from child_table;
SET FOREIGN_KEY_CHECKS=1;
SET rename_table_preserve_foreign_key=1;
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;
SET rename_table_preserve_foreign_key=0;
show create table child_table;
Table Create Table
child_table CREATE TABLE `child_table` (
Expand Down
46 changes: 42 additions & 4 deletions mysql-test/r/rename_preserve_foreign_key_parent.result
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,47 @@ PRIMARY KEY (id)
);
insert into parent_table_new values (1, 7), (2, 7), (55, 7);
SET FOREIGN_KEY_CHECKS=1;
SET rename_table_preserve_foreign_key=1;
rename table parent_table to parent_table_old, parent_table_new to parent_table;
SET rename_table_preserve_foreign_key=0;
show create table child_table;
Table Create Table
child_table CREATE TABLE `child_table` (
`id` int NOT NULL,
`parent_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parent_id_idx` (`parent_id`),
CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `parent_table_old` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
rename table parent_table to parent_table_new, parent_table_old to parent_table;
show create table child_table;
Table Create Table
child_table CREATE TABLE `child_table` (
`id` int NOT NULL,
`parent_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parent_id_idx` (`parent_id`),
CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `parent_table` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
rename table parent_table to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
show create table child_table;
Table Create Table
child_table CREATE TABLE `child_table` (
`id` int NOT NULL,
`parent_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parent_id_idx` (`parent_id`),
CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `_84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
rename table _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl to parent_table;
show create table child_table;
Table Create Table
child_table CREATE TABLE `child_table` (
`id` int NOT NULL,
`parent_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parent_id_idx` (`parent_id`),
CONSTRAINT `child_parent_fk` FOREIGN KEY (`parent_id`) REFERENCES `parent_table` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
rename table parent_table to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl, parent_table_new to parent_table;
show create table child_table;
Table Create Table
child_table CREATE TABLE `child_table` (
Expand All @@ -44,15 +82,15 @@ id hint
55 7
delete from parent_table where id=1;
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`))
delete from parent_table_old where id=1;
delete from _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl where id=1;
insert into child_table values (14, 55);
alter table child_table force;
select id, hint from parent_table;
id hint
1 7
2 7
55 7
delete from parent_table_old;
delete from _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
delete from parent_table where id=2;
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`))
drop table if exists _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl, _vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410, child_table, child_table_old, child_table_new;
Expand Down
2 changes: 0 additions & 2 deletions mysql-test/t/rename_preserve_foreign_key_child.test
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ CREATE TABLE _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl (
insert into _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl select * from child_table;
# rename, preserving foreign key
SET FOREIGN_KEY_CHECKS=1;
SET rename_table_preserve_foreign_key=1;
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;
SET rename_table_preserve_foreign_key=0;
# child_table's foreign key definition should point to parent_table
show create table child_table;
select * from child_table;
Expand Down
20 changes: 14 additions & 6 deletions mysql-test/t/rename_preserve_foreign_key_parent.test
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,34 @@ CREATE TABLE parent_table_new (
PRIMARY KEY (id)
);
insert into parent_table_new values (1, 7), (2, 7), (55, 7);
# rename, preserving foreign key
# rename, using non-vitess names, expecting standard RENAME behavior
SET FOREIGN_KEY_CHECKS=1;
SET rename_table_preserve_foreign_key=1;
rename table parent_table to parent_table_old, parent_table_new to parent_table;
SET rename_table_preserve_foreign_key=0;
show create table child_table;
rename table parent_table to parent_table_new, parent_table_old to parent_table;
show create table child_table;
# rename, but only a single table named, expecting standard RENAME behavior
rename table parent_table to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
show create table child_table;
rename table _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl to parent_table;
show create table child_table;
# rename, preserving foreign key
rename table parent_table to _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl, parent_table_new to parent_table;
# child_table's foreign key definition should point to parent_table (formerly parent_table_new)
show create table child_table;
select id, hint from parent_table;
# Verify that child's FK is now associated with the newly instated `parent_table`:
--error ER_ROW_IS_REFERENCED_2
delete from parent_table where id=1;
# This should work, this table is no longer the parent of child_table
delete from parent_table_old where id=1;
# This should work, this table is no longer the parent of child_table, and also it is an internal table
delete from _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl where id=1;
# insert rows matching data only available in the new `parent_table`
insert into child_table values (14, 55);
# Rebuild child table. Foreign key should point to parent_table (the new one)
alter table child_table force;
select id, hint from parent_table;
# This should work:
delete from parent_table_old;
delete from _84371a37_6153_11eb_9917_f875a4d24e90_20210128122816_vrepl;
# This should error because of ON DELETE NO ACTION:
--error ER_ROW_IS_REFERENCED_2
delete from parent_table where id=2;
Expand Down
36 changes: 32 additions & 4 deletions sql/sql_rename.cc
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ static bool do_rename(THD *thd, Table_ref *ren_table, const char *new_db,
const char *new_table_name, const char *new_table_alias,
bool *int_commit_done,
std::set<handlerton *> *post_ddl_htons,
Foreign_key_parents_invalidator *fk_invalidator) {
Foreign_key_parents_invalidator *fk_invalidator, bool preserve_foreign_key) {
const char *new_alias = new_table_name;
const char *old_alias = ren_table->table_name;

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

DBUG_TRACE;

// PlanetScale patch: if _any_ table at all in this `RENAME` TABLE statement is an
// internal Vitess table, then apply a "preserve foreign key" logic to the `RENAME`.
// Also, there must be at least two renamed tables in this clause. Otherwise, again
// this is treated just as a normal MySQL `RENAME`.
// What we want to catch here are Vitess-specific `RENAME TABLE` statements that
// should preserve the foreign key.
bool preserve_foreign_key = false;
int count_renames = 0;
for (ren_table = table_list; ren_table; ren_table = new_table->next_local) {
new_table = ren_table->next_local;
{
Table_name_inspector table_inspector(ren_table->table_name);
if (table_inspector.skip_fk_checks()) {
preserve_foreign_key = true;
}
}
{
Table_name_inspector table_inspector(new_table->table_name);
if (table_inspector.skip_fk_checks()) {
preserve_foreign_key = true;
}
}
count_renames++;
}
if (count_renames < 2) {
preserve_foreign_key = false;
}

for (ren_table = table_list; ren_table; ren_table = new_table->next_local) {
new_table = ren_table->next_local;
if (do_rename(thd, ren_table, new_table->db, new_table->table_name,
new_table->alias, int_commit_done, post_ddl_htons,
fk_invalidator))
fk_invalidator, preserve_foreign_key))
return ren_table;
}
return nullptr;
Expand Down

0 comments on commit c2f1344

Please sign in to comment.