diff --git a/go/test/endtoend/vtgate/gen4/gen4_test.go b/go/test/endtoend/vtgate/gen4/gen4_test.go index a242ef0bb7a..ff18795fb5e 100644 --- a/go/test/endtoend/vtgate/gen4/gen4_test.go +++ b/go/test/endtoend/vtgate/gen4/gen4_test.go @@ -520,3 +520,40 @@ func TestDualJoinQueries(t *testing.T) { mcmp.Exec("select t.title, t2.id from t2 left join (select 'ABC' as title) as t on t.title = t2.tcol1") } + +// TestSchemaTrackingGlobalTables tests that schema tracking works as intended with global table routing. +// This test creates a new table in a schema and verifies we can query it without needing to add it to the vschema as long +// as the name of the table is unique. It also creates a table which is already in the vschema to ensure that we +// don't mark it as ambiguous when schema tracking also finds it. +func TestSchemaTrackingGlobalTables(t *testing.T) { + // Create a new vtgate connection. + tables := []string{"uniqueTableName", "t1"} + for _, table := range tables { + t.Run(table, func(t *testing.T) { + vtConn, err := mysql.Connect(context.Background(), &vtParams) + require.NoError(t, err) + defer vtConn.Close() + + // Create a new table in the unsharded keyspace such that it has a unique name that allows for global routing. + utils.Exec(t, vtConn, `use `+unshardedKs) + // Use the same schema as t1 from sharded_schema.sql + utils.Exec(t, vtConn, fmt.Sprintf(`create table if not exists %s(id bigint, col bigint, primary key(id))`, table)) + defer utils.Exec(t, vtConn, fmt.Sprintf(`drop table %s`, table)) + + // Wait for schema tracking to see this column. + err = utils.WaitForAuthoritative(t, unshardedKs, table, clusterInstance.VtgateProcess.ReadVSchema) + require.NoError(t, err) + + // Create a new vtgate connection. + vtConn2, err := mysql.Connect(context.Background(), &vtParams) + require.NoError(t, err) + defer vtConn2.Close() + + // Insert rows into the table and select them to verify we can use them. + utils.Exec(t, vtConn2, fmt.Sprintf(`insert into %s(id, col) values (10, 100),(20, 200)`, table)) + require.NoError(t, err) + utils.AssertMatches(t, vtConn2, fmt.Sprintf(`select * from %s order by id`, table), + `[[INT64(10) INT64(100)] [INT64(20) INT64(200)]]`) + }) + } +} diff --git a/go/vt/vtgate/vindexes/vschema.go b/go/vt/vtgate/vindexes/vschema.go index 3852bbfcde3..92bba97facf 100644 --- a/go/vt/vtgate/vindexes/vschema.go +++ b/go/vt/vtgate/vindexes/vschema.go @@ -356,7 +356,7 @@ func BuildVSchema(source *vschemapb.SrvVSchema, parser *sqlparser.Parser) (vsche buildKeyspaces(source, vschema, parser) // buildGlobalTables before buildReferences so that buildReferences can // resolve sources which reference global tables. - buildGlobalTables(source, vschema) + BuildGlobalTables(source, vschema, true) buildReferences(source, vschema) buildRoutingRule(source, vschema, parser) buildShardRoutingRule(source, vschema) @@ -461,7 +461,7 @@ func (vschema *VSchema) AddUDF(ksname, udfName string) error { return nil } -func buildGlobalTables(source *vschemapb.SrvVSchema, vschema *VSchema) { +func BuildGlobalTables(source *vschemapb.SrvVSchema, vschema *VSchema, skipIfAlreadyGlobal bool) { for ksname, ks := range source.Keyspaces { ksvschema := vschema.Keyspaces[ksname] // If the keyspace requires explicit routing, don't include any of @@ -469,15 +469,19 @@ func buildGlobalTables(source *vschemapb.SrvVSchema, vschema *VSchema) { if ks.RequireExplicitRouting { continue } - buildKeyspaceGlobalTables(vschema, ksvschema) + buildKeyspaceGlobalTables(vschema, ksvschema, skipIfAlreadyGlobal) } } -func buildKeyspaceGlobalTables(vschema *VSchema, ksvschema *KeyspaceSchema) { +func buildKeyspaceGlobalTables(vschema *VSchema, ksvschema *KeyspaceSchema, skipIfAlreadyGlobal bool) { for tname, t := range ksvschema.Tables { if gt, ok := vschema.globalTables[tname]; ok { // There is already an entry table stored in global tables // with this name. + if !skipIfAlreadyGlobal { + // Called when updating from schema tracking + continue + } if gt == nil { // Table name is already marked ambiguous, nothing to do. continue diff --git a/go/vt/vtgate/vschema_manager.go b/go/vt/vtgate/vschema_manager.go index 62ea2cd3455..a5167913a8c 100644 --- a/go/vt/vtgate/vschema_manager.go +++ b/go/vt/vtgate/vschema_manager.go @@ -194,6 +194,10 @@ func (vm *VSchemaManager) buildAndEnhanceVSchema(v *vschemapb.SrvVSchema) *vinde // We mark the keyspaces that have foreign key management in Vitess and have cyclic foreign keys // to have an error. This makes all queries against them to fail. markErrorIfCyclesInFk(vschema) + // Add tables from schema tracking into globally routable tables, if they are not already present. + // We need to skip if already present, to handle the case where MoveTables has switched traffic + // and removed the source vschema but not from the source database because user asked to --keep-data + vindexes.BuildGlobalTables(v, vschema, false) } return vschema }