diff --git a/executor/pkg_test.go b/executor/pkg_test.go index e75e5fade8a55..3115a634b7ee6 100644 --- a/executor/pkg_test.go +++ b/executor/pkg_test.go @@ -110,3 +110,33 @@ func (s *pkgTestSuite) TestNestedLoopApply(c *C) { } } } + +func (s *pkgTestSuite) TestMoveInfoSchemaToFront(c *C) { + dbss := [][]string{ + {}, + {"A", "B", "C", "a", "b", "c"}, + {"A", "B", "C", "INFORMATION_SCHEMA"}, + {"A", "B", "INFORMATION_SCHEMA", "a"}, + {"INFORMATION_SCHEMA"}, + {"A", "B", "C", "INFORMATION_SCHEMA", "a", "b"}, + } + wanted := [][]string{ + {}, + {"A", "B", "C", "a", "b", "c"}, + {"INFORMATION_SCHEMA", "A", "B", "C"}, + {"INFORMATION_SCHEMA", "A", "B", "a"}, + {"INFORMATION_SCHEMA"}, + {"INFORMATION_SCHEMA", "A", "B", "C", "a", "b"}, + } + + for _, dbs := range dbss { + moveInfoSchemaToFront(dbs) + } + + for i, dbs := range wanted { + c.Check(len(dbss[i]), Equals, len(dbs)) + for j, db := range dbs { + c.Check(dbss[i][j], Equals, db) + } + } +} diff --git a/executor/show.go b/executor/show.go index 0a76e27f683f7..e94e8b4bc19c4 100644 --- a/executor/show.go +++ b/executor/show.go @@ -166,11 +166,25 @@ func (e *ShowExec) fetchShowEngines() error { return nil } +// moveInfoSchemaToFront moves information_schema to the first, and the others are sorted in the origin ascending order. +func moveInfoSchemaToFront(dbs []string) { + if len(dbs) > 0 && strings.EqualFold(dbs[0], "INFORMATION_SCHEMA") { + return + } + + i := sort.SearchStrings(dbs, "INFORMATION_SCHEMA") + if i < len(dbs) && strings.EqualFold(dbs[i], "INFORMATION_SCHEMA") { + copy(dbs[1:i+1], dbs[0:i]) + dbs[0] = "INFORMATION_SCHEMA" + } +} + func (e *ShowExec) fetchShowDatabases() error { dbs := e.is.AllSchemaNames() checker := privilege.GetPrivilegeManager(e.ctx) - // TODO: let information_schema be the first database sort.Strings(dbs) + // let information_schema be the first database + moveInfoSchemaToFront(dbs) for _, d := range dbs { if checker != nil && !checker.DBIsVisible(d) { continue diff --git a/executor/show_test.go b/executor/show_test.go index cf1bbfef8e8de..94a717ff46cbd 100644 --- a/executor/show_test.go +++ b/executor/show_test.go @@ -462,6 +462,30 @@ func (s *testSuite) TestShowVisibility(c *C) { tk.MustExec("drop database showdatabase") } +func (s *testSuite) TestShowDatabasesInfoSchemaFirst(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustQuery("show databases").Check(testkit.Rows("INFORMATION_SCHEMA")) + tk.MustExec(`create user 'show'@'%'`) + tk.MustExec(`flush privileges`) + + tk.MustExec(`create database AAAA`) + tk.MustExec(`create database BBBB`) + tk.MustExec(`grant select on AAAA.* to 'show'@'%'`) + tk.MustExec(`grant select on BBBB.* to 'show'@'%'`) + tk.MustExec(`flush privileges`) + + tk1 := testkit.NewTestKit(c, s.store) + se, err := session.CreateSession4Test(s.store) + c.Assert(err, IsNil) + c.Assert(se.Auth(&auth.UserIdentity{Username: "show", Hostname: "%"}, nil, nil), IsTrue) + tk1.Se = se + tk1.MustQuery("show databases").Check(testkit.Rows("INFORMATION_SCHEMA", "AAAA", "BBBB")) + + tk.MustExec(`drop user 'show'@'%'`) + tk.MustExec(`drop database AAAA`) + tk.MustExec(`drop database BBBB`) +} + // mockSessionManager is a mocked session manager that wraps one session // it returns only this session's current process info as processlist for test. type mockSessionManager struct {