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  }