Skip to content

Commit

Permalink
Online DDL shadow table: rename referenced table name in self referen…
Browse files Browse the repository at this point in the history
…cing FK (#16205)

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
  • Loading branch information
shlomi-noach authored Jun 17, 2024
1 parent adef4c2 commit 6f85089
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
20 changes: 19 additions & 1 deletion go/vt/vttablet/onlineddl/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,6 @@ func (e *Executor) cutOverVReplMigration(ctx context.Context, s *VReplStream, sh
}

renameQuery := sqlparser.BuildParsedQuery(sqlSwapTables, onlineDDL.Table, sentryTableName, vreplTable, onlineDDL.Table, sentryTableName, vreplTable)

waitForRenameProcess := func() error {
// This function waits until it finds the RENAME TABLE... query running in MySQL's PROCESSLIST, or until timeout
// The function assumes that one of the renamed tables is locked, thus causing the RENAME to block. If nothing
Expand Down Expand Up @@ -1404,6 +1403,25 @@ func (e *Executor) duplicateCreateTable(ctx context.Context, onlineDDL *schema.O
}
newCreateTable = sqlparser.Clone(originalCreateTable)
newCreateTable.SetTable(newCreateTable.GetTable().Qualifier.CompliantName(), newTableName)

// If this table has a self-referencing foreign key constraint, ensure the referenced table gets renamed:
renameSelfFK := func(node sqlparser.SQLNode) (kontinue bool, err error) {
switch node := node.(type) {
case *sqlparser.ConstraintDefinition:
fk, ok := node.Details.(*sqlparser.ForeignKeyDefinition)
if !ok {
return true, nil
}
if referencedTableName := fk.ReferenceDefinition.ReferencedTable.Name.String(); referencedTableName == originalCreateTable.Table.Name.String() {
// This is a self-referencing foreign key
// We need to rename the referenced table as well
fk.ReferenceDefinition.ReferencedTable.Name = sqlparser.NewIdentifierCS(newTableName)
}
}
return true, nil
}
_ = sqlparser.Walk(renameSelfFK, newCreateTable)

// manipulate CreateTable statement: take care of constraints names which have to be
// unique across the schema
constraintMap, err = e.validateAndEditCreateTableStatement(onlineDDL, newCreateTable)
Expand Down
18 changes: 18 additions & 0 deletions go/vt/vttablet/onlineddl/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,24 @@ func TestDuplicateCreateTable(t *testing.T) {
expectSQL: "create table mytable (\n\tid int primary key,\n\ti int,\n\tconstraint f_bjj16562shq086ozik3zf6kjg foreign key (i) references parent (id) on delete cascade\n)",
expectMapSize: 1,
},
{
sql: "create table self (id int primary key, i int, constraint f foreign key (i) references self (id))",
newName: "mytable",
expectSQL: "create table mytable (\n\tid int primary key,\n\ti int,\n\tconstraint f_8aymb58nzb78l5jhq600veg6y foreign key (i) references mytable (id)\n)",
expectMapSize: 1,
},
{
sql: "create table self (id int primary key, i1 int, i2 int, constraint f1 foreign key (i1) references self (id), constraint f1 foreign key (i2) references parent (id))",
newName: "mytable",
expectSQL: `create table mytable (
id int primary key,
i1 int,
i2 int,
constraint f1_1rlsg9yls1t91i35zq5gyeoq7 foreign key (i1) references mytable (id),
constraint f1_59t4lvb1ncti6fxy27drad4jp foreign key (i2) references parent (id)
)`,
expectMapSize: 1,
},
}
for _, tcase := range tcases {
t.Run(tcase.sql, func(t *testing.T) {
Expand Down

0 comments on commit 6f85089

Please sign in to comment.