github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/optimizer/plan/planbuilder.go (about) 1 // Copyright 2015 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 "math" 18 19 "github.com/insionng/yougam/libraries/golang/protobuf/proto" 20 "github.com/insionng/yougam/libraries/juju/errors" 21 "github.com/insionng/yougam/libraries/ngaut/log" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/ast" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/infoschema" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 25 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 26 "github.com/insionng/yougam/libraries/pingcap/tidb/parser/opcode" 27 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 28 "github.com/insionng/yougam/libraries/pingcap/tidb/util/charset" 29 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 30 ) 31 32 // Error instances. 33 var ( 34 ErrUnsupportedType = terror.ClassOptimizerPlan.New(CodeUnsupportedType, "Unsupported type") 35 SystemInternalErrorType = terror.ClassOptimizerPlan.New(SystemInternalError, "System internal error") 36 ) 37 38 // Error codes. 39 const ( 40 CodeUnsupportedType terror.ErrCode = 1 41 SystemInternalError terror.ErrCode = 2 42 ) 43 44 // BuildPlan builds a plan from a node. 45 // It returns ErrUnsupportedType if ast.Node type is not supported yet. 46 func BuildPlan(node ast.Node, sb SubQueryBuilder) (Plan, error) { 47 builder := planBuilder{sb: sb} 48 p := builder.build(node) 49 return p, builder.err 50 } 51 52 // planBuilder builds Plan from an ast.Node. 53 // It just builds the ast node straightforwardly. 54 type planBuilder struct { 55 err error 56 hasAgg bool 57 sb SubQueryBuilder 58 obj interface{} 59 } 60 61 func (b *planBuilder) build(node ast.Node) Plan { 62 switch x := node.(type) { 63 case *ast.AdminStmt: 64 return b.buildAdmin(x) 65 case *ast.AlterTableStmt: 66 return b.buildDDL(x) 67 case *ast.CreateDatabaseStmt: 68 return b.buildDDL(x) 69 case *ast.CreateIndexStmt: 70 return b.buildDDL(x) 71 case *ast.CreateTableStmt: 72 return b.buildDDL(x) 73 case *ast.DeallocateStmt: 74 return &Deallocate{Name: x.Name} 75 case *ast.DeleteStmt: 76 return b.buildDelete(x) 77 case *ast.DropDatabaseStmt: 78 return b.buildDDL(x) 79 case *ast.DropIndexStmt: 80 return b.buildDDL(x) 81 case *ast.DropTableStmt: 82 return b.buildDDL(x) 83 case *ast.ExecuteStmt: 84 return &Execute{Name: x.Name, UsingVars: x.UsingVars} 85 case *ast.ExplainStmt: 86 return b.buildExplain(x) 87 case *ast.InsertStmt: 88 return b.buildInsert(x) 89 case *ast.PrepareStmt: 90 return b.buildPrepare(x) 91 case *ast.SelectStmt: 92 if UseNewPlanner { 93 return b.buildNewSelect(x) 94 } 95 return b.buildSelect(x) 96 case *ast.UnionStmt: 97 return b.buildUnion(x) 98 case *ast.UpdateStmt: 99 return b.buildUpdate(x) 100 case *ast.UseStmt: 101 return b.buildSimple(x) 102 case *ast.SetCharsetStmt: 103 return b.buildSimple(x) 104 case *ast.SetStmt: 105 return b.buildSimple(x) 106 case *ast.ShowStmt: 107 return b.buildShow(x) 108 case *ast.DoStmt: 109 return b.buildSimple(x) 110 case *ast.BeginStmt: 111 return b.buildSimple(x) 112 case *ast.CommitStmt: 113 return b.buildSimple(x) 114 case *ast.RollbackStmt: 115 return b.buildSimple(x) 116 case *ast.CreateUserStmt: 117 return b.buildSimple(x) 118 case *ast.SetPwdStmt: 119 return b.buildSimple(x) 120 case *ast.GrantStmt: 121 return b.buildSimple(x) 122 case *ast.TruncateTableStmt: 123 return b.buildDDL(x) 124 } 125 b.err = ErrUnsupportedType.Gen("Unsupported type %T", node) 126 return nil 127 } 128 129 // Detect aggregate function or groupby clause. 130 func (b *planBuilder) detectSelectAgg(sel *ast.SelectStmt) bool { 131 if sel.GroupBy != nil { 132 return true 133 } 134 for _, f := range sel.GetResultFields() { 135 if ast.HasAggFlag(f.Expr) { 136 return true 137 } 138 } 139 if sel.Having != nil { 140 if ast.HasAggFlag(sel.Having.Expr) { 141 return true 142 } 143 } 144 if sel.OrderBy != nil { 145 for _, item := range sel.OrderBy.Items { 146 if ast.HasAggFlag(item.Expr) { 147 return true 148 } 149 } 150 } 151 return false 152 } 153 154 // extractSelectAgg extracts aggregate functions and converts ColumnNameExpr to aggregate function. 155 func (b *planBuilder) extractSelectAgg(sel *ast.SelectStmt) []*ast.AggregateFuncExpr { 156 extractor := &ast.AggregateFuncExtractor{AggFuncs: make([]*ast.AggregateFuncExpr, 0)} 157 for _, f := range sel.GetResultFields() { 158 n, ok := f.Expr.Accept(extractor) 159 if !ok { 160 b.err = errors.New("Failed to extract agg expr!") 161 return nil 162 } 163 ve, ok := f.Expr.(*ast.ValueExpr) 164 if ok && len(f.Column.Name.O) > 0 { 165 agg := &ast.AggregateFuncExpr{ 166 F: ast.AggFuncFirstRow, 167 Args: []ast.ExprNode{ve}, 168 } 169 extractor.AggFuncs = append(extractor.AggFuncs, agg) 170 n = agg 171 } 172 f.Expr = n.(ast.ExprNode) 173 } 174 // Extract agg funcs from having clause. 175 if sel.Having != nil { 176 n, ok := sel.Having.Expr.Accept(extractor) 177 if !ok { 178 b.err = errors.New("Failed to extract agg expr from having clause") 179 return nil 180 } 181 sel.Having.Expr = n.(ast.ExprNode) 182 } 183 // Extract agg funcs from orderby clause. 184 if sel.OrderBy != nil { 185 for _, item := range sel.OrderBy.Items { 186 n, ok := item.Expr.Accept(extractor) 187 if !ok { 188 b.err = errors.New("Failed to extract agg expr from orderby clause") 189 return nil 190 } 191 item.Expr = n.(ast.ExprNode) 192 // If item is PositionExpr, we need to rebind it. 193 // For PositionExpr will refer to a ResultField in fieldlist. 194 // After extract AggExpr from fieldlist, it may be changed (See the code above). 195 if pe, ok := item.Expr.(*ast.PositionExpr); ok { 196 pe.Refer = sel.GetResultFields()[pe.N-1] 197 } 198 } 199 } 200 return extractor.AggFuncs 201 } 202 203 func (b *planBuilder) buildSubquery(n ast.Node) { 204 sv := &subqueryVisitor{ 205 builder: b, 206 } 207 _, ok := n.Accept(sv) 208 if !ok { 209 log.Errorf("Extract subquery error") 210 } 211 } 212 213 func (b *planBuilder) buildSelect(sel *ast.SelectStmt) Plan { 214 var aggFuncs []*ast.AggregateFuncExpr 215 hasAgg := b.detectSelectAgg(sel) 216 canPushLimit := !hasAgg 217 if hasAgg { 218 aggFuncs = b.extractSelectAgg(sel) 219 } 220 // Build subquery 221 // Convert subquery to expr with plan 222 b.buildSubquery(sel) 223 var p Plan 224 if sel.From != nil { 225 p = b.buildFrom(sel) 226 if b.err != nil { 227 return nil 228 } 229 if sel.LockTp != ast.SelectLockNone { 230 p = b.buildSelectLock(p, sel.LockTp) 231 if b.err != nil { 232 return nil 233 } 234 } 235 if hasAgg { 236 p = b.buildAggregate(p, aggFuncs, sel.GroupBy) 237 } 238 p = b.buildSelectFields(p, sel.GetResultFields()) 239 if b.err != nil { 240 return nil 241 } 242 } else { 243 canPushLimit = false 244 if sel.Where != nil { 245 p = b.buildTableDual(sel) 246 } 247 if hasAgg { 248 p = b.buildAggregate(p, aggFuncs, nil) 249 } 250 p = b.buildSelectFields(p, sel.GetResultFields()) 251 if b.err != nil { 252 return nil 253 } 254 } 255 if sel.Having != nil { 256 p = b.buildHaving(p, sel.Having) 257 if b.err != nil { 258 return nil 259 } 260 } 261 if sel.Distinct { 262 canPushLimit = false 263 p = b.buildDistinct(p) 264 if b.err != nil { 265 return nil 266 } 267 } 268 if sel.OrderBy != nil && !pushOrder(p, sel.OrderBy.Items) { 269 canPushLimit = false 270 p = b.buildSort(p, sel.OrderBy.Items) 271 if b.err != nil { 272 return nil 273 } 274 } 275 if sel.Limit != nil { 276 if canPushLimit { 277 pushLimit(p, sel.Limit) 278 } 279 p = b.buildLimit(p, sel.Limit) 280 if b.err != nil { 281 return nil 282 } 283 } 284 return p 285 } 286 287 func (b *planBuilder) buildFrom(sel *ast.SelectStmt) Plan { 288 from := sel.From.TableRefs 289 if from.Right == nil { 290 return b.buildTableSource(sel) 291 } 292 return b.buildJoin(sel) 293 } 294 295 func (b *planBuilder) buildTableSource(sel *ast.SelectStmt) Plan { 296 from := sel.From.TableRefs 297 ts, ok := from.Left.(*ast.TableSource) 298 if !ok { 299 b.err = ErrUnsupportedType.Gen("Unsupported type %T", from.Left) 300 return nil 301 } 302 var bestPlan Plan 303 switch v := ts.Source.(type) { 304 case *ast.TableName: 305 case *ast.SelectStmt: 306 bestPlan = b.buildSelect(v) 307 case *ast.UnionStmt: 308 bestPlan = b.buildUnion(v) 309 } 310 if bestPlan != nil { 311 return bestPlan 312 } 313 tn, ok := ts.Source.(*ast.TableName) 314 if !ok { 315 b.err = ErrUnsupportedType.Gen("Unsupported type %T", ts.Source) 316 return nil 317 } 318 conditions := splitWhere(sel.Where) 319 path := &joinPath{table: tn, conditions: conditions} 320 candidates := b.buildAllAccessMethodsPlan(path) 321 var lowestCost float64 322 for _, v := range candidates { 323 cost := EstimateCost(b.buildPseudoSelectPlan(v, sel)) 324 if bestPlan == nil { 325 bestPlan = v 326 lowestCost = cost 327 } 328 if cost <= lowestCost { 329 bestPlan = v 330 lowestCost = cost 331 } 332 } 333 return bestPlan 334 } 335 336 func (b *planBuilder) buildAllAccessMethodsPlan(path *joinPath) []Plan { 337 indices, includeTableScan := b.availableIndices(path.table) 338 var candidates []Plan 339 if includeTableScan { 340 p := b.buildTableScanPlan(path) 341 candidates = append(candidates, p) 342 } 343 for _, index := range indices { 344 ip := b.buildIndexScanPlan(index, path) 345 candidates = append(candidates, ip) 346 } 347 return candidates 348 } 349 350 func (b *planBuilder) availableIndices(table *ast.TableName) (indices []*model.IndexInfo, includeTableScan bool) { 351 var usableHints []*ast.IndexHint 352 for _, hint := range table.IndexHints { 353 if hint.HintScope == ast.HintForScan { 354 usableHints = append(usableHints, hint) 355 } 356 } 357 if len(usableHints) == 0 { 358 return table.TableInfo.Indices, true 359 } 360 var hasUse bool 361 var ignores []*model.IndexInfo 362 for _, hint := range usableHints { 363 switch hint.HintType { 364 case ast.HintUse, ast.HintForce: 365 // Currently we don't distinguish between Force and Use because our cost estimation is not reliable. 366 hasUse = true 367 for _, idxName := range hint.IndexNames { 368 idx := findIndexByName(table.TableInfo.Indices, idxName) 369 if idx != nil { 370 indices = append(indices, idx) 371 } 372 } 373 case ast.HintIgnore: 374 // Collect all the ignore index hints. 375 for _, idxName := range hint.IndexNames { 376 idx := findIndexByName(table.TableInfo.Indices, idxName) 377 if idx != nil { 378 ignores = append(ignores, idx) 379 } 380 } 381 } 382 } 383 indices = removeIgnores(indices, ignores) 384 // If we have got FORCE or USE index hint, table scan is excluded. 385 if len(indices) != 0 { 386 return indices, false 387 } 388 if hasUse { 389 // Empty use hint means don't use any index. 390 return nil, true 391 } 392 if len(ignores) == 0 { 393 return table.TableInfo.Indices, true 394 } 395 for _, idx := range table.TableInfo.Indices { 396 // Exclude ignored index. 397 if findIndexByName(ignores, idx.Name) == nil { 398 indices = append(indices, idx) 399 } 400 } 401 return indices, true 402 } 403 404 func removeIgnores(indices, ignores []*model.IndexInfo) []*model.IndexInfo { 405 if len(ignores) == 0 { 406 return indices 407 } 408 var remainedIndices []*model.IndexInfo 409 for _, index := range indices { 410 if findIndexByName(ignores, index.Name) == nil { 411 remainedIndices = append(remainedIndices, index) 412 } 413 } 414 return remainedIndices 415 } 416 417 func findIndexByName(indices []*model.IndexInfo, name model.CIStr) *model.IndexInfo { 418 for _, idx := range indices { 419 if idx.Name.L == name.L { 420 return idx 421 } 422 } 423 return nil 424 } 425 426 func (b *planBuilder) buildTableDual(sel *ast.SelectStmt) Plan { 427 dual := &TableDual{FilterConditions: splitWhere(sel.Where)} 428 ret := ast.ResultField{} 429 dual.SetFields([]*ast.ResultField{&ret}) 430 return dual 431 } 432 433 func getTableAsName(fields []*ast.ResultField) *model.CIStr { 434 if len(fields) > 0 { 435 return &fields[0].TableAsName 436 } 437 return nil 438 } 439 440 func (b *planBuilder) buildTableScanPlan(path *joinPath) Plan { 441 tn := path.table 442 p := &TableScan{ 443 Table: tn.TableInfo, 444 TableName: tn, 445 } 446 // Equal condition contains a column from previous joined table. 447 p.RefAccess = len(path.eqConds) > 0 448 p.SetFields(tn.GetResultFields()) 449 p.TableAsName = getTableAsName(p.Fields()) 450 var pkName model.CIStr 451 if p.Table.PKIsHandle { 452 for _, colInfo := range p.Table.Columns { 453 if mysql.HasPriKeyFlag(colInfo.Flag) { 454 pkName = colInfo.Name 455 } 456 } 457 } 458 for _, con := range path.conditions { 459 if pkName.L != "" { 460 checker := conditionChecker{tableName: tn.TableInfo.Name, pkName: pkName} 461 if checker.check(con) { 462 p.AccessConditions = append(p.AccessConditions, con) 463 } else { 464 p.FilterConditions = append(p.FilterConditions, con) 465 } 466 } else { 467 p.FilterConditions = append(p.FilterConditions, con) 468 } 469 } 470 return p 471 } 472 473 func (b *planBuilder) buildIndexScanPlan(index *model.IndexInfo, path *joinPath) Plan { 474 tn := path.table 475 ip := &IndexScan{Table: tn.TableInfo, Index: index, TableName: tn} 476 ip.RefAccess = len(path.eqConds) > 0 477 ip.SetFields(tn.GetResultFields()) 478 ip.TableAsName = getTableAsName(ip.Fields()) 479 480 condMap := map[ast.ExprNode]bool{} 481 for _, con := range path.conditions { 482 condMap[con] = true 483 } 484 out: 485 // Build equal access conditions first. 486 // Starts from the first index column, if equal condition is found, add it to access conditions, 487 // proceed to the next index column. until we can't find any equal condition for the column. 488 for ip.AccessEqualCount < len(index.Columns) { 489 for con := range condMap { 490 binop, ok := con.(*ast.BinaryOperationExpr) 491 if !ok || binop.Op != opcode.EQ { 492 continue 493 } 494 if ast.IsPreEvaluable(binop.L) { 495 binop.L, binop.R = binop.R, binop.L 496 } 497 if !ast.IsPreEvaluable(binop.R) { 498 continue 499 } 500 cn, ok2 := binop.L.(*ast.ColumnNameExpr) 501 if !ok2 || cn.Refer.Column.Name.L != index.Columns[ip.AccessEqualCount].Name.L { 502 continue 503 } 504 ip.AccessConditions = append(ip.AccessConditions, con) 505 delete(condMap, con) 506 ip.AccessEqualCount++ 507 continue out 508 } 509 break 510 } 511 512 for con := range condMap { 513 if ip.AccessEqualCount < len(ip.Index.Columns) { 514 // Try to add non-equal access condition for index column at AccessEqualCount. 515 checker := conditionChecker{tableName: tn.TableInfo.Name, idx: index, columnOffset: ip.AccessEqualCount} 516 if checker.check(con) { 517 ip.AccessConditions = append(ip.AccessConditions, con) 518 } else { 519 ip.FilterConditions = append(ip.FilterConditions, con) 520 } 521 } else { 522 ip.FilterConditions = append(ip.FilterConditions, con) 523 } 524 } 525 return ip 526 } 527 528 // buildPseudoSelectPlan pre-builds more complete plans that may affect total cost. 529 // Also set OutOfOrder and NoLimit property. 530 func (b *planBuilder) buildPseudoSelectPlan(p Plan, sel *ast.SelectStmt) Plan { 531 if sel.OrderBy == nil { 532 return p 533 } 534 if sel.GroupBy != nil { 535 return p 536 } 537 if !pushOrder(p, sel.OrderBy.Items) { 538 switch x := p.(type) { 539 case *IndexScan: 540 x.OutOfOrder = true 541 x.NoLimit = true 542 } 543 np := &Sort{ByItems: sel.OrderBy.Items} 544 addChild(np, p) 545 p = np 546 } 547 if sel.Limit != nil { 548 np := &Limit{Offset: sel.Limit.Offset, Count: sel.Limit.Count} 549 addChild(np, p) 550 np.SetLimit(0) 551 p = np 552 } else { 553 switch x := p.(type) { 554 case *IndexScan: 555 x.NoLimit = true 556 } 557 } 558 return p 559 } 560 561 func (b *planBuilder) buildSelectLock(src Plan, lock ast.SelectLockType) *SelectLock { 562 selectLock := &SelectLock{ 563 Lock: lock, 564 } 565 addChild(selectLock, src) 566 selectLock.SetFields(src.Fields()) 567 return selectLock 568 } 569 570 func (b *planBuilder) buildSelectFields(src Plan, fields []*ast.ResultField) Plan { 571 selectFields := &SelectFields{} 572 addChild(selectFields, src) 573 selectFields.SetFields(fields) 574 return selectFields 575 } 576 577 func (b *planBuilder) buildAggregate(src Plan, aggFuncs []*ast.AggregateFuncExpr, groupby *ast.GroupByClause) Plan { 578 // Add aggregate plan. 579 aggPlan := &Aggregate{ 580 AggFuncs: aggFuncs, 581 } 582 addChild(aggPlan, src) 583 if src != nil { 584 aggPlan.SetFields(src.Fields()) 585 } 586 if groupby != nil { 587 aggPlan.GroupByItems = groupby.Items 588 } 589 return aggPlan 590 } 591 592 func (b *planBuilder) buildHaving(src Plan, having *ast.HavingClause) Plan { 593 p := &Having{ 594 Conditions: splitWhere(having.Expr), 595 } 596 addChild(p, src) 597 p.SetFields(src.Fields()) 598 return p 599 } 600 601 func (b *planBuilder) buildSort(src Plan, byItems []*ast.ByItem) Plan { 602 sort := &Sort{ 603 ByItems: byItems, 604 } 605 addChild(sort, src) 606 sort.SetFields(src.Fields()) 607 return sort 608 } 609 610 func (b *planBuilder) buildLimit(src Plan, limit *ast.Limit) Plan { 611 li := &Limit{ 612 Offset: limit.Offset, 613 Count: limit.Count, 614 } 615 if s, ok := src.(*Sort); ok { 616 s.ExecLimit = li 617 return s 618 } 619 addChild(li, src) 620 li.SetFields(src.Fields()) 621 return li 622 } 623 624 func (b *planBuilder) buildPrepare(x *ast.PrepareStmt) Plan { 625 p := &Prepare{ 626 Name: x.Name, 627 } 628 if x.SQLVar != nil { 629 p.SQLText, _ = x.SQLVar.GetValue().(string) 630 } else { 631 p.SQLText = x.SQLText 632 } 633 return p 634 } 635 636 func (b *planBuilder) buildAdmin(as *ast.AdminStmt) Plan { 637 var p Plan 638 639 switch as.Tp { 640 case ast.AdminCheckTable: 641 p = &CheckTable{Tables: as.Tables} 642 case ast.AdminShowDDL: 643 p = &ShowDDL{} 644 p.SetFields(buildShowDDLFields()) 645 default: 646 b.err = ErrUnsupportedType.Gen("Unsupported type %T", as) 647 } 648 649 return p 650 } 651 652 func buildShowDDLFields() []*ast.ResultField { 653 rfs := make([]*ast.ResultField, 0, 6) 654 rfs = append(rfs, buildResultField("", "SCHEMA_VER", mysql.TypeLonglong, 4)) 655 rfs = append(rfs, buildResultField("", "OWNER", mysql.TypeVarchar, 64)) 656 rfs = append(rfs, buildResultField("", "JOB", mysql.TypeVarchar, 128)) 657 rfs = append(rfs, buildResultField("", "BG_SCHEMA_VER", mysql.TypeLonglong, 4)) 658 rfs = append(rfs, buildResultField("", "BG_OWNER", mysql.TypeVarchar, 64)) 659 rfs = append(rfs, buildResultField("", "BG_JOB", mysql.TypeVarchar, 128)) 660 661 return rfs 662 } 663 664 func buildResultField(tableName, name string, tp byte, size int) *ast.ResultField { 665 cs := charset.CharsetBin 666 cl := charset.CharsetBin 667 flag := mysql.UnsignedFlag 668 if tp == mysql.TypeVarchar || tp == mysql.TypeBlob { 669 cs = mysql.DefaultCharset 670 cl = mysql.DefaultCollationName 671 flag = 0 672 } 673 674 fieldType := types.FieldType{ 675 Charset: cs, 676 Collate: cl, 677 Tp: tp, 678 Flen: size, 679 Flag: uint(flag), 680 } 681 colInfo := &model.ColumnInfo{ 682 Name: model.NewCIStr(name), 683 FieldType: fieldType, 684 } 685 expr := &ast.ValueExpr{} 686 expr.SetType(&fieldType) 687 688 return &ast.ResultField{ 689 Column: colInfo, 690 ColumnAsName: colInfo.Name, 691 TableAsName: model.NewCIStr(tableName), 692 DBName: model.NewCIStr(infoschema.Name), 693 Expr: expr, 694 } 695 } 696 697 func pushLimit(p Plan, limit *ast.Limit) { 698 switch x := p.(type) { 699 case *IndexScan: 700 limitCount := limit.Offset + limit.Count 701 if limitCount < math.MaxInt64 { 702 x.LimitCount = proto.Int64(int64(limitCount)) 703 } 704 case *TableScan: 705 limitCount := limit.Offset + limit.Count 706 if limitCount < math.MaxInt64 { 707 x.LimitCount = proto.Int64(int64(limitCount)) 708 } 709 default: 710 child := x.GetChildByIndex(0) 711 if child != nil { 712 pushLimit(child, limit) 713 } 714 } 715 } 716 717 // pushOrder tries to push order by items to the plan, returns true if 718 // order is pushed. 719 func pushOrder(p Plan, items []*ast.ByItem) bool { 720 switch x := p.(type) { 721 case *Aggregate: 722 return false 723 case *IndexScan: 724 if len(items) > len(x.Index.Columns) { 725 return false 726 } 727 var hasDesc bool 728 var hasAsc bool 729 for i, item := range items { 730 var rf *ast.ResultField 731 switch y := item.Expr.(type) { 732 case *ast.ColumnNameExpr: 733 rf = y.Refer 734 case *ast.PositionExpr: 735 rf = y.Refer 736 default: 737 return false 738 } 739 if rf.Table.Name.L != x.Table.Name.L || rf.Column.Name.L != x.Index.Columns[i].Name.L { 740 return false 741 } 742 if item.Desc { 743 if hasAsc { 744 return false 745 } 746 hasDesc = true 747 } else { 748 if hasDesc { 749 return false 750 } 751 hasAsc = true 752 } 753 } 754 x.Desc = hasDesc 755 return true 756 case *TableScan: 757 if len(items) != 1 || !x.Table.PKIsHandle { 758 return false 759 } 760 var refer *ast.ResultField 761 switch x := items[0].Expr.(type) { 762 case *ast.ColumnNameExpr: 763 refer = x.Refer 764 case *ast.PositionExpr: 765 refer = x.Refer 766 default: 767 return false 768 } 769 if mysql.HasPriKeyFlag(refer.Column.Flag) { 770 x.Desc = items[0].Desc 771 return true 772 } 773 return false 774 case *JoinOuter: 775 return false 776 case *JoinInner: 777 return false 778 case *Sort: 779 // Sort plan should not be checked here as there should only be one sort plan in a plan tree. 780 return false 781 default: 782 child := x.GetChildByIndex(0) 783 if child != nil { 784 return pushOrder(child, items) 785 } 786 } 787 return false 788 } 789 790 // splitWhere split a where expression to a list of AND conditions. 791 func splitWhere(where ast.ExprNode) []ast.ExprNode { 792 var conditions []ast.ExprNode 793 switch x := where.(type) { 794 case nil: 795 case *ast.BinaryOperationExpr: 796 if x.Op == opcode.AndAnd { 797 conditions = append(conditions, splitWhere(x.L)...) 798 conditions = append(conditions, splitWhere(x.R)...) 799 } else { 800 conditions = append(conditions, x) 801 } 802 case *ast.ParenthesesExpr: 803 conditions = append(conditions, splitWhere(x.Expr)...) 804 default: 805 conditions = append(conditions, where) 806 } 807 return conditions 808 } 809 810 // SubQueryBuilder is the interface for building SubQuery executor. 811 type SubQueryBuilder interface { 812 Build(p Plan) ast.SubqueryExec 813 } 814 815 // subqueryVisitor visits AST and handles SubqueryExpr. 816 type subqueryVisitor struct { 817 builder *planBuilder 818 } 819 820 func (se *subqueryVisitor) Enter(in ast.Node) (out ast.Node, skipChildren bool) { 821 switch x := in.(type) { 822 case *ast.SubqueryExpr: 823 p := se.builder.build(x.Query) 824 // The expr pointor is copyed into ResultField when running name resolver. 825 // So we can not just replace the expr node in AST. We need to put SubQuery into the expr. 826 // See: optimizer.nameResolver.createResultFields() 827 x.SubqueryExec = se.builder.sb.Build(p) 828 return in, true 829 case *ast.Join: 830 // SubSelect in from clause will be handled in buildJoin(). 831 return in, true 832 } 833 return in, false 834 } 835 836 func (se *subqueryVisitor) Leave(in ast.Node) (out ast.Node, ok bool) { 837 return in, true 838 } 839 840 func (b *planBuilder) buildUnion(union *ast.UnionStmt) Plan { 841 sels := make([]Plan, len(union.SelectList.Selects)) 842 for i, sel := range union.SelectList.Selects { 843 if UseNewPlanner { 844 sels[i] = b.buildNewSelect(sel) 845 } else { 846 sels[i] = b.buildSelect(sel) 847 } 848 } 849 var p Plan 850 p = &Union{ 851 Selects: sels, 852 basePlan: basePlan{ 853 children: sels, 854 }, 855 } 856 unionFields := union.GetResultFields() 857 for _, sel := range sels { 858 for i, f := range sel.Fields() { 859 if i == len(unionFields) { 860 b.err = errors.New("The used SELECT statements have a different number of columns") 861 return nil 862 } 863 uField := unionFields[i] 864 /* 865 * The lengths of the columns in the UNION result take into account the values retrieved by all of the SELECT statements 866 * SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10); 867 * +---------------+ 868 * | REPEAT('a',1) | 869 * +---------------+ 870 * | a | 871 * | bbbbbbbbbb | 872 * +---------------+ 873 */ 874 if f.Column.Flen > uField.Column.Flen { 875 uField.Column.Flen = f.Column.Flen 876 } 877 // For select nul union select "abc", we should not convert "abc" to nil. 878 // And the result field type should be VARCHAR. 879 if uField.Column.Tp == 0 || uField.Column.Tp == mysql.TypeNull { 880 uField.Column.Tp = f.Column.Tp 881 } 882 } 883 addChild(p, sel) 884 } 885 for _, v := range unionFields { 886 v.Expr.SetType(&v.Column.FieldType) 887 } 888 889 p.SetFields(unionFields) 890 if union.Distinct { 891 p = b.buildDistinct(p) 892 } 893 if union.OrderBy != nil { 894 p = b.buildSort(p, union.OrderBy.Items) 895 } 896 if union.Limit != nil { 897 p = b.buildLimit(p, union.Limit) 898 } 899 return p 900 } 901 902 func (b *planBuilder) buildDistinct(src Plan) Plan { 903 d := &Distinct{} 904 addChild(d, src) 905 d.SetFields(src.Fields()) 906 return d 907 } 908 909 func (b *planBuilder) buildUpdate(update *ast.UpdateStmt) Plan { 910 sel := &ast.SelectStmt{From: update.TableRefs, Where: update.Where, OrderBy: update.Order, Limit: update.Limit} 911 p := b.buildFrom(sel) 912 for _, v := range p.Fields() { 913 v.Referenced = true 914 } 915 if sel.OrderBy != nil && !pushOrder(p, sel.OrderBy.Items) { 916 p = b.buildSort(p, sel.OrderBy.Items) 917 if b.err != nil { 918 return nil 919 } 920 } 921 if sel.Limit != nil { 922 pushLimit(p, sel.Limit) 923 p = b.buildLimit(p, sel.Limit) 924 if b.err != nil { 925 return nil 926 } 927 } 928 orderedList := b.buildUpdateLists(update.List, p.Fields()) 929 if b.err != nil { 930 return nil 931 } 932 return &Update{OrderedList: orderedList, SelectPlan: p, basePlan: basePlan{children: []Plan{p}}} 933 } 934 935 func (b *planBuilder) buildUpdateLists(list []*ast.Assignment, fields []*ast.ResultField) []*ast.Assignment { 936 newList := make([]*ast.Assignment, len(fields)) 937 for _, assign := range list { 938 offset, err := columnOffsetInFields(assign.Column, fields) 939 if err != nil { 940 b.err = errors.Trace(err) 941 return nil 942 } 943 newList[offset] = assign 944 } 945 return newList 946 } 947 948 func (b *planBuilder) buildDelete(del *ast.DeleteStmt) Plan { 949 sel := &ast.SelectStmt{From: del.TableRefs, Where: del.Where, OrderBy: del.Order, Limit: del.Limit} 950 p := b.buildFrom(sel) 951 for _, v := range p.Fields() { 952 v.Referenced = true 953 } 954 if sel.OrderBy != nil && !pushOrder(p, sel.OrderBy.Items) { 955 p = b.buildSort(p, sel.OrderBy.Items) 956 if b.err != nil { 957 return nil 958 } 959 } 960 if sel.Limit != nil { 961 pushLimit(p, sel.Limit) 962 p = b.buildLimit(p, sel.Limit) 963 if b.err != nil { 964 return nil 965 } 966 } 967 var tables []*ast.TableName 968 if del.Tables != nil { 969 tables = del.Tables.Tables 970 } 971 return &Delete{ 972 Tables: tables, 973 IsMultiTable: del.IsMultiTable, 974 SelectPlan: p, 975 basePlan: basePlan{children: []Plan{p}}, 976 } 977 } 978 979 func columnOffsetInFields(cn *ast.ColumnName, fields []*ast.ResultField) (int, error) { 980 offset := -1 981 tableNameL := cn.Table.L 982 columnNameL := cn.Name.L 983 if tableNameL != "" { 984 for i, f := range fields { 985 // Check table name. 986 if f.TableAsName.L != "" { 987 if tableNameL != f.TableAsName.L { 988 continue 989 } 990 } else { 991 if tableNameL != f.Table.Name.L { 992 continue 993 } 994 } 995 // Check column name. 996 if f.ColumnAsName.L != "" { 997 if columnNameL != f.ColumnAsName.L { 998 continue 999 } 1000 } else { 1001 if columnNameL != f.Column.Name.L { 1002 continue 1003 } 1004 } 1005 1006 offset = i 1007 } 1008 } else { 1009 for i, f := range fields { 1010 matchAsName := f.ColumnAsName.L != "" && f.ColumnAsName.L == columnNameL 1011 matchColumnName := f.ColumnAsName.L == "" && f.Column.Name.L == columnNameL 1012 if matchAsName || matchColumnName { 1013 if offset != -1 { 1014 return -1, errors.Errorf("column %s is ambiguous.", cn.Name.O) 1015 } 1016 offset = i 1017 } 1018 } 1019 } 1020 if offset == -1 { 1021 return -1, errors.Errorf("column %s not found", cn.Name.O) 1022 } 1023 return offset, nil 1024 } 1025 1026 func (b *planBuilder) buildShow(show *ast.ShowStmt) Plan { 1027 var p Plan 1028 p = &Show{ 1029 Tp: show.Tp, 1030 DBName: show.DBName, 1031 Table: show.Table, 1032 Column: show.Column, 1033 Flag: show.Flag, 1034 Full: show.Full, 1035 User: show.User, 1036 } 1037 p.SetFields(show.GetResultFields()) 1038 var conditions []ast.ExprNode 1039 if show.Pattern != nil { 1040 conditions = append(conditions, show.Pattern) 1041 } 1042 if show.Where != nil { 1043 conditions = append(conditions, show.Where) 1044 } 1045 if len(conditions) != 0 { 1046 filter := &Filter{Conditions: conditions} 1047 addChild(filter, p) 1048 p = filter 1049 } 1050 return p 1051 } 1052 1053 func (b *planBuilder) buildSimple(node ast.StmtNode) Plan { 1054 return &Simple{Statement: node} 1055 } 1056 1057 func (b *planBuilder) buildInsert(insert *ast.InsertStmt) Plan { 1058 insertPlan := &Insert{ 1059 Table: insert.Table, 1060 Columns: insert.Columns, 1061 Lists: insert.Lists, 1062 Setlist: insert.Setlist, 1063 OnDuplicate: insert.OnDuplicate, 1064 IsReplace: insert.IsReplace, 1065 Priority: insert.Priority, 1066 } 1067 if insert.Select != nil { 1068 insertPlan.SelectPlan = b.build(insert.Select) 1069 addChild(insertPlan, insertPlan.SelectPlan) 1070 if b.err != nil { 1071 return nil 1072 } 1073 } 1074 return insertPlan 1075 } 1076 1077 func (b *planBuilder) buildDDL(node ast.DDLNode) Plan { 1078 return &DDL{Statement: node} 1079 } 1080 1081 func (b *planBuilder) buildExplain(explain *ast.ExplainStmt) Plan { 1082 if show, ok := explain.Stmt.(*ast.ShowStmt); ok { 1083 return b.buildShow(show) 1084 } 1085 targetPlan := b.build(explain.Stmt) 1086 if b.err != nil { 1087 return nil 1088 } 1089 p := &Explain{StmtPlan: targetPlan} 1090 addChild(p, targetPlan) 1091 p.SetFields(buildExplainFields()) 1092 return p 1093 } 1094 1095 // See: https://dev.mysql.com/doc/refman/5.7/en/explain-output.html 1096 func buildExplainFields() []*ast.ResultField { 1097 rfs := make([]*ast.ResultField, 0, 10) 1098 rfs = append(rfs, buildResultField("", "id", mysql.TypeLonglong, 4)) 1099 rfs = append(rfs, buildResultField("", "select_type", mysql.TypeVarchar, 128)) 1100 rfs = append(rfs, buildResultField("", "table", mysql.TypeVarchar, 128)) 1101 rfs = append(rfs, buildResultField("", "type", mysql.TypeVarchar, 128)) 1102 rfs = append(rfs, buildResultField("", "possible_keys", mysql.TypeVarchar, 128)) 1103 rfs = append(rfs, buildResultField("", "key", mysql.TypeVarchar, 128)) 1104 rfs = append(rfs, buildResultField("", "key_len", mysql.TypeVarchar, 128)) 1105 rfs = append(rfs, buildResultField("", "ref", mysql.TypeVarchar, 128)) 1106 rfs = append(rfs, buildResultField("", "rows", mysql.TypeVarchar, 128)) 1107 rfs = append(rfs, buildResultField("", "Extra", mysql.TypeVarchar, 128)) 1108 return rfs 1109 }