diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index 71bf08f06c8..cd7ee6f6453 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -695,3 +695,17 @@ func (db *DB) VerifyAllExecutedOrFail() { db.t.Errorf("%v: not all expected queries were executed. leftovers: %v", db.name, db.expectedExecuteFetch[db.expectedExecuteFetchIndex:]) } } + +//LastQuery returns the last query +func (db *DB) LastQuery() interface{} { + size := len(db.querylog) + if size == 0 { + return "no queries have been run" + } + return db.querylog[size-1] +} + +//Name returns that database name +func (db *DB) Name() string { + return db.name +} diff --git a/go/vt/vttablet/tabletserver/planbuilder/builder.go b/go/vt/vttablet/tabletserver/planbuilder/builder.go index abd09d7d987..2b90ad49472 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/builder.go +++ b/go/vt/vttablet/tabletserver/planbuilder/builder.go @@ -17,6 +17,8 @@ limitations under the License. package planbuilder import ( + "strings" + "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" @@ -132,6 +134,36 @@ func analyzeSet(set *sqlparser.Set) (plan *Plan) { } } +const tablesIn = "tables_in_" + +func analyzeShow(show *sqlparser.Show, keyspace string, dbName string) (plan *Plan) { + rewriteShowStatement(show, keyspace, dbName) + return &Plan{ + PlanID: PlanOtherRead, + FullQuery: GenerateFullQuery(show), + } +} + +// rewriteShowStatement replaces the keyspace with the database name +func rewriteShowStatement(show *sqlparser.Show, keyspace string, dbName string) { + opt := show.ShowTablesOpt + if opt != nil { + lowerDbName := strings.ToLower(dbName) + if strings.EqualFold(opt.DbName, keyspace) { + opt.DbName = lowerDbName + } + sqlparser.Rewrite(show.ShowTablesOpt.Filter, func(cursor *sqlparser.Cursor) bool { + switch n := cursor.Node().(type) { + case *sqlparser.ColName: + if n.Name.EqualString(tablesIn + keyspace) { + n.Name = sqlparser.NewColIdent(tablesIn + lowerDbName) + } + } + return true + }, nil) + } +} + func lookupTable(tableExprs sqlparser.TableExprs, tables map[string]*schema.Table) *schema.Table { if len(tableExprs) > 1 { return nil diff --git a/go/vt/vttablet/tabletserver/planbuilder/plan.go b/go/vt/vttablet/tabletserver/planbuilder/plan.go index 7714e36ad64..812f0ecfa53 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/plan.go +++ b/go/vt/vttablet/tabletserver/planbuilder/plan.go @@ -151,7 +151,7 @@ func (plan *Plan) TableName() sqlparser.TableIdent { } // Build builds a plan based on the schema. -func Build(statement sqlparser.Statement, tables map[string]*schema.Table) (*Plan, error) { +func Build(statement sqlparser.Statement, tables map[string]*schema.Table, keyspace, dbName string) (*Plan, error) { var plan *Plan err := checkForPoolingUnsafeConstructs(statement) @@ -179,9 +179,9 @@ func Build(statement sqlparser.Statement, tables map[string]*schema.Table) (*Pla case *sqlparser.DDL: // DDLs and other statements below don't get fully parsed. // We have to use the original query at the time of execution. - plan = &Plan{PlanID: PlanDDL} + plan, err = &Plan{PlanID: PlanDDL}, nil case *sqlparser.Show: - plan, err = &Plan{PlanID: PlanOtherRead}, nil + plan, err = analyzeShow(stmt, keyspace, dbName), nil case *sqlparser.OtherRead: plan, err = &Plan{PlanID: PlanOtherRead}, nil case *sqlparser.OtherAdmin: diff --git a/go/vt/vttablet/tabletserver/planbuilder/plan_test.go b/go/vt/vttablet/tabletserver/planbuilder/plan_test.go index 8f5f030c574..72d7958905a 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/plan_test.go +++ b/go/vt/vttablet/tabletserver/planbuilder/plan_test.go @@ -72,7 +72,7 @@ func TestPlan(t *testing.T) { var err error statement, err := sqlparser.Parse(tcase.input) if err == nil { - plan, err = Build(statement, testSchema) + plan, err = Build(statement, testSchema, "keyspace", "dbName") } PassthroughDMLs = false @@ -123,7 +123,7 @@ func TestCustom(t *testing.T) { if err != nil { t.Fatalf("Got error: %v, parsing sql: %v", err.Error(), tcase.input) } - plan, err := Build(statement, schem) + plan, err := Build(statement, schem, "keyspace", "dbName") var out string if err != nil { out = err.Error() diff --git a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt index a38170b92da..aa9077776ea 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt +++ b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt @@ -753,7 +753,24 @@ options:PassthroughDMLs "show a" { "PlanID": "OtherRead", - "TableName": "" + "TableName": "", + "FullQuery": "show a" +} + +# show tables with filter +"show tables from keyspace where Tables_in_keyspace='table1'" +{ + "PlanID": "OtherRead", + "TableName": "", + "FullQuery": "show tables from dbname where tables_in_dbname = 'table1'" +} + +# show tables with filter no matter case +"show tables from KeYsPaCe where Tables_in_keYSPace='table1'" +{ + "PlanID": "OtherRead", + "TableName": "", + "FullQuery": "show tables from dbname where tables_in_dbname = 'table1'" } # describe diff --git a/go/vt/vttablet/tabletserver/query_engine.go b/go/vt/vttablet/tabletserver/query_engine.go index 1ce97b70b87..e707af6b87d 100644 --- a/go/vt/vttablet/tabletserver/query_engine.go +++ b/go/vt/vttablet/tabletserver/query_engine.go @@ -285,7 +285,7 @@ func (qe *QueryEngine) Close() { } // GetPlan returns the TabletPlan that for the query. Plans are cached in a cache.LRUCache. -func (qe *QueryEngine) GetPlan(ctx context.Context, logStats *tabletenv.LogStats, sql string, skipQueryPlanCache bool) (*TabletPlan, error) { +func (qe *QueryEngine) GetPlan(ctx context.Context, logStats *tabletenv.LogStats, sql string, skipQueryPlanCache bool, keyspace string) (*TabletPlan, error) { span, ctx := trace.NewSpan(ctx, "QueryEngine.GetPlan") defer span.Finish() @@ -305,7 +305,7 @@ func (qe *QueryEngine) GetPlan(ctx context.Context, logStats *tabletenv.LogStats if err != nil { return nil, err } - splan, err := planbuilder.Build(statement, qe.tables) + splan, err := planbuilder.Build(statement, qe.tables, keyspace, qe.env.Config().DB.DBName) if err != nil { return nil, err } diff --git a/go/vt/vttablet/tabletserver/query_engine_test.go b/go/vt/vttablet/tabletserver/query_engine_test.go index 902ce858202..2be4468633e 100644 --- a/go/vt/vttablet/tabletserver/query_engine_test.go +++ b/go/vt/vttablet/tabletserver/query_engine_test.go @@ -91,14 +91,14 @@ func TestGetPlanPanicDuetoEmptyQuery(t *testing.T) { for query, result := range schematest.Queries() { db.AddQuery(query, result) } - qe := newTestQueryEngine(10, 10*time.Second, true, newDBConfigs(db)) + qe := newTestQueryEngine(10, 10*time.Second, newDBConfigs(db)) qe.se.Open() qe.Open() defer qe.Close() ctx := context.Background() logStats := tabletenv.NewLogStats(ctx, "GetPlanStats") - _, err := qe.GetPlan(ctx, logStats, "", false) + _, err := qe.GetPlan(ctx, logStats, "", false /*skipQueryPlanCache*/, "keyspace") want := "empty statement" if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("qe.GetPlan: %v, want %s", err, want) @@ -111,7 +111,7 @@ func TestGetMessageStreamPlan(t *testing.T) { for query, result := range schematest.Queries() { db.AddQuery(query, result) } - qe := newTestQueryEngine(10, 10*time.Second, true, newDBConfigs(db)) + qe := newTestQueryEngine(10, 10*time.Second, newDBConfigs(db)) qe.se.Open() qe.Open() defer qe.Close() @@ -148,7 +148,7 @@ func TestQueryPlanCache(t *testing.T) { db.AddQuery("select * from test_table_01 where 1 != 1", &sqltypes.Result{}) db.AddQuery("select * from test_table_02 where 1 != 1", &sqltypes.Result{}) - qe := newTestQueryEngine(10, 10*time.Second, true, newDBConfigs(db)) + qe := newTestQueryEngine(10, 10*time.Second, newDBConfigs(db)) qe.se.Open() qe.Open() defer qe.Close() @@ -156,14 +156,14 @@ func TestQueryPlanCache(t *testing.T) { ctx := context.Background() logStats := tabletenv.NewLogStats(ctx, "GetPlanStats") qe.SetQueryPlanCacheCap(1) - firstPlan, err := qe.GetPlan(ctx, logStats, firstQuery, false) + firstPlan, err := qe.GetPlan(ctx, logStats, firstQuery, false /*skipQueryPlanCache*/, "keyspace") if err != nil { t.Fatal(err) } if firstPlan == nil { t.Fatalf("plan should not be nil") } - secondPlan, err := qe.GetPlan(ctx, logStats, secondQuery, false) + secondPlan, err := qe.GetPlan(ctx, logStats, secondQuery, false /*skipQueryPlanCache*/, "keyspace") if err != nil { t.Fatal(err) } @@ -190,7 +190,7 @@ func TestNoQueryPlanCache(t *testing.T) { db.AddQuery("select * from test_table_01 where 1 != 1", &sqltypes.Result{}) db.AddQuery("select * from test_table_02 where 1 != 1", &sqltypes.Result{}) - qe := newTestQueryEngine(10, 10*time.Second, true, newDBConfigs(db)) + qe := newTestQueryEngine(10, 10*time.Second, newDBConfigs(db)) qe.se.Open() qe.Open() defer qe.Close() @@ -198,7 +198,7 @@ func TestNoQueryPlanCache(t *testing.T) { ctx := context.Background() logStats := tabletenv.NewLogStats(ctx, "GetPlanStats") qe.SetQueryPlanCacheCap(1) - firstPlan, err := qe.GetPlan(ctx, logStats, firstQuery, true) + firstPlan, err := qe.GetPlan(ctx, logStats, firstQuery, true /*skipQueryPlanCache*/, "keyspace") if err != nil { t.Fatal(err) } @@ -222,7 +222,7 @@ func TestNoQueryPlanCacheDirective(t *testing.T) { db.AddQuery("select /*vt+ SKIP_QUERY_PLAN_CACHE=1 */ * from test_table_01 where 1 != 1", &sqltypes.Result{}) db.AddQuery("select /*vt+ SKIP_QUERY_PLAN_CACHE=1 */ * from test_table_02 where 1 != 1", &sqltypes.Result{}) - qe := newTestQueryEngine(10, 10*time.Second, true, newDBConfigs(db)) + qe := newTestQueryEngine(10, 10*time.Second, newDBConfigs(db)) qe.se.Open() qe.Open() defer qe.Close() @@ -230,7 +230,7 @@ func TestNoQueryPlanCacheDirective(t *testing.T) { ctx := context.Background() logStats := tabletenv.NewLogStats(ctx, "GetPlanStats") qe.SetQueryPlanCacheCap(1) - firstPlan, err := qe.GetPlan(ctx, logStats, firstQuery, false) + firstPlan, err := qe.GetPlan(ctx, logStats, firstQuery, false /*skipQueryPlanCache*/, "keyspace") if err != nil { t.Fatal(err) } @@ -251,14 +251,14 @@ func TestStatsURL(t *testing.T) { } query := "select * from test_table_01" db.AddQuery("select * from test_table_01 where 1 != 1", &sqltypes.Result{}) - qe := newTestQueryEngine(10, 1*time.Second, true, newDBConfigs(db)) + qe := newTestQueryEngine(10, 1*time.Second, newDBConfigs(db)) qe.se.Open() qe.Open() defer qe.Close() // warm up cache ctx := context.Background() logStats := tabletenv.NewLogStats(ctx, "GetPlanStats") - qe.GetPlan(ctx, logStats, query, false) + qe.GetPlan(ctx, logStats, query, false /*skipQueryPlanCache*/, "keyspace") request, _ := http.NewRequest("GET", "/debug/tablet_plans", nil) response := httptest.NewRecorder() @@ -273,7 +273,7 @@ func TestStatsURL(t *testing.T) { qe.handleHTTPQueryRules(response, request) } -func newTestQueryEngine(queryCacheSize int, idleTimeout time.Duration, strict bool, dbcfgs *dbconfigs.DBConfigs) *QueryEngine { +func newTestQueryEngine(queryCacheSize int, idleTimeout time.Duration, dbcfgs *dbconfigs.DBConfigs) *QueryEngine { config := tabletenv.NewDefaultConfig() config.DB = dbcfgs config.QueryCacheSize = queryCacheSize @@ -291,7 +291,7 @@ func runConsolidatedQuery(t *testing.T, sql string) *QueryEngine { db := fakesqldb.New(t) defer db.Close() - qe := newTestQueryEngine(10, 1*time.Second, true, newDBConfigs(db)) + qe := newTestQueryEngine(10, 1*time.Second, newDBConfigs(db)) qe.se.Open() qe.Open() defer qe.Close() diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index 13ad566677a..b266f8eb3cb 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -526,7 +526,14 @@ func (qre *QueryExecutor) execOther() (*sqltypes.Result, error) { return nil, err } defer conn.Recycle() - return qre.execSQL(conn, qre.query, true) + var query string + if qre.plan.FullQuery != nil { + query = qre.plan.FullQuery.Query + } else { + query = qre.query + } + + return qre.execSQL(conn, query, true) } func (qre *QueryExecutor) getConn() (*connpool.DBConn, error) { diff --git a/go/vt/vttablet/tabletserver/query_executor_test.go b/go/vt/vttablet/tabletserver/query_executor_test.go index 922cf7d2762..feea0c98414 100644 --- a/go/vt/vttablet/tabletserver/query_executor_test.go +++ b/go/vt/vttablet/tabletserver/query_executor_test.go @@ -112,14 +112,14 @@ func TestQueryExecutorPlans(t *testing.T) { // not get re-executed. inTxWant: "select * from t limit 1", }, { - input: "set a=1", + input: "set a = 1", dbResponses: []dbResponse{{ - query: "set a=1", + query: "set a = 1", result: dmlResult, }}, resultWant: dmlResult, planWant: "Set", - logWant: "set a=1", + logWant: "set a = 1", }, { input: "show engines", dbResponses: []dbResponse{{ @@ -241,14 +241,14 @@ func TestQueryExecutorPlans(t *testing.T) { inTxWant: "RELEASE savepoint a", }} for _, tcase := range testcases { - func() { + t.Run(tcase.input, func(t *testing.T) { db := setUpQueryExecutorTest(t) defer db.Close() for _, dbr := range tcase.dbResponses { db.AddQuery(dbr.query, dbr.result) } ctx := context.Background() - tsv := newTestTabletServer(ctx, noFlags, db) + tsv := newTestTabletServer(t, noFlags, db) defer tsv.StopService() tsv.SetPassthroughDMLs(tcase.passThrough) @@ -279,7 +279,7 @@ func TestQueryExecutorPlans(t *testing.T) { want = tcase.inTxWant } assert.Equal(t, want, qre.logStats.RewrittenSQL(), "in tx: %v", tcase.input) - }() + }) } } @@ -320,7 +320,7 @@ func TestQueryExecutorSelectImpossible(t *testing.T) { db.AddQuery(dbr.query, dbr.result) } ctx := context.Background() - tsv := newTestTabletServer(ctx, noFlags, db) + tsv := newTestTabletServer(t, noFlags, db) defer tsv.StopService() qre := newTestQueryExecutor(ctx, tsv, tcase.input, 0) @@ -424,7 +424,7 @@ func TestQueryExecutorLimitFailure(t *testing.T) { db.AddQuery(dbr.query, dbr.result) } ctx := callerid.NewContext(context.Background(), callerid.NewEffectiveCallerID("a", "b", "c"), callerid.NewImmediateCallerID("d")) - tsv := newTestTabletServer(ctx, smallResultSize, db) + tsv := newTestTabletServer(t, smallResultSize, db) defer tsv.StopService() tsv.SetPassthroughDMLs(false) @@ -481,7 +481,7 @@ func TestQueryExecutorPlanPassSelectWithLockOutsideATransaction(t *testing.T) { Fields: getTestTableFields(), }) ctx := context.Background() - tsv := newTestTabletServer(ctx, noFlags, db) + tsv := newTestTabletServer(t, noFlags, db) qre := newTestQueryExecutor(ctx, tsv, query, 0) defer tsv.StopService() assert.Equal(t, planbuilder.PlanSelectLock, qre.plan.PlanID) @@ -509,7 +509,7 @@ func TestQueryExecutorPlanNextval(t *testing.T) { updateQuery := "update seq set next_id = 4 where id = 0" db.AddQuery(updateQuery, &sqltypes.Result{}) ctx := context.Background() - tsv := newTestTabletServer(ctx, noFlags, db) + tsv := newTestTabletServer(t, noFlags, db) defer tsv.StopService() qre := newTestQueryExecutor(ctx, tsv, "select next value from seq", 0) assert.Equal(t, planbuilder.PlanNextval, qre.plan.PlanID) @@ -639,7 +639,7 @@ func TestQueryExecutorMessageStreamACL(t *testing.T) { db := setUpQueryExecutorTest(t) defer db.Close() - tsv := newTestTabletServer(ctx, enableStrictTableACL, db) + tsv := newTestTabletServer(t, enableStrictTableACL, db) defer tsv.StopService() plan, err := tsv.qe.GetMessageStreamPlan("msg") @@ -716,7 +716,7 @@ func TestQueryExecutorTableAcl(t *testing.T) { t.Fatalf("unable to load tableacl config, error: %v", err) } - tsv := newTestTabletServer(ctx, noFlags, db) + tsv := newTestTabletServer(t, noFlags, db) qre := newTestQueryExecutor(ctx, tsv, query, 0) defer tsv.StopService() assert.Equal(t, planbuilder.PlanSelect, qre.plan.PlanID) @@ -761,7 +761,7 @@ func TestQueryExecutorTableAclNoPermission(t *testing.T) { t.Fatalf("unable to load tableacl config, error: %v", err) } // without enabling Config.StrictTableAcl - tsv := newTestTabletServer(ctx, noFlags, db) + tsv := newTestTabletServer(t, noFlags, db) qre := newTestQueryExecutor(ctx, tsv, query, 0) assert.Equal(t, planbuilder.PlanSelect, qre.plan.PlanID) got, err := qre.Execute() @@ -774,7 +774,7 @@ func TestQueryExecutorTableAclNoPermission(t *testing.T) { tsv.StopService() // enable Config.StrictTableAcl - tsv = newTestTabletServer(ctx, enableStrictTableACL, db) + tsv = newTestTabletServer(t, enableStrictTableACL, db) qre = newTestQueryExecutor(ctx, tsv, query, 0) defer tsv.StopService() assert.Equal(t, planbuilder.PlanSelect, qre.plan.PlanID) @@ -810,7 +810,7 @@ func TestQueryExecutorTableAclDualTableExempt(t *testing.T) { } // enable Config.StrictTableAcl - tsv := newTestTabletServer(ctx, enableStrictTableACL, db) + tsv := newTestTabletServer(t, enableStrictTableACL, db) query := "select * from test_table where 1 != 1" qre := newTestQueryExecutor(ctx, tsv, query, 0) defer tsv.StopService() @@ -870,7 +870,7 @@ func TestQueryExecutorTableAclExemptACL(t *testing.T) { } // enable Config.StrictTableAcl - tsv := newTestTabletServer(ctx, enableStrictTableACL, db) + tsv := newTestTabletServer(t, enableStrictTableACL, db) qre := newTestQueryExecutor(ctx, tsv, query, 0) defer tsv.StopService() assert.Equal(t, planbuilder.PlanSelect, qre.plan.PlanID) @@ -943,7 +943,7 @@ func TestQueryExecutorTableAclDryRun(t *testing.T) { username, }, ".") // enable Config.StrictTableAcl - tsv := newTestTabletServer(ctx, enableStrictTableACL, db) + tsv := newTestTabletServer(t, enableStrictTableACL, db) tsv.qe.enableTableACLDryRun = true qre := newTestQueryExecutor(ctx, tsv, query, 0) defer tsv.StopService() @@ -994,7 +994,7 @@ func TestQueryExecutorBlacklistQRFail(t *testing.T) { User: bannedUser, } ctx := callinfo.NewContext(context.Background(), callInfo) - tsv := newTestTabletServer(ctx, noFlags, db) + tsv := newTestTabletServer(t, noFlags, db) tsv.qe.queryRuleSources.UnRegisterSource(rulesName) tsv.qe.queryRuleSources.RegisterSource(rulesName) defer tsv.qe.queryRuleSources.UnRegisterSource(rulesName) @@ -1048,7 +1048,7 @@ func TestQueryExecutorBlacklistQRRetry(t *testing.T) { User: bannedUser, } ctx := callinfo.NewContext(context.Background(), callInfo) - tsv := newTestTabletServer(ctx, noFlags, db) + tsv := newTestTabletServer(t, noFlags, db) tsv.qe.queryRuleSources.UnRegisterSource(rulesName) tsv.qe.queryRuleSources.RegisterSource(rulesName) defer tsv.qe.queryRuleSources.UnRegisterSource(rulesName) @@ -1079,7 +1079,7 @@ const ( ) // newTestQueryExecutor uses a package level variable testTabletServer defined in tabletserver_test.go -func newTestTabletServer(ctx context.Context, flags executorFlags, db *fakesqldb.DB) *TabletServer { +func newTestTabletServer(t *testing.T, flags executorFlags, db *fakesqldb.DB) *TabletServer { config := tabletenv.NewDefaultConfig() config.OltpReadPool.Size = 100 if flags&smallTxPool > 0 { @@ -1110,9 +1110,7 @@ func newTestTabletServer(ctx context.Context, flags executorFlags, db *fakesqldb dbconfigs := newDBConfigs(db) target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} err := tsv.StartService(target, dbconfigs) - if err != nil { - panic(err) - } + require.NoError(t, err) return tsv } @@ -1127,7 +1125,7 @@ func newTransaction(tsv *TabletServer, options *querypb.ExecuteOptions) int64 { func newTestQueryExecutor(ctx context.Context, tsv *TabletServer, sql string, txID int64) *QueryExecutor { logStats := tabletenv.NewLogStats(ctx, "TestQueryExecutor") - plan, err := tsv.qe.GetPlan(ctx, logStats, sql, false) + plan, err := tsv.qe.GetPlan(ctx, logStats, sql, false, "keyspace") if err != nil { panic(err) } @@ -1149,7 +1147,7 @@ func setUpQueryExecutorTest(t *testing.T) *fakesqldb.DB { } func initQueryExecutorTestDB(db *fakesqldb.DB, testTableHasMultipleUniqueKeys bool) { - for query, result := range getQueryExecutorSupportedQueries(testTableHasMultipleUniqueKeys) { + for query, result := range getQueryExecutorSupportedQueries() { db.AddQuery(query, result) } } @@ -1162,7 +1160,7 @@ func getTestTableFields() []*querypb.Field { } } -func getQueryExecutorSupportedQueries(testTableHasMultipleUniqueKeys bool) map[string]*sqltypes.Result { +func getQueryExecutorSupportedQueries() map[string]*sqltypes.Result { return map[string]*sqltypes.Result{ // queries for twopc fmt.Sprintf(sqlCreateSidecarDB, "_vt"): {}, @@ -1291,9 +1289,10 @@ func getQueryExecutorSupportedQueries(testTableHasMultipleUniqueKeys bool) map[s Type: sqltypes.Int64, }}, }, - "begin": {}, - "commit": {}, - "rollback": {}, + "begin": {}, + "commit": {}, + "rollback": {}, + "use `fakesqldb`": {}, fmt.Sprintf(sqlReadAllRedo, "_vt", "_vt"): {}, } } diff --git a/go/vt/vttablet/tabletserver/queryz_test.go b/go/vt/vttablet/tabletserver/queryz_test.go index cfcc26a45e5..e4c5e9c9dc4 100644 --- a/go/vt/vttablet/tabletserver/queryz_test.go +++ b/go/vt/vttablet/tabletserver/queryz_test.go @@ -35,7 +35,7 @@ import ( func TestQueryzHandler(t *testing.T) { resp := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/schemaz", nil) - qe := newTestQueryEngine(100, 10*time.Second, true, &dbconfigs.DBConfigs{}) + qe := newTestQueryEngine(100, 10*time.Second, &dbconfigs.DBConfigs{}) plan1 := &TabletPlan{ Plan: &planbuilder.Plan{ diff --git a/go/vt/vttablet/tabletserver/schema/schematest/schematest.go b/go/vt/vttablet/tabletserver/schema/schematest/schematest.go index 64395121714..29a2dcd57b7 100644 --- a/go/vt/vttablet/tabletserver/schema/schematest/schematest.go +++ b/go/vt/vttablet/tabletserver/schema/schematest/schematest.go @@ -135,7 +135,8 @@ func Queries() map[string]*sqltypes.Result { Type: sqltypes.Int64, }}, }, - "begin": {}, - "commit": {}, + "begin": {}, + "commit": {}, + "use `fakesqldb`": {}, } } diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index ae1dfa4c176..990e484ff81 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -629,7 +629,7 @@ func (tsv *TabletServer) Execute(ctx context.Context, target *querypb.Target, sq bindVariables = make(map[string]*querypb.BindVariable) } query, comments := sqlparser.SplitMarginComments(sql) - plan, err := tsv.qe.GetPlan(ctx, logStats, query, skipQueryPlanCache(options)) + plan, err := tsv.qe.GetPlan(ctx, logStats, query, skipQueryPlanCache(options), tsv.configureKeyspace()) if err != nil { return err } @@ -663,6 +663,10 @@ func (tsv *TabletServer) Execute(ctx context.Context, target *querypb.Target, sq return result, err } +func (tsv *TabletServer) configureKeyspace() string { + return tsv.sm.target.Keyspace +} + // StreamExecute executes the query and streams the result. // The first QueryResult will have Fields set (and Rows nil). // The subsequent QueryResult will have Rows set (and Fields nil). @@ -857,7 +861,7 @@ func (tsv *TabletServer) beginWaitForSameRangeTransactions(ctx context.Context, func (tsv *TabletServer) computeTxSerializerKey(ctx context.Context, logStats *tabletenv.LogStats, sql string, bindVariables map[string]*querypb.BindVariable) (string, string) { // Strip trailing comments so we don't pollute the query cache. sql, _ = sqlparser.SplitMarginComments(sql) - plan, err := tsv.qe.GetPlan(ctx, logStats, sql, false /* skipQueryPlanCache */) + plan, err := tsv.qe.GetPlan(ctx, logStats, sql, false /* skipQueryPlanCache */, tsv.configureKeyspace()) if err != nil { logComputeRowSerializerKey.Errorf("failed to get plan for query: %v err: %v", sql, err) return "", "" diff --git a/go/vt/vttablet/tabletserver/tabletserver_test.go b/go/vt/vttablet/tabletserver/tabletserver_test.go index e72c376327c..33999d886ff 100644 --- a/go/vt/vttablet/tabletserver/tabletserver_test.go +++ b/go/vt/vttablet/tabletserver/tabletserver_test.go @@ -364,7 +364,7 @@ func TestTabletServerConcludeTransaction(t *testing.T) { func TestTabletServerBeginFail(t *testing.T) { config := tabletenv.NewDefaultConfig() config.TxPool.Size = 1 - db, tsv := setupTabletServerTestCustom(t, config) + db, tsv := setupTabletServerTestCustom(t, config, nil, "") defer tsv.StopService() defer db.Close() @@ -537,6 +537,25 @@ func TestMakeSureToCloseDbConnWhenBeginQueryFails(t *testing.T) { require.Error(t, err) } +func TestShowTablesWithFilter(t *testing.T) { + target := querypb.Target{TabletType: topodatapb.TabletType_MASTER, Keyspace: "keyspace"} + config := tabletenv.NewDefaultConfig() + db, tsv := setupTabletServerTestCustom(t, config, &target, "dbName") + defer tsv.StopService() + defer db.Close() + + db.AddQueryPattern(".*", &sqltypes.Result{}) + options := &querypb.ExecuteOptions{} + + _, err := tsv.Execute(ctx, &target, "show tables from keyspace where Tables_in_keyspace = 'table1'", nil, 0, 0, options) + require.NoError(t, err) + require.Equal(t, "show tables from dbname where tables_in_dbname = 'table1'", db.LastQuery()) + + _, err = tsv.Execute(ctx, &target, "show tables where Tables_in_keyspace = 'table1'", nil, 0, 0, options) + require.NoError(t, err) + require.Equal(t, "show tables where tables_in_dbname = 'table1'", db.LastQuery()) +} + func TestTabletServerReserveAndBeginCommit(t *testing.T) { db, tsv := setupTabletServerTest(t) defer tsv.StopService() @@ -860,7 +879,7 @@ func TestSerializeTransactionsSameRow(t *testing.T) { config.HotRowProtection.MaxConcurrency = 1 // Reduce the txpool to 2 because we should never consume more than two slots. config.TxPool.Size = 2 - db, tsv := setupTabletServerTestCustom(t, config) + db, tsv := setupTabletServerTestCustom(t, config, nil, "") defer tsv.StopService() defer db.Close() @@ -965,7 +984,7 @@ func TestDMLQueryWithoutWhereClause(t *testing.T) { config.HotRowProtection.Mode = tabletenv.Enable config.HotRowProtection.MaxConcurrency = 1 config.TxPool.Size = 2 - db, tsv := setupTabletServerTestCustom(t, config) + db, tsv := setupTabletServerTestCustom(t, config, nil, "") defer tsv.StopService() defer db.Close() @@ -1001,7 +1020,7 @@ func TestSerializeTransactionsSameRow_ExecuteBatchAsTransaction(t *testing.T) { config.HotRowProtection.MaxConcurrency = 1 // Reduce the txpool to 2 because we should never consume more than two slots. config.TxPool.Size = 2 - db, tsv := setupTabletServerTestCustom(t, config) + db, tsv := setupTabletServerTestCustom(t, config, nil, "") defer tsv.StopService() defer db.Close() @@ -1113,7 +1132,7 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { config.HotRowProtection.MaxConcurrency = 2 // Reduce the txpool to 2 because we should never consume more than two slots. config.TxPool.Size = 2 - db, tsv := setupTabletServerTestCustom(t, config) + db, tsv := setupTabletServerTestCustom(t, config, nil, "") defer tsv.StopService() defer db.Close() @@ -1247,7 +1266,7 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests(t *testing.T) { config.HotRowProtection.Mode = tabletenv.Enable config.HotRowProtection.MaxQueueSize = 1 config.HotRowProtection.MaxConcurrency = 1 - db, tsv := setupTabletServerTestCustom(t, config) + db, tsv := setupTabletServerTestCustom(t, config, nil, "") defer tsv.StopService() defer db.Close() @@ -1330,7 +1349,7 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests_ExecuteBatchAsTrans config.HotRowProtection.Mode = tabletenv.Enable config.HotRowProtection.MaxQueueSize = 1 config.HotRowProtection.MaxConcurrency = 1 - db, tsv := setupTabletServerTestCustom(t, config) + db, tsv := setupTabletServerTestCustom(t, config, nil, "") defer tsv.StopService() defer db.Close() @@ -1416,7 +1435,7 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { config := tabletenv.NewDefaultConfig() config.HotRowProtection.Mode = tabletenv.Enable config.HotRowProtection.MaxConcurrency = 1 - db, tsv := setupTabletServerTestCustom(t, config) + db, tsv := setupTabletServerTestCustom(t, config, nil, "") defer tsv.StopService() defer db.Close() @@ -2156,22 +2175,30 @@ func TestReserveStats(t *testing.T) { func setupTabletServerTest(t *testing.T) (*fakesqldb.DB, *TabletServer) { config := tabletenv.NewDefaultConfig() - return setupTabletServerTestCustom(t, config) + return setupTabletServerTestCustom(t, config, nil, "") } -func setupTabletServerTestCustom(t *testing.T, config *tabletenv.TabletConfig) (*fakesqldb.DB, *TabletServer) { - db := setupFakeDB(t) +func setupTabletServerTestCustom(t *testing.T, config *tabletenv.TabletConfig, target *querypb.Target, dbName string) (*fakesqldb.DB, *TabletServer) { + db := setupFakeDB(t, dbName) tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) require.Equal(t, StateNotConnected, tsv.sm.State()) dbcfgs := newDBConfigs(db) - target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} - err := tsv.StartService(target, dbcfgs) + if target == nil { + // default target if none is provided + target = &querypb.Target{TabletType: topodatapb.TabletType_MASTER} + } + if dbName != "" { + cmd := fmt.Sprintf("use `%s`", db.Name()) + db.AddQuery(cmd, &sqltypes.Result{}) + } + err := tsv.StartService(*target, dbcfgs) require.NoError(t, err) return db, tsv } -func setupFakeDB(t *testing.T) *fakesqldb.DB { - db := fakesqldb.New(t) +func setupFakeDB(t *testing.T, dbName string) *fakesqldb.DB { + db := fakesqldb.New(t).SetName(dbName) + for query, result := range getSupportedQueries() { db.AddQuery(query, result) } diff --git a/go/vt/vttablet/tabletserver/testutils_test.go b/go/vt/vttablet/tabletserver/testutils_test.go index f64f76492ab..93d25f16d5c 100644 --- a/go/vt/vttablet/tabletserver/testutils_test.go +++ b/go/vt/vttablet/tabletserver/testutils_test.go @@ -28,5 +28,5 @@ var errRejected = errors.New("rejected") func newDBConfigs(db *fakesqldb.DB) *dbconfigs.DBConfigs { params, _ := db.ConnParams().MysqlParams() cp := *params - return dbconfigs.NewTestDBConfigs(cp, cp, "") + return dbconfigs.NewTestDBConfigs(cp, cp, db.Name()) } diff --git a/go/vt/vttablet/tabletserver/tx_engine_test.go b/go/vt/vttablet/tabletserver/tx_engine_test.go index 2c3f6e8e974..df8eb9332dd 100644 --- a/go/vt/vttablet/tabletserver/tx_engine_test.go +++ b/go/vt/vttablet/tabletserver/tx_engine_test.go @@ -156,7 +156,7 @@ func TestTxEngineBegin(t *testing.T) { require.NoError(t, err) _, _, err = te.Commit(ctx, tx1) require.NoError(t, err) - require.Equal(t, "start transaction read only;commit", db.QueryLog()) + assert.Contains(t, db.QueryLog(), "start transaction read only;commit") db.ResetQueryLog() te.AcceptReadWrite() @@ -164,7 +164,7 @@ func TestTxEngineBegin(t *testing.T) { require.NoError(t, err) _, _, err = te.Commit(ctx, tx2) require.NoError(t, err) - require.Equal(t, "begin;commit", db.QueryLog()) + assert.Contains(t, db.QueryLog(), "begin;commit") } func TestTxEngineRenewFails(t *testing.T) { diff --git a/go/vt/vttablet/tabletserver/tx_executor_test.go b/go/vt/vttablet/tabletserver/tx_executor_test.go index efd3a9b8868..34f3555508e 100644 --- a/go/vt/vttablet/tabletserver/tx_executor_test.go +++ b/go/vt/vttablet/tabletserver/tx_executor_test.go @@ -495,7 +495,7 @@ func TestNoTwopc(t *testing.T) { func newTestTxExecutor(t *testing.T) (txe *TxExecutor, tsv *TabletServer, db *fakesqldb.DB) { db = setUpQueryExecutorTest(t) logStats := tabletenv.NewLogStats(ctx, "TestTxExecutor") - tsv = newTestTabletServer(ctx, smallTxPool, db) + tsv = newTestTabletServer(t, smallTxPool, db) db.AddQueryPattern("insert into _vt\\.redo_state\\(dtid, state, time_created\\) values \\('aa', 1,.*", &sqltypes.Result{}) db.AddQueryPattern("insert into _vt\\.redo_statement.*", &sqltypes.Result{}) db.AddQuery("delete from _vt.redo_state where dtid = 'aa'", &sqltypes.Result{}) @@ -512,7 +512,7 @@ func newTestTxExecutor(t *testing.T) (txe *TxExecutor, tsv *TabletServer, db *fa func newShortAgeExecutor(t *testing.T) (txe *TxExecutor, tsv *TabletServer, db *fakesqldb.DB) { db = setUpQueryExecutorTest(t) logStats := tabletenv.NewLogStats(ctx, "TestTxExecutor") - tsv = newTestTabletServer(ctx, smallTxPool|shortTwopcAge, db) + tsv = newTestTabletServer(t, smallTxPool|shortTwopcAge, db) db.AddQueryPattern("insert into _vt\\.redo_state\\(dtid, state, time_created\\) values \\('aa', 1,.*", &sqltypes.Result{}) db.AddQueryPattern("insert into _vt\\.redo_statement.*", &sqltypes.Result{}) db.AddQuery("delete from _vt.redo_state where dtid = 'aa'", &sqltypes.Result{}) @@ -529,7 +529,7 @@ func newShortAgeExecutor(t *testing.T) (txe *TxExecutor, tsv *TabletServer, db * func newNoTwopcExecutor(t *testing.T) (txe *TxExecutor, tsv *TabletServer, db *fakesqldb.DB) { db = setUpQueryExecutorTest(t) logStats := tabletenv.NewLogStats(ctx, "TestTxExecutor") - tsv = newTestTabletServer(ctx, noTwopc, db) + tsv = newTestTabletServer(t, noTwopc, db) return &TxExecutor{ ctx: ctx, logStats: logStats,