Skip to content

Commit fdf38b2

Browse files
fix: ignore internal tables in schema tracking (#15141)
Signed-off-by: Harshit Gangal <harshit@planetscale.com>
1 parent 209a74b commit fdf38b2

File tree

4 files changed

+124
-1
lines changed

4 files changed

+124
-1
lines changed

go/vt/vtgate/vschema_manager.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"vitess.io/vitess/go/vt/log"
2424
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
25+
"vitess.io/vitess/go/vt/schema"
2526
"vitess.io/vitess/go/vt/sqlparser"
2627
"vitess.io/vitess/go/vt/srvtopo"
2728
"vitess.io/vitess/go/vt/topo"
@@ -206,6 +207,10 @@ func (vm *VSchemaManager) updateFromSchema(vschema *vindexes.VSchema) {
206207
// in the tables.
207208
for tblName, tblInfo := range m {
208209
for _, fkDef := range tblInfo.ForeignKeys {
210+
// Ignore internal tables as part of foreign key references.
211+
if schema.IsInternalOperationTableName(fkDef.ReferenceDefinition.ReferencedTable.Name.String()) {
212+
continue
213+
}
209214
parentTbl, err := vschema.FindRoutedTable(ksName, fkDef.ReferenceDefinition.ReferencedTable.Name.String(), topodatapb.TabletType_PRIMARY)
210215
if err != nil {
211216
log.Errorf("error finding parent table %s: %v", fkDef.ReferenceDefinition.ReferencedTable.Name.String(), err)

go/vt/vtgate/vschema_manager_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,100 @@ func TestRebuildVSchema(t *testing.T) {
372372
}
373373
}
374374

375+
// TestVSchemaUpdateWithFKReferenceToInternalTables tests that any internal table as part of fk reference is ignored.
376+
func TestVSchemaUpdateWithFKReferenceToInternalTables(t *testing.T) {
377+
ks := &vindexes.Keyspace{Name: "ks"}
378+
cols1 := []vindexes.Column{{
379+
Name: sqlparser.NewIdentifierCI("id"),
380+
Type: querypb.Type_INT64,
381+
}}
382+
sqlparserCols1 := sqlparser.MakeColumns("id")
383+
384+
vindexTable_t1 := &vindexes.Table{
385+
Name: sqlparser.NewIdentifierCS("t1"),
386+
Keyspace: ks,
387+
Columns: cols1,
388+
ColumnListAuthoritative: true,
389+
}
390+
vindexTable_t2 := &vindexes.Table{
391+
Name: sqlparser.NewIdentifierCS("t2"),
392+
Keyspace: ks,
393+
Columns: cols1,
394+
ColumnListAuthoritative: true,
395+
}
396+
397+
vindexTable_t1.ChildForeignKeys = append(vindexTable_t1.ChildForeignKeys, vindexes.ChildFKInfo{
398+
Table: vindexTable_t2,
399+
ChildColumns: sqlparserCols1,
400+
ParentColumns: sqlparserCols1,
401+
OnDelete: sqlparser.SetNull,
402+
OnUpdate: sqlparser.Cascade,
403+
})
404+
vindexTable_t2.ParentForeignKeys = append(vindexTable_t2.ParentForeignKeys, vindexes.ParentFKInfo{
405+
Table: vindexTable_t1,
406+
ChildColumns: sqlparserCols1,
407+
ParentColumns: sqlparserCols1,
408+
})
409+
410+
vm := &VSchemaManager{}
411+
var vs *vindexes.VSchema
412+
vm.subscriber = func(vschema *vindexes.VSchema, _ *VSchemaStats) {
413+
vs = vschema
414+
vs.ResetCreated()
415+
}
416+
vm.schema = &fakeSchema{t: map[string]*vindexes.TableInfo{
417+
"t1": {Columns: cols1},
418+
"t2": {
419+
Columns: cols1,
420+
ForeignKeys: []*sqlparser.ForeignKeyDefinition{
421+
createFkDefinition([]string{"id"}, "t1", []string{"id"}, sqlparser.Cascade, sqlparser.SetNull),
422+
createFkDefinition([]string{"id"}, "_vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410", []string{"id"}, sqlparser.Cascade, sqlparser.SetNull),
423+
},
424+
},
425+
}}
426+
vm.VSchemaUpdate(&vschemapb.SrvVSchema{
427+
Keyspaces: map[string]*vschemapb.Keyspace{
428+
"ks": {
429+
ForeignKeyMode: vschemapb.Keyspace_managed,
430+
Tables: map[string]*vschemapb.Table{
431+
"t1": {Columns: []*vschemapb.Column{{Name: "id", Type: querypb.Type_INT64}}},
432+
"t2": {Columns: []*vschemapb.Column{{Name: "id", Type: querypb.Type_INT64}}},
433+
},
434+
},
435+
},
436+
}, nil)
437+
438+
utils.MustMatchFn(".globalTables", ".uniqueVindexes")(t, &vindexes.VSchema{
439+
RoutingRules: map[string]*vindexes.RoutingRule{},
440+
Keyspaces: map[string]*vindexes.KeyspaceSchema{
441+
"ks": {
442+
Keyspace: ks,
443+
ForeignKeyMode: vschemapb.Keyspace_managed,
444+
Vindexes: map[string]vindexes.Vindex{},
445+
Tables: map[string]*vindexes.Table{
446+
"t1": vindexTable_t1,
447+
"t2": vindexTable_t2,
448+
},
449+
},
450+
},
451+
}, vs)
452+
utils.MustMatch(t, vs, vm.currentVschema, "currentVschema should have same reference as Vschema")
453+
}
454+
455+
// createFkDefinition is a helper function to create a Foreign key definition struct from the columns used in it provided as list of strings.
456+
func createFkDefinition(childCols []string, parentTableName string, parentCols []string, onUpdate, onDelete sqlparser.ReferenceAction) *sqlparser.ForeignKeyDefinition {
457+
pKs, pTbl, _ := sqlparser.ParseTable(parentTableName)
458+
return &sqlparser.ForeignKeyDefinition{
459+
Source: sqlparser.MakeColumns(childCols...),
460+
ReferenceDefinition: &sqlparser.ReferenceDefinition{
461+
ReferencedTable: sqlparser.NewTableNameWithQualifier(pTbl, pKs),
462+
ReferencedColumns: sqlparser.MakeColumns(parentCols...),
463+
OnUpdate: onUpdate,
464+
OnDelete: onDelete,
465+
},
466+
}
467+
}
468+
375469
func makeTestVSchema(ks string, sharded bool, tbls map[string]*vindexes.Table) *vindexes.VSchema {
376470
keyspaceSchema := &vindexes.KeyspaceSchema{
377471
Keyspace: &vindexes.Keyspace{

go/vt/vttablet/endtoend/rpc_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,25 @@ func TestGetSchemaRPC(t *testing.T) {
169169
},
170170
getSchemaQueryType: querypb.SchemaTableType_ALL,
171171
getSchemaTables: []string{"vitess_temp1", "vitess_temp3", "unknown_table", "vitess_view3", "vitess_view1", "unknown_view"},
172+
}, {
173+
name: "Create some internal tables",
174+
queries: []string{
175+
"create table if not exists _vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410(id bigint primary key);",
176+
"create table vitess_temp1 (eid int);",
177+
"create view vitess_view1 as select eid from vitess_a",
178+
},
179+
deferQueries: []string{
180+
"drop table _vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410",
181+
"drop table vitess_temp1",
182+
"drop view vitess_view1",
183+
},
184+
mapToExpect: map[string]string{
185+
"vitess_view1": "CREATE ALGORITHM=UNDEFINED DEFINER=`vt_dba`@`localhost` SQL SECURITY DEFINER VIEW `vitess_view1` AS select `vitess_a`.`eid` AS `eid` from `vitess_a`",
186+
"vitess_temp1": "CREATE TABLE `vitess_temp1` (\n `eid` int DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci",
187+
// These shouldn't be part of the result, so we verify it is empty.
188+
"_vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410": "",
189+
},
190+
getSchemaQueryType: querypb.SchemaTableType_ALL,
172191
},
173192
}
174193

go/vt/vttablet/tabletserver/query_executor.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1172,7 +1172,12 @@ func (qre *QueryExecutor) executeGetSchemaQuery(query string, callback func(sche
11721172
return qre.execStreamSQL(conn, false /* isTransaction */, query, func(result *sqltypes.Result) error {
11731173
schemaDef := make(map[string]string)
11741174
for _, row := range result.Rows {
1175-
schemaDef[row[0].ToString()] = row[1].ToString()
1175+
tableName := row[0].ToString()
1176+
// Schema RPC should ignore the internal table in the response.
1177+
if schema.IsInternalOperationTableName(tableName) {
1178+
continue
1179+
}
1180+
schemaDef[tableName] = row[1].ToString()
11761181
}
11771182
return callback(&querypb.GetSchemaResponse{TableDefinition: schemaDef})
11781183
})

0 commit comments

Comments
 (0)