diff --git a/go/test/endtoend/vtgate/foreignkey/fk_test.go b/go/test/endtoend/vtgate/foreignkey/fk_test.go index eb4ba14580e..3f59a247273 100644 --- a/go/test/endtoend/vtgate/foreignkey/fk_test.go +++ b/go/test/endtoend/vtgate/foreignkey/fk_test.go @@ -20,13 +20,15 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/test/endtoend/utils" ) // TestInsertWithFK tests that insertions work as expected when foreign key management is enabled in Vitess. func TestInsertWithFK(t *testing.T) { - conn, closer := start(t) + mcmp, closer := start(t) + conn := mcmp.VtConn defer closer() // insert some data. @@ -56,7 +58,8 @@ func TestInsertWithFK(t *testing.T) { // TestDeleteWithFK tests that deletions work as expected when foreign key management is enabled in Vitess. func TestDeleteWithFK(t *testing.T) { - conn, closer := start(t) + mcmp, closer := start(t) + conn := mcmp.VtConn defer closer() // insert some data. @@ -100,7 +103,8 @@ func TestDeleteWithFK(t *testing.T) { // TestUpdations tests that update work as expected when foreign key management is enabled in Vitess. func TestUpdateWithFK(t *testing.T) { - conn, closer := start(t) + mcmp, closer := start(t) + conn := mcmp.VtConn defer closer() // insert some data. @@ -157,3 +161,509 @@ func TestUpdateWithFK(t *testing.T) { utils.AssertMatches(t, conn, `select * from u_t2 order by id`, `[[INT64(19) INT64(1234)] [INT64(342) NULL]]`) utils.AssertMatches(t, conn, `select * from u_t3 order by id`, `[[INT64(1) INT64(12)] [INT64(32) INT64(13)]]`) } + +// TestFkScenarios tests the various foreign key scenarios with different constraints +// and makes sure that Vitess works with them as expected. All the tables are present in both sharded and unsharded keyspace +// and all the foreign key constraints are cross-shard ones for the sharded keyspace. +// The test has 4 independent Schemas that are used for testing - +/* + * fk_t1 + * │ + * │ On Delete Restrict + * │ On Update Restrict + * ▼ + * ┌────────────────fk_t2────────────────┐ + * │ │ + * │On Delete Set Null │ On Delete Set Null + * │On Update Set Null │ On Update Set Null + * ▼ ▼ + * fk_t7 fk_t3───────────────────┐ + * │ │ + * │ │ On Delete Set Null + * On Delete Set Null │ │ On Update Set Null + * On Update Set Null │ │ + * ▼ ▼ + * fk_t4 fk_t6 + * │ + * │ + * On Delete Restrict │ + * On Update Restrict │ + * │ + * ▼ + * fk_t5 + */ +/* + * fk_t10 + * │ + * On Delete Cascade │ + * On Update Cascade │ + * │ + * ▼ + * fk_t11──────────────────┐ + * │ │ + * │ │ On Delete Restrict + * On Delete Cascade │ │ On Update Restrict + * On Update Cascade │ │ + * │ │ + * ▼ ▼ + * fk_t12 fk_t13 + */ +/* + * fk_t15 + * │ + * │ + * On Delete Cascade │ + * On Update Cascade │ + * │ + * ▼ + * fk_t16 + * │ + * On Delete Set Null │ + * On Update Set Null │ + * │ + * ▼ + * fk_t17──────────────────┐ + * │ │ + * │ │ On Delete Set Null + * On Delete Cascade │ │ On Update Set Null + * On Update Cascade │ │ + * │ │ + * ▼ ▼ + * fk_t18 fk_t19 + */ +/* + Self referenced foreign key from col2 to col in fk_t20 +*/ +func TestFkScenarios(t *testing.T) { + // Wait for schema-tracking to be complete. + err := utils.WaitForColumn(t, clusterInstance.VtgateProcess, shardedKs, "fk_t1", "col") + require.NoError(t, err) + err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, shardedKs, "fk_t18", "col") + require.NoError(t, err) + err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, shardedKs, "fk_t11", "col") + require.NoError(t, err) + err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, unshardedKs, "fk_t1", "col") + require.NoError(t, err) + err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, unshardedKs, "fk_t18", "col") + require.NoError(t, err) + err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, unshardedKs, "fk_t11", "col") + require.NoError(t, err) + + testcases := []struct { + name string + dataQueries []string + dmlQuery string + assertionQueries []string + }{ + { + name: "Insert failure due to parent key not existing", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 5)", + }, + dmlQuery: "insert into t2(id, col) values (1, 7)", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + }, + }, { + name: "Insert success", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7)", + }, + dmlQuery: "insert into fk_t2(id, col) values (1, 7)", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + }, + }, { + name: "Update failure with restrict foreign keys", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7)", + "insert into fk_t2(id, col) values (1, 7)", + }, + dmlQuery: "update fk_t1 set col = 5 where id = 1", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + }, + }, { + name: "Update success with restrict foreign keys", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7), (2, 9)", + "insert into fk_t2(id, col) values (1, 7)", + }, + dmlQuery: "update fk_t1 set col = 5 where id = 2", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + }, + }, { + name: "Delete failure with restrict foreign keys", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7)", + "insert into fk_t2(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t1 where id = 1", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + }, + }, { + name: "Delete success with restrict foreign keys", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7), (2, 9)", + "insert into fk_t2(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t1 where id = 2", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + }, + }, { + name: "Update success with set null foreign key", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7), (2, 9)", + "insert into fk_t2(id, col) values (1, 7), (2, 9)", + "insert into fk_t3(id, col) values (1, 7), (2, 9)", + "insert into fk_t6(id, col) values (1, 7)", + }, + dmlQuery: "update fk_t3 set col = 9 where id = 1", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + "select * from fk_t3 order by id", + "select * from fk_t6 order by id", + }, + }, { + name: "Update failure with set null foreign key with child having a restrict foreign key", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7), (2, 9)", + "insert into fk_t2(id, col) values (1, 7), (2, 9)", + "insert into fk_t3(id, col) values (1, 7), (2, 9)", + "insert into fk_t4(id, col) values (1, 7)", + "insert into fk_t5(id, col) values (1, 7)", + }, + dmlQuery: "update fk_t3 set col = 9 where id = 1", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + "select * from fk_t3 order by id", + "select * from fk_t4 order by id", + "select * from fk_t5 order by id", + }, + }, { + name: "Update success with cascaded set nulls", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7), (2, 9)", + "insert into fk_t2(id, col) values (1, 7), (2, 9)", + "insert into fk_t3(id, col) values (1, 7), (2, 9)", + "insert into fk_t4(id, col) values (1, 7), (2, 9)", + "insert into fk_t6(id, col) values (1, 7), (2, 9)", + }, + dmlQuery: "update fk_t2 set col = 9 where id = 1", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + "select * from fk_t3 order by id", + "select * from fk_t4 order by id", + "select * from fk_t6 order by id", + }, + }, { + name: "Delete success with set null foreign key", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7), (2, 9)", + "insert into fk_t2(id, col) values (1, 7), (2, 9)", + "insert into fk_t3(id, col) values (1, 7), (2, 9)", + "insert into fk_t6(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t3 where id = 1", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + "select * from fk_t3 order by id", + "select * from fk_t6 order by id", + }, + }, { + name: "Delete failure with set null foreign key with child having a restrict foreign key", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7), (2, 9)", + "insert into fk_t2(id, col) values (1, 7), (2, 9)", + "insert into fk_t3(id, col) values (1, 7), (2, 9)", + "insert into fk_t4(id, col) values (1, 7)", + "insert into fk_t5(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t3 where id = 1", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + "select * from fk_t3 order by id", + "select * from fk_t4 order by id", + "select * from fk_t5 order by id", + }, + }, { + name: "Delete success with cascaded set nulls", + dataQueries: []string{ + "insert into fk_t1(id, col) values (1, 7), (2, 9)", + "insert into fk_t2(id, col) values (1, 7), (2, 9)", + "insert into fk_t3(id, col) values (1, 7), (2, 9)", + "insert into fk_t4(id, col) values (1, 7), (2, 9)", + "insert into fk_t6(id, col) values (1, 7), (2, 9)", + }, + dmlQuery: "delete from fk_t2 where id = 1", + assertionQueries: []string{ + "select * from fk_t1 order by id", + "select * from fk_t2 order by id", + "select * from fk_t3 order by id", + "select * from fk_t4 order by id", + "select * from fk_t6 order by id", + }, + }, { + name: "Update success with cascade foreign key", + dataQueries: []string{ + "insert into fk_t10(id, col) values (1, 7), (2, 9)", + "insert into fk_t11(id, col) values (1, 7)", + }, + dmlQuery: "update fk_t10 set col = 5 where id = 1", + assertionQueries: []string{ + "select * from fk_t10 order by id", + "select * from fk_t11 order by id", + }, + }, { + name: "Update failure with cascade foreign key with child having a restrict foreign key", + dataQueries: []string{ + "insert into fk_t10(id, col) values (1, 7), (2, 9)", + "insert into fk_t11(id, col) values (1, 7)", + "insert into fk_t13(id, col) values (1, 7)", + }, + dmlQuery: "update fk_t10 set col = 5 where id = 1", + assertionQueries: []string{ + "select * from fk_t10 order by id", + "select * from fk_t11 order by id", + "select * from fk_t13 order by id", + }, + }, { + name: "Update success with cascaded cascade foreign keys", + dataQueries: []string{ + "insert into fk_t10(id, col) values (1, 7), (2, 9)", + "insert into fk_t11(id, col) values (1, 7)", + "insert into fk_t12(id, col) values (1, 7)", + }, + dmlQuery: "update fk_t10 set col = 5 where id = 1", + assertionQueries: []string{ + "select * from fk_t10 order by id", + "select * from fk_t11 order by id", + "select * from fk_t12 order by id", + }, + }, { + name: "Delete success with cascade foreign key", + dataQueries: []string{ + "insert into fk_t10(id, col) values (1, 7), (2, 9)", + "insert into fk_t11(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t10 where id = 1", + assertionQueries: []string{ + "select * from fk_t10 order by id", + "select * from fk_t11 order by id", + }, + }, { + name: "Delete failure with cascade foreign key with child having a restrict foreign key", + dataQueries: []string{ + "insert into fk_t10(id, col) values (1, 7), (2, 9)", + "insert into fk_t11(id, col) values (1, 7)", + "insert into fk_t13(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t10 where id = 1", + assertionQueries: []string{ + "select * from fk_t10 order by id", + "select * from fk_t11 order by id", + "select * from fk_t13 order by id", + }, + }, { + name: "Delete success with cascaded cascade foreign keys", + dataQueries: []string{ + "insert into fk_t10(id, col) values (1, 7), (2, 9)", + "insert into fk_t11(id, col) values (1, 7)", + "insert into fk_t12(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t10 where id = 1", + assertionQueries: []string{ + "select * from fk_t10 order by id", + "select * from fk_t11 order by id", + "select * from fk_t12 order by id", + }, + }, { + name: "Delete success with set null to an update cascade foreign key", + dataQueries: []string{ + "insert into fk_t15(id, col) values (1, 7), (2, 9)", + "insert into fk_t16(id, col) values (1, 7), (2, 9)", + "insert into fk_t17(id, col) values (1, 7)", + "insert into fk_t18(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t16 where id = 1", + assertionQueries: []string{ + "select * from fk_t15 order by id", + "select * from fk_t16 order by id", + "select * from fk_t17 order by id", + "select * from fk_t18 order by id", + }, + }, { + name: "Delete success with cascade to delete with set null to an update set null foreign key", + dataQueries: []string{ + "insert into fk_t15(id, col) values (1, 7), (2, 9)", + "insert into fk_t16(id, col) values (1, 7), (2, 9)", + "insert into fk_t17(id, col) values (1, 7)", + "insert into fk_t19(id, col) values (1, 7)", + }, + dmlQuery: "delete from fk_t15 where id = 1", + assertionQueries: []string{ + "select * from fk_t15 order by id", + "select * from fk_t16 order by id", + "select * from fk_t17 order by id", + "select * from fk_t19 order by id", + }, + }, { + name: "Update success with cascade to an update set null to an update cascade foreign key", + dataQueries: []string{ + "insert into fk_t15(id, col) values (1, 7), (2, 9)", + "insert into fk_t16(id, col) values (1, 7), (2, 9)", + "insert into fk_t17(id, col) values (1, 7)", + "insert into fk_t18(id, col) values (1, 7)", + }, + dmlQuery: "update fk_t15 set col = 3 where id = 1", + assertionQueries: []string{ + "select * from fk_t15 order by id", + "select * from fk_t16 order by id", + "select * from fk_t17 order by id", + "select * from fk_t18 order by id", + }, + }, { + name: "Insert success for self-referenced foreign key", + dataQueries: []string{ + "insert into fk_t20(id, col, col2) values (1, 7, NULL)", + }, + dmlQuery: "insert into fk_t20(id, col, col2) values (2, 9, 7), (3, 10, 9)", + assertionQueries: []string{ + "select * from fk_t20 order by id", + }, + }, { + name: "Insert failure for self-referenced foreign key", + dataQueries: []string{ + "insert into fk_t20(id, col, col2) values (5, 7, NULL)", + }, + dmlQuery: "insert into fk_t20(id, col, col2) values (6, 9, 6)", + assertionQueries: []string{ + "select * from fk_t20 order by id", + }, + }, + } + + for _, tt := range testcases { + for _, testSharded := range []bool{false, true} { + t.Run(getTestName(tt.name, testSharded), func(t *testing.T) { + mcmp, closer := start(t) + defer closer() + // Set the correct keyspace to use from VtGates. + if testSharded { + t.Skip("Skip test since we don't have sharded foreign key support yet") + _ = utils.Exec(t, mcmp.VtConn, "use `ks`") + } else { + _ = utils.Exec(t, mcmp.VtConn, "use `uks`") + } + + // Insert all the data required for running the test. + for _, query := range tt.dataQueries { + mcmp.Exec(query) + } + + // Run the DML query that needs to be tested and verify output with MySQL. + _, _ = mcmp.ExecAllowAndCompareError(tt.dmlQuery) + + // Run the assertion queries and verify we get the expected outputs. + for _, query := range tt.assertionQueries { + mcmp.Exec(query) + } + }) + } + } + + for _, testSharded := range []bool{false, true} { + t.Run(getTestName("Transactions with intermediate failure", testSharded), func(t *testing.T) { + mcmp, closer := start(t) + defer closer() + // Set the correct keyspace to use from VtGates. + if testSharded { + t.Skip("Skip test since we don't have sharded foreign key support yet") + _ = utils.Exec(t, mcmp.VtConn, "use `ks`") + } else { + _ = utils.Exec(t, mcmp.VtConn, "use `uks`") + } + + // Insert some rows + mcmp.Exec("INSERT INTO fk_t10(id, col) VALUES (1, 7), (2, 9), (3, 5)") + mcmp.Exec("INSERT INTO fk_t11(id, col) VALUES (1, 7), (2, 9), (3, 5)") + mcmp.Exec("INSERT INTO fk_t12(id, col) VALUES (1, 7), (2, 9), (3, 5)") + + // Start a transaction + mcmp.Exec("BEGIN") + + // Insert another row. + mcmp.Exec("INSERT INTO fk_t13(id, col) VALUES (1, 7)") + + // Delete success for cascaded (2, 9) + mcmp.Exec("DELETE FROM fk_t10 WHERE id = 2") + + // Verify the results + mcmp.Exec("SELECT * FROM fk_t10 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t11 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t12 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t13 ORDER BY id") + + // Update that fails + _, err = mcmp.ExecAllowAndCompareError("UPDATE fk_t10 SET col = 15 WHERE id = 1") + require.Error(t, err) + + // Verify the results + // Since we are in a transaction, we still expect the transaction to be ongoing, with no change to the tables + // since the update should fail. + mcmp.Exec("SELECT * FROM fk_t10 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t11 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t12 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t13 ORDER BY id") + + // Update that is a success + mcmp.Exec("UPDATE fk_t10 SET col = 15 where id = 3") + + // Verify the results + mcmp.Exec("SELECT * FROM fk_t10 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t11 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t12 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t13 ORDER BY id") + + // Insert a new row + mcmp.Exec("INSERT INTO fk_t13(id, col) VALUES (3, 15)") + + // Verify the results + mcmp.Exec("SELECT * FROM fk_t10 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t11 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t12 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t13 ORDER BY id") + + // Rollback the transaction. + mcmp.Exec("ROLLBACK") + + // Verify the results + mcmp.Exec("SELECT * FROM fk_t10 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t11 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t12 ORDER BY id") + mcmp.Exec("SELECT * FROM fk_t13 ORDER BY id") + }) + } +} + +// getTestName prepends whether the test is for a sharded keyspace or not to the test name. +func getTestName(testName string, testSharded bool) string { + if testSharded { + return "Sharded - " + testName + } + return "Unsharded - " + testName +} diff --git a/go/test/endtoend/vtgate/foreignkey/main_test.go b/go/test/endtoend/vtgate/foreignkey/main_test.go index 9e1a799c2a1..cf0c76b5404 100644 --- a/go/test/endtoend/vtgate/foreignkey/main_test.go +++ b/go/test/endtoend/vtgate/foreignkey/main_test.go @@ -17,9 +17,9 @@ limitations under the License. package foreignkey import ( - "context" _ "embed" "flag" + "fmt" "os" "testing" @@ -34,6 +34,7 @@ import ( var ( clusterInstance *cluster.LocalProcessCluster vtParams mysql.ConnParams + mysqlParams mysql.ConnParams shardedKs = "ks" unshardedKs = "uks" Cell = "test" @@ -101,37 +102,51 @@ func TestMain(m *testing.M) { Port: clusterInstance.VtgateMySQLPort, } + connParams, closer, err := utils.NewMySQL(clusterInstance, shardedKs, shardedSchemaSQL) + if err != nil { + fmt.Println(err) + return 1 + } + defer closer() + mysqlParams = connParams return m.Run() }() os.Exit(exitCode) } -func start(t *testing.T) (*mysql.Conn, func()) { - conn, err := mysql.Connect(context.Background(), &vtParams) +func start(t *testing.T) (utils.MySQLCompare, func()) { + mcmp, err := utils.NewMySQLCompare(t, vtParams, mysqlParams) require.NoError(t, err) deleteAll := func() { - _ = utils.Exec(t, conn, "use `ks/-80`") + _ = utils.Exec(t, mcmp.VtConn, "use `ks/-80`") tables := []string{"t4", "t3", "t2", "t1", "multicol_tbl2", "multicol_tbl1"} + for i := 20; i > 0; i-- { + tables = append(tables, fmt.Sprintf("fk_t%v", i)) + } for _, table := range tables { - _ = utils.Exec(t, conn, "delete from "+table) + _, _ = mcmp.ExecAndIgnore("delete from " + table) } - _ = utils.Exec(t, conn, "use `ks/80-`") + _ = utils.Exec(t, mcmp.VtConn, "use `ks/80-`") for _, table := range tables { - _ = utils.Exec(t, conn, "delete from "+table) + _, _ = mcmp.ExecAndIgnore("delete from " + table) + } + _ = utils.Exec(t, mcmp.VtConn, "use `uks`") + tables = []string{"u_t1", "u_t2", "u_t3"} + for i := 20; i > 0; i-- { + tables = append(tables, fmt.Sprintf("fk_t%v", i)) } - _ = utils.Exec(t, conn, "use `uks`") - for _, table := range []string{"u_t1", "u_t2"} { - _ = utils.Exec(t, conn, "delete from "+table) + for _, table := range tables { + _, _ = mcmp.ExecAndIgnore("delete from " + table) } - _ = utils.Exec(t, conn, "use `ks`") + _ = utils.Exec(t, mcmp.VtConn, "use `ks`") } deleteAll() - return conn, func() { + return mcmp, func() { deleteAll() - conn.Close() + mcmp.Close() cluster.PanicHandler(t) } } diff --git a/go/test/endtoend/vtgate/foreignkey/sharded_schema.sql b/go/test/endtoend/vtgate/foreignkey/sharded_schema.sql index 8475104fecc..b530c982904 100644 --- a/go/test/endtoend/vtgate/foreignkey/sharded_schema.sql +++ b/go/test/endtoend/vtgate/foreignkey/sharded_schema.sql @@ -72,3 +72,226 @@ create table t6 primary key (pk), foreign key (sk, col1) references t5 (sk, col1) on delete restrict on update restrict ) Engine = InnoDB; + +/* + * fk_t1 + * │ + * │ On Delete Restrict + * │ On Update Restrict + * ▼ + * ┌────────────────fk_t2────────────────┐ + * │ │ + * │On Delete Set Null │ On Delete Set Null + * │On Update Set Null │ On Update Set Null + * ▼ ▼ + * fk_t7 fk_t3───────────────────┐ + * │ │ + * │ │ On Delete Set Null + * On Delete Set Null │ │ On Update Set Null + * On Update Set Null │ │ + * ▼ ▼ + * fk_t4 fk_t6 + * │ + * │ + * On Delete Restrict │ + * On Update Restrict │ + * │ + * ▼ + * fk_t5 + */ + +create table fk_t1 +( + id bigint, + col varchar(10), + primary key (id), + index(col) +) Engine = InnoDB; + +create table fk_t2 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t1(col) on delete restrict on update restrict +) Engine = InnoDB; + +create table fk_t3 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t2(col) on delete set null on update set null +) Engine = InnoDB; + +create table fk_t4 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t3(col) on delete set null on update set null +) Engine = InnoDB; + +create table fk_t5 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t4(col) on delete restrict on update restrict +) Engine = InnoDB; + +create table fk_t6 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t3(col) on delete set null on update set null +) Engine = InnoDB; + +create table fk_t7 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t2(col) on delete set null on update set null +) Engine = InnoDB; + +/* + * fk_t10 + * │ + * On Delete Cascade │ + * On Update Cascade │ + * │ + * ▼ + * fk_t11──────────────────┐ + * │ │ + * │ │ On Delete Restrict + * On Delete Cascade │ │ On Update Restrict + * On Update Cascade │ │ + * │ │ + * ▼ ▼ + * fk_t12 fk_t13 + */ + +create table fk_t10 +( + id bigint, + col varchar(10), + primary key (id), + index(col) +) Engine = InnoDB; + +create table fk_t11 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t10(col) on delete cascade on update cascade +) Engine = InnoDB; + +create table fk_t12 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t11(col) on delete cascade on update cascade +) Engine = InnoDB; + +create table fk_t13 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t11(col) on delete restrict on update restrict +) Engine = InnoDB; + +/* + * fk_t15 + * │ + * │ + * On Delete Cascade │ + * On Update Cascade │ + * │ + * ▼ + * fk_t16 + * │ + * On Delete Set Null │ + * On Update Set Null │ + * │ + * ▼ + * fk_t17──────────────────┐ + * │ │ + * │ │ On Delete Set Null + * On Delete Cascade │ │ On Update Set Null + * On Update Cascade │ │ + * │ │ + * ▼ ▼ + * fk_t18 fk_t19 + */ + +create table fk_t15 +( + id bigint, + col varchar(10), + primary key (id), + index(col) +) Engine = InnoDB; + +create table fk_t16 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t15(col) on delete cascade on update cascade +) Engine = InnoDB; + +create table fk_t17 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t16(col) on delete set null on update set null +) Engine = InnoDB; + +create table fk_t18 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t17(col) on delete cascade on update cascade +) Engine = InnoDB; + +create table fk_t19 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t17(col) on delete set null on update set null +) Engine = InnoDB; + +/* + Self referenced foreign key from col2 to col in fk_t20 +*/ + +create table fk_t20 +( + id bigint, + col varchar(10), + col2 varchar(10), + primary key (id), + index(col), + foreign key (col2) references fk_t20(col) on delete restrict on update restrict +) Engine = InnoDB; \ No newline at end of file diff --git a/go/test/endtoend/vtgate/foreignkey/sharded_vschema.json b/go/test/endtoend/vtgate/foreignkey/sharded_vschema.json index c80662b6852..074f08ce848 100644 --- a/go/test/endtoend/vtgate/foreignkey/sharded_vschema.json +++ b/go/test/endtoend/vtgate/foreignkey/sharded_vschema.json @@ -86,6 +86,134 @@ "name": "multicol_vdx" } ] + }, + "fk_t1": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t2": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t3": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t4": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t5": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t6": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t7": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t10": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t11": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t12": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t13": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t15": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t16": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t17": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t18": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] + }, + "fk_t19": { + "column_vindexes": [ + { + "column": "id", + "name": "xxhash" + } + ] } } } \ No newline at end of file diff --git a/go/test/endtoend/vtgate/foreignkey/unsharded_schema.sql b/go/test/endtoend/vtgate/foreignkey/unsharded_schema.sql index 9c21510046b..dc6cba7bb08 100644 --- a/go/test/endtoend/vtgate/foreignkey/unsharded_schema.sql +++ b/go/test/endtoend/vtgate/foreignkey/unsharded_schema.sql @@ -20,4 +20,228 @@ create table u_t3 col3 bigint, primary key (id), foreign key (col3) references u_t1 (col1) on delete cascade on update cascade +) Engine = InnoDB; + + +/* + * fk_t1 + * │ + * │ On Delete Restrict + * │ On Update Restrict + * ▼ + * ┌────────────────fk_t2────────────────┐ + * │ │ + * │On Delete Set Null │ On Delete Set Null + * │On Update Set Null │ On Update Set Null + * ▼ ▼ + * fk_t7 fk_t3───────────────────┐ + * │ │ + * │ │ On Delete Set Null + * On Delete Set Null │ │ On Update Set Null + * On Update Set Null │ │ + * ▼ ▼ + * fk_t4 fk_t6 + * │ + * │ + * On Delete Restrict │ + * On Update Restrict │ + * │ + * ▼ + * fk_t5 + */ + +create table fk_t1 +( + id bigint, + col varchar(10), + primary key (id), + index(col) +) Engine = InnoDB; + +create table fk_t2 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t1(col) on delete restrict on update restrict +) Engine = InnoDB; + +create table fk_t3 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t2(col) on delete set null on update set null +) Engine = InnoDB; + +create table fk_t4 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t3(col) on delete set null on update set null +) Engine = InnoDB; + +create table fk_t5 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t4(col) on delete restrict on update restrict +) Engine = InnoDB; + +create table fk_t6 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t3(col) on delete set null on update set null +) Engine = InnoDB; + +create table fk_t7 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t2(col) on delete set null on update set null +) Engine = InnoDB; + +/* + * fk_t10 + * │ + * On Delete Cascade │ + * On Update Cascade │ + * │ + * ▼ + * fk_t11──────────────────┐ + * │ │ + * │ │ On Delete Restrict + * On Delete Cascade │ │ On Update Restrict + * On Update Cascade │ │ + * │ │ + * ▼ ▼ + * fk_t12 fk_t13 + */ + +create table fk_t10 +( + id bigint, + col varchar(10), + primary key (id), + index(col) +) Engine = InnoDB; + +create table fk_t11 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t10(col) on delete cascade on update cascade +) Engine = InnoDB; + +create table fk_t12 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t11(col) on delete cascade on update cascade +) Engine = InnoDB; + +create table fk_t13 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t11(col) on delete restrict on update restrict +) Engine = InnoDB; + +/* + * fk_t15 + * │ + * │ + * On Delete Cascade │ + * On Update Cascade │ + * │ + * ▼ + * fk_t16 + * │ + * On Delete Set Null │ + * On Update Set Null │ + * │ + * ▼ + * fk_t17──────────────────┐ + * │ │ + * │ │ On Delete Set Null + * On Delete Cascade │ │ On Update Set Null + * On Update Cascade │ │ + * │ │ + * ▼ ▼ + * fk_t18 fk_t19 + */ + +create table fk_t15 +( + id bigint, + col varchar(10), + primary key (id), + index(col) +) Engine = InnoDB; + +create table fk_t16 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t15(col) on delete cascade on update cascade +) Engine = InnoDB; + +create table fk_t17 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t16(col) on delete set null on update set null +) Engine = InnoDB; + +create table fk_t18 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t17(col) on delete cascade on update cascade +) Engine = InnoDB; + +create table fk_t19 +( + id bigint, + col varchar(10), + primary key (id), + index(col), + foreign key (col) references fk_t17(col) on delete set null on update set null +) Engine = InnoDB; + +/* + Self referenced foreign key from col2 to col in fk_t20 +*/ + +create table fk_t20 +( + id bigint, + col varchar(10), + col2 varchar(10), + primary key (id), + index(col), + foreign key (col2) references fk_t20(col) on delete restrict on update restrict ) Engine = InnoDB; \ No newline at end of file diff --git a/go/test/endtoend/vtgate/foreignkey/unsharded_vschema.json b/go/test/endtoend/vtgate/foreignkey/unsharded_vschema.json index f46ecbe83c3..c0d2368849f 100644 --- a/go/test/endtoend/vtgate/foreignkey/unsharded_vschema.json +++ b/go/test/endtoend/vtgate/foreignkey/unsharded_vschema.json @@ -2,7 +2,23 @@ "sharded": false, "foreignKeyMode": "FK_MANAGED", "tables": { - "u_a": {}, - "u_b": {} + "u_t1": {}, + "u_t2": {}, + "fk_t1": {}, + "fk_t2": {}, + "fk_t3": {}, + "fk_t4": {}, + "fk_t5": {}, + "fk_t6": {}, + "fk_t7": {}, + "fk_t10": {}, + "fk_t11": {}, + "fk_t12": {}, + "fk_t13": {}, + "fk_t15": {}, + "fk_t16": {}, + "fk_t17": {}, + "fk_t18": {}, + "fk_t19": {} } } \ No newline at end of file