github.com/XiaoMi/Gaea@v1.2.5/proxy/plan/decorator_between_expr.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 20 "github.com/XiaoMi/Gaea/parser/ast" 21 "github.com/XiaoMi/Gaea/parser/format" 22 driver "github.com/XiaoMi/Gaea/parser/tidb-types/parser_driver" 23 "github.com/XiaoMi/Gaea/proxy/router" 24 "github.com/XiaoMi/Gaea/util" 25 ) 26 27 // BetweenExprDecorator decorate BetweenExpr 28 // Between只需要改写表名并计算路由, 不需要改写边界值. 29 type BetweenExprDecorator struct { 30 *ast.BetweenExpr // origin 31 column *ColumnNameExprDecorator 32 33 tableIndexes []int 34 35 rule router.Rule 36 result *RouteResult 37 } 38 39 // NeedCreateBetweenExprDecorator check if BetweenExpr needs decoration 40 func NeedCreateBetweenExprDecorator(p *TableAliasStmtInfo, n *ast.BetweenExpr) (router.Rule, bool, bool, error) { 41 // 如果不是ColumnNameExpr, 则不做任何路由计算和装饰, 直接返回 42 columnNameExpr, ok := n.Expr.(*ast.ColumnNameExpr) 43 if !ok { 44 return nil, false, false, nil 45 } 46 47 rule, need, isAlias, err := NeedCreateColumnNameExprDecoratorInCondition(p, columnNameExpr) 48 if err != nil { 49 return nil, false, false, fmt.Errorf("check ColumnName error: %v", err) 50 } 51 52 return rule, need, isAlias, nil 53 } 54 55 // CreateBetweenExprDecorator create BetweenExprDecorator 56 func CreateBetweenExprDecorator(n *ast.BetweenExpr, rule router.Rule, isAlias bool, result *RouteResult) (*BetweenExprDecorator, error) { 57 columnNameExpr := n.Expr.(*ast.ColumnNameExpr) 58 columnNameExprDecorator := CreateColumnNameExprDecorator(columnNameExpr, rule, isAlias, result) 59 60 tableIndexes, err := getBetweenExprRouteResult(rule, n) 61 if err != nil { 62 return nil, fmt.Errorf("getBetweenExprRouteResult error: %v", err) 63 } 64 65 ret := &BetweenExprDecorator{ 66 BetweenExpr: n, 67 column: columnNameExprDecorator, 68 tableIndexes: tableIndexes, 69 rule: rule, 70 result: result, 71 } 72 return ret, nil 73 } 74 75 // Accept do nothing and return current decorator 76 func (b *BetweenExprDecorator) Accept(v ast.Visitor) (ast.Node, bool) { 77 return b, true 78 } 79 80 // Restore column name restore is different from BetweenExpr 81 func (b *BetweenExprDecorator) Restore(ctx *format.RestoreCtx) error { 82 if err := b.column.Restore(ctx); err != nil { 83 return fmt.Errorf("an error occurred while restore BetweenExpr.Expr: %v", err) 84 } 85 if b.Not { 86 ctx.WriteKeyWord(" NOT BETWEEN ") 87 } else { 88 ctx.WriteKeyWord(" BETWEEN ") 89 } 90 if err := b.Left.Restore(ctx); err != nil { 91 return fmt.Errorf("an error occurred while restore BetweenExpr.Left: %v", err) 92 } 93 ctx.WriteKeyWord(" AND ") 94 if err := b.Right.Restore(ctx); err != nil { 95 return fmt.Errorf("an error occurred while restore BetweenExpr.Right: %v", err) 96 } 97 return nil 98 } 99 100 // GetCurrentRouteResult return route result 101 func (b *BetweenExprDecorator) GetCurrentRouteResult() []int { 102 return b.tableIndexes 103 } 104 105 func getBetweenExprRouteResult(rule router.Rule, n *ast.BetweenExpr) ([]int, error) { 106 //如果是全局表, 则返回广播路由 107 if rule.GetType() == router.GlobalTableRuleType { 108 indexes := rule.GetSubTableIndexes() 109 return indexes, nil 110 } 111 112 columnNameExpr := n.Expr.(*ast.ColumnNameExpr) 113 _, _, column := getColumnInfoFromColumnName(columnNameExpr.Name) 114 115 if rule.GetShardingColumn() != column { 116 indexes := rule.GetSubTableIndexes() 117 return indexes, nil 118 } 119 120 if _, ok := rule.GetShard().(router.RangeShard); ok { 121 return getShardBetweenExprRouteResult(rule, n) 122 } 123 124 indexes := rule.GetSubTableIndexes() 125 return indexes, nil 126 } 127 128 // copy from origin PlanBuilder.getRangeShardTableIndex 129 func getShardBetweenExprRouteResult(rule router.Rule, n *ast.BetweenExpr) ([]int, error) { 130 rangeShard := rule.GetShard().(router.RangeShard) 131 132 leftValueExpr, ok := n.Left.(*driver.ValueExpr) 133 if !ok { 134 return nil, fmt.Errorf("n.Left is not a ValueExpr, type: %T", n.Left) 135 } 136 leftValue, err := util.GetValueExprResult(leftValueExpr) 137 if err != nil { 138 return nil, fmt.Errorf("get value from n.Left error: %v", err) 139 } 140 141 rightValueExpr, ok := n.Right.(*driver.ValueExpr) 142 if !ok { 143 return nil, fmt.Errorf("n.Left is not a ValueExpr, type: %T", n.Right) 144 } 145 rightValue, err := util.GetValueExprResult(rightValueExpr) 146 if err != nil { 147 return nil, fmt.Errorf("get value from n.Right error: %v", err) 148 } 149 150 start, err := rule.FindTableIndex(leftValue) 151 if err != nil { 152 return nil, fmt.Errorf("FindTableIndex for n.Left error: %v", err) 153 } 154 last, err := rule.FindTableIndex(rightValue) 155 if err != nil { 156 return nil, fmt.Errorf("FindTableIndex for n.Right error: %v", err) 157 } 158 159 if n.Not { 160 if start > last { 161 start, last = last, start 162 start = adjustShardIndex(rangeShard, rightValue, start) 163 } else { 164 start = adjustShardIndex(rangeShard, leftValue, start) 165 } 166 167 l1 := makeList(rule.GetFirstTableIndex(), start+1) 168 l2 := makeList(last, rule.GetLastTableIndex()+1) 169 return unionList(l1, l2), nil 170 171 } 172 if start > last { 173 start, last = last, start 174 } 175 return makeList(start, last+1), nil 176 }