587 lines
12 KiB
Go
587 lines
12 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 ast
|
|
|
|
import (
|
|
"github.com/pingcap/tidb/model"
|
|
)
|
|
|
|
var (
|
|
_ DMLNode = &InsertStmt{}
|
|
_ DMLNode = &DeleteStmt{}
|
|
_ DMLNode = &UpdateStmt{}
|
|
_ DMLNode = &SelectStmt{}
|
|
_ Node = &Join{}
|
|
_ Node = &TableName{}
|
|
_ Node = &TableSource{}
|
|
_ Node = &Assignment{}
|
|
_ Node = &Limit{}
|
|
_ Node = &WildCardField{}
|
|
_ Node = &SelectField{}
|
|
)
|
|
|
|
// JoinType is join type, including cross/left/right/full.
|
|
type JoinType int
|
|
|
|
const (
|
|
// CrossJoin is cross join type.
|
|
CrossJoin JoinType = iota + 1
|
|
// LeftJoin is left Join type.
|
|
LeftJoin
|
|
// RightJoin is right Join type.
|
|
RightJoin
|
|
)
|
|
|
|
// Join represents table join.
|
|
type Join struct {
|
|
node
|
|
resultSetNode
|
|
|
|
// Left table can be TableSource or JoinNode.
|
|
Left ResultSetNode
|
|
// Right table can be TableSource or JoinNode or nil.
|
|
Right ResultSetNode
|
|
// Tp represents join type.
|
|
Tp JoinType
|
|
// On represents join on condition.
|
|
On ExprNode
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (j *Join) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(j); skipChildren {
|
|
return j, ok
|
|
}
|
|
node, ok := j.Left.Accept(v)
|
|
if !ok {
|
|
return j, false
|
|
}
|
|
j.Left = node.(ResultSetNode)
|
|
if j.Right != nil {
|
|
node, ok = j.Right.Accept(v)
|
|
if !ok {
|
|
return j, false
|
|
}
|
|
j.Right = node.(ResultSetNode)
|
|
}
|
|
if j.On != nil {
|
|
node, ok = j.On.Accept(v)
|
|
if !ok {
|
|
return j, false
|
|
}
|
|
j.On = node.(ExprNode)
|
|
}
|
|
return v.Leave(j)
|
|
}
|
|
|
|
// TableName represents a table name.
|
|
type TableName struct {
|
|
node
|
|
resultSetNode
|
|
|
|
Schema model.CIStr
|
|
Name model.CIStr
|
|
|
|
DBInfo *model.DBInfo
|
|
TableInfo *model.TableInfo
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (tr *TableName) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(tr); skipChildren {
|
|
return tr, ok
|
|
}
|
|
return v.Leave(tr)
|
|
}
|
|
|
|
// TableSource represents table source with a name.
|
|
type TableSource struct {
|
|
node
|
|
|
|
// Source is the source of the data, can be a TableName,
|
|
// a SubQuery, or a JoinNode.
|
|
Source ResultSetNode
|
|
|
|
// AsName is the as name of the table source.
|
|
AsName model.CIStr
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (ts *TableSource) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(ts); skipChildren {
|
|
return ts, ok
|
|
}
|
|
node, ok := ts.Source.Accept(v)
|
|
if !ok {
|
|
return ts, false
|
|
}
|
|
ts.Source = node.(ResultSetNode)
|
|
return v.Leave(ts)
|
|
}
|
|
|
|
// SetResultFields implements ResultSet interface.
|
|
func (ts *TableSource) SetResultFields(rfs []*ResultField) {
|
|
ts.Source.SetResultFields(rfs)
|
|
}
|
|
|
|
// GetResultFields implements ResultSet interface.
|
|
func (ts *TableSource) GetResultFields() []*ResultField {
|
|
return ts.Source.GetResultFields()
|
|
}
|
|
|
|
// UnionClause represents a single "UNION SELECT ..." or "UNION (SELECT ...)" clause.
|
|
type UnionClause struct {
|
|
node
|
|
|
|
Distinct bool
|
|
Select *SelectStmt
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (uc *UnionClause) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(uc); skipChildren {
|
|
return uc, ok
|
|
}
|
|
node, ok := uc.Select.Accept(v)
|
|
if !ok {
|
|
return uc, false
|
|
}
|
|
uc.Select = node.(*SelectStmt)
|
|
return v.Leave(uc)
|
|
}
|
|
|
|
// SelectLockType is the lock type for SelectStmt.
|
|
type SelectLockType int
|
|
|
|
// Select lock types.
|
|
const (
|
|
SelectLockNone SelectLockType = iota
|
|
SelectLockForUpdate
|
|
SelectLockInShareMode
|
|
)
|
|
|
|
// WildCardField is a special type of select field content.
|
|
type WildCardField struct {
|
|
node
|
|
|
|
Table *TableName
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (wf *WildCardField) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(wf); skipChildren {
|
|
return wf, ok
|
|
}
|
|
if wf.Table != nil {
|
|
node, ok := wf.Table.Accept(v)
|
|
if !ok {
|
|
return wf, false
|
|
}
|
|
wf.Table = node.(*TableName)
|
|
}
|
|
return v.Leave(wf)
|
|
}
|
|
|
|
// SelectField represents fields in select statement.
|
|
// There are two type of select field: wildcard
|
|
// and expression with optional alias name.
|
|
type SelectField struct {
|
|
node
|
|
|
|
// If WildCard is not nil, Expr will be nil.
|
|
WildCard *WildCardField
|
|
// If Expr is not nil, WildCard will be nil.
|
|
Expr ExprNode
|
|
// AsName name for Expr.
|
|
AsName model.CIStr
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (sf *SelectField) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(sf); skipChildren {
|
|
return sf, ok
|
|
}
|
|
if sf.Expr != nil {
|
|
node, ok := sf.Expr.Accept(v)
|
|
if !ok {
|
|
return sf, false
|
|
}
|
|
sf.Expr = node.(ExprNode)
|
|
}
|
|
return v.Leave(sf)
|
|
}
|
|
|
|
// OrderByItem represents a single order by item.
|
|
type OrderByItem struct {
|
|
node
|
|
|
|
Expr ExprNode
|
|
Desc bool
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (ob *OrderByItem) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(ob); skipChildren {
|
|
return ob, ok
|
|
}
|
|
node, ok := ob.Expr.Accept(v)
|
|
if !ok {
|
|
return ob, false
|
|
}
|
|
ob.Expr = node.(ExprNode)
|
|
return v.Leave(ob)
|
|
}
|
|
|
|
// SelectStmt represents the select query node.
|
|
type SelectStmt struct {
|
|
dmlNode
|
|
resultSetNode
|
|
|
|
// Distinct represents if the select has distinct option.
|
|
Distinct bool
|
|
// Fields is the select expression list.
|
|
Fields []*SelectField
|
|
// From is the from clause of the query.
|
|
From *Join
|
|
// Where is the where clause in select statement.
|
|
Where ExprNode
|
|
// GroupBy is the group by expression list.
|
|
GroupBy []ExprNode
|
|
// Having is the having condition.
|
|
Having ExprNode
|
|
// OrderBy is the odering expression list.
|
|
OrderBy []*OrderByItem
|
|
// Limit is the limit clause.
|
|
Limit *Limit
|
|
// Lock is the lock type
|
|
LockTp SelectLockType
|
|
|
|
// Union clauses.
|
|
Unions []*UnionClause
|
|
// Order by for union select.
|
|
UnionOrderBy []*OrderByItem
|
|
// Limit for union select.
|
|
UnionLimit *Limit
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (sn *SelectStmt) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(sn); skipChildren {
|
|
return sn, ok
|
|
}
|
|
for i, val := range sn.Fields {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.Fields[i] = node.(*SelectField)
|
|
}
|
|
if sn.From != nil {
|
|
node, ok := sn.From.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.From = node.(*Join)
|
|
}
|
|
|
|
if sn.Where != nil {
|
|
node, ok := sn.Where.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.Where = node.(ExprNode)
|
|
}
|
|
|
|
for i, val := range sn.GroupBy {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.GroupBy[i] = node.(ExprNode)
|
|
}
|
|
if sn.Having != nil {
|
|
node, ok := sn.Having.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.Having = node.(ExprNode)
|
|
}
|
|
|
|
for i, val := range sn.OrderBy {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.OrderBy[i] = node.(*OrderByItem)
|
|
}
|
|
|
|
if sn.Limit != nil {
|
|
node, ok := sn.Limit.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.Limit = node.(*Limit)
|
|
}
|
|
|
|
for i, val := range sn.Unions {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.Unions[i] = node.(*UnionClause)
|
|
}
|
|
for i, val := range sn.UnionOrderBy {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.UnionOrderBy[i] = node.(*OrderByItem)
|
|
}
|
|
if sn.UnionLimit != nil {
|
|
node, ok := sn.UnionLimit.Accept(v)
|
|
if !ok {
|
|
return sn, false
|
|
}
|
|
sn.UnionLimit = node.(*Limit)
|
|
}
|
|
return v.Leave(sn)
|
|
}
|
|
|
|
// Assignment is the expression for assignment, like a = 1.
|
|
type Assignment struct {
|
|
node
|
|
// Column is the column name to be assigned.
|
|
Column *ColumnName
|
|
// Expr is the expression assigning to ColName.
|
|
Expr ExprNode
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (as *Assignment) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(as); skipChildren {
|
|
return as, ok
|
|
}
|
|
node, ok := as.Column.Accept(v)
|
|
if !ok {
|
|
return as, false
|
|
}
|
|
as.Column = node.(*ColumnName)
|
|
node, ok = as.Expr.Accept(v)
|
|
if !ok {
|
|
return as, false
|
|
}
|
|
as.Expr = node.(ExprNode)
|
|
return v.Leave(as)
|
|
}
|
|
|
|
// Priority const values.
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/insert.html
|
|
const (
|
|
NoPriority = iota
|
|
LowPriority
|
|
HighPriority
|
|
DelayedPriority
|
|
)
|
|
|
|
// InsertStmt is a statement to insert new rows into an existing table.
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/insert.html
|
|
type InsertStmt struct {
|
|
dmlNode
|
|
|
|
Columns []*ColumnName
|
|
Lists [][]ExprNode
|
|
Table *TableName
|
|
Setlist []*Assignment
|
|
Priority int
|
|
OnDuplicate []*Assignment
|
|
Select *SelectStmt
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (in *InsertStmt) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(in); skipChildren {
|
|
return in, ok
|
|
}
|
|
for i, val := range in.Columns {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return in, false
|
|
}
|
|
in.Columns[i] = node.(*ColumnName)
|
|
}
|
|
for i, list := range in.Lists {
|
|
for j, val := range list {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return in, false
|
|
}
|
|
in.Lists[i][j] = node.(ExprNode)
|
|
}
|
|
}
|
|
for i, val := range in.Setlist {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return in, false
|
|
}
|
|
in.Setlist[i] = node.(*Assignment)
|
|
}
|
|
for i, val := range in.OnDuplicate {
|
|
node, ok := val.Accept(v)
|
|
if !ok {
|
|
return in, false
|
|
}
|
|
in.OnDuplicate[i] = node.(*Assignment)
|
|
}
|
|
if in.Select != nil {
|
|
node, ok := in.Select.Accept(v)
|
|
if !ok {
|
|
return in, false
|
|
}
|
|
in.Select = node.(*SelectStmt)
|
|
}
|
|
return v.Leave(in)
|
|
}
|
|
|
|
// DeleteStmt is a statement to delete rows from table.
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/delete.html
|
|
type DeleteStmt struct {
|
|
dmlNode
|
|
|
|
TableRefs *Join
|
|
Tables []*TableName
|
|
Where ExprNode
|
|
Order []*OrderByItem
|
|
Limit *Limit
|
|
LowPriority bool
|
|
Ignore bool
|
|
Quick bool
|
|
MultiTable bool
|
|
BeforeFrom bool
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (de *DeleteStmt) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(de); skipChildren {
|
|
return de, ok
|
|
}
|
|
|
|
node, ok := de.TableRefs.Accept(v)
|
|
if !ok {
|
|
return de, false
|
|
}
|
|
de.TableRefs = node.(*Join)
|
|
|
|
for i, val := range de.Tables {
|
|
node, ok = val.Accept(v)
|
|
if !ok {
|
|
return de, false
|
|
}
|
|
de.Tables[i] = node.(*TableName)
|
|
}
|
|
|
|
if de.Where != nil {
|
|
node, ok = de.Where.Accept(v)
|
|
if !ok {
|
|
return de, false
|
|
}
|
|
de.Where = node.(ExprNode)
|
|
}
|
|
|
|
for i, val := range de.Order {
|
|
node, ok = val.Accept(v)
|
|
if !ok {
|
|
return de, false
|
|
}
|
|
de.Order[i] = node.(*OrderByItem)
|
|
}
|
|
|
|
node, ok = de.Limit.Accept(v)
|
|
if !ok {
|
|
return de, false
|
|
}
|
|
de.Limit = node.(*Limit)
|
|
return v.Leave(de)
|
|
}
|
|
|
|
// UpdateStmt is a statement to update columns of existing rows in tables with new values.
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/update.html
|
|
type UpdateStmt struct {
|
|
dmlNode
|
|
|
|
TableRefs *Join
|
|
List []*Assignment
|
|
Where ExprNode
|
|
Order []*OrderByItem
|
|
Limit *Limit
|
|
LowPriority bool
|
|
Ignore bool
|
|
MultipleTable bool
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (up *UpdateStmt) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(up); skipChildren {
|
|
return up, ok
|
|
}
|
|
node, ok := up.TableRefs.Accept(v)
|
|
if !ok {
|
|
return up, false
|
|
}
|
|
up.TableRefs = node.(*Join)
|
|
for i, val := range up.List {
|
|
node, ok = val.Accept(v)
|
|
if !ok {
|
|
return up, false
|
|
}
|
|
up.List[i] = node.(*Assignment)
|
|
}
|
|
if up.Where != nil {
|
|
node, ok = up.Where.Accept(v)
|
|
if !ok {
|
|
return up, false
|
|
}
|
|
up.Where = node.(ExprNode)
|
|
}
|
|
|
|
for i, val := range up.Order {
|
|
node, ok = val.Accept(v)
|
|
if !ok {
|
|
return up, false
|
|
}
|
|
up.Order[i] = node.(*OrderByItem)
|
|
}
|
|
node, ok = up.Limit.Accept(v)
|
|
if !ok {
|
|
return up, false
|
|
}
|
|
up.Limit = node.(*Limit)
|
|
return v.Leave(up)
|
|
}
|
|
|
|
// Limit is the limit clause.
|
|
type Limit struct {
|
|
node
|
|
|
|
Offset uint64
|
|
Count uint64
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (l *Limit) Accept(v Visitor) (Node, bool) {
|
|
if skipChildren, ok := v.Enter(l); skipChildren {
|
|
return l, ok
|
|
}
|
|
return v.Leave(l)
|
|
}
|