From 36093db500fdd41b804e9ab5a75abbe589450360 Mon Sep 17 00:00:00 2001 From: binbin0325 Date: Mon, 4 Sep 2023 19:46:36 +0800 Subject: [PATCH] show table rules --- go.mod | 1 - pkg/executor/redirect.go | 5 +- pkg/mysql/thead/thead.go | 8 ++ pkg/reduce/reduce_test.go | 1 + pkg/runtime/ast/ast.go | 2 + pkg/runtime/ast/proto.go | 2 + pkg/runtime/ast/show.go | 22 ++++- pkg/runtime/optimize/dal/show_table_rule.go | 42 ++++++++++ pkg/runtime/plan/dal/show_database_rules.go | 30 +++---- pkg/runtime/plan/dal/show_table_rules.go | 93 +++++++++++++++++++++ test/integration_test.go | 33 ++++++++ 11 files changed, 220 insertions(+), 19 deletions(-) create mode 100644 pkg/runtime/optimize/dal/show_table_rule.go create mode 100644 pkg/runtime/plan/dal/show_table_rules.go diff --git a/go.mod b/go.mod index e8649596..c023d0f8 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,6 @@ require ( github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/docker v20.10.11+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect - github.com/dubbogo/tools v1.0.9 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-errors/errors v1.0.1 // indirect diff --git a/pkg/executor/redirect.go b/pkg/executor/redirect.go index 0d6e97ec..8e8edd87 100644 --- a/pkg/executor/redirect.go +++ b/pkg/executor/redirect.go @@ -280,8 +280,9 @@ func (executor *RedirectExecutor) doExecutorComQuery(ctx *proto.Context, act ast allowSchemaless := func(stmt *ast.ShowStmt) bool { switch stmt.Tp { case ast.ShowDatabases, ast.ShowVariables, ast.ShowTopology, ast.ShowStatus, ast.ShowTableStatus, - ast.ShowWarnings, ast.ShowCharset, ast.ShowMasterStatus, ast.ShowProcessList, ast.ShowReplicas, ast.ShowShardingTable, - ast.ShowReplicaStatus, ast.ShowNodes, ast.ShowUsers, ast.ShowCreateSequence, ast.ShowDatabaseRules: + ast.ShowWarnings, ast.ShowCharset, ast.ShowMasterStatus, ast.ShowProcessList, ast.ShowReplicas, + ast.ShowShardingTable, ast.ShowReplicaStatus, ast.ShowNodes, ast.ShowUsers, ast.ShowCreateSequence, + ast.ShowDatabaseRules, ast.ShowTableRules: return true default: return false diff --git a/pkg/mysql/thead/thead.go b/pkg/mysql/thead/thead.go index 70ffa0eb..6dcdc034 100644 --- a/pkg/mysql/thead/thead.go +++ b/pkg/mysql/thead/thead.go @@ -70,6 +70,14 @@ var ( Col{Name: "expr", FieldType: consts.FieldTypeVarString}, Col{Name: "step", FieldType: consts.FieldTypeInt24}, } + + TableRule = Thead{ + Col{Name: "table_name", FieldType: consts.FieldTypeVarString}, + Col{Name: "column", FieldType: consts.FieldTypeVarString}, + Col{Name: "type", FieldType: consts.FieldTypeVarString}, + Col{Name: "expr", FieldType: consts.FieldTypeVarString}, + Col{Name: "step", FieldType: consts.FieldTypeVarString}, + } ) type Col struct { diff --git a/pkg/reduce/reduce_test.go b/pkg/reduce/reduce_test.go index da850c25..e4880c59 100644 --- a/pkg/reduce/reduce_test.go +++ b/pkg/reduce/reduce_test.go @@ -24,6 +24,7 @@ import ( import ( "github.com/shopspring/decimal" + "github.com/stretchr/testify/assert" ) diff --git a/pkg/runtime/ast/ast.go b/pkg/runtime/ast/ast.go index e8333c62..8eaa693a 100644 --- a/pkg/runtime/ast/ast.go +++ b/pkg/runtime/ast/ast.go @@ -754,6 +754,8 @@ func (cc *convCtx) convShowStmt(node *ast.ShowStmt) Statement { pattern.String = like } return &ShowDatabases{BaseShowWithSingleColumn: &BaseShowWithSingleColumn{toBaseShow(), pattern}} + case ast.ShowTableRules: + return &ShowTableRule{BaseShow: toBaseShow(), Database: node.DBName, TableName: node.Table.Name.String()} case ast.ShowDatabaseRules: return &ShowDatabaseRule{BaseShow: toBaseShow(), Database: node.DBName, TableName: node.Table.Name.String()} case ast.ShowCollation: diff --git a/pkg/runtime/ast/proto.go b/pkg/runtime/ast/proto.go index 73c55c86..130dc426 100644 --- a/pkg/runtime/ast/proto.go +++ b/pkg/runtime/ast/proto.go @@ -68,6 +68,7 @@ const ( SQLTypeRepairTable // REPAIR TABLE SQLTypeCreateTable // CREATE TABLE SQLTypeShowDatabaseRules // SHOW DATABASE RULES + SQLTypeShowTableRules // SHOW TABLE RULES ) var _sqlTypeNames = [...]string{ @@ -108,6 +109,7 @@ var _sqlTypeNames = [...]string{ SQLTypeRepairTable: "REPAIR TABLE", SQLTypeCreateTable: "CREATE TABLE", SQLTypeShowDatabaseRules: "SHOW DATABASE RULES", + SQLTypeShowTableRules: "SHOW TABLE RULES", } // SQLType represents the type of SQL. diff --git a/pkg/runtime/ast/show.go b/pkg/runtime/ast/show.go index 4b2c7997..b5376a97 100644 --- a/pkg/runtime/ast/show.go +++ b/pkg/runtime/ast/show.go @@ -670,14 +670,32 @@ type ShowDatabaseRule struct { TableName string } -func (s ShowDatabaseRule) Mode() SQLType { +func (s *ShowDatabaseRule) Mode() SQLType { return SQLTypeShowDatabaseRules } -func (s ShowDatabaseRule) Restore(flag RestoreFlag, sb *strings.Builder, args *[]int) error { +func (s *ShowDatabaseRule) Restore(flag RestoreFlag, sb *strings.Builder, args *[]int) error { sb.WriteString("SHOW DATABASE RULES ") if err := s.BaseShow.Restore(flag, sb, args); err != nil { return errors.WithStack(err) } return nil } + +type ShowTableRule struct { + *BaseShow + Database string + TableName string +} + +func (s *ShowTableRule) Mode() SQLType { + return SQLTypeShowTableRules +} + +func (s *ShowTableRule) Restore(flag RestoreFlag, sb *strings.Builder, args *[]int) error { + sb.WriteString("SHOW TABLE RULES ") + if err := s.BaseShow.Restore(flag, sb, args); err != nil { + return errors.WithStack(err) + } + return nil +} diff --git a/pkg/runtime/optimize/dal/show_table_rule.go b/pkg/runtime/optimize/dal/show_table_rule.go new file mode 100644 index 00000000..c1f0a387 --- /dev/null +++ b/pkg/runtime/optimize/dal/show_table_rule.go @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dal + +import ( + "context" +) + +import ( + "github.com/arana-db/arana/pkg/proto" + "github.com/arana-db/arana/pkg/runtime/ast" + "github.com/arana-db/arana/pkg/runtime/optimize" + "github.com/arana-db/arana/pkg/runtime/plan/dal" +) + +func init() { + optimize.Register(ast.SQLTypeShowTableRules, optimizeShowTableRules) +} + +func optimizeShowTableRules(_ context.Context, o *optimize.Optimizer) (proto.Plan, error) { + rule := o.Rule + stmt := o.Stmt.(*ast.ShowTableRule) + ret := dal.NewShowTableRulesPlan(stmt) + ret.BindArgs(o.Args) + ret.SetRule(rule) + return ret, nil +} diff --git a/pkg/runtime/plan/dal/show_database_rules.go b/pkg/runtime/plan/dal/show_database_rules.go index 9281f20c..e327c48d 100644 --- a/pkg/runtime/plan/dal/show_database_rules.go +++ b/pkg/runtime/plan/dal/show_database_rules.go @@ -55,22 +55,24 @@ func (s *ShowDatabaseRulesPlan) ExecIn(ctx context.Context, _ proto.VConn) (prot Columns: fields, } - if vt, ok := s.rule.VTable(s.Stmt.TableName); ok { - for _, vs := range vt.GetVShards() { - var columns []string - for i := range vs.DB.ShardColumns { - columns = append(columns, vs.DB.ShardColumns[i].Name) - } - ds.Rows = append(ds.Rows, rows.NewTextVirtualRow(fields, []proto.Value{ - proto.NewValueString(s.Stmt.TableName), - proto.NewValueString(strings.Join(columns, ",")), - proto.NewValueString(""), - proto.NewValueString(fmt.Sprintf("%s", vs.DB.Computer)), - proto.NewValueInt64(1), - })) - } + vt, ok := s.rule.VTable(s.Stmt.TableName) + if !ok { + return resultx.New(resultx.WithDataset(ds)), nil } + for _, vs := range vt.GetVShards() { + var columns []string + for i := range vs.DB.ShardColumns { + columns = append(columns, vs.DB.ShardColumns[i].Name) + } + ds.Rows = append(ds.Rows, rows.NewTextVirtualRow(fields, []proto.Value{ + proto.NewValueString(s.Stmt.TableName), + proto.NewValueString(strings.Join(columns, ",")), + proto.NewValueString(""), + proto.NewValueString(fmt.Sprintf("%s", vs.DB.Computer)), + proto.NewValueInt64(1), + })) + } return resultx.New(resultx.WithDataset(ds)), nil } diff --git a/pkg/runtime/plan/dal/show_table_rules.go b/pkg/runtime/plan/dal/show_table_rules.go new file mode 100644 index 00000000..e414c2b7 --- /dev/null +++ b/pkg/runtime/plan/dal/show_table_rules.go @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dal + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/arana-db/arana/pkg/dataset" + "github.com/arana-db/arana/pkg/mysql/rows" + "github.com/arana-db/arana/pkg/mysql/thead" + "github.com/arana-db/arana/pkg/proto" + "github.com/arana-db/arana/pkg/proto/rule" + "github.com/arana-db/arana/pkg/resultx" + "github.com/arana-db/arana/pkg/runtime/ast" + "github.com/arana-db/arana/pkg/runtime/plan" +) + +var _ proto.Plan = (*ShowTableRulesPlan)(nil) + +type ShowTableRulesPlan struct { + plan.BasePlan + Stmt *ast.ShowTableRule + rule *rule.Rule +} + +func (s *ShowTableRulesPlan) Type() proto.PlanType { + return proto.PlanTypeQuery +} + +func (s *ShowTableRulesPlan) ExecIn(ctx context.Context, _ proto.VConn) (proto.Result, error) { + _, span := plan.Tracer.Start(ctx, "ShowTableRulesPlan.ExecIn") + defer span.End() + + fields := thead.TableRule.ToFields() + ds := &dataset.VirtualDataset{ + Columns: fields, + } + vt, ok := s.rule.VTable(s.Stmt.TableName) + if !ok { + return resultx.New(resultx.WithDataset(ds)), nil + } + + for _, vs := range vt.GetVShards() { + var ( + columns []string + steps []string + ) + + for i := range vs.Table.ShardColumns { + columns = append(columns, vs.Table.ShardColumns[i].Name) + steps = append(steps, strconv.Itoa(vs.Table.ShardColumns[i].Steps)) + } + + ds.Rows = append(ds.Rows, rows.NewTextVirtualRow(fields, []proto.Value{ + proto.NewValueString(s.Stmt.TableName), + proto.NewValueString(strings.Join(columns, ",")), + proto.NewValueString(""), + proto.NewValueString(fmt.Sprintf("%s", vs.Table.Computer)), + proto.NewValueString(strings.Join(steps, ",")), + })) + } + + return resultx.New(resultx.WithDataset(ds)), nil +} + +func (s *ShowTableRulesPlan) SetRule(rule *rule.Rule) { + s.rule = rule +} + +// NewShowTableRulesPlan create ShowTableRules Plan +func NewShowTableRulesPlan(stmt *ast.ShowTableRule) *ShowTableRulesPlan { + return &ShowTableRulesPlan{ + Stmt: stmt, + } +} diff --git a/test/integration_test.go b/test/integration_test.go index d92bfc1f..3ff21944 100644 --- a/test/integration_test.go +++ b/test/integration_test.go @@ -680,6 +680,39 @@ func (s *IntegrationSuite) TestShowDatabaseRules() { } } +func (s *IntegrationSuite) TestShowTableRules() { + var ( + db = s.DB() + t = s.T() + ) + + tests := []struct { + name string + sql string + expectNum int + }{ + { + name: "show table rules from employees", + sql: "show table rules from employees", + expectNum: 0, + }, + { + name: "show table rules from student", + sql: "show table rules from student", + expectNum: 1, + }, + } + + for _, v := range tests { + rows, err := db.Query(v.sql) + defer rows.Close() + assert.NoErrorf(t, err, "show table rules error: %v", err) + results, err := utils.PrintTable(rows) + assert.NoErrorf(t, err, "show table rules error: %v", err) + assert.Equal(t, len(results), v.expectNum) + } +} + func (s *IntegrationSuite) TestDropTrigger() { var ( db = s.DB()