From a4047952f8d7fcc2cb0af25ca0fe6ea8c4bdaee1 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Mon, 4 Apr 2022 13:21:05 +0200 Subject: [PATCH 1/2] feat: route explain tab plan to the correct keyspace using VSchema's FindKeyspace Signed-off-by: Florent Poinsard --- go/vt/vtgate/executor_test.go | 9 +++++++++ go/vt/vtgate/planbuilder/explain.go | 12 ++++++++++-- go/vt/vtgate/planbuilder/plan_test.go | 11 +++++++++++ go/vt/vtgate/planbuilder/plancontext/vschema.go | 1 + go/vt/vtgate/vcursor_impl.go | 17 +++++++++++++++-- 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index 58023d16353..688bf85c1d7 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -2476,6 +2476,15 @@ func TestExecutorShowVitessMigrations(t *testing.T) { assert.Contains(t, sbc2.StringQueries(), "SELECT * FROM _vt.schema_migrations") } +func TestExecutorDescHash(t *testing.T) { + executor, _, _, _ := createExecutorEnv() + showQuery := "desc hash_index" + session := NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}) + ctx := context.Background() + _, err := executor.Execute(ctx, "", session, showQuery, nil) + require.NoError(t, err) +} + func exec(executor *Executor, session *SafeSession, sql string) (*sqltypes.Result, error) { return executor.Execute(context.Background(), "TestExecute", session, sql, nil) } diff --git a/go/vt/vtgate/planbuilder/explain.go b/go/vt/vtgate/planbuilder/explain.go index d1ee1902a70..0cb33cf4428 100644 --- a/go/vt/vtgate/planbuilder/explain.go +++ b/go/vt/vtgate/planbuilder/explain.go @@ -45,7 +45,7 @@ func buildExplainPlan(stmt sqlparser.Explain, reservedVars *sqlparser.ReservedVa } func explainTabPlan(explain *sqlparser.ExplainTab, vschema plancontext.VSchema) (engine.Primitive, error) { - table, _, _, _, destination, err := vschema.FindTableOrVindex(explain.Table) + _, _, ks, _, destination, err := vschema.FindTableOrVindex(explain.Table) if err != nil { return nil, err } @@ -55,8 +55,16 @@ func explainTabPlan(explain *sqlparser.ExplainTab, vschema plancontext.VSchema) destination = key.DestinationAnyShard{} } + keyspace, err := vschema.FindKeyspace(ks) + if err != nil { + return nil, err + } + if keyspace == nil { + return nil, vterrors.Errorf(vtrpcpb.Code_UNAVAILABLE, "Cannot find keyspace for: %s", ks) + } + return &engine.Send{ - Keyspace: table.Keyspace, + Keyspace: keyspace, TargetDestination: destination, Query: sqlparser.String(explain), SingleShardOnly: true, diff --git a/go/vt/vtgate/planbuilder/plan_test.go b/go/vt/vtgate/planbuilder/plan_test.go index 593b3164f13..d17ab1a66f4 100644 --- a/go/vt/vtgate/planbuilder/plan_test.go +++ b/go/vt/vtgate/planbuilder/plan_test.go @@ -497,6 +497,17 @@ func (vw *vschemaWrapper) AllKeyspace() ([]*vindexes.Keyspace, error) { return []*vindexes.Keyspace{vw.keyspace}, nil } +// FindKeyspace implements the VSchema interface +func (vw *vschemaWrapper) FindKeyspace(keyspace string) (*vindexes.Keyspace, error) { + if vw.keyspace == nil { + return nil, errors.New("keyspace not available") + } + if vw.keyspace.Name == keyspace { + return vw.keyspace, nil + } + return nil, nil +} + func (vw *vschemaWrapper) Planner() plancontext.PlannerVersion { return vw.version } diff --git a/go/vt/vtgate/planbuilder/plancontext/vschema.go b/go/vt/vtgate/planbuilder/plancontext/vschema.go index 9640a87fec7..5514459bd52 100644 --- a/go/vt/vtgate/planbuilder/plancontext/vschema.go +++ b/go/vt/vtgate/planbuilder/plancontext/vschema.go @@ -30,6 +30,7 @@ type VSchema interface { SysVarSetEnabled() bool KeyspaceExists(keyspace string) bool AllKeyspace() ([]*vindexes.Keyspace, error) + FindKeyspace(keyspace string) (*vindexes.Keyspace, error) GetSemTable() *semantics.SemTable Planner() PlannerVersion SetPlannerVersion(pv PlannerVersion) diff --git a/go/vt/vtgate/vcursor_impl.go b/go/vt/vtgate/vcursor_impl.go index 379a6102b1b..dec4a0af02c 100644 --- a/go/vt/vtgate/vcursor_impl.go +++ b/go/vt/vtgate/vcursor_impl.go @@ -77,7 +77,7 @@ type iExecute interface { VSchema() *vindexes.VSchema } -//VSchemaOperator is an interface to Vschema Operations +// VSchemaOperator is an interface to Vschema Operations type VSchemaOperator interface { GetCurrentSrvVschema() *vschemapb.SrvVSchema UpdateVSchema(ctx context.Context, ksName string, vschema *vschemapb.SrvVSchema) error @@ -378,6 +378,19 @@ func (vc *vcursorImpl) AllKeyspace() ([]*vindexes.Keyspace, error) { return kss, nil } +// FindKeyspace implements the VSchema interface +func (vc *vcursorImpl) FindKeyspace(keyspace string) (*vindexes.Keyspace, error) { + if len(vc.vschema.Keyspaces) == 0 { + return nil, errNoDbAvailable + } + for _, ks := range vc.vschema.Keyspaces { + if ks.Keyspace.Name == keyspace { + return ks.Keyspace, nil + } + } + return nil, nil +} + // Planner implements the ContextVSchema interface func (vc *vcursorImpl) Planner() plancontext.PlannerVersion { if vc.safeSession.Options != nil && @@ -608,7 +621,7 @@ func (vc *vcursorImpl) SetSysVar(name string, expr string) { vc.safeSession.SetSystemVariable(name, expr) } -//NeedsReservedConn implements the SessionActions interface +// NeedsReservedConn implements the SessionActions interface func (vc *vcursorImpl) NeedsReservedConn() { vc.safeSession.SetReservedConn(true) } From 8ef90be85ba62088f62bba1bfa44695cb4b06d95 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Mon, 4 Apr 2022 13:42:09 +0200 Subject: [PATCH 2/2] test: addition of an end-to-end test to describe vindex Signed-off-by: Florent Poinsard --- go/test/endtoend/vtgate/misc_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/go/test/endtoend/vtgate/misc_test.go b/go/test/endtoend/vtgate/misc_test.go index 068696194b5..018dfc61d4f 100644 --- a/go/test/endtoend/vtgate/misc_test.go +++ b/go/test/endtoend/vtgate/misc_test.go @@ -806,3 +806,13 @@ func TestFilterAfterLeftJoin(t *testing.T) { query := "select /*vt+ PLANNER=gen4 */ A.id1, A.id2 from t1 as A left join t1 as B on A.id1 = B.id2 WHERE B.id1 IS NULL" utils.AssertMatches(t, conn, query, `[[INT64(1) INT64(10)]]`) } + +func TestDescribeVindex(t *testing.T) { + defer cluster.PanicHandler(t) + ctx := context.Background() + conn, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer conn.Close() + + utils.AssertContainsError(t, conn, "describe hash", "'vt_ks.hash' doesn't exist") +}