186 lines
5.2 KiB
Go
186 lines
5.2 KiB
Go
// 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
|
|
}
|