github.com/XiaoMi/Gaea@v1.2.5/proxy/plan/plan_explain.go (about) 1 // Copyright 2019 The Gaea Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 "fmt" 19 "github.com/XiaoMi/Gaea/mysql" 20 "github.com/XiaoMi/Gaea/parser/ast" 21 "github.com/XiaoMi/Gaea/proxy/router" 22 "github.com/XiaoMi/Gaea/proxy/sequence" 23 "github.com/XiaoMi/Gaea/util" 24 ) 25 26 // constants of ShardType 27 const ( 28 ShardTypeUnshard = "unshard" 29 ShardTypeShard = "shard" 30 ) 31 32 // ExplainPlan is the plan for explain statement 33 type ExplainPlan struct { 34 shardType string 35 sqls map[string]map[string][]string 36 } 37 38 func buildExplainPlan(stmt *ast.ExplainStmt, phyDBs map[string]string, db, sql string, r *router.Router, seq *sequence.SequenceManager) (*ExplainPlan, error) { 39 stmtToExplain := stmt.Stmt 40 if _, ok := stmtToExplain.(*ast.ExplainStmt); ok { 41 return nil, fmt.Errorf("nested explain") 42 } 43 44 p, err := BuildPlan(stmtToExplain, phyDBs, db, sql, r, seq) 45 if err != nil { 46 return nil, fmt.Errorf("build plan to explain error: %v", err) 47 } 48 49 ep := &ExplainPlan{} 50 51 switch pl := p.(type) { 52 case *SelectPlan: 53 ep.shardType = ShardTypeShard 54 ep.sqls = pl.sqls 55 return ep, nil 56 case *DeletePlan: 57 ep.shardType = ShardTypeShard 58 ep.sqls = pl.sqls 59 return ep, nil 60 case *UpdatePlan: 61 ep.shardType = ShardTypeShard 62 ep.sqls = pl.sqls 63 return ep, nil 64 case *InsertPlan: 65 ep.shardType = ShardTypeShard 66 ep.sqls = pl.sqls 67 return ep, nil 68 case *UnshardPlan: 69 ep.shardType = ShardTypeUnshard 70 ep.sqls = make(map[string]map[string][]string) 71 dbSQLs := make(map[string][]string) 72 if phyDB, ok := phyDBs[pl.db]; ok { 73 pl.db = phyDB 74 } 75 dbSQLs[pl.db] = []string{pl.sql} 76 ep.sqls[r.GetDefaultRule().GetSlice(0)] = dbSQLs 77 return ep, nil 78 default: 79 return nil, fmt.Errorf("unsupport plan to explain, type: %T", p) 80 } 81 } 82 83 // ExecuteIn implement Plan 84 func (p *ExplainPlan) ExecuteIn(*util.RequestContext, Executor) (*mysql.Result, error) { 85 return createExplainResult(p.shardType, p.sqls), nil 86 } 87 88 // Size implement Plan 89 func (p *ExplainPlan) Size() int { 90 return 1 91 } 92 93 func createExplainResult(shardType string, sqls map[string]map[string][]string) *mysql.Result { 94 var rows [][]interface{} 95 var names = []string{"type", "slice", "db", "sql"} 96 97 for slice, dbSQLs := range sqls { 98 for db, tableSQLs := range dbSQLs { 99 for _, sql := range tableSQLs { 100 row := []interface{}{shardType, slice, db, sql} 101 rows = append(rows, row) 102 } 103 } 104 } 105 106 r, _ := mysql.BuildResultset(nil, names, rows) 107 ret := &mysql.Result{ 108 Resultset: r, 109 } 110 111 return ret 112 }