Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FK Actions: Handling interleaving & dropping issues correctly when dropping FKs #871

Merged
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
40fcfc9
MySQL foreign key action handling at the backend with warning generation
aasthabharill-google Jul 3, 2024
eaeaa22
Merge remote-tracking branch 'origin/master' into mysql-fkactions
aasthabharill-google Jul 3, 2024
66cf781
report_helpers issues fixed
aasthabharill-google Jul 3, 2024
51c08b0
Cleaning up comments
aasthabharill-google Jul 3, 2024
fef0511
Addressing review comments by Deep
aasthabharill-google Jul 4, 2024
0c3ce90
Cleaning up comments
aasthabharill-google Jul 4, 2024
2dcf829
Changing FK Action strings to constants
aasthabharill-google Jul 4, 2024
08b8a49
Merge branch 'mysql-fkactions' of https://github.com/aasthabharill/sp…
aasthabharill-google Jul 4, 2024
168fbba
testing
aasthabharill-google Jul 4, 2024
4d15322
Merge branch 'master' into mysql-fkactions
aasthabharill Jul 5, 2024
9a764e3
Postgres (in progress) + unconditional UI
aasthabharill-google Jul 5, 2024
6839c3f
Modified some unit tests
aasthabharill-google Jul 5, 2024
910974e
Merge branch 'mysql-fkactions' of https://github.com/aasthabharill/sp…
aasthabharill-google Jul 5, 2024
733b2d1
Postgres support + UI + warning message generation for unsupported di…
aasthabharill-google Jul 6, 2024
79b7bd6
Merge branch 'mysql-fkactions' into postgres-ui-fkactions
aasthabharill-google Jul 6, 2024
14a15b2
final code for Postgres + UI
aasthabharill-google Jul 8, 2024
3b5a02b
Unsupported sources warnings + Report tests
aasthabharill-google Jul 9, 2024
5c917ba
Merge branch 'master' into tests-warnings-fkactions
aasthabharill Jul 9, 2024
8b74afd
Merge branch 'master' into tests-warnings-fkactions
aasthabharill Jul 9, 2024
223546b
Addressing review comments by Deep
aasthabharill-google Jul 10, 2024
4ad222b
Merge branch 'tests-warnings-fkactions' of https://github.com/aasthab…
aasthabharill-google Jul 10, 2024
be97c33
Merge branch 'master' into tests-warnings-fkactions
aasthabharill Jul 10, 2024
e2f0208
resolving slice issue
aasthabharill-google Jul 10, 2024
5a00814
Merge branch 'tests-warnings-fkactions' of https://github.com/aasthab…
aasthabharill-google Jul 10, 2024
ca1fed7
unit test issue resolved
aasthabharill-google Jul 10, 2024
3302b3c
add interleave struct
aasthabharill-google Jul 10, 2024
060d390
Merge branch 'tests-warnings-fkactions' into interleave-fkactions
aasthabharill-google Jul 10, 2024
950d2e4
Foreign Key Actions: Interleaving + Drop Foreign Key properly handled
aasthabharill-google Jul 16, 2024
97f1929
Merge branch 'master' into interleave-fkactions
aasthabharill Jul 16, 2024
64e692d
Addressing reviews
aasthabharill-google Jul 18, 2024
7daf613
Merge branch 'interleave-fkactions' of https://github.com/aasthabhari…
aasthabharill-google Jul 18, 2024
1b49665
adding support for interleaving for sources without foreign key actio…
aasthabharill-google Jul 18, 2024
77f7043
improving TestCreateTable unit
aasthabharill-google Jul 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 101 additions & 99 deletions accessors/spanner/spanner_accessor_test.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions common/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ func getMigrationDataSchemaPatterns(conv *internal.Conv, migrationData *migratio
numIndexes += int32(len(table.Indexes))
depth := 0
tableId := table.Id
for conv.SpSchema[tableId].ParentId != "" {
for conv.SpSchema[tableId].ParentTable.Id != "" {
numInterleaves++
depth++
tableId = conv.SpSchema[tableId].ParentId
tableId = conv.SpSchema[tableId].ParentTable.Id
}
maxInterleaveDepth = int32(math.Max(float64(maxInterleaveDepth), float64(depth)))
}
Expand Down
14 changes: 10 additions & 4 deletions common/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,11 +521,12 @@ func ReadSpannerSchema(ctx context.Context, conv *internal.Conv, client *sp.Clie
conv.Unexpected(fmt.Sprintf("error trying to fetch interleave table info from schema: %v", err))
}
// Assign parents if any.
// TODO: Assign ParentTable.OnDelete too
aasthabharill marked this conversation as resolved.
Show resolved Hide resolved
for tableName, parentName := range parentTables {
tableId, _ := internal.GetTableIdFromSpName(conv.SpSchema, tableName)
parentTableId, _ := internal.GetTableIdFromSpName(conv.SpSchema, parentName)
spTable := conv.SpSchema[tableId]
spTable.ParentId = parentTableId
spTable.ParentTable.Id = parentTableId
conv.SpSchema[tableId] = spTable
}
return nil
Expand All @@ -542,8 +543,8 @@ func CompareSchema(sessionFileConv, actualSpannerConv *internal.Conv) error {
return fmt.Errorf("table %v not found in the spanner database schema but found in the session file. If this table does not need to be migrated, please exclude it during the schema conversion and migration process", sessionTable.Name)
}
spannerTable := actualSpannerConv.SpSchema[spannerTableId]
sessionTableParentName := sessionFileConv.SpSchema[sessionTable.ParentId].Name
spannerTableParentName := actualSpannerConv.SpSchema[spannerTable.ParentId].Name
sessionTableParentName := sessionFileConv.SpSchema[sessionTable.ParentTable.Id].Name
spannerTableParentName := actualSpannerConv.SpSchema[spannerTable.ParentTable.Id].Name

//table names should match
if sessionTable.Name != spannerTable.Name {
Expand All @@ -555,6 +556,11 @@ func CompareSchema(sessionFileConv, actualSpannerConv *internal.Conv) error {
return fmt.Errorf("parent table name don't match: session table %v, parent session table name: %v, spanner table %v, parent spanner table name: %v", sessionTable.Name, sessionTableParentName, spannerTable.Name, spannerTableParentName)
}

//parent table on delete actions should match
if sessionTable.ParentTable.OnDelete != spannerTable.ParentTable.OnDelete {
return fmt.Errorf("parent table on delete actions don't match: session table %v, parent session table name: %v, spanner table %v, parent spanner table name: %v", sessionTable.Name, sessionTable.ParentTable.OnDelete, spannerTable.Name, spannerTable.ParentTable.OnDelete)
}

//number of columns should match
if len(sessionTable.ColDefs) != len(spannerTable.ColDefs) {
return fmt.Errorf("number of columns don't match: session table %v, spanner table %v", sessionTable.Name, spannerTable.Name)
Expand Down Expand Up @@ -659,4 +665,4 @@ func SetDataflowTemplatePath(path string) {

func GetDataflowTemplatePath() string {
return dataflowTemplatePath
}
}
1 change: 1 addition & 0 deletions sources/spanner/infoschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ func (isi InfoSchemaImpl) GetIndexes(conv *internal.Conv, table common.SchemaAnd
return indexes, nil
}

// TODO: Extract & initialise ON DELETE action and return it (ON_DELETE_ACTION in information_schema.tables)
func (isi InfoSchemaImpl) GetInterleaveTables() (map[string]string, error) {
q := `SELECT table_name, parent_table_name FROM information_schema.tables
WHERE interleave_type = 'IN PARENT' AND table_type = 'BASE TABLE' AND table_schema = ''`
Expand Down
26 changes: 17 additions & 9 deletions spanner/ddl/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,14 @@ type Foreignkey struct {
OnUpdate string
}

// InterleavedParent encodes the following DDL definition:
//
// INTERLEAVE IN PARENT parent_name ON DELETE delete_rule
aasthabharill marked this conversation as resolved.
Show resolved Hide resolved
type InterleavedParent struct {
Id string
OnDelete string
}

// PrintForeignKey unparses the foreign keys.
func (k Foreignkey) PrintForeignKey(c Config) string {
var cols, referCols []string
Expand Down Expand Up @@ -311,7 +319,7 @@ type CreateTable struct {
PrimaryKeys []IndexKey
ForeignKeys []Foreignkey
Indexes []CreateIndex
ParentId string //if not empty, this table will be interleaved
ParentTable InterleavedParent //if not empty, this table will be interleaved
Comment string
Id string
}
Expand Down Expand Up @@ -353,14 +361,14 @@ func (ct CreateTable) PrintCreateTable(spSchema Schema, config Config) string {
}

var interleave string
if ct.ParentId != "" {
parent := spSchema[ct.ParentId].Name
if ct.ParentTable.Id != "" {
parent := spSchema[ct.ParentTable.Id].Name
if config.SpDialect == constants.DIALECT_POSTGRESQL {
// PG spanner only supports PRIMARY KEY() inside the CREATE TABLE()
// and thus INTERLEAVE follows immediately after closing brace.
interleave = " INTERLEAVE IN PARENT " + config.quote(parent)
interleave = " INTERLEAVE IN PARENT " + config.quote(parent) + " ON DELETE " + ct.ParentTable.OnDelete
} else {
interleave = ",\nINTERLEAVE IN PARENT " + config.quote(parent)
interleave = ",\nINTERLEAVE IN PARENT " + config.quote(parent) + " ON DELETE " + ct.ParentTable.OnDelete
}
}

Expand Down Expand Up @@ -507,14 +515,14 @@ func GetSortedTableIdsBySpName(s Schema) []string {
table := s[tableNameIdMap[tableName]]
tableQueue = tableQueue[1:]
parentTableExists := false
if table.ParentId != "" {
_, parentTableExists = s[table.ParentId]
if table.ParentTable.Id != "" {
_, parentTableExists = s[table.ParentTable.Id]
}

// Add table t if either:
// a) t is not interleaved in another table, or
// b) t is interleaved in another table and that table has already been added to the list.
if table.ParentId == "" || tableAdded[s[table.ParentId].Name] || !parentTableExists {
if table.ParentTable.Id == "" || tableAdded[s[table.ParentTable.Id].Name] || !parentTableExists {
sortedTableNames = append(sortedTableNames, tableName)
tableAdded[tableName] = true
} else {
Expand Down Expand Up @@ -578,7 +586,7 @@ func GetDDL(c Config, tableSchema Schema, sequenceSchema map[string]Sequence) []
// CheckInterleaved checks if schema contains interleaved tables.
func (s Schema) CheckInterleaved() bool {
for _, table := range s {
if table.ParentId != "" {
if table.ParentTable.Id != "" {
return true
}
}
Expand Down
116 changes: 59 additions & 57 deletions spanner/ddl/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,29 +133,30 @@ func TestPrintCreateTable(t *testing.T) {
cds["col1"] = ColumnDef{Name: "col1", T: Type{Name: Int64}, NotNull: true}
cds["col2"] = ColumnDef{Name: "col2", T: Type{Name: String, Len: MaxLength}, NotNull: false}
cds["col3"] = ColumnDef{Name: "col3", T: Type{Name: Bytes, Len: int64(42)}, NotNull: false}

t1 := CreateTable{
"mytable",
[]string{"col1", "col2", "col3"},
"",
cds,
[]IndexKey{{ColId: "col1", Desc: true}},
nil,
nil,
"",
"",
"1",
Name: "mytable",
ColIds: []string{"col1", "col2", "col3"},
ShardIdColumn: "",
ColDefs: cds,
PrimaryKeys: []IndexKey{{ColId: "col1", Desc: true}},
ForeignKeys: nil,
Indexes: nil,
ParentTable: InterleavedParent{},
Comment: "",
Id: "1",
}
t2 := CreateTable{
"mytable",
[]string{"col1", "col2", "col3"},
"",
cds,
[]IndexKey{{ColId: "col1", Desc: true}},
nil,
nil,
"parent",
"",
"1",
Name: "mytable",
ColIds: []string{"col1", "col2", "col3"},
ShardIdColumn: "",
ColDefs: cds,
PrimaryKeys: []IndexKey{{ColId: "col1", Desc: true}},
ForeignKeys: nil,
Indexes: nil,
ParentTable: InterleavedParent{Id: "par1", OnDelete: constants.FK_CASCADE},
Comment: "",
Id: "1",
}
tests := []struct {
name string
Expand Down Expand Up @@ -192,7 +193,7 @@ func TestPrintCreateTable(t *testing.T) {
" col2 STRING(MAX),\n" +
" col3 BYTES(42),\n" +
") PRIMARY KEY (col1 DESC),\n" +
"INTERLEAVE IN PARENT ",
"INTERLEAVE IN PARENT ON DELETE CASCADE",
aasthabharill marked this conversation as resolved.
Show resolved Hide resolved
},
}
for _, tc := range tests {
Expand All @@ -205,29 +206,30 @@ func TestPrintCreateTablePG(t *testing.T) {
cds["col1"] = ColumnDef{Name: "col1", T: Type{Name: Int64}, NotNull: true}
cds["col2"] = ColumnDef{Name: "col2", T: Type{Name: String, Len: MaxLength}, NotNull: false}
cds["col3"] = ColumnDef{Name: "col3", T: Type{Name: Bytes, Len: int64(42)}, NotNull: false}

t1 := CreateTable{
"mytable",
[]string{"col1", "col2", "col3"},
"",
cds,
[]IndexKey{{ColId: "col1", Desc: true}},
nil,
nil,
"",
"",
"1",
Name: "mytable",
ColIds: []string{"col1", "col2", "col3"},
ShardIdColumn: "",
ColDefs: cds,
PrimaryKeys: []IndexKey{{ColId: "col1", Desc: true}},
ForeignKeys: nil,
Indexes: nil,
ParentTable: InterleavedParent{},
Comment: "",
Id: "1",
}
t2 := CreateTable{
"mytable",
[]string{"col1", "col2", "col3"},
"",
cds,
[]IndexKey{{ColId: "col1", Desc: true}},
nil,
nil,
"parent",
"",
"1",
Name: "mytable",
ColIds: []string{"col1", "col2", "col3"},
ShardIdColumn: "",
ColDefs: cds,
PrimaryKeys: []IndexKey{{ColId: "col1", Desc: true}},
ForeignKeys: nil,
Indexes: nil,
ParentTable: InterleavedParent{Id: "par1", OnDelete: constants.FK_CASCADE},
Comment: "",
Id: "1",
}
tests := []struct {
name string
Expand Down Expand Up @@ -266,7 +268,7 @@ func TestPrintCreateTablePG(t *testing.T) {
" col2 VARCHAR(2621440),\n" +
" col3 BYTEA,\n" +
" PRIMARY KEY (col1 DESC)\n" +
") INTERLEAVE IN PARENT ",
") INTERLEAVE IN PARENT ON DELETE CASCADE",
},
}
for _, tc := range tests {
Expand Down Expand Up @@ -631,7 +633,7 @@ func TestGetDDL(t *testing.T) {
"c9": {Name: "c", Id: "c9", T: Type{Name: Int64}},
},
PrimaryKeys: []IndexKey{{ColId: "c7"}, {ColId: "c8"}},
ParentId: "t1",
ParentTable: InterleavedParent{Id: "t1", OnDelete: constants.FK_NO_ACTION},
},
}
tablesOnly := GetDDL(Config{Tables: true, ForeignKeys: false}, s, make(map[string]Sequence))
Expand All @@ -652,7 +654,7 @@ func TestGetDDL(t *testing.T) {
" b INT64,\n" +
" c INT64,\n" +
") PRIMARY KEY (a, b),\n" +
"INTERLEAVE IN PARENT table1",
"INTERLEAVE IN PARENT table1 ON DELETE NO ACTION",
}
assert.ElementsMatch(t, e, tablesOnly)

Expand Down Expand Up @@ -681,7 +683,7 @@ func TestGetDDL(t *testing.T) {
" b INT64,\n" +
" c INT64,\n" +
") PRIMARY KEY (a, b),\n" +
"INTERLEAVE IN PARENT table1",
"INTERLEAVE IN PARENT table1 ON DELETE NO ACTION",
"ALTER TABLE table1 ADD CONSTRAINT fk1 FOREIGN KEY (b) REFERENCES table2 (b) ON DELETE CASCADE",
"ALTER TABLE table2 ADD CONSTRAINT fk2 FOREIGN KEY (b, c) REFERENCES table3 (b, c) ON DELETE NO ACTION",
}
Expand Down Expand Up @@ -739,7 +741,7 @@ func TestGetPGDDL(t *testing.T) {
"c8": {Name: "c", Id: "c8", T: Type{Name: Int64}},
},
PrimaryKeys: []IndexKey{{ColId: "c6"}, {ColId: "c7"}},
ParentId: "t1",
ParentTable: InterleavedParent{Id: "t1", OnDelete: constants.FK_NO_ACTION},
},
}
tablesOnly := GetDDL(Config{Tables: true, ForeignKeys: false, SpDialect: constants.DIALECT_POSTGRESQL}, s, make(map[string]Sequence))
Expand All @@ -762,7 +764,7 @@ func TestGetPGDDL(t *testing.T) {
" b INT8,\n" +
" c INT8,\n" +
" PRIMARY KEY (a, b)\n" +
") INTERLEAVE IN PARENT table1",
") INTERLEAVE IN PARENT table1 ON DELETE NO ACTION",
}
assert.ElementsMatch(t, e, tablesOnly)

Expand Down Expand Up @@ -793,7 +795,7 @@ func TestGetPGDDL(t *testing.T) {
" b INT8,\n" +
" c INT8,\n" +
" PRIMARY KEY (a, b)\n" +
") INTERLEAVE IN PARENT table1",
") INTERLEAVE IN PARENT table1 ON DELETE NO ACTION",
"ALTER TABLE table1 ADD CONSTRAINT fk1 FOREIGN KEY (b) REFERENCES table2 (b) ON DELETE CASCADE",
"ALTER TABLE table2 ADD CONSTRAINT fk2 FOREIGN KEY (b, c) REFERENCES table3 (b, c) ON DELETE NO ACTION",
}
Expand Down Expand Up @@ -846,14 +848,14 @@ func TestGetSortedTableIdsBySpName(t *testing.T) {
Id: "table_id_1",
},
"table_id_2": CreateTable{
Name: "Table2",
Id: "table_id_2",
ParentId: "table_id_1",
Name: "Table2",
Id: "table_id_2",
ParentTable: InterleavedParent{Id: "table_id_1", OnDelete: constants.FK_CASCADE},
},
"table_id_3": CreateTable{
Name: "Table3",
Id: "table_id_3",
ParentId: "table_id_2",
Name: "Table3",
Id: "table_id_3",
ParentTable: InterleavedParent{Id: "table_id_2", OnDelete: constants.FK_NO_ACTION},
},
},
expected: []string{"table_id_1", "table_id_2", "table_id_3"},
Expand All @@ -878,9 +880,9 @@ func TestGetSortedTableIdsBySpName(t *testing.T) {
description: "Schema with a table having a non-existent parent",
schema: Schema{
"table_id_1": CreateTable{
Name: "Table1",
Id: "table_id_1",
ParentId: "table_id_2",
Name: "Table1",
Id: "table_id_1",
ParentTable: InterleavedParent{Id: "table_id_2", OnDelete: constants.FK_NO_ACTION},
},
},
expected: []string{"table_id_1"},
Expand Down
2 changes: 1 addition & 1 deletion test_data/basic_session_file_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
],
"ForeignKeys": null,
"Indexes": null,
"ParentId": "",
"ParentTable": {"Id": "", "OnDelete": ""},
"Comment": "Spanner schema for source table numbers",
aasthabharill marked this conversation as resolved.
Show resolved Hide resolved
"Id": "t1"
}
Expand Down
2 changes: 1 addition & 1 deletion test_data/basic_sessions_file_wo_sequences_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
],
"ForeignKeys": null,
"Indexes": null,
"ParentId": "",
"ParentTable": {"Id": "", "OnDelete": ""},
"Comment": "Spanner schema for source table numbers",
"Id": "t1"
}
Expand Down
4 changes: 2 additions & 2 deletions test_data/mysql_interleave_session_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
}
],
"Indexes": null,
"ParentId": "",
"ParentTable": {"Id": "", "OnDelete": ""},
"Comment": "Spanner schema for source table cart",
"Id": "t46"
},
Expand Down Expand Up @@ -101,7 +101,7 @@
],
"ForeignKeys": null,
"Indexes": null,
"ParentId": "",
"ParentTable": {"Id": "", "OnDelete": ""},
"Comment": "Spanner schema for source table user",
"Id": "t51"
}
Expand Down
2 changes: 1 addition & 1 deletion ui/dist/ui/index.html

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading
Loading