Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
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) |
|
}
|
|
|