// Copyright 2015 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // See the License for the specific language governing permissions and // limitations under the License. package plan import ( "fmt" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/model" "github.com/pingcap/tidb/util/types" ) // TableRange represents a range of row handle. type TableRange struct { LowVal int64 HighVal int64 } // TableScan represents a table scan plan. type TableScan struct { basePlan Table *model.TableInfo Desc bool Ranges []TableRange // RefAccess indicates it references a previous joined table, used in explain. RefAccess bool // AccessConditions can be used to build index range. AccessConditions []ast.ExprNode // FilterConditions can be used to filter result. FilterConditions []ast.ExprNode } // Accept implements Plan Accept interface. func (p *TableScan) Accept(v Visitor) (Plan, bool) { np, _ := v.Enter(p) return v.Leave(np) } // ShowDDL is for showing DDL information. type ShowDDL struct { basePlan } // Accept implements Plan Accept interface. func (p *ShowDDL) Accept(v Visitor) (Plan, bool) { np, _ := v.Enter(p) return v.Leave(np) } // CheckTable is for checking table data. type CheckTable struct { basePlan Tables []*ast.TableName } // Accept implements Plan Accept interface. func (p *CheckTable) Accept(v Visitor) (Plan, bool) { np, _ := v.Enter(p) return v.Leave(np) } // IndexRange represents an index range to be scanned. type IndexRange struct { LowVal []types.Datum LowExclude bool HighVal []types.Datum HighExclude bool } // IsPoint returns if the index range is a point. func (ir *IndexRange) IsPoint() bool { if len(ir.LowVal) != len(ir.HighVal) { return false } for i := range ir.LowVal { a := ir.LowVal[i] b := ir.HighVal[i] if a.Kind() == types.KindMinNotNull || b.Kind() == types.KindMaxValue { return false } cmp, err := a.CompareDatum(b) if err != nil { return false } if cmp != 0 { return false } } return !ir.LowExclude && !ir.HighExclude } // IndexScan represents an index scan plan. type IndexScan struct { basePlan // The index used. Index *model.IndexInfo // The table to lookup. Table *model.TableInfo // Ordered and non-overlapping ranges to be scanned. Ranges []*IndexRange // Desc indicates whether the index should be scanned in descending order. Desc bool // RefAccess indicates it references a previous joined table, used in explain. RefAccess bool // AccessConditions can be used to build index range. AccessConditions []ast.ExprNode // Number of leading equal access condition. // The offset of each equal condition correspond to the offset of index column. // For example, an index has column (a, b, c), condition is 'a = 0 and b = 0 and c > 0' // AccessEqualCount would be 2. AccessEqualCount int // FilterConditions can be used to filter result. FilterConditions []ast.ExprNode } // Accept implements Plan Accept interface. func (p *IndexScan) Accept(v Visitor) (Plan, bool) { np, _ := v.Enter(p) return v.Leave(np) } // JoinOuter represents outer join plan. type JoinOuter struct { basePlan Outer Plan Inner Plan } // Accept implements Plan interface. func (p *JoinOuter) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*JoinOuter) var ok bool p.Outer, ok = p.Outer.Accept(v) if !ok { return p, false } p.Inner, ok = p.Inner.Accept(v) if !ok { return p, false } return v.Leave(p) } // JoinInner represents inner join plan. type JoinInner struct { basePlan Inners []Plan Conditions []ast.ExprNode } func (p *JoinInner) String() string { return fmt.Sprintf("JoinInner()") } // Accept implements Plan interface. func (p *JoinInner) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*JoinInner) for i, in := range p.Inners { x, ok := in.Accept(v) if !ok { return p, false } p.Inners[i] = x } return v.Leave(p) } // SelectLock represents a select lock plan. type SelectLock struct { planWithSrc Lock ast.SelectLockType } // Accept implements Plan Accept interface. func (p *SelectLock) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*SelectLock) var ok bool p.src, ok = p.src.Accept(v) if !ok { return p, false } return v.Leave(p) } // SetLimit implements Plan SetLimit interface. func (p *SelectLock) SetLimit(limit float64) { p.limit = limit p.src.SetLimit(p.limit) } // SelectFields represents a select fields plan. type SelectFields struct { planWithSrc } // Accept implements Plan Accept interface. func (p *SelectFields) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*SelectFields) if p.src != nil { var ok bool p.src, ok = p.src.Accept(v) if !ok { return p, false } } return v.Leave(p) } // SetLimit implements Plan SetLimit interface. func (p *SelectFields) SetLimit(limit float64) { p.limit = limit if p.src != nil { p.src.SetLimit(limit) } } // Sort represents a sorting plan. type Sort struct { planWithSrc ByItems []*ast.ByItem } // Accept implements Plan Accept interface. func (p *Sort) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Sort) var ok bool p.src, ok = p.src.Accept(v) if !ok { return p, false } return v.Leave(p) } // SetLimit implements Plan SetLimit interface. // It set the Src limit only if it is bypassed. // Bypass has to be determined before this get called. func (p *Sort) SetLimit(limit float64) { p.limit = limit } // Limit represents offset and limit plan. type Limit struct { planWithSrc Offset uint64 Count uint64 } // Accept implements Plan Accept interface. func (p *Limit) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Limit) var ok bool p.src, ok = p.src.Accept(v) if !ok { return p, false } return v.Leave(p) } // SetLimit implements Plan SetLimit interface. // As Limit itself determine the real limit, // We just ignore the input, and set the real limit. func (p *Limit) SetLimit(limit float64) { p.limit = float64(p.Offset + p.Count) p.src.SetLimit(p.limit) } // Union represents Union plan. type Union struct { basePlan Selects []Plan } // Accept implements Plan Accept interface. func (p *Union) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(p) } p = np.(*Union) for i, sel := range p.Selects { var ok bool p.Selects[i], ok = sel.Accept(v) if !ok { return p, false } } return v.Leave(p) } // Distinct represents Distinct plan. type Distinct struct { planWithSrc } // Accept implements Plan Accept interface. func (p *Distinct) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(p) } p = np.(*Distinct) var ok bool p.src, ok = p.src.Accept(v) if !ok { return p, false } return v.Leave(p) } // SetLimit implements Plan SetLimit interface. func (p *Distinct) SetLimit(limit float64) { p.limit = limit if p.src != nil { p.src.SetLimit(limit) } } // Prepare represents prepare plan. type Prepare struct { basePlan Name string SQLText string } // Accept implements Plan Accept interface. func (p *Prepare) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Prepare) return v.Leave(p) } // Execute represents prepare plan. type Execute struct { basePlan Name string UsingVars []ast.ExprNode ID uint32 } // Accept implements Plan Accept interface. func (p *Execute) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Execute) return v.Leave(p) } // Deallocate represents deallocate plan. type Deallocate struct { basePlan Name string } // Accept implements Plan Accept interface. func (p *Deallocate) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Deallocate) return v.Leave(p) } // Aggregate represents a select fields plan. type Aggregate struct { planWithSrc AggFuncs []*ast.AggregateFuncExpr GroupByItems []*ast.ByItem } // Accept implements Plan Accept interface. func (p *Aggregate) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Aggregate) if p.src != nil { var ok bool p.src, ok = p.src.Accept(v) if !ok { return p, false } } return v.Leave(p) } // SetLimit implements Plan SetLimit interface. func (p *Aggregate) SetLimit(limit float64) { p.limit = limit if p.src != nil { p.src.SetLimit(limit) } } // Having represents a having plan. // The having plan should after aggregate plan. type Having struct { planWithSrc // Originally the WHERE or ON condition is parsed into a single expression, // but after we converted to CNF(Conjunctive normal form), it can be // split into a list of AND conditions. Conditions []ast.ExprNode } // Accept implements Plan Accept interface. func (p *Having) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Having) var ok bool p.src, ok = p.src.Accept(v) if !ok { return p, false } return v.Leave(p) } // SetLimit implements Plan SetLimit interface. func (p *Having) SetLimit(limit float64) { p.limit = limit // We assume 50% of the src row is filtered out. p.src.SetLimit(limit * 2) } // Update represents an update plan. type Update struct { basePlan OrderedList []*ast.Assignment // OrderedList has the same offset as TablePlan's result fields. SelectPlan Plan } // Accept implements Plan Accept interface. func (p *Update) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Update) var ok bool p.SelectPlan, ok = p.SelectPlan.Accept(v) if !ok { return p, false } return v.Leave(p) } // Delete represents a delete plan. type Delete struct { basePlan SelectPlan Plan Tables []*ast.TableName IsMultiTable bool } // Accept implements Plan Accept interface. func (p *Delete) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Delete) var ok bool p.SelectPlan, ok = p.SelectPlan.Accept(v) if !ok { return p, false } return v.Leave(p) } // Filter represents a plan that filter srcplan result. type Filter struct { planWithSrc // Originally the WHERE or ON condition is parsed into a single expression, // but after we converted to CNF(Conjunctive normal form), it can be // split into a list of AND conditions. Conditions []ast.ExprNode } // Accept implements Plan Accept interface. func (p *Filter) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Filter) var ok bool p.src, ok = p.src.Accept(v) if !ok { return p, false } return v.Leave(p) } // SetLimit implements Plan SetLimit interface. func (p *Filter) SetLimit(limit float64) { p.limit = limit // We assume 50% of the src row is filtered out. p.src.SetLimit(limit * 2) } // Show represents a show plan. type Show struct { basePlan Tp ast.ShowStmtType // Databases/Tables/Columns/.... DBName string Table *ast.TableName // Used for showing columns. Column *ast.ColumnName // Used for `desc table column`. Flag int // Some flag parsed from sql, such as FULL. Full bool User string // Used for show grants. // Used by show variables GlobalScope bool } // Accept implements Plan Accept interface. func (p *Show) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Show) return v.Leave(p) } // Simple represents a simple statement plan which doesn't need any optimization. type Simple struct { basePlan Statement ast.StmtNode } // Accept implements Plan Accept interface. func (p *Simple) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Simple) return v.Leave(p) } // Insert represents an insert plan. type Insert struct { basePlan Table *ast.TableRefsClause Columns []*ast.ColumnName Lists [][]ast.ExprNode Setlist []*ast.Assignment OnDuplicate []*ast.Assignment SelectPlan Plan IsReplace bool Priority int } // Accept implements Plan Accept interface. func (p *Insert) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*Insert) if p.SelectPlan != nil { var ok bool p.SelectPlan, ok = p.SelectPlan.Accept(v) if !ok { return p, false } } return v.Leave(p) } // DDL represents a DDL statement plan. type DDL struct { basePlan Statement ast.DDLNode } // Accept implements Plan Accept interface. func (p *DDL) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { return v.Leave(np) } p = np.(*DDL) return v.Leave(p) } // Explain represents a explain plan. type Explain struct { basePlan StmtPlan Plan } // Accept implements Plan Accept interface. func (p *Explain) Accept(v Visitor) (Plan, bool) { np, skip := v.Enter(p) if skip { v.Leave(np) } p = np.(*Explain) return v.Leave(p) }