From 48e875c689ae9667667b202270d25db632ee90f6 Mon Sep 17 00:00:00 2001 From: Manan Gupta Date: Tue, 7 Nov 2023 15:46:43 +0530 Subject: [PATCH] feat: ignore foreign keys planning if fk checks are turned off Signed-off-by: Manan Gupta --- go/test/vschemawrapper/vschema_wrapper.go | 21 ++++++++++++------- go/vt/schemadiff/semantics.go | 4 ++++ .../vtgate/planbuilder/plancontext/vschema.go | 2 ++ go/vt/vtgate/semantics/FakeSI.go | 4 ++++ go/vt/vtgate/semantics/analyzer.go | 11 ++++++---- go/vt/vtgate/semantics/analyzer_test.go | 2 +- go/vt/vtgate/semantics/info_schema.go | 4 ++++ go/vt/vtgate/semantics/semantic_state.go | 3 ++- 8 files changed, 37 insertions(+), 14 deletions(-) diff --git a/go/test/vschemawrapper/vschema_wrapper.go b/go/test/vschemawrapper/vschema_wrapper.go index 78cf0f8d41c..04cedba581a 100644 --- a/go/test/vschemawrapper/vschema_wrapper.go +++ b/go/test/vschemawrapper/vschema_wrapper.go @@ -40,14 +40,15 @@ import ( var _ plancontext.VSchema = (*VSchemaWrapper)(nil) type VSchemaWrapper struct { - V *vindexes.VSchema - Keyspace *vindexes.Keyspace - TabletType_ topodatapb.TabletType - Dest key.Destination - SysVarEnabled bool - Version plancontext.PlannerVersion - EnableViews bool - TestBuilder func(query string, vschema plancontext.VSchema, keyspace string) (*engine.Plan, error) + V *vindexes.VSchema + Keyspace *vindexes.Keyspace + TabletType_ topodatapb.TabletType + Dest key.Destination + SysVarEnabled bool + ForeignKeyChecksState sqlparser.FkChecksState + Version plancontext.PlannerVersion + EnableViews bool + TestBuilder func(query string, vschema plancontext.VSchema, keyspace string) (*engine.Plan, error) } func (vw *VSchemaWrapper) GetPrepareData(stmtName string) *vtgatepb.PrepareData { @@ -140,6 +141,10 @@ func (vw *VSchemaWrapper) KeyspaceError(keyspace string) error { return nil } +func (vw *VSchemaWrapper) GetForeignKeyChecksState() sqlparser.FkChecksState { + return vw.ForeignKeyChecksState +} + func (vw *VSchemaWrapper) AllKeyspace() ([]*vindexes.Keyspace, error) { if vw.Keyspace == nil { return nil, vterrors.VT13001("keyspace not available") diff --git a/go/vt/schemadiff/semantics.go b/go/vt/schemadiff/semantics.go index da9c6b1e2a9..c2c4580ba28 100644 --- a/go/vt/schemadiff/semantics.go +++ b/go/vt/schemadiff/semantics.go @@ -64,6 +64,10 @@ func (si *declarativeSchemaInformation) KeyspaceError(keyspace string) error { return nil } +func (si *declarativeSchemaInformation) GetForeignKeyChecksState() sqlparser.FkChecksState { + return sqlparser.FkChecksUnspecified +} + // addTable adds a fake table with an empty column list func (si *declarativeSchemaInformation) addTable(tableName string) { tbl := &vindexes.Table{ diff --git a/go/vt/vtgate/planbuilder/plancontext/vschema.go b/go/vt/vtgate/planbuilder/plancontext/vschema.go index 9dde6dee31c..10fbd4c4e80 100644 --- a/go/vt/vtgate/planbuilder/plancontext/vschema.go +++ b/go/vt/vtgate/planbuilder/plancontext/vschema.go @@ -60,6 +60,8 @@ type VSchema interface { // KeyspaceError returns any error in the keyspace vschema. KeyspaceError(keyspace string) error + GetForeignKeyChecksState() sqlparser.FkChecksState + // GetVSchema returns the latest cached vindexes.VSchema GetVSchema() *vindexes.VSchema diff --git a/go/vt/vtgate/semantics/FakeSI.go b/go/vt/vtgate/semantics/FakeSI.go index b7043b42980..f085d9ea92e 100644 --- a/go/vt/vtgate/semantics/FakeSI.go +++ b/go/vt/vtgate/semantics/FakeSI.go @@ -61,6 +61,10 @@ func (s *FakeSI) ForeignKeyMode(keyspace string) (vschemapb.Keyspace_ForeignKeyM return vschemapb.Keyspace_unmanaged, nil } +func (s *FakeSI) GetForeignKeyChecksState() sqlparser.FkChecksState { + return sqlparser.FkChecksUnspecified +} + func (s *FakeSI) KeyspaceError(keyspace string) error { if s.KsError != nil { fkErr, isPresent := s.KsError[keyspace] diff --git a/go/vt/vtgate/semantics/analyzer.go b/go/vt/vtgate/semantics/analyzer.go index e524b1a33cf..4ee6797e390 100644 --- a/go/vt/vtgate/semantics/analyzer.go +++ b/go/vt/vtgate/semantics/analyzer.go @@ -77,7 +77,7 @@ func Analyze(statement sqlparser.Statement, currentDb string, si SchemaInformati } // Creation of the semantic table - return analyzer.newSemTable(statement, si.ConnCollation()) + return analyzer.newSemTable(statement, si.ConnCollation(), si.GetForeignKeyChecksState()) } // AnalyzeStrict analyzes the parsed query, and fails the analysis for any possible errors @@ -97,7 +97,7 @@ func AnalyzeStrict(statement sqlparser.Statement, currentDb string, si SchemaInf return st, nil } -func (a *analyzer) newSemTable(statement sqlparser.Statement, coll collations.ID) (*SemTable, error) { +func (a *analyzer) newSemTable(statement sqlparser.Statement, coll collations.ID, fkChecksState sqlparser.FkChecksState) (*SemTable, error) { var comments *sqlparser.ParsedComments commentedStmt, isCommented := statement.(sqlparser.Commented) if isCommented { @@ -108,7 +108,7 @@ func (a *analyzer) newSemTable(statement sqlparser.Statement, coll collations.ID columns[union] = info.exprs } - childFks, parentFks, err := a.getInvolvedForeignKeys(statement) + childFks, parentFks, err := a.getInvolvedForeignKeys(statement, fkChecksState) if err != nil { return nil, err } @@ -317,7 +317,10 @@ func (a *analyzer) noteQuerySignature(node sqlparser.SQLNode) { } // getInvolvedForeignKeys gets the foreign keys that might require taking care off when executing the given statement. -func (a *analyzer) getInvolvedForeignKeys(statement sqlparser.Statement) (map[TableSet][]vindexes.ChildFKInfo, map[TableSet][]vindexes.ParentFKInfo, error) { +func (a *analyzer) getInvolvedForeignKeys(statement sqlparser.Statement, fkChecksState sqlparser.FkChecksState) (map[TableSet][]vindexes.ChildFKInfo, map[TableSet][]vindexes.ParentFKInfo, error) { + if fkChecksState == sqlparser.FkChecksOff { + return nil, nil, nil + } // There are only the DML statements that require any foreign keys handling. switch stmt := statement.(type) { case *sqlparser.Delete: diff --git a/go/vt/vtgate/semantics/analyzer_test.go b/go/vt/vtgate/semantics/analyzer_test.go index c8251dd36c3..b261a53e9ef 100644 --- a/go/vt/vtgate/semantics/analyzer_test.go +++ b/go/vt/vtgate/semantics/analyzer_test.go @@ -2152,7 +2152,7 @@ func TestGetInvolvedForeignKeys(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - childFks, parentFks, err := tt.analyzer.getInvolvedForeignKeys(tt.stmt) + childFks, parentFks, err := tt.analyzer.getInvolvedForeignKeys(tt.stmt, sqlparser.FkChecksOn) if tt.expectedErr != "" { require.EqualError(t, err, tt.expectedErr) return diff --git a/go/vt/vtgate/semantics/info_schema.go b/go/vt/vtgate/semantics/info_schema.go index 838f6276472..d402f2f7ca5 100644 --- a/go/vt/vtgate/semantics/info_schema.go +++ b/go/vt/vtgate/semantics/info_schema.go @@ -1718,6 +1718,10 @@ func (i *infoSchemaWithColumns) ForeignKeyMode(keyspace string) (vschemapb.Keysp return i.inner.ForeignKeyMode(keyspace) } +func (i *infoSchemaWithColumns) GetForeignKeyChecksState() sqlparser.FkChecksState { + return sqlparser.FkChecksUnspecified +} + func (i *infoSchemaWithColumns) KeyspaceError(keyspace string) error { return i.inner.KeyspaceError(keyspace) } diff --git a/go/vt/vtgate/semantics/semantic_state.go b/go/vt/vtgate/semantics/semantic_state.go index 94b1302b357..d6dd881919c 100644 --- a/go/vt/vtgate/semantics/semantic_state.go +++ b/go/vt/vtgate/semantics/semantic_state.go @@ -144,12 +144,13 @@ type ( ColumnName string } - // SchemaInformation is used tp provide table information from Vschema. + // SchemaInformation is used to provide table information from Vschema. SchemaInformation interface { FindTableOrVindex(tablename sqlparser.TableName) (*vindexes.Table, vindexes.Vindex, string, topodatapb.TabletType, key.Destination, error) ConnCollation() collations.ID // ForeignKeyMode returns the foreign_key flag value ForeignKeyMode(keyspace string) (vschemapb.Keyspace_ForeignKeyMode, error) + GetForeignKeyChecksState() sqlparser.FkChecksState KeyspaceError(keyspace string) error }