You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							507 lines
						
					
					
						
							11 KiB
						
					
					
				
			
		
		
	
	
							507 lines
						
					
					
						
							11 KiB
						
					
					
				| // 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 ast
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/pingcap/tidb/context"
 | |
| 	"github.com/pingcap/tidb/model"
 | |
| 	"github.com/pingcap/tidb/mysql"
 | |
| 	"github.com/pingcap/tidb/sessionctx/db"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	_ StmtNode = &AdminStmt{}
 | |
| 	_ StmtNode = &BeginStmt{}
 | |
| 	_ StmtNode = &CommitStmt{}
 | |
| 	_ StmtNode = &CreateUserStmt{}
 | |
| 	_ StmtNode = &DeallocateStmt{}
 | |
| 	_ StmtNode = &DoStmt{}
 | |
| 	_ StmtNode = &ExecuteStmt{}
 | |
| 	_ StmtNode = &ExplainStmt{}
 | |
| 	_ StmtNode = &GrantStmt{}
 | |
| 	_ StmtNode = &PrepareStmt{}
 | |
| 	_ StmtNode = &RollbackStmt{}
 | |
| 	_ StmtNode = &SetCharsetStmt{}
 | |
| 	_ StmtNode = &SetPwdStmt{}
 | |
| 	_ StmtNode = &SetStmt{}
 | |
| 	_ StmtNode = &UseStmt{}
 | |
| 
 | |
| 	_ Node = &PrivElem{}
 | |
| 	_ Node = &VariableAssignment{}
 | |
| )
 | |
| 
 | |
| // TypeOpt is used for parsing data type option from SQL.
 | |
| type TypeOpt struct {
 | |
| 	IsUnsigned bool
 | |
| 	IsZerofill bool
 | |
| }
 | |
| 
 | |
| // FloatOpt is used for parsing floating-point type option from SQL.
 | |
| // See: http://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html
 | |
| type FloatOpt struct {
 | |
| 	Flen    int
 | |
| 	Decimal int
 | |
| }
 | |
| 
 | |
| // AuthOption is used for parsing create use statement.
 | |
| type AuthOption struct {
 | |
| 	// AuthString/HashString can be empty, so we need to decide which one to use.
 | |
| 	ByAuthString bool
 | |
| 	AuthString   string
 | |
| 	HashString   string
 | |
| 	// TODO: support auth_plugin
 | |
| }
 | |
| 
 | |
| // ExplainStmt is a statement to provide information about how is SQL statement executed
 | |
| // or get columns information in a table.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/explain.html
 | |
| type ExplainStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	Stmt StmtNode
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *ExplainStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*ExplainStmt)
 | |
| 	node, ok := n.Stmt.Accept(v)
 | |
| 	if !ok {
 | |
| 		return n, false
 | |
| 	}
 | |
| 	n.Stmt = node.(DMLNode)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // PrepareStmt is a statement to prepares a SQL statement which contains placeholders,
 | |
| // and it is executed with ExecuteStmt and released with DeallocateStmt.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/prepare.html
 | |
| type PrepareStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	Name    string
 | |
| 	SQLText string
 | |
| 	SQLVar  *VariableExpr
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *PrepareStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*PrepareStmt)
 | |
| 	if n.SQLVar != nil {
 | |
| 		node, ok := n.SQLVar.Accept(v)
 | |
| 		if !ok {
 | |
| 			return n, false
 | |
| 		}
 | |
| 		n.SQLVar = node.(*VariableExpr)
 | |
| 	}
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // DeallocateStmt is a statement to release PreparedStmt.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/deallocate-prepare.html
 | |
| type DeallocateStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	Name string
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *DeallocateStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*DeallocateStmt)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // ExecuteStmt is a statement to execute PreparedStmt.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/execute.html
 | |
| type ExecuteStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	Name      string
 | |
| 	UsingVars []ExprNode
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *ExecuteStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*ExecuteStmt)
 | |
| 	for i, val := range n.UsingVars {
 | |
| 		node, ok := val.Accept(v)
 | |
| 		if !ok {
 | |
| 			return n, false
 | |
| 		}
 | |
| 		n.UsingVars[i] = node.(ExprNode)
 | |
| 	}
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // BeginStmt is a statement to start a new transaction.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/commit.html
 | |
| type BeginStmt struct {
 | |
| 	stmtNode
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *BeginStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*BeginStmt)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // CommitStmt is a statement to commit the current transaction.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/commit.html
 | |
| type CommitStmt struct {
 | |
| 	stmtNode
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *CommitStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*CommitStmt)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // RollbackStmt is a statement to roll back the current transaction.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/commit.html
 | |
| type RollbackStmt struct {
 | |
| 	stmtNode
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *RollbackStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*RollbackStmt)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // UseStmt is a statement to use the DBName database as the current database.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/use.html
 | |
| type UseStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	DBName string
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *UseStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*UseStmt)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // VariableAssignment is a variable assignment struct.
 | |
| type VariableAssignment struct {
 | |
| 	node
 | |
| 	Name     string
 | |
| 	Value    ExprNode
 | |
| 	IsGlobal bool
 | |
| 	IsSystem bool
 | |
| }
 | |
| 
 | |
| // Accept implements Node interface.
 | |
| func (n *VariableAssignment) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*VariableAssignment)
 | |
| 	node, ok := n.Value.Accept(v)
 | |
| 	if !ok {
 | |
| 		return n, false
 | |
| 	}
 | |
| 	n.Value = node.(ExprNode)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // SetStmt is the statement to set variables.
 | |
| type SetStmt struct {
 | |
| 	stmtNode
 | |
| 	// Variables is the list of variable assignment.
 | |
| 	Variables []*VariableAssignment
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *SetStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*SetStmt)
 | |
| 	for i, val := range n.Variables {
 | |
| 		node, ok := val.Accept(v)
 | |
| 		if !ok {
 | |
| 			return n, false
 | |
| 		}
 | |
| 		n.Variables[i] = node.(*VariableAssignment)
 | |
| 	}
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // SetCharsetStmt is a statement to assign values to character and collation variables.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/set-statement.html
 | |
| type SetCharsetStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	Charset string
 | |
| 	Collate string
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *SetCharsetStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*SetCharsetStmt)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // SetPwdStmt is a statement to assign a password to user account.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/set-password.html
 | |
| type SetPwdStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	User     string
 | |
| 	Password string
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *SetPwdStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*SetPwdStmt)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // UserSpec is used for parsing create user statement.
 | |
| type UserSpec struct {
 | |
| 	User    string
 | |
| 	AuthOpt *AuthOption
 | |
| }
 | |
| 
 | |
| // CreateUserStmt creates user account.
 | |
| // See: https://dev.mysql.com/doc/refman/5.7/en/create-user.html
 | |
| type CreateUserStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	IfNotExists bool
 | |
| 	Specs       []*UserSpec
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *CreateUserStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*CreateUserStmt)
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // DoStmt is the struct for DO statement.
 | |
| type DoStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	Exprs []ExprNode
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *DoStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*DoStmt)
 | |
| 	for i, val := range n.Exprs {
 | |
| 		node, ok := val.Accept(v)
 | |
| 		if !ok {
 | |
| 			return n, false
 | |
| 		}
 | |
| 		n.Exprs[i] = node.(ExprNode)
 | |
| 	}
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // AdminStmtType is the type for admin statement.
 | |
| type AdminStmtType int
 | |
| 
 | |
| // Admin statement types.
 | |
| const (
 | |
| 	AdminShowDDL = iota + 1
 | |
| 	AdminCheckTable
 | |
| )
 | |
| 
 | |
| // AdminStmt is the struct for Admin statement.
 | |
| type AdminStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	Tp     AdminStmtType
 | |
| 	Tables []*TableName
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accpet interface.
 | |
| func (n *AdminStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 
 | |
| 	n = newNode.(*AdminStmt)
 | |
| 	for i, val := range n.Tables {
 | |
| 		node, ok := val.Accept(v)
 | |
| 		if !ok {
 | |
| 			return n, false
 | |
| 		}
 | |
| 		n.Tables[i] = node.(*TableName)
 | |
| 	}
 | |
| 
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // PrivElem is the privilege type and optional column list.
 | |
| type PrivElem struct {
 | |
| 	node
 | |
| 
 | |
| 	Priv mysql.PrivilegeType
 | |
| 	Cols []*ColumnName
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *PrivElem) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*PrivElem)
 | |
| 	for i, val := range n.Cols {
 | |
| 		node, ok := val.Accept(v)
 | |
| 		if !ok {
 | |
| 			return n, false
 | |
| 		}
 | |
| 		n.Cols[i] = node.(*ColumnName)
 | |
| 	}
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // ObjectTypeType is the type for object type.
 | |
| type ObjectTypeType int
 | |
| 
 | |
| const (
 | |
| 	// ObjectTypeNone is for empty object type.
 | |
| 	ObjectTypeNone ObjectTypeType = iota + 1
 | |
| 	// ObjectTypeTable means the following object is a table.
 | |
| 	ObjectTypeTable
 | |
| )
 | |
| 
 | |
| // GrantLevelType is the type for grant level.
 | |
| type GrantLevelType int
 | |
| 
 | |
| const (
 | |
| 	// GrantLevelNone is the dummy const for default value.
 | |
| 	GrantLevelNone GrantLevelType = iota + 1
 | |
| 	// GrantLevelGlobal means the privileges are administrative or apply to all databases on a given server.
 | |
| 	GrantLevelGlobal
 | |
| 	// GrantLevelDB means the privileges apply to all objects in a given database.
 | |
| 	GrantLevelDB
 | |
| 	// GrantLevelTable means the privileges apply to all columns in a given table.
 | |
| 	GrantLevelTable
 | |
| )
 | |
| 
 | |
| // GrantLevel is used for store the privilege scope.
 | |
| type GrantLevel struct {
 | |
| 	Level     GrantLevelType
 | |
| 	DBName    string
 | |
| 	TableName string
 | |
| }
 | |
| 
 | |
| // GrantStmt is the struct for GRANT statement.
 | |
| type GrantStmt struct {
 | |
| 	stmtNode
 | |
| 
 | |
| 	Privs      []*PrivElem
 | |
| 	ObjectType ObjectTypeType
 | |
| 	Level      *GrantLevel
 | |
| 	Users      []*UserSpec
 | |
| }
 | |
| 
 | |
| // Accept implements Node Accept interface.
 | |
| func (n *GrantStmt) Accept(v Visitor) (Node, bool) {
 | |
| 	newNode, skipChildren := v.Enter(n)
 | |
| 	if skipChildren {
 | |
| 		return v.Leave(newNode)
 | |
| 	}
 | |
| 	n = newNode.(*GrantStmt)
 | |
| 	for i, val := range n.Privs {
 | |
| 		node, ok := val.Accept(v)
 | |
| 		if !ok {
 | |
| 			return n, false
 | |
| 		}
 | |
| 		n.Privs[i] = node.(*PrivElem)
 | |
| 	}
 | |
| 	return v.Leave(n)
 | |
| }
 | |
| 
 | |
| // Ident is the table identifier composed of schema name and table name.
 | |
| type Ident struct {
 | |
| 	Schema model.CIStr
 | |
| 	Name   model.CIStr
 | |
| }
 | |
| 
 | |
| // Full returns an Ident which set schema to the current schema if it is empty.
 | |
| func (i Ident) Full(ctx context.Context) (full Ident) {
 | |
| 	full.Name = i.Name
 | |
| 	if i.Schema.O != "" {
 | |
| 		full.Schema = i.Schema
 | |
| 	} else {
 | |
| 		full.Schema = model.NewCIStr(db.GetCurrentSchema(ctx))
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // String implements fmt.Stringer interface
 | |
| func (i Ident) String() string {
 | |
| 	if i.Schema.O == "" {
 | |
| 		return i.Name.O
 | |
| 	}
 | |
| 	return fmt.Sprintf("%s.%s", i.Schema, i.Name)
 | |
| }
 | |
| 
 |