From 1c353eabdb93af9019d1f1aac355eb4d1d44111e Mon Sep 17 00:00:00 2001 From: scott lewis <33612882+dk-lockdown@users.noreply.github.com> Date: Fri, 7 Oct 2022 08:42:32 +0800 Subject: [PATCH] feat: in sharding mode support show tables (#267) * feat: in sharding mode support show tables --- pkg/optimize/optimize_show_tables.go | 45 ++++++++++++ pkg/optimize/optimizer.go | 2 + pkg/plan/show_tables.go | 101 +++++++++++++++++++++++++++ test/shd/sharding_test.go | 14 ++++ 4 files changed, 162 insertions(+) create mode 100644 pkg/optimize/optimize_show_tables.go create mode 100644 pkg/plan/show_tables.go diff --git a/pkg/optimize/optimize_show_tables.go b/pkg/optimize/optimize_show_tables.go new file mode 100644 index 00000000..d8aa999f --- /dev/null +++ b/pkg/optimize/optimize_show_tables.go @@ -0,0 +1,45 @@ +/* + * Copyright 2022 CECTC, Inc. + * + * Licensed 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 optimize + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/cectc/dbpack/pkg/plan" + "github.com/cectc/dbpack/pkg/proto" + "github.com/cectc/dbpack/third_party/parser/ast" +) + +func (o Optimizer) optimizeShowTables(ctx context.Context, stmt *ast.ShowStmt, args []interface{}) (proto.Plan, error) { + var logicTables []string + if stmt.Tp != ast.ShowTables { + return nil, errors.New("statement must be show tables stmt") + } + + for logicTable := range o.topologies { + logicTables = append(logicTables, logicTable) + } + + return &plan.ShowTablesPlan{ + Stmt: stmt, + Args: args, + Executor: o.executors[0], + LogicTables: logicTables, + }, nil +} diff --git a/pkg/optimize/optimizer.go b/pkg/optimize/optimizer.go index d45169e1..87f9b0cb 100644 --- a/pkg/optimize/optimizer.go +++ b/pkg/optimize/optimizer.go @@ -69,6 +69,8 @@ func (o Optimizer) Optimize(ctx context.Context, stmt ast.StmtNode, args ...inte switch t.Tp { case ast.ShowTableStatus: return o.optimizeShowTableStatus(ctx, t, args) + case ast.ShowTables: + return o.optimizeShowTables(ctx, t, args) case ast.ShowColumns, ast.ShowIndex: return o.optimizeShowTableMeta(ctx, t, args) } diff --git a/pkg/plan/show_tables.go b/pkg/plan/show_tables.go new file mode 100644 index 00000000..c585c829 --- /dev/null +++ b/pkg/plan/show_tables.go @@ -0,0 +1,101 @@ +/* + * Copyright 2022 CECTC, Inc. + * + * Licensed 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 plan + +import ( + "context" + "regexp" + "strings" + + "github.com/pkg/errors" + + "github.com/cectc/dbpack/pkg/constant" + "github.com/cectc/dbpack/pkg/mysql" + "github.com/cectc/dbpack/pkg/proto" + "github.com/cectc/dbpack/third_party/parser/ast" + "github.com/cectc/dbpack/third_party/parser/format" +) + +const ( + tableNameRegex = `^(\w+)_(\d+)$` +) + +var ( + tableNameRegexp = regexp.MustCompile(tableNameRegex) +) + +type ShowTablesPlan struct { + Stmt *ast.ShowStmt + Args []interface{} + Executor proto.DBGroupExecutor + LogicTables []string +} + +func (p *ShowTablesPlan) Execute(ctx context.Context, _ ...*ast.TableOptimizerHint) (proto.Result, uint16, error) { + var ( + sb strings.Builder + sql string + result proto.Result + warns uint16 + err error + ) + restoreCtx := format.NewRestoreCtx(constant.DBPackRestoreFormat, &sb) + if err = p.Stmt.Restore(restoreCtx); err != nil { + return nil, 0, errors.WithStack(err) + } + sql = sb.String() + + result, warns, err = p.Executor.Query(ctx, sql) + if err != nil { + return nil, 0, err + } + mysqlResult := result.(*mysql.Result) + rows := make([]proto.Row, 0) + rowMap := make(map[string]struct{}) + for _, row := range mysqlResult.Rows { + if _, err := row.Decode(); err != nil { + return nil, 0, err + } + textRow := row.(*mysql.TextRow) + table, filtered := filterTable(string(textRow.Values[0].Val.([]byte)), p.LogicTables) + if filtered { + textRow.Values[0].Val = []byte(table) + } + if _, exist := rowMap[table]; !exist { + rows = append(rows, textRow) + rowMap[table] = struct{}{} + } + } + return &mysql.Result{ + Fields: mysqlResult.Fields, + AffectedRows: mysqlResult.AffectedRows, + InsertId: mysqlResult.InsertId, + Rows: rows, + }, warns, nil +} + +// filterTable return table, filtered +func filterTable(table string, logicTables []string) (string, bool) { + for _, logicTable := range logicTables { + if tableNameRegexp.MatchString(table) { + if strings.Contains(table, logicTable) { + return logicTable, true + } + } + } + return table, false +} diff --git a/test/shd/sharding_test.go b/test/shd/sharding_test.go index bc4078c1..5a4ff0ef 100644 --- a/test/shd/sharding_test.go +++ b/test/shd/sharding_test.go @@ -277,6 +277,20 @@ func (suite *_ShardingSuite) TestShowTableStatus() { } } +func (suite *_ShardingSuite) TestShowTables() { + rows, err := suite.db.Query("SHOW TABLES") + if suite.NoErrorf(err, "show tables error: %v", err) { + var ( + table string + ) + for rows.Next() { + err := rows.Scan(&table) + suite.NoError(err) + suite.T().Logf("%s", table) + } + } +} + func (suite *_ShardingSuite) TestShowTableMeta() { rows, err := suite.db.Query("SHOW COLUMNS FROM city") if suite.NoErrorf(err, "show columns error: %v", err) {