github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/optimizer/plan/newplanbuilder.go (about) 1 // Copyright 2016 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package plan 15 16 import ( 17 "github.com/insionng/yougam/libraries/pingcap/tidb/ast" 18 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 19 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 20 "github.com/insionng/yougam/libraries/pingcap/tidb/parser/opcode" 21 ) 22 23 // UseNewPlanner means if use the new planner. 24 var UseNewPlanner = false 25 26 func (b *planBuilder) buildNewSinglePathPlan(node ast.ResultSetNode) Plan { 27 switch x := node.(type) { 28 case *ast.Join: 29 return b.buildNewJoin(x) 30 case *ast.TableSource: 31 switch v := x.Source.(type) { 32 case *ast.SelectStmt: 33 return b.buildNewSelect(v) 34 case *ast.UnionStmt: 35 return b.buildUnion(v) 36 case *ast.TableName: 37 //TODO: select physical algorithm during cbo phase. 38 return b.buildNewTableScanPlan(v) 39 default: 40 b.err = ErrUnsupportedType.Gen("unsupported table source type %T", v) 41 return nil 42 } 43 default: 44 b.err = ErrUnsupportedType.Gen("unsupported table source type %T", x) 45 return nil 46 } 47 } 48 49 func fromFields(col *ast.ColumnNameExpr, fields []*ast.ResultField) bool { 50 for _, field := range fields { 51 if field == col.Refer { 52 return true 53 } 54 } 55 return false 56 } 57 58 type columnsExtractor struct { 59 result []*ast.ColumnNameExpr 60 } 61 62 func (ce *columnsExtractor) Enter(expr ast.Node) (ret ast.Node, skipChildren bool) { 63 switch v := expr.(type) { 64 case *ast.ColumnNameExpr: 65 ce.result = append(ce.result, v) 66 } 67 return expr, false 68 } 69 70 func (ce *columnsExtractor) Leave(expr ast.Node) (ret ast.Node, skipChildren bool) { 71 return expr, true 72 } 73 74 func extractOnCondition(conditions []ast.ExprNode, left Plan, right Plan) (eqCond []ast.ExprNode, leftCond []ast.ExprNode, rightCond []ast.ExprNode, otherCond []ast.ExprNode) { 75 for _, expr := range conditions { 76 binop, ok := expr.(*ast.BinaryOperationExpr) 77 if ok && binop.Op == opcode.EQ { 78 ln, lOK := binop.L.(*ast.ColumnNameExpr) 79 rn, rOK := binop.R.(*ast.ColumnNameExpr) 80 if lOK && rOK { 81 if fromFields(ln, left.Fields()) && fromFields(rn, right.Fields()) { 82 eqCond = append(eqCond, expr) 83 continue 84 } else if fromFields(rn, left.Fields()) && fromFields(ln, right.Fields()) { 85 eqCond = append(eqCond, &ast.BinaryOperationExpr{Op: opcode.EQ, L: rn, R: ln}) 86 continue 87 } 88 } 89 } 90 ce := &columnsExtractor{} 91 expr.Accept(ce) 92 columns := ce.result 93 allFromLeft, allFromRight := true, true 94 for _, col := range columns { 95 if fromFields(col, left.Fields()) { 96 allFromRight = false 97 } else { 98 allFromLeft = false 99 } 100 } 101 if allFromRight { 102 rightCond = append(rightCond, expr) 103 } else if allFromLeft { 104 leftCond = append(leftCond, expr) 105 } else { 106 otherCond = append(otherCond, expr) 107 } 108 } 109 return eqCond, leftCond, rightCond, otherCond 110 } 111 112 func (b *planBuilder) buildNewJoin(join *ast.Join) Plan { 113 if join.Right == nil { 114 return b.buildNewSinglePathPlan(join.Left) 115 } 116 leftPlan := b.buildNewSinglePathPlan(join.Left) 117 rightPlan := b.buildNewSinglePathPlan(join.Right) 118 var eqCond, leftCond, rightCond, otherCond []ast.ExprNode 119 if join.On != nil { 120 onCondition := splitWhere(join.On.Expr) 121 eqCond, leftCond, rightCond, otherCond = extractOnCondition(onCondition, leftPlan, rightPlan) 122 } 123 joinPlan := &Join{EqualConditions: eqCond, LeftConditions: leftCond, RightConditions: rightCond, OtherConditions: otherCond} 124 if join.Tp == ast.LeftJoin { 125 joinPlan.JoinType = LeftOuterJoin 126 } else if join.Tp == ast.RightJoin { 127 joinPlan.JoinType = RightOuterJoin 128 } else { 129 joinPlan.JoinType = InnerJoin 130 } 131 addChild(joinPlan, leftPlan) 132 addChild(joinPlan, rightPlan) 133 joinPlan.SetFields(append(leftPlan.Fields(), rightPlan.Fields()...)) 134 return joinPlan 135 } 136 137 func (b *planBuilder) buildFilter(p Plan, where ast.ExprNode) Plan { 138 conditions := splitWhere(where) 139 filter := &Filter{Conditions: conditions} 140 addChild(filter, p) 141 filter.SetFields(p.Fields()) 142 return filter 143 } 144 145 func (b *planBuilder) buildNewSelect(sel *ast.SelectStmt) Plan { 146 var aggFuncs []*ast.AggregateFuncExpr 147 hasAgg := b.detectSelectAgg(sel) 148 if hasAgg { 149 aggFuncs = b.extractSelectAgg(sel) 150 } 151 // Build subquery 152 // Convert subquery to expr with plan 153 b.buildSubquery(sel) 154 var p Plan 155 if sel.From != nil { 156 p = b.buildNewSinglePathPlan(sel.From.TableRefs) 157 if sel.Where != nil { 158 p = b.buildFilter(p, sel.Where) 159 } 160 if b.err != nil { 161 return nil 162 } 163 if sel.LockTp != ast.SelectLockNone { 164 p = b.buildSelectLock(p, sel.LockTp) 165 if b.err != nil { 166 return nil 167 } 168 } 169 if hasAgg { 170 p = b.buildAggregate(p, aggFuncs, sel.GroupBy) 171 } 172 p = b.buildSelectFields(p, sel.GetResultFields()) 173 if b.err != nil { 174 return nil 175 } 176 } else { 177 if sel.Where != nil { 178 p = b.buildTableDual(sel) 179 } 180 if hasAgg { 181 p = b.buildAggregate(p, aggFuncs, nil) 182 } 183 p = b.buildSelectFields(p, sel.GetResultFields()) 184 if b.err != nil { 185 return nil 186 } 187 } 188 if sel.Having != nil { 189 p = b.buildFilter(p, sel.Having.Expr) 190 if b.err != nil { 191 return nil 192 } 193 } 194 if sel.Distinct { 195 p = b.buildDistinct(p) 196 if b.err != nil { 197 return nil 198 } 199 } 200 if sel.OrderBy != nil && !pushOrder(p, sel.OrderBy.Items) { 201 p = b.buildSort(p, sel.OrderBy.Items) 202 if b.err != nil { 203 return nil 204 } 205 } 206 if sel.Limit != nil { 207 p = b.buildLimit(p, sel.Limit) 208 if b.err != nil { 209 return nil 210 } 211 } 212 return p 213 } 214 215 func (ts *TableScan) attachCondition(conditions []ast.ExprNode) { 216 var pkName model.CIStr 217 if ts.Table.PKIsHandle { 218 for _, colInfo := range ts.Table.Columns { 219 if mysql.HasPriKeyFlag(colInfo.Flag) { 220 pkName = colInfo.Name 221 } 222 } 223 } 224 for _, con := range conditions { 225 if pkName.L != "" { 226 checker := conditionChecker{tableName: ts.Table.Name, pkName: pkName} 227 if checker.check(con) { 228 ts.AccessConditions = append(ts.AccessConditions, con) 229 } else { 230 ts.FilterConditions = append(ts.FilterConditions, con) 231 } 232 } else { 233 ts.FilterConditions = append(ts.FilterConditions, con) 234 } 235 } 236 } 237 238 func (b *planBuilder) buildNewTableScanPlan(tn *ast.TableName) Plan { 239 p := &TableScan{ 240 Table: tn.TableInfo, 241 TableName: tn, 242 } 243 // Equal condition contains a column from previous joined table. 244 p.RefAccess = false 245 p.SetFields(tn.GetResultFields()) 246 p.TableAsName = getTableAsName(p.Fields()) 247 return p 248 }