* Dropped unused codekit config * Integrated dynamic and static bindata for public * Ignore public bindata * Add a general generate make task * Integrated flexible public assets into web command * Updated vendoring, added all missiong govendor deps * Made the linter happy with the bindata and dynamic code * Moved public bindata definition to modules directory * Ignoring the new bindata path now * Updated to the new public modules import path * Updated public bindata command and drop the new prefix
		
			
				
	
	
		
			678 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			678 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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)
 | |
| }
 |