Skip to content

Commit f2654cc

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

File tree

4 files changed

+160
-51
lines changed

4 files changed

+160
-51
lines changed

go/vt/vtgate/vschema_manager.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"vitess.io/vitess/go/vt/graph"
2424
"vitess.io/vitess/go/vt/log"
2525
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
26+
"vitess.io/vitess/go/vt/schema"
2627
"vitess.io/vitess/go/vt/sqlparser"
2728
"vitess.io/vitess/go/vt/srvtopo"
2829
"vitess.io/vitess/go/vt/topo"
@@ -217,6 +218,10 @@ func (vm *VSchemaManager) updateFromSchema(vschema *vindexes.VSchema) {
217218
continue
218219
}
219220
for _, fkDef := range tblInfo.ForeignKeys {
221+
// Ignore internal tables as part of foreign key references.
222+
if schema.IsInternalOperationTableName(fkDef.ReferenceDefinition.ReferencedTable.Name.String()) {
223+
continue
224+
}
220225
parentTbl, err := vschema.FindRoutedTable(ksName, fkDef.ReferenceDefinition.ReferencedTable.Name.String(), topodatapb.TabletType_PRIMARY)
221226
if err != nil {
222227
log.Errorf("error finding parent table %s: %v", fkDef.ReferenceDefinition.ReferencedTable.Name.String(), err)

go/vt/vtgate/vschema_manager_test.go

Lines changed: 130 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -438,56 +438,6 @@ func TestRebuildVSchema(t *testing.T) {
438438
}
439439
}
440440

441-
func makeTestVSchema(ks string, sharded bool, tbls map[string]*vindexes.Table) *vindexes.VSchema {
442-
keyspaceSchema := &vindexes.KeyspaceSchema{
443-
Keyspace: &vindexes.Keyspace{
444-
Name: ks,
445-
Sharded: sharded,
446-
},
447-
// Default foreign key mode
448-
ForeignKeyMode: vschemapb.Keyspace_unmanaged,
449-
Tables: tbls,
450-
Vindexes: map[string]vindexes.Vindex{},
451-
}
452-
vs := makeTestEmptyVSchema()
453-
vs.Keyspaces[ks] = keyspaceSchema
454-
vs.ResetCreated()
455-
return vs
456-
}
457-
458-
func makeTestEmptyVSchema() *vindexes.VSchema {
459-
return &vindexes.VSchema{
460-
RoutingRules: map[string]*vindexes.RoutingRule{},
461-
Keyspaces: map[string]*vindexes.KeyspaceSchema{},
462-
}
463-
}
464-
465-
func makeTestSrvVSchema(ks string, sharded bool, tbls map[string]*vschemapb.Table) *vschemapb.SrvVSchema {
466-
keyspaceSchema := &vschemapb.Keyspace{
467-
Sharded: sharded,
468-
Tables: tbls,
469-
// Default foreign key mode
470-
ForeignKeyMode: vschemapb.Keyspace_unmanaged,
471-
}
472-
return &vschemapb.SrvVSchema{
473-
Keyspaces: map[string]*vschemapb.Keyspace{ks: keyspaceSchema},
474-
}
475-
}
476-
477-
type fakeSchema struct {
478-
t map[string]*vindexes.TableInfo
479-
}
480-
481-
func (f *fakeSchema) Tables(string) map[string]*vindexes.TableInfo {
482-
return f.t
483-
}
484-
485-
func (f *fakeSchema) Views(string) map[string]sqlparser.SelectStatement {
486-
return nil
487-
}
488-
489-
var _ SchemaInfo = (*fakeSchema)(nil)
490-
491441
func TestMarkErrorIfCyclesInFk(t *testing.T) {
492442
ksName := "ks"
493443
keyspace := &vindexes.Keyspace{
@@ -573,6 +523,86 @@ func TestMarkErrorIfCyclesInFk(t *testing.T) {
573523
}
574524
}
575525

526+
// TestVSchemaUpdateWithFKReferenceToInternalTables tests that any internal table as part of fk reference is ignored.
527+
func TestVSchemaUpdateWithFKReferenceToInternalTables(t *testing.T) {
528+
ks := &vindexes.Keyspace{Name: "ks"}
529+
cols1 := []vindexes.Column{{
530+
Name: sqlparser.NewIdentifierCI("id"),
531+
Type: querypb.Type_INT64,
532+
}}
533+
sqlparserCols1 := sqlparser.MakeColumns("id")
534+
535+
vindexTable_t1 := &vindexes.Table{
536+
Name: sqlparser.NewIdentifierCS("t1"),
537+
Keyspace: ks,
538+
Columns: cols1,
539+
ColumnListAuthoritative: true,
540+
}
541+
vindexTable_t2 := &vindexes.Table{
542+
Name: sqlparser.NewIdentifierCS("t2"),
543+
Keyspace: ks,
544+
Columns: cols1,
545+
ColumnListAuthoritative: true,
546+
}
547+
548+
vindexTable_t1.ChildForeignKeys = append(vindexTable_t1.ChildForeignKeys, vindexes.ChildFKInfo{
549+
Table: vindexTable_t2,
550+
ChildColumns: sqlparserCols1,
551+
ParentColumns: sqlparserCols1,
552+
OnDelete: sqlparser.SetNull,
553+
OnUpdate: sqlparser.Cascade,
554+
})
555+
vindexTable_t2.ParentForeignKeys = append(vindexTable_t2.ParentForeignKeys, vindexes.ParentFKInfo{
556+
Table: vindexTable_t1,
557+
ChildColumns: sqlparserCols1,
558+
ParentColumns: sqlparserCols1,
559+
})
560+
561+
vm := &VSchemaManager{}
562+
var vs *vindexes.VSchema
563+
vm.subscriber = func(vschema *vindexes.VSchema, _ *VSchemaStats) {
564+
vs = vschema
565+
vs.ResetCreated()
566+
}
567+
vm.schema = &fakeSchema{t: map[string]*vindexes.TableInfo{
568+
"t1": {Columns: cols1},
569+
"t2": {
570+
Columns: cols1,
571+
ForeignKeys: []*sqlparser.ForeignKeyDefinition{
572+
createFkDefinition([]string{"id"}, "t1", []string{"id"}, sqlparser.Cascade, sqlparser.SetNull),
573+
createFkDefinition([]string{"id"}, "_vt_HOLD_6ace8bcef73211ea87e9f875a4d24e90_20200915120410", []string{"id"}, sqlparser.Cascade, sqlparser.SetNull),
574+
},
575+
},
576+
}}
577+
vm.VSchemaUpdate(&vschemapb.SrvVSchema{
578+
Keyspaces: map[string]*vschemapb.Keyspace{
579+
"ks": {
580+
ForeignKeyMode: vschemapb.Keyspace_managed,
581+
Tables: map[string]*vschemapb.Table{
582+
"t1": {Columns: []*vschemapb.Column{{Name: "id", Type: querypb.Type_INT64}}},
583+
"t2": {Columns: []*vschemapb.Column{{Name: "id", Type: querypb.Type_INT64}}},
584+
},
585+
},
586+
},
587+
}, nil)
588+
589+
utils.MustMatchFn(".globalTables", ".uniqueVindexes")(t, &vindexes.VSchema{
590+
RoutingRules: map[string]*vindexes.RoutingRule{},
591+
Keyspaces: map[string]*vindexes.KeyspaceSchema{
592+
"ks": {
593+
Keyspace: ks,
594+
ForeignKeyMode: vschemapb.Keyspace_managed,
595+
Vindexes: map[string]vindexes.Vindex{},
596+
Tables: map[string]*vindexes.Table{
597+
"t1": vindexTable_t1,
598+
"t2": vindexTable_t2,
599+
},
600+
},
601+
},
602+
}, vs)
603+
utils.MustMatch(t, vs, vm.currentVschema, "currentVschema should have same reference as Vschema")
604+
}
605+
576606
// createFkDefinition is a helper function to create a Foreign key definition struct from the columns used in it provided as list of strings.
577607
func createFkDefinition(childCols []string, parentTableName string, parentCols []string, onUpdate, onDelete sqlparser.ReferenceAction) *sqlparser.ForeignKeyDefinition {
578608
pKs, pTbl, _ := sqlparser.NewTestParser().ParseTable(parentTableName)
@@ -586,3 +616,53 @@ func createFkDefinition(childCols []string, parentTableName string, parentCols [
586616
},
587617
}
588618
}
619+
620+
func makeTestVSchema(ks string, sharded bool, tbls map[string]*vindexes.Table) *vindexes.VSchema {
621+
keyspaceSchema := &vindexes.KeyspaceSchema{
622+
Keyspace: &vindexes.Keyspace{
623+
Name: ks,
624+
Sharded: sharded,
625+
},
626+
// Default foreign key mode
627+
ForeignKeyMode: vschemapb.Keyspace_unmanaged,
628+
Tables: tbls,
629+
Vindexes: map[string]vindexes.Vindex{},
630+
}
631+
vs := makeTestEmptyVSchema()
632+
vs.Keyspaces[ks] = keyspaceSchema
633+
vs.ResetCreated()
634+
return vs
635+
}
636+
637+
func makeTestEmptyVSchema() *vindexes.VSchema {
638+
return &vindexes.VSchema{
639+
RoutingRules: map[string]*vindexes.RoutingRule{},
640+
Keyspaces: map[string]*vindexes.KeyspaceSchema{},
641+
}
642+
}
643+
644+
func makeTestSrvVSchema(ks string, sharded bool, tbls map[string]*vschemapb.Table) *vschemapb.SrvVSchema {
645+
keyspaceSchema := &vschemapb.Keyspace{
646+
Sharded: sharded,
647+
Tables: tbls,
648+
// Default foreign key mode
649+
ForeignKeyMode: vschemapb.Keyspace_unmanaged,
650+
}
651+
return &vschemapb.SrvVSchema{
652+
Keyspaces: map[string]*vschemapb.Keyspace{ks: keyspaceSchema},
653+
}
654+
}
655+
656+
type fakeSchema struct {
657+
t map[string]*vindexes.TableInfo
658+
}
659+
660+
func (f *fakeSchema) Tables(string) map[string]*vindexes.TableInfo {
661+
return f.t
662+
}
663+
664+
func (f *fakeSchema) Views(string) map[string]sqlparser.SelectStatement {
665+
return nil
666+
}
667+
668+
var _ SchemaInfo = (*fakeSchema)(nil)

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
@@ -1182,7 +1182,12 @@ func (qre *QueryExecutor) executeGetSchemaQuery(query string, callback func(sche
11821182
return qre.execStreamSQL(conn, false /* isTransaction */, query, func(result *sqltypes.Result) error {
11831183
schemaDef := make(map[string]string)
11841184
for _, row := range result.Rows {
1185-
schemaDef[row[0].ToString()] = row[1].ToString()
1185+
tableName := row[0].ToString()
1186+
// Schema RPC should ignore the internal table in the response.
1187+
if schema.IsInternalOperationTableName(tableName) {
1188+
continue
1189+
}
1190+
schemaDef[tableName] = row[1].ToString()
11861191
}
11871192
return callback(&querypb.GetSchemaResponse{TableDefinition: schemaDef})
11881193
})

0 commit comments

Comments
 (0)