Skip to content

Commit

Permalink
Merge pull request pingcap#651 from pingcap/coocood/new-plan
Browse files Browse the repository at this point in the history
optimizer, executor: Use new plan for simple select statement.
  • Loading branch information
coocood committed Dec 9, 2015
2 parents 6c8821e + 418a5fb commit d44db8b
Show file tree
Hide file tree
Showing 45 changed files with 6,559 additions and 1,168 deletions.
25 changes: 19 additions & 6 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,29 @@ type DMLNode interface {
dmlStatement()
}

// ResultField is computed from a parsed select statement.
// ResultField represents a result field which can be a column from a table,
// or an expression in select field. It is a generated property during
// binding process. ResultField is the key element to evaluate a ColumnNameExpr.
// After resolving process, every ColumnNameExpr will be resolved to a ResultField.
// During execution, every row retrieved from table will set the row value to
// ResultFields of that table, so ColumnNameExpr resolved to that ResultField can be
// easily evaluated.
type ResultField struct {
Column *model.ColumnInfo
ColumnAsName model.CIStr
Table *model.TableInfo
TableAsName model.CIStr
DBName model.CIStr

// The expression for the result field. If it is generated from a select field, it would
// be the expression of that select field, otherwise the type would be ValueExpr and value
// will be set for every retrieved row.
Expr ExprNode
}

// ResultSetNode interface has ResultFields property which is computed and set by visitor.
// Implementations include SelectStmt, SubqueryExpr, TableSource, TableName and Join.
// ResultSetNode interface has ResultFields property which is computed and set by
// optimizer.InfoBinder during binding process. Implementations include SelectStmt,
// SubqueryExpr, TableSource, TableName and Join.
type ResultSetNode interface {
Node
// GetResultFields gets result fields of the result set node.
Expand All @@ -101,13 +113,14 @@ type ResultSetNode interface {

// Visitor visits a Node.
type Visitor interface {
// VisitEnter is called before children nodes is visited.
// Enter is called before children nodes are visited.
// The returned node must be the same type as the input node n.
// skipChildren returns true means children nodes should be skipped,
// this is useful when work is done in Enter and there is no need to visit children.
Enter(n Node) (node Node, skipChildren bool)
// VisitLeave is called after children nodes has been visited.
// The returned node must be the same type as the input node n.
// Leave is called after children nodes have been visited.
// The returned node's type can be different from the input node if it is a ExprNode,
// Non-expression node must be the same type as the input node n.
// ok returns false to stop visiting.
Leave(n Node) (node Node, ok bool)
}
3 changes: 0 additions & 3 deletions ast/cloner.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@ func copyStruct(in Node) (out Node) {
case *DefaultExpr:
nv := *v
out = &nv
case *IdentifierExpr:
nv := *v
out = &nv
case *ExistsSubqueryExpr:
nv := *v
out = &nv
Expand Down
92 changes: 45 additions & 47 deletions ast/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ package ast

import (
"fmt"
"regexp"

"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/parser/opcode"
"github.com/pingcap/tidb/util/charset"
"github.com/pingcap/tidb/util/types"
)

Expand All @@ -32,7 +35,6 @@ var (
_ Node = &ColumnName{}
_ ExprNode = &ColumnNameExpr{}
_ ExprNode = &DefaultExpr{}
_ ExprNode = &IdentifierExpr{}
_ ExprNode = &ExistsSubqueryExpr{}
_ ExprNode = &PatternInExpr{}
_ ExprNode = &IsNullExpr{}
Expand All @@ -58,10 +60,10 @@ func NewValueExpr(value interface{}) *ValueExpr {
ve := &ValueExpr{}
ve.Data = types.RawData(value)
// TODO: make it more precise.
switch value.(type) {
switch x := value.(type) {
case nil:
ve.Type = types.NewFieldType(mysql.TypeNull)
case bool, int64:
case bool, int64, int:
ve.Type = types.NewFieldType(mysql.TypeLonglong)
case uint64:
ve.Type = types.NewFieldType(mysql.TypeLonglong)
Expand All @@ -74,14 +76,24 @@ func NewValueExpr(value interface{}) *ValueExpr {
ve.Type = types.NewFieldType(mysql.TypeDouble)
case []byte:
ve.Type = types.NewFieldType(mysql.TypeBlob)
ve.Type.Charset = "binary"
ve.Type.Collate = "binary"
ve.Type.Charset = charset.CharsetBin
ve.Type.Collate = charset.CharsetBin
case mysql.Bit:
ve.Type = types.NewFieldType(mysql.TypeBit)
case mysql.Hex:
ve.Type = types.NewFieldType(mysql.TypeVarchar)
ve.Type.Charset = "binary"
ve.Type.Collate = "binary"
ve.Type.Charset = charset.CharsetBin
ve.Type.Collate = charset.CharsetBin
case mysql.Time:
ve.Type = types.NewFieldType(x.Type)
case mysql.Duration:
ve.Type = types.NewFieldType(mysql.TypeDuration)
case mysql.Decimal:
ve.Type = types.NewFieldType(mysql.TypeNewDecimal)
case mysql.Enum:
ve.Type = types.NewFieldType(mysql.TypeEnum)
case mysql.Set:
ve.Type = types.NewFieldType(mysql.TypeSet)
case *types.DataItem:
ve.Type = value.(*types.DataItem).Type
default:
Expand Down Expand Up @@ -221,11 +233,6 @@ func (n *WhenClause) Accept(v Visitor) (Node, bool) {
return v.Leave(n)
}

// IsStatic implements the ExprNode IsStatic interface.
func (n *WhenClause) IsStatic() bool {
return n.Expr.IsStatic() && n.Result.IsStatic()
}

// CaseExpr is the case expression.
type CaseExpr struct {
exprNode
Expand Down Expand Up @@ -274,7 +281,7 @@ func (n *CaseExpr) IsStatic() bool {
return false
}
for _, w := range n.WhenClauses {
if !w.IsStatic() {
if !w.Expr.IsStatic() || !w.Result.IsStatic() {
return false
}
}
Expand All @@ -284,7 +291,7 @@ func (n *CaseExpr) IsStatic() bool {
return true
}

// SubqueryExpr represents a sub query.
// SubqueryExpr represents a subquery.
type SubqueryExpr struct {
exprNode
// Query is the query SelectNode.
Expand Down Expand Up @@ -326,8 +333,8 @@ type CompareSubqueryExpr struct {
L ExprNode
// Op is the comparison opcode.
Op opcode.Op
// R is the sub query for right expression.
R *SubqueryExpr
// R is the subquery for right expression, may be rewritten to other type of expression.
R ExprNode
// All is true, we should compare all records in subquery.
All bool
}
Expand All @@ -348,7 +355,7 @@ func (n *CompareSubqueryExpr) Accept(v Visitor) (Node, bool) {
if !ok {
return n, false
}
n.R = node.(*SubqueryExpr)
n.R = node.(ExprNode)
return v.Leave(n)
}

Expand All @@ -358,10 +365,6 @@ type ColumnName struct {
Schema model.CIStr
Table model.CIStr
Name model.CIStr

DBInfo *model.DBInfo
TableInfo *model.TableInfo
ColumnInfo *model.ColumnInfo
}

// Accept implements Node Accept interface.
Expand All @@ -380,6 +383,10 @@ type ColumnNameExpr struct {

// Name is the referenced column name.
Name *ColumnName

// Refer is the result field the column name refers to.
// The value of Refer.Expr is used as the value of the expression.
Refer *ResultField
}

// Accept implements Node Accept interface.
Expand Down Expand Up @@ -421,29 +428,12 @@ func (n *DefaultExpr) Accept(v Visitor) (Node, bool) {
return v.Leave(n)
}

// IdentifierExpr represents an identifier expression.
type IdentifierExpr struct {
exprNode
// Name is the identifier name.
Name model.CIStr
}

// Accept implements Node Accept interface.
func (n *IdentifierExpr) Accept(v Visitor) (Node, bool) {
newNod, skipChildren := v.Enter(n)
if skipChildren {
return v.Leave(newNod)
}
n = newNod.(*IdentifierExpr)
return v.Leave(n)
}

// ExistsSubqueryExpr is the expression for "exists (select ...)".
// https://dev.mysql.com/doc/refman/5.7/en/exists-and-not-exists-subqueries.html
type ExistsSubqueryExpr struct {
exprNode
// Sel is the sub query.
Sel *SubqueryExpr
// Sel is the subquery, may be rewritten to other type of expression.
Sel ExprNode
}

// Accept implements Node Accept interface.
Expand All @@ -457,7 +447,7 @@ func (n *ExistsSubqueryExpr) Accept(v Visitor) (Node, bool) {
if !ok {
return n, false
}
n.Sel = node.(*SubqueryExpr)
n.Sel = node.(ExprNode)
return v.Leave(n)
}

Expand All @@ -470,8 +460,8 @@ type PatternInExpr struct {
List []ExprNode
// Not is true, the expression is "not in".
Not bool
// Sel is the sub query.
Sel *SubqueryExpr
// Sel is the subquery, may be rewritten to other type of expression.
Sel ExprNode
}

// Accept implements Node Accept interface.
Expand All @@ -498,7 +488,7 @@ func (n *PatternInExpr) Accept(v Visitor) (Node, bool) {
if !ok {
return n, false
}
n.Sel = node.(*SubqueryExpr)
n.Sel = node.(ExprNode)
}
return v.Leave(n)
}
Expand Down Expand Up @@ -574,6 +564,9 @@ type PatternLikeExpr struct {
Not bool

Escape byte

PatChars []byte
PatTypes []byte
}

// Accept implements Node Accept interface.
Expand Down Expand Up @@ -658,13 +651,13 @@ type PositionExpr struct {
exprNode
// N is the position, started from 1 now.
N int
// Name is the corresponding field name if we want better format and explain instead of position.
Name string
// Refer is the result field the position refers to.
Refer *ResultField
}

// IsStatic implements the ExprNode IsStatic interface.
func (n *PositionExpr) IsStatic() bool {
return true
return false
}

// Accept implements Node Accept interface.
Expand All @@ -686,6 +679,11 @@ type PatternRegexpExpr struct {
Pattern ExprNode
// Not is true, the expression is "not rlike",
Not bool

// Re is the compiled regexp.
Re *regexp.Regexp
// Sexpr is the string for Expr expression.
Sexpr *string
}

// Accept implements Node Accept interface.
Expand Down
38 changes: 27 additions & 11 deletions ast/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
package ast

import (
"strings"

"github.com/pingcap/tidb/expression/builtin"
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/util/types"
)

Expand All @@ -38,8 +37,8 @@ type UnquoteString string
// FuncCallExpr is for function expression.
type FuncCallExpr struct {
funcNode
// F is the function name.
FnName string
// FnName is the function name.
FnName model.CIStr
// Args is the function args.
Args []ExprNode
}
Expand All @@ -63,7 +62,7 @@ func (n *FuncCallExpr) Accept(v Visitor) (Node, bool) {

// IsStatic implements the ExprNode IsStatic interface.
func (n *FuncCallExpr) IsStatic() bool {
v := builtin.Funcs[strings.ToLower(n.FnName)]
v := builtin.Funcs[n.FnName.L]
if v.F == nil || !v.IsStatic {
return false
}
Expand Down Expand Up @@ -216,7 +215,14 @@ func (n *FuncSubstringExpr) Accept(v Visitor) (Node, bool) {

// IsStatic implements the ExprNode IsStatic interface.
func (n *FuncSubstringExpr) IsStatic() bool {
return n.StrExpr.IsStatic() && n.Pos.IsStatic() && n.Len.IsStatic()
static := n.StrExpr.IsStatic() && n.Pos.IsStatic()
if !static {
return false
}
if n.Len != nil {
return n.Len.IsStatic()
}
return true
}

// FuncSubstringIndexExpr returns the substring as specified.
Expand Down Expand Up @@ -325,17 +331,22 @@ func (n *FuncTrimExpr) Accept(v Visitor) (Node, bool) {
return n, false
}
n.Str = node.(ExprNode)
node, ok = n.RemStr.Accept(v)
if !ok {
return n, false
if n.RemStr != nil {
node, ok = n.RemStr.Accept(v)
if !ok {
return n, false
}
n.RemStr = node.(ExprNode)
}
n.RemStr = node.(ExprNode)
return v.Leave(n)
}

// IsStatic implements the ExprNode IsStatic interface.
func (n *FuncTrimExpr) IsStatic() bool {
return n.Str.IsStatic() && n.RemStr.IsStatic()
if n.RemStr != nil {
return n.Str.IsStatic() && n.RemStr.IsStatic()
}
return n.Str.IsStatic()
}

// DateArithType is type for DateArith type.
Expand Down Expand Up @@ -397,6 +408,11 @@ func (n *FuncDateArithExpr) Accept(v Visitor) (Node, bool) {
return v.Leave(n)
}

// IsStatic implements the ExprNode IsStatic interface.
func (n *FuncDateArithExpr) IsStatic() bool {
return n.Date.IsStatic() && n.Interval.IsStatic()
}

// AggregateFuncExpr represents aggregate function expression.
type AggregateFuncExpr struct {
funcNode
Expand Down
Loading

0 comments on commit d44db8b

Please sign in to comment.