Files
tidb/executor/compiler.go

190 lines
5.3 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 executor
import (
"github.com/juju/errors"
"github.com/ngaut/log"
"github.com/pingcap/tidb/ast"
"github.com/pingcap/tidb/context"
"github.com/pingcap/tidb/infoschema"
"github.com/pingcap/tidb/plan"
)
// Compiler compiles an ast.StmtNode to a stmt.Statement.
type Compiler struct {
}
const (
// IGNORE is a special label to identify the situations we want to ignore.
IGNORE = "Ignore"
// SimpleSelect represents SELECT statements like "select a from t" or "select 2".
SimpleSelect = "Simple-Select"
// ComplexSelect represents the other SELECT statements besides SIMPLE_SELECT.
ComplexSelect = "Complex-Select"
// AlterTable represents alter table statements.
AlterTable = "AlterTable"
// AnalyzeTable represents analyze table statements.
AnalyzeTable = "AnalyzeTable"
// Begin represents begin statements.
Begin = "Begin"
// Commit represents commit statements.
Commit = "Commit"
// CreateDatabase represents create database statements.
CreateDatabase = "CreateDatabase"
// CreateIndex represents create index statements.
CreateIndex = "CreateIndex"
// CreateTable represents create table statements.
CreateTable = "CreateTable"
// CreateUser represents create user statements.
CreateUser = "CreateUser"
// Delete represents delete statements.
Delete = "Delete"
// DropDatabase represents drop database statements.
DropDatabase = "DropDatabase"
// DropIndex represents drop index statements.
DropIndex = "DropIndex"
// DropTable represents drop table statements.
DropTable = "DropTable"
// Explain represents explain statements.
Explain = "Explain"
// Replace represents replace statements.
Replace = "Replace"
// Insert represents insert statements.
Insert = "Insert"
// LoadDataStmt represents load data statements.
LoadDataStmt = "LoadData"
// RollBack represents roll back statements.
RollBack = "RollBack"
// Set represents set statements.
Set = "Set"
// Show represents show statements.
Show = "Show"
// TruncateTable represents truncate table statements.
TruncateTable = "TruncateTable"
// Update represents update statements.
Update = "Update"
)
func statementLabel(node ast.StmtNode) string {
switch x := node.(type) {
case *ast.AlterTableStmt:
return AlterTable
case *ast.AnalyzeTableStmt:
return AnalyzeTable
case *ast.BeginStmt:
return Begin
case *ast.CommitStmt:
return Commit
case *ast.CreateDatabaseStmt:
return CreateDatabase
case *ast.CreateIndexStmt:
return CreateIndex
case *ast.CreateTableStmt:
return CreateTable
case *ast.CreateUserStmt:
return CreateUser
case *ast.DeleteStmt:
return Delete
case *ast.DropDatabaseStmt:
return DropDatabase
case *ast.DropIndexStmt:
return DropIndex
case *ast.DropTableStmt:
return DropTable
case *ast.ExplainStmt:
return Explain
case *ast.InsertStmt:
if x.IsReplace {
return Replace
}
return Insert
case *ast.LoadDataStmt:
return LoadDataStmt
case *ast.RollbackStmt:
return RollBack
case *ast.SelectStmt:
return getSelectStmtLabel(x)
case *ast.SetStmt, *ast.SetPwdStmt:
return Set
case *ast.ShowStmt:
return Show
case *ast.TruncateTableStmt:
return TruncateTable
case *ast.UpdateStmt:
return Update
case *ast.DeallocateStmt, *ast.ExecuteStmt, *ast.PrepareStmt, *ast.UseStmt:
return IGNORE
}
return "other"
}
func getSelectStmtLabel(x *ast.SelectStmt) string {
if x.From == nil {
return SimpleSelect
}
tableRefs := x.From.TableRefs
if tableRefs.Right == nil {
switch ref := tableRefs.Left.(type) {
case *ast.TableSource:
switch ref.Source.(type) {
case *ast.TableName:
return SimpleSelect
}
}
}
return ComplexSelect
}
// Compile compiles an ast.StmtNode to an ast.Statement.
// After preprocessed and validated, it will be optimized to a plan,
// then wrappped to an adapter *statement as stmt.Statement.
func (c *Compiler) Compile(ctx context.Context, node ast.StmtNode) (ast.Statement, error) {
stmtCount(node)
is := GetInfoSchema(ctx)
if err := plan.Preprocess(node, is, ctx); err != nil {
return nil, errors.Trace(err)
}
// Validate should be after NameResolve.
if err := plan.Validate(node, false); err != nil {
return nil, errors.Trace(err)
}
p, err := plan.Optimize(ctx, node, is)
if err != nil {
return nil, errors.Trace(err)
}
_, isDDL := node.(ast.DDLNode)
sa := &statement{
is: is,
plan: p,
text: node.Text(),
isDDL: isDDL,
}
return sa, nil
}
// GetInfoSchema gets TxnCtx InfoSchema if snapshot schema is not set,
// Otherwise, snapshot schema is returned.
func GetInfoSchema(ctx context.Context) infoschema.InfoSchema {
sessVar := ctx.GetSessionVars()
var is infoschema.InfoSchema
if snap := sessVar.SnapshotInfoschema; snap != nil {
is = snap.(infoschema.InfoSchema)
log.Infof("[%d] use snapshot schema %d", sessVar.ConnectionID, is.SchemaMetaVersion())
} else {
is = sessVar.TxnCtx.InfoSchema.(infoschema.InfoSchema)
}
return is
}