// Copyright 2017 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 core import ( "github.com/pingcap/parser/ast" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/types" ) // AggregateFuncExtractor visits Expr tree. // It converts ColunmNameExpr to AggregateFuncExpr and collects AggregateFuncExpr. type AggregateFuncExtractor struct { inAggregateFuncExpr bool // AggFuncs is the collected AggregateFuncExprs. AggFuncs []*ast.AggregateFuncExpr } // Enter implements Visitor interface. func (a *AggregateFuncExtractor) Enter(n ast.Node) (ast.Node, bool) { switch n.(type) { case *ast.AggregateFuncExpr: a.inAggregateFuncExpr = true case *ast.SelectStmt, *ast.UnionStmt: return n, true } return n, false } // Leave implements Visitor interface. func (a *AggregateFuncExtractor) Leave(n ast.Node) (ast.Node, bool) { switch v := n.(type) { case *ast.AggregateFuncExpr: a.inAggregateFuncExpr = false a.AggFuncs = append(a.AggFuncs, v) } return n, true } // WindowFuncExtractor visits Expr tree. // It converts ColunmNameExpr to WindowFuncExpr and collects WindowFuncExpr. type WindowFuncExtractor struct { // WindowFuncs is the collected WindowFuncExprs. windowFuncs []*ast.WindowFuncExpr } // Enter implements Visitor interface. func (a *WindowFuncExtractor) Enter(n ast.Node) (ast.Node, bool) { switch n.(type) { case *ast.SelectStmt, *ast.UnionStmt: return n, true } return n, false } // Leave implements Visitor interface. func (a *WindowFuncExtractor) Leave(n ast.Node) (ast.Node, bool) { switch v := n.(type) { case *ast.WindowFuncExpr: a.windowFuncs = append(a.windowFuncs, v) } return n, true } // logicalSchemaProducer stores the schema for the logical plans who can produce schema directly. type logicalSchemaProducer struct { schema *expression.Schema baseLogicalPlan } // Schema implements the Plan.Schema interface. func (s *logicalSchemaProducer) Schema() *expression.Schema { if s.schema == nil { s.schema = expression.NewSchema() } return s.schema } // SetSchema implements the Plan.SetSchema interface. func (s *logicalSchemaProducer) SetSchema(schema *expression.Schema) { s.schema = schema } // physicalSchemaProducer stores the schema for the physical plans who can produce schema directly. type physicalSchemaProducer struct { schema *expression.Schema basePhysicalPlan } // Schema implements the Plan.Schema interface. func (s *physicalSchemaProducer) Schema() *expression.Schema { if s.schema == nil { s.schema = expression.NewSchema() } return s.schema } // SetSchema implements the Plan.SetSchema interface. func (s *physicalSchemaProducer) SetSchema(schema *expression.Schema) { s.schema = schema } // baseSchemaProducer stores the schema for the base plans who can produce schema directly. type baseSchemaProducer struct { schema *expression.Schema names []*types.FieldName basePlan } // OutputNames returns the outputting names of each column. func (s *baseSchemaProducer) OutputNames() []*types.FieldName { return s.names } // Schema implements the Plan.Schema interface. func (s *baseSchemaProducer) Schema() *expression.Schema { if s.schema == nil { s.schema = expression.NewSchema() } return s.schema } // SetSchema implements the Plan.SetSchema interface. func (s *baseSchemaProducer) SetSchema(schema *expression.Schema) { s.schema = schema } func buildLogicalJoinSchema(joinType JoinType, join LogicalPlan) *expression.Schema { switch joinType { case SemiJoin, AntiSemiJoin: return join.Children()[0].Schema().Clone() case LeftOuterSemiJoin, AntiLeftOuterSemiJoin: newSchema := join.Children()[0].Schema().Clone() newSchema.Append(join.Schema().Columns[join.Schema().Len()-1]) return newSchema } return expression.MergeSchema(join.Children()[0].Schema(), join.Children()[1].Schema()) } func buildPhysicalJoinSchema(joinType JoinType, join PhysicalPlan) *expression.Schema { switch joinType { case SemiJoin, AntiSemiJoin: return join.Children()[0].Schema().Clone() case LeftOuterSemiJoin, AntiLeftOuterSemiJoin: newSchema := join.Children()[0].Schema().Clone() newSchema.Append(join.Schema().Columns[join.Schema().Len()-1]) return newSchema } return expression.MergeSchema(join.Children()[0].Schema(), join.Children()[1].Schema()) } // GetStatsInfo gets the statistics info from a physical plan tree. func GetStatsInfo(i interface{}) map[string]uint64 { p := i.(Plan) var physicalPlan PhysicalPlan switch x := p.(type) { case *Insert: physicalPlan = x.SelectPlan case *Update: physicalPlan = x.SelectPlan case *Delete: physicalPlan = x.SelectPlan case PhysicalPlan: physicalPlan = x } if physicalPlan == nil { return nil } statsInfos := make(map[string]uint64) statsInfos = CollectPlanStatsVersion(physicalPlan, statsInfos) return statsInfos }