From 61ddc7413344ce45ef7ab41dac5079dc077971fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=B6=85?= Date: Sun, 26 Sep 2021 14:56:46 +0800 Subject: [PATCH] *: Add `SHOW PLACEMENT` support for tables (#28266) --- ddl/placement_policy_test.go | 12 +- ddl/placement_sql_test.go | 4 +- executor/show.go | 2 + executor/show_placement.go | 104 +++++++++++++- executor/show_placement_test.go | 236 +++++++++++++++++++++++++++++--- planner/core/planbuilder.go | 8 +- 6 files changed, 335 insertions(+), 31 deletions(-) diff --git a/ddl/placement_policy_test.go b/ddl/placement_policy_test.go index da03510a9175b..7f4e255877832 100644 --- a/ddl/placement_policy_test.go +++ b/ddl/placement_policy_test.go @@ -219,7 +219,7 @@ func (s *testDBSuite6) TestConstraintCompatibility(c *C) { err := tk.ExecToErr(sql) c.Assert(err, NotNil) c.Assert(err.Error(), Equals, ca.errmsg) - tk.MustQuery("show placement where target='POLICY x'").Check(testkit.Rows("POLICY x REGIONS=\"cn-east1,cn-east\" SCHEDULED")) + tk.MustQuery("show placement where target='POLICY x'").Check(testkit.Rows("POLICY x REGIONS=\"cn-east1,cn-east\"")) } } tk.MustExec("drop placement policy x") @@ -234,20 +234,20 @@ func (s *testDBSuite6) TestAlterPlacementPolicy(c *C) { // test for normal cases tk.MustExec("alter placement policy x REGIONS=\"bj,sh\"") - tk.MustQuery("show placement where target='POLICY x'").Check(testkit.Rows("POLICY x REGIONS=\"bj,sh\" SCHEDULED")) + tk.MustQuery("show placement where target='POLICY x'").Check(testkit.Rows("POLICY x REGIONS=\"bj,sh\"")) tk.MustExec("alter placement policy x " + "PRIMARY_REGION=\"bj\" " + "REGIONS=\"sh\" " + "SCHEDULE=\"EVEN\"") - tk.MustQuery("show placement where target='POLICY x'").Check(testkit.Rows("POLICY x PRIMARY_REGION=\"bj\" REGIONS=\"sh\" SCHEDULE=\"EVEN\" SCHEDULED")) + tk.MustQuery("show placement where target='POLICY x'").Check(testkit.Rows("POLICY x PRIMARY_REGION=\"bj\" REGIONS=\"sh\" SCHEDULE=\"EVEN\"")) tk.MustExec("alter placement policy x " + "LEADER_CONSTRAINTS=\"[+region=us-east-1]\" " + "FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" " + "FOLLOWERS=3") tk.MustQuery("show placement where target='POLICY x'").Check( - testkit.Rows("POLICY x LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULED"), + testkit.Rows("POLICY x LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\""), ) tk.MustExec("alter placement policy x " + @@ -257,7 +257,7 @@ func (s *testDBSuite6) TestAlterPlacementPolicy(c *C) { "VOTERS=5 " + "LEARNERS=3") tk.MustQuery("show placement where target='POLICY x'").Check( - testkit.Rows("POLICY x CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\" SCHEDULED"), + testkit.Rows("POLICY x CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\""), ) // test alter not exist policies @@ -472,7 +472,7 @@ func (s *testDBSuite6) TestPolicyCacheAndPolicyDependencyCache(c *C) { tk.MustExec("create placement policy x primary_region=\"r1\" regions=\"r1,r2\" schedule=\"EVEN\";") po := testGetPolicyByName(c, tk.Se, "x", true) c.Assert(po, NotNil) - tk.MustQuery("show placement").Check(testkit.Rows("POLICY x PRIMARY_REGION=\"r1\" REGIONS=\"r1,r2\" SCHEDULE=\"EVEN\" SCHEDULED")) + tk.MustQuery("show placement").Check(testkit.Rows("POLICY x PRIMARY_REGION=\"r1\" REGIONS=\"r1,r2\" SCHEDULE=\"EVEN\"")) tk.MustExec("drop table if exists t") tk.MustExec("create table t (a int) placement policy \"x\"") diff --git a/ddl/placement_sql_test.go b/ddl/placement_sql_test.go index c3ef8e1b3aab3..3b45e67ffc2e2 100644 --- a/ddl/placement_sql_test.go +++ b/ddl/placement_sql_test.go @@ -736,8 +736,8 @@ func (s *testDBSuite6) TestCreateSchemaWithPlacement(c *C) { tk.MustExec(`CREATE PLACEMENT POLICY PolicySchemaTest LEADER_CONSTRAINTS = "[+region=nl]" FOLLOWER_CONSTRAINTS="[+region=se]" FOLLOWERS=4 LEARNER_CONSTRAINTS="[+region=be]" LEARNERS=4`) tk.MustExec(`CREATE PLACEMENT POLICY PolicyTableTest LEADER_CONSTRAINTS = "[+region=tl]" FOLLOWER_CONSTRAINTS="[+region=tf]" FOLLOWERS=2 LEARNER_CONSTRAINTS="[+region=tle]" LEARNERS=1`) - tk.MustQuery("SHOW PLACEMENT like 'POLICY %PolicySchemaTest%'").Check(testkit.Rows("POLICY PolicySchemaTest LEADER_CONSTRAINTS=\"[+region=nl]\" FOLLOWERS=4 FOLLOWER_CONSTRAINTS=\"[+region=se]\" LEARNERS=4 LEARNER_CONSTRAINTS=\"[+region=be]\" SCHEDULED")) - tk.MustQuery("SHOW PLACEMENT like 'POLICY %PolicyTableTest%'").Check(testkit.Rows("POLICY PolicyTableTest LEADER_CONSTRAINTS=\"[+region=tl]\" FOLLOWERS=2 FOLLOWER_CONSTRAINTS=\"[+region=tf]\" LEARNERS=1 LEARNER_CONSTRAINTS=\"[+region=tle]\" SCHEDULED")) + tk.MustQuery("SHOW PLACEMENT like 'POLICY %PolicySchemaTest%'").Check(testkit.Rows("POLICY PolicySchemaTest LEADER_CONSTRAINTS=\"[+region=nl]\" FOLLOWERS=4 FOLLOWER_CONSTRAINTS=\"[+region=se]\" LEARNERS=4 LEARNER_CONSTRAINTS=\"[+region=be]\"")) + tk.MustQuery("SHOW PLACEMENT like 'POLICY %PolicyTableTest%'").Check(testkit.Rows("POLICY PolicyTableTest LEADER_CONSTRAINTS=\"[+region=tl]\" FOLLOWERS=2 FOLLOWER_CONSTRAINTS=\"[+region=tf]\" LEARNERS=1 LEARNER_CONSTRAINTS=\"[+region=tle]\"")) tk.MustExec("CREATE SCHEMA SchemaPolicyPlacementTest PLACEMENT POLICY = `PolicySchemaTest`") tk.MustQuery("SHOW CREATE SCHEMA SCHEMAPOLICYPLACEMENTTEST").Check(testkit.Rows("SchemaPolicyPlacementTest CREATE DATABASE `SchemaPolicyPlacementTest` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ PLACEMENT POLICY = `PolicySchemaTest`")) diff --git a/executor/show.go b/executor/show.go index 88ad555306274..df77147725cf6 100644 --- a/executor/show.go +++ b/executor/show.go @@ -218,6 +218,8 @@ func (e *ShowExec) fetchAll(ctx context.Context) error { return e.fetchShowPlacementLabels(ctx) case ast.ShowPlacement: return e.fetchShowPlacement(ctx) + case ast.ShowPlacementForTable: + return e.fetchShowPlacementForTable(ctx) } return nil } diff --git a/executor/show_placement.go b/executor/show_placement.go index 32da7f6d8827d..bfd7ed3099a2d 100644 --- a/executor/show_placement.go +++ b/executor/show_placement.go @@ -20,7 +20,11 @@ import ( "sort" "github.com/pingcap/errors" + "github.com/pingcap/parser/ast" + "github.com/pingcap/parser/model" + "github.com/pingcap/parser/mysql" "github.com/pingcap/tidb/infoschema" + "github.com/pingcap/tidb/privilege" "github.com/pingcap/tidb/store/helper" "github.com/pingcap/tidb/types/json" "github.com/pingcap/tidb/util/sqlexec" @@ -128,23 +132,117 @@ func (e *ShowExec) fetchShowPlacementLabels(ctx context.Context) error { return nil } -func (e *ShowExec) fetchShowPlacement(_ context.Context) error { - err := e.fetchAllPlacementPolicies() +func (e *ShowExec) fetchShowPlacementForTable(_ context.Context) (err error) { + tbl, err := e.getTable() + if err != nil { + return err + } + + tblInfo := tbl.Meta() + placement, err := e.getTablePlacement(tblInfo) if err != nil { return err } + if placement != nil { + ident := ast.Ident{Schema: e.Table.DBInfo.Name, Name: tblInfo.Name} + e.appendRow([]interface{}{"TABLE " + ident.String(), placement.String()}) + } + return nil } +func (e *ShowExec) fetchShowPlacement(_ context.Context) error { + if err := e.fetchAllPlacementPolicies(); err != nil { + return err + } + + return e.fetchAllTablePlacements() +} + func (e *ShowExec) fetchAllPlacementPolicies() error { policies := e.is.AllPlacementPolicies() sort.Slice(policies, func(i, j int) bool { return policies[i].Name.O < policies[j].Name.O }) for _, policy := range policies { name := policy.Name settings := policy.PlacementSettings - e.appendRow([]interface{}{"POLICY " + name.String(), settings.String(), "SCHEDULED"}) + e.appendRow([]interface{}{"POLICY " + name.String(), settings.String()}) + } + + return nil +} + +func (e *ShowExec) fetchAllTablePlacements() error { + checker := privilege.GetPrivilegeManager(e.ctx) + activeRoles := e.ctx.GetSessionVars().ActiveRoles + + dbs := e.is.AllSchemas() + sort.Slice(dbs, func(i, j int) bool { return dbs[i].Name.O < dbs[j].Name.O }) + + for _, dbInfo := range dbs { + tableRowSets := make([]struct { + name string + rows [][]interface{} + }, 0) + + for _, tbl := range e.is.SchemaTables(dbInfo.Name) { + tblInfo := tbl.Meta() + if checker != nil && !checker.RequestVerification(activeRoles, dbInfo.Name.O, tblInfo.Name.O, "", mysql.AllPrivMask) { + continue + } + + var rows [][]interface{} + ident := ast.Ident{Schema: dbInfo.Name, Name: tblInfo.Name} + placement, err := e.getTablePlacement(tblInfo) + if err != nil { + return err + } + + if placement != nil { + rows = append(rows, []interface{}{"TABLE " + ident.String(), placement.String()}) + } + + // TODO: Add partition placement rules + + if len(rows) > 0 { + tableRowSets = append(tableRowSets, struct { + name string + rows [][]interface{} + }{ + name: tblInfo.Name.String(), + rows: rows, + }) + } + } + + sort.Slice(tableRowSets, func(i, j int) bool { return tableRowSets[i].name < tableRowSets[j].name }) + for _, rowSet := range tableRowSets { + for _, row := range rowSet.rows { + e.appendRow(row) + } + } } return nil } + +func (e *ShowExec) getTablePlacement(tblInfo *model.TableInfo) (*model.PlacementSettings, error) { + placement := tblInfo.DirectPlacementOpts + if placement != nil { + return placement, nil + } + + return e.getPolicyPlacement(tblInfo.PlacementPolicyRef) +} + +func (e *ShowExec) getPolicyPlacement(policyRef *model.PolicyRefInfo) (settings *model.PlacementSettings, err error) { + if policyRef == nil { + return nil, nil + } + + policy, ok := e.is.PolicyByName(policyRef.Name) + if !ok { + return nil, errors.Errorf("Policy with name '%s' not found", policyRef.Name) + } + return policy.PlacementSettings, nil +} diff --git a/executor/show_placement_test.go b/executor/show_placement_test.go index c51a1292ea396..8bf71e4423dbb 100644 --- a/executor/show_placement_test.go +++ b/executor/show_placement_test.go @@ -16,25 +16,34 @@ package executor_test import ( . "github.com/pingcap/check" + "github.com/pingcap/parser/auth" + "github.com/pingcap/tidb/planner/core" + "github.com/pingcap/tidb/session" "github.com/pingcap/tidb/util/testkit" ) func (s *testSuite5) TestShowPlacement(c *C) { tk := testkit.NewTestKit(c, s.store) - tk.MustExec("drop placement policy if exists p1") - - tk.MustExec("create placement policy pa1 " + - "PRIMARY_REGION=\"cn-east-1\" " + - "REGIONS=\"cn-east-1,cn-east-2\"" + - "SCHEDULE=\"EVEN\"") - defer tk.MustExec("drop placement policy pa1") + tk.MustExec("use test") + tk.MustExec("drop placement policy if exists pa1") + tk.MustExec("drop placement policy if exists pa2") + tk.MustExec("drop placement policy if exists pb1") + tk.MustExec("drop table if exists t1, t2, t3, db2.t2") + tk.MustExec("drop database if exists db2") + // prepare policies tk.MustExec("create placement policy pa2 " + "LEADER_CONSTRAINTS=\"[+region=us-east-1]\" " + "FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" " + "FOLLOWERS=3") defer tk.MustExec("drop placement policy pa2") + tk.MustExec("create placement policy pa1 " + + "PRIMARY_REGION=\"cn-east-1\" " + + "REGIONS=\"cn-east-1,cn-east-2\"" + + "SCHEDULE=\"EVEN\"") + defer tk.MustExec("drop placement policy pa1") + tk.MustExec("create placement policy pb1 " + "VOTER_CONSTRAINTS=\"[+region=bj]\" " + "LEARNER_CONSTRAINTS=\"[+region=sh]\" " + @@ -43,24 +52,219 @@ func (s *testSuite5) TestShowPlacement(c *C) { "LEARNERS=3") defer tk.MustExec("drop placement policy pb1") + // prepare database + tk.MustExec("create database db2") + defer tk.MustExec("drop database if exists db2") + + // prepare tables + tk.MustExec("create table t2 (id int) LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2") + defer tk.MustExec("drop table if exists t2") + + tk.MustExec("create table t1 (id int) placement policy pa1") + defer tk.MustExec("drop table if exists t1") + + tk.MustExec("create table t3 (id int)") + defer tk.MustExec("drop table if exists t3") + + tk.MustExec("create table db2.t2 (id int) LEADER_CONSTRAINTS=\"[+region=bj]\" FOLLOWERS=2") + defer tk.MustExec("drop table if exists db2.t2") + tk.MustQuery("show placement").Check(testkit.Rows( - "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\" SCHEDULED", - "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULED", - "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\" SCHEDULED", + "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\"", + "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\"", + "TABLE db2.t2 LEADER_CONSTRAINTS=\"[+region=bj]\" FOLLOWERS=2", + "TABLE test.t1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + "TABLE test.t2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2", )) tk.MustQuery("show placement like 'POLICY%'").Check(testkit.Rows( - "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\" SCHEDULED", - "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULED", - "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\" SCHEDULED", + "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\"", + "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\"", )) tk.MustQuery("show placement like 'POLICY pa%'").Check(testkit.Rows( - "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\" SCHEDULED", - "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULED", + "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\"", )) tk.MustQuery("show placement where Target='POLICY pb1'").Check(testkit.Rows( - "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\" SCHEDULED", + "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\"", + )) +} + +func (s *testSuite5) TestShowPlacementPrivilege(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop placement policy if exists p1") + tk.MustExec("drop table if exists t1,t2, db2.t1") + tk.MustExec("drop database if exists db2") + tk.MustExec("drop user if exists user1") + + // prepare user + tk.MustExec("create user user1") + defer tk.MustExec("drop user user1") + + // prepare database + tk.MustExec("create database db2") + defer tk.MustExec("drop database db2") + + // prepare policy + tk.MustExec("create placement policy p1 " + + "PRIMARY_REGION=\"cn-east-1\" " + + "REGIONS=\"cn-east-1,cn-east-2\"" + + "SCHEDULE=\"EVEN\"") + defer tk.MustExec("drop placement policy p1") + + // prepare tables + tk.MustExec("create table t1 (id int) placement policy p1") + defer tk.MustExec("drop table if exists t1") + tk.MustExec("create table t2 (id int) LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2") + defer tk.MustExec("drop table if exists t2") + tk.MustExec("create table db2.t1 (id int) LEADER_CONSTRAINTS=\"[+region=bj]\" FOLLOWERS=2") + defer tk.MustExec("drop table if exists db2.t1") + + tk1 := testkit.NewTestKit(c, s.store) + se, err := session.CreateSession4Test(s.store) + c.Assert(err, IsNil) + c.Assert(se.Auth(&auth.UserIdentity{Username: "user1", Hostname: "%"}, nil, nil), IsTrue) + tk1.Se = se + + // before grant + tk1.MustQuery("show placement").Check(testkit.Rows( + "POLICY p1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", )) + + // do some grant + tk.MustExec(`grant select on test.t1 to 'user1'@'%'`) + + // after grant + tk1.MustQuery("show placement").Check(testkit.Rows( + "POLICY p1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + "TABLE test.t1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + )) +} + +func (s *testSuite5) TestShowPlacementForTable(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop placement policy if exists p1") + tk.MustExec("drop table if exists t1,t2,t3,db2.t1") + tk.MustExec("drop database if exists db2") + + tk.MustExec("create placement policy p1 " + + "PRIMARY_REGION=\"cn-east-1\" " + + "REGIONS=\"cn-east-1,cn-east-2\"" + + "SCHEDULE=\"EVEN\"") + defer tk.MustExec("drop placement policy p1") + + // ref a policy + tk.MustExec("create table t1 (id int) placement policy p1") + defer tk.MustExec("drop table if exists t1") + tk.MustQuery("show placement for table t1").Check(testkit.Rows( + "TABLE test.t1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + )) + + // direct setting + tk.MustExec("create table t2 (id int) LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2") + defer tk.MustExec("drop table if exists t2") + tk.MustQuery("show placement for table t2").Check(testkit.Rows( + "TABLE test.t2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2", + )) + + // no placement + tk.MustExec("create table t3 (id int)") + defer tk.MustExec("drop table if exists t3") + tk.MustQuery("show placement for table t3").Check(testkit.Rows()) + + // table name with format db.table + tk.MustExec("create database db2") + defer tk.MustExec("drop database if exists db2") + tk.MustExec("create table db2.t1 (id int) LEADER_CONSTRAINTS=\"[+region=bj]\" FOLLOWERS=2") + defer tk.MustExec("drop table if exists db2.t1") + tk.MustQuery("show placement for table db2.t1").Check(testkit.Rows( + "TABLE db2.t1 LEADER_CONSTRAINTS=\"[+region=bj]\" FOLLOWERS=2", + )) + + // not exists + err := tk.ExecToErr("show placement for table tn") + c.Assert(err.Error(), Equals, "[schema:1146]Table 'test.tn' doesn't exist") + err = tk.ExecToErr("show placement for table dbn.t1") + c.Assert(err.Error(), Equals, "[schema:1146]Table 'dbn.t1' doesn't exist") +} + +func (s *testSuite5) TestShowPlacementForTablePrivilege(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop placement policy if exists p1") + tk.MustExec("drop table if exists t1,t2,t3,db2.t1") + tk.MustExec("drop database if exists db2") + tk.MustExec("drop user if exists user1") + + // prepare user + tk.MustExec("create user user1") + defer tk.MustExec("drop user user1") + + // prepare database + tk.MustExec("create database db2") + defer tk.MustExec("drop database db2") + + // prepare policy + tk.MustExec("create placement policy p1 " + + "PRIMARY_REGION=\"cn-east-1\" " + + "REGIONS=\"cn-east-1,cn-east-2\"" + + "SCHEDULE=\"EVEN\"") + defer tk.MustExec("drop placement policy p1") + + // prepare tables + tk.MustExec("create table t1 (id int) placement policy p1") + defer tk.MustExec("drop table if exists t1") + tk.MustExec("create table t2 (id int) LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2") + defer tk.MustExec("drop table if exists t2") + tk.MustExec("create table t3 (id int)") + defer tk.MustExec("drop table if exists t3") + tk.MustExec("create table db2.t1 (id int) LEADER_CONSTRAINTS=\"[+region=bj]\" FOLLOWERS=2") + defer tk.MustExec("drop table if exists db2.t1") + + tk1 := testkit.NewTestKit(c, s.store) + se, err := session.CreateSession4Test(s.store) + c.Assert(err, IsNil) + c.Assert(se.Auth(&auth.UserIdentity{Username: "user1", Hostname: "%"}, nil, nil), IsTrue) + tk1.Se = se + + // before grant + err = tk1.ExecToErr("show placement for table test.t1") + c.Assert(err.Error(), Equals, core.ErrTableaccessDenied.GenWithStackByArgs("SHOW", "user1", "%", "t1").Error()) + + err = tk1.ExecToErr("show placement for table test.t2") + c.Assert(err.Error(), Equals, core.ErrTableaccessDenied.GenWithStackByArgs("SHOW", "user1", "%", "t2").Error()) + + err = tk1.ExecToErr("show placement for table test.t3") + c.Assert(err.Error(), Equals, core.ErrTableaccessDenied.GenWithStackByArgs("SHOW", "user1", "%", "t3").Error()) + + err = tk1.ExecToErr("show placement for table db2.t1") + c.Assert(err.Error(), Equals, core.ErrTableaccessDenied.GenWithStackByArgs("SHOW", "user1", "%", "t1").Error()) + + // do some grant + tk.MustExec(`grant select on test.t1 to 'user1'@'%'`) + + // after grant + tk1.MustQuery("show placement").Check(testkit.Rows( + "POLICY p1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + "TABLE test.t1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + )) + + tk1.MustQuery("show placement for table test.t1").Check(testkit.Rows( + "TABLE test.t1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\"", + )) + + err = tk1.ExecToErr("show placement for table test.t2") + c.Assert(err.Error(), Equals, core.ErrTableaccessDenied.GenWithStackByArgs("SHOW", "user1", "%", "t2").Error()) + + err = tk1.ExecToErr("show placement for table test.t3") + c.Assert(err.Error(), Equals, core.ErrTableaccessDenied.GenWithStackByArgs("SHOW", "user1", "%", "t3").Error()) + + err = tk1.ExecToErr("show placement for table db2.t1") + c.Assert(err.Error(), Equals, core.ErrTableaccessDenied.GenWithStackByArgs("SHOW", "user1", "%", "t1").Error()) } diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 979cb0f6c83d9..72a16fc27af05 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -2356,7 +2356,7 @@ func (b *PlanBuilder) buildShow(ctx context.Context, show *ast.ShowStmt) (Plan, if p.DBName == "" { return nil, ErrNoDB } - case ast.ShowCreateTable, ast.ShowCreateSequence: + case ast.ShowCreateTable, ast.ShowCreateSequence, ast.ShowPlacementForTable: user := b.ctx.GetSessionVars().User var err error if user != nil { @@ -4130,9 +4130,9 @@ func buildShowSchema(s *ast.ShowStmt, isView bool, isSequence bool) (schema *exp case ast.ShowPlacementLabels: names = []string{"Key", "Values"} ftypes = []byte{mysql.TypeVarchar, mysql.TypeJSON} - case ast.ShowPlacement: - names = []string{"Target", "Placement", "Scheduling_state"} - ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar} + case ast.ShowPlacement, ast.ShowPlacementForDatabase, ast.ShowPlacementForTable, ast.ShowPlacementForPartition: + names = []string{"Target", "Placement"} + ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar} } schema = expression.NewSchema(make([]*expression.Column, 0, len(names))...)