gitea/vendor/github.com/pingcap/tidb/optimizer/plan/plans.go

678 lines
13 KiB
Go
Raw Normal View History

// 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)
}