github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqlparse/tidbparser/ast/misc.go (about)

     1  // Copyright 2015 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package ast
    15  
    16  import (
    17  	"bytes"
    18  	"fmt"
    19  	"strings"
    20  
    21  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/model"
    22  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/mysql"
    23  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/util/auth"
    24  )
    25  
    26  var (
    27  	_ StmtNode = &AdminStmt{}
    28  	_ StmtNode = &AlterUserStmt{}
    29  	_ StmtNode = &BeginStmt{}
    30  	_ StmtNode = &BinlogStmt{}
    31  	_ StmtNode = &CommitStmt{}
    32  	_ StmtNode = &CreateUserStmt{}
    33  	_ StmtNode = &DeallocateStmt{}
    34  	_ StmtNode = &DoStmt{}
    35  	_ StmtNode = &ExecuteStmt{}
    36  	_ StmtNode = &ExplainStmt{}
    37  	_ StmtNode = &GrantStmt{}
    38  	_ StmtNode = &PrepareStmt{}
    39  	_ StmtNode = &RollbackStmt{}
    40  	_ StmtNode = &SetPwdStmt{}
    41  	_ StmtNode = &SetStmt{}
    42  	_ StmtNode = &UseStmt{}
    43  	_ StmtNode = &FlushStmt{}
    44  	_ StmtNode = &KillStmt{}
    45  
    46  	_ Node = &PrivElem{}
    47  	_ Node = &VariableAssignment{}
    48  )
    49  
    50  // Isolation level constants.
    51  const (
    52  	ReadCommitted   = "READ-COMMITTED"
    53  	ReadUncommitted = "READ-UNCOMMITTED"
    54  	Serializable    = "SERIALIZABLE"
    55  	RepeatableRead  = "REPEATABLE-READ"
    56  
    57  	// Valid formats for explain statement.
    58  	ExplainFormatROW = "row"
    59  	ExplainFormatDOT = "dot"
    60  )
    61  
    62  // ExplainFormats stores the valid formats for explain statement, used by validator.
    63  var ExplainFormats = []string{
    64  	ExplainFormatROW,
    65  	ExplainFormatDOT,
    66  }
    67  
    68  // TypeOpt is used for parsing data type option from SQL.
    69  type TypeOpt struct {
    70  	IsUnsigned bool
    71  	IsZerofill bool
    72  }
    73  
    74  // FloatOpt is used for parsing floating-point type option from SQL.
    75  // See http://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html
    76  type FloatOpt struct {
    77  	Flen    int
    78  	Decimal int
    79  }
    80  
    81  // AuthOption is used for parsing create use statement.
    82  type AuthOption struct {
    83  	// ByAuthString set as true, if AuthString is used for authorization. Otherwise, authorization is done by HashString.
    84  	ByAuthString bool
    85  	AuthString   string
    86  	HashString   string
    87  	// TODO: support auth_plugin
    88  }
    89  
    90  // ExplainStmt is a statement to provide information about how is SQL statement executed
    91  // or get columns information in a table.
    92  // See https://dev.mysql.com/doc/refman/5.7/en/explain.html
    93  type ExplainStmt struct {
    94  	stmtNode
    95  
    96  	Stmt   StmtNode
    97  	Format string
    98  }
    99  
   100  // Accept implements Node Accept interface.
   101  func (n *ExplainStmt) Accept(v Visitor) (Node, bool) {
   102  	newNode, skipChildren := v.Enter(n)
   103  	if skipChildren {
   104  		return v.Leave(newNode)
   105  	}
   106  	n = newNode.(*ExplainStmt)
   107  	node, ok := n.Stmt.Accept(v)
   108  	if !ok {
   109  		return n, false
   110  	}
   111  	n.Stmt = node.(DMLNode)
   112  	return v.Leave(n)
   113  }
   114  
   115  // PrepareStmt is a statement to prepares a SQL statement which contains placeholders,
   116  // and it is executed with ExecuteStmt and released with DeallocateStmt.
   117  // See https://dev.mysql.com/doc/refman/5.7/en/prepare.html
   118  type PrepareStmt struct {
   119  	stmtNode
   120  
   121  	Name    string
   122  	SQLText string
   123  	SQLVar  *VariableExpr
   124  }
   125  
   126  // Accept implements Node Accept interface.
   127  func (n *PrepareStmt) Accept(v Visitor) (Node, bool) {
   128  	newNode, skipChildren := v.Enter(n)
   129  	if skipChildren {
   130  		return v.Leave(newNode)
   131  	}
   132  	n = newNode.(*PrepareStmt)
   133  	if n.SQLVar != nil {
   134  		node, ok := n.SQLVar.Accept(v)
   135  		if !ok {
   136  			return n, false
   137  		}
   138  		n.SQLVar = node.(*VariableExpr)
   139  	}
   140  	return v.Leave(n)
   141  }
   142  
   143  // DeallocateStmt is a statement to release PreparedStmt.
   144  // See https://dev.mysql.com/doc/refman/5.7/en/deallocate-prepare.html
   145  type DeallocateStmt struct {
   146  	stmtNode
   147  
   148  	Name string
   149  }
   150  
   151  // Accept implements Node Accept interface.
   152  func (n *DeallocateStmt) Accept(v Visitor) (Node, bool) {
   153  	newNode, skipChildren := v.Enter(n)
   154  	if skipChildren {
   155  		return v.Leave(newNode)
   156  	}
   157  	n = newNode.(*DeallocateStmt)
   158  	return v.Leave(n)
   159  }
   160  
   161  // ExecuteStmt is a statement to execute PreparedStmt.
   162  // See https://dev.mysql.com/doc/refman/5.7/en/execute.html
   163  type ExecuteStmt struct {
   164  	stmtNode
   165  
   166  	Name      string
   167  	UsingVars []ExprNode
   168  	ExecID    uint32
   169  }
   170  
   171  // Accept implements Node Accept interface.
   172  func (n *ExecuteStmt) Accept(v Visitor) (Node, bool) {
   173  	newNode, skipChildren := v.Enter(n)
   174  	if skipChildren {
   175  		return v.Leave(newNode)
   176  	}
   177  	n = newNode.(*ExecuteStmt)
   178  	for i, val := range n.UsingVars {
   179  		node, ok := val.Accept(v)
   180  		if !ok {
   181  			return n, false
   182  		}
   183  		n.UsingVars[i] = node.(ExprNode)
   184  	}
   185  	return v.Leave(n)
   186  }
   187  
   188  // BeginStmt is a statement to start a new transaction.
   189  // See https://dev.mysql.com/doc/refman/5.7/en/commit.html
   190  type BeginStmt struct {
   191  	stmtNode
   192  }
   193  
   194  // Accept implements Node Accept interface.
   195  func (n *BeginStmt) Accept(v Visitor) (Node, bool) {
   196  	newNode, skipChildren := v.Enter(n)
   197  	if skipChildren {
   198  		return v.Leave(newNode)
   199  	}
   200  	n = newNode.(*BeginStmt)
   201  	return v.Leave(n)
   202  }
   203  
   204  // BinlogStmt is an internal-use statement.
   205  // We just parse and ignore it.
   206  // See http://dev.mysql.com/doc/refman/5.7/en/binlog.html
   207  type BinlogStmt struct {
   208  	stmtNode
   209  	Str string
   210  }
   211  
   212  // Accept implements Node Accept interface.
   213  func (n *BinlogStmt) Accept(v Visitor) (Node, bool) {
   214  	newNode, skipChildren := v.Enter(n)
   215  	if skipChildren {
   216  		return v.Leave(newNode)
   217  	}
   218  	n = newNode.(*BinlogStmt)
   219  	return v.Leave(n)
   220  }
   221  
   222  // CommitStmt is a statement to commit the current transaction.
   223  // See https://dev.mysql.com/doc/refman/5.7/en/commit.html
   224  type CommitStmt struct {
   225  	stmtNode
   226  }
   227  
   228  // Accept implements Node Accept interface.
   229  func (n *CommitStmt) Accept(v Visitor) (Node, bool) {
   230  	newNode, skipChildren := v.Enter(n)
   231  	if skipChildren {
   232  		return v.Leave(newNode)
   233  	}
   234  	n = newNode.(*CommitStmt)
   235  	return v.Leave(n)
   236  }
   237  
   238  // RollbackStmt is a statement to roll back the current transaction.
   239  // See https://dev.mysql.com/doc/refman/5.7/en/commit.html
   240  type RollbackStmt struct {
   241  	stmtNode
   242  }
   243  
   244  // Accept implements Node Accept interface.
   245  func (n *RollbackStmt) Accept(v Visitor) (Node, bool) {
   246  	newNode, skipChildren := v.Enter(n)
   247  	if skipChildren {
   248  		return v.Leave(newNode)
   249  	}
   250  	n = newNode.(*RollbackStmt)
   251  	return v.Leave(n)
   252  }
   253  
   254  // UseStmt is a statement to use the DBName database as the current database.
   255  // See https://dev.mysql.com/doc/refman/5.7/en/use.html
   256  type UseStmt struct {
   257  	stmtNode
   258  
   259  	DBName string
   260  }
   261  
   262  // Accept implements Node Accept interface.
   263  func (n *UseStmt) Accept(v Visitor) (Node, bool) {
   264  	newNode, skipChildren := v.Enter(n)
   265  	if skipChildren {
   266  		return v.Leave(newNode)
   267  	}
   268  	n = newNode.(*UseStmt)
   269  	return v.Leave(n)
   270  }
   271  
   272  const (
   273  	// SetNames is the const for set names/charset stmt.
   274  	// If VariableAssignment.Name == Names, it should be set names/charset stmt.
   275  	SetNames = "SetNAMES"
   276  )
   277  
   278  // VariableAssignment is a variable assignment struct.
   279  type VariableAssignment struct {
   280  	node
   281  	Name     string
   282  	Value    ExprNode
   283  	IsGlobal bool
   284  	IsSystem bool
   285  
   286  	// ExtendValue is a way to store extended info.
   287  	// VariableAssignment should be able to store information for SetCharset/SetPWD Stmt.
   288  	// For SetCharsetStmt, Value is charset, ExtendValue is collation.
   289  	// TODO: Use SetStmt to implement set password statement.
   290  	ExtendValue *ValueExpr
   291  }
   292  
   293  // Accept implements Node interface.
   294  func (n *VariableAssignment) Accept(v Visitor) (Node, bool) {
   295  	newNode, skipChildren := v.Enter(n)
   296  	if skipChildren {
   297  		return v.Leave(newNode)
   298  	}
   299  	n = newNode.(*VariableAssignment)
   300  	node, ok := n.Value.Accept(v)
   301  	if !ok {
   302  		return n, false
   303  	}
   304  	n.Value = node.(ExprNode)
   305  	return v.Leave(n)
   306  }
   307  
   308  // FlushStmtType is the type for FLUSH statement.
   309  type FlushStmtType int
   310  
   311  // Flush statement types.
   312  const (
   313  	FlushNone FlushStmtType = iota
   314  	FlushTables
   315  	FlushPrivileges
   316  )
   317  
   318  // FlushStmt is a statement to flush tables/privileges/optimizer costs and so on.
   319  type FlushStmt struct {
   320  	stmtNode
   321  
   322  	Tp              FlushStmtType // Privileges/Tables/...
   323  	NoWriteToBinLog bool
   324  	Tables          []*TableName // For FlushTableStmt, if Tables is empty, it means flush all tables.
   325  	ReadLock        bool
   326  }
   327  
   328  // Accept implements Node Accept interface.
   329  func (n *FlushStmt) Accept(v Visitor) (Node, bool) {
   330  	newNode, skipChildren := v.Enter(n)
   331  	if skipChildren {
   332  		return v.Leave(newNode)
   333  	}
   334  	n = newNode.(*FlushStmt)
   335  	return v.Leave(n)
   336  }
   337  
   338  // KillStmt is a statement to kill a query or connection.
   339  type KillStmt struct {
   340  	stmtNode
   341  
   342  	// Query indicates whether terminate a single query on this connection or the whole connection.
   343  	// If Query is true, terminates the statement the connection is currently executing, but leaves the connection itself intact.
   344  	// If Query is false, terminates the connection associated with the given ConnectionID, after terminating any statement the connection is executing.
   345  	Query        bool
   346  	ConnectionID uint64
   347  	// TiDBExtension is used to indicate whether the user knows he is sending kill statement to the right tidb-server.
   348  	// When the SQL grammar is "KILL TIDB [CONNECTION | QUERY] connectionID", TiDBExtension will be set.
   349  	// It's a special grammar extension in TiDB. This extension exists because, when the connection is:
   350  	// client -> LVS proxy -> TiDB, and type Ctrl+C in client, the following action will be executed:
   351  	// new a connection; kill xxx;
   352  	// kill command may send to the wrong TiDB, because the exists of LVS proxy, and kill the wrong session.
   353  	// So, "KILL TIDB" grammar is introduced, and it REQUIRES DIRECT client -> TiDB TOPOLOGY.
   354  	// TODO: The standard KILL grammar will be supported once we have global connectionID.
   355  	TiDBExtension bool
   356  }
   357  
   358  // Accept implements Node Accept interface.
   359  func (n *KillStmt) Accept(v Visitor) (Node, bool) {
   360  	newNode, skipChildren := v.Enter(n)
   361  	if skipChildren {
   362  		return v.Leave(newNode)
   363  	}
   364  	n = newNode.(*KillStmt)
   365  	return v.Leave(n)
   366  }
   367  
   368  // SetStmt is the statement to set variables.
   369  type SetStmt struct {
   370  	stmtNode
   371  	// Variables is the list of variable assignment.
   372  	Variables []*VariableAssignment
   373  }
   374  
   375  // Accept implements Node Accept interface.
   376  func (n *SetStmt) Accept(v Visitor) (Node, bool) {
   377  	newNode, skipChildren := v.Enter(n)
   378  	if skipChildren {
   379  		return v.Leave(newNode)
   380  	}
   381  	n = newNode.(*SetStmt)
   382  	for i, val := range n.Variables {
   383  		node, ok := val.Accept(v)
   384  		if !ok {
   385  			return n, false
   386  		}
   387  		n.Variables[i] = node.(*VariableAssignment)
   388  	}
   389  	return v.Leave(n)
   390  }
   391  
   392  /*
   393  // SetCharsetStmt is a statement to assign values to character and collation variables.
   394  // See https://dev.mysql.com/doc/refman/5.7/en/set-statement.html
   395  type SetCharsetStmt struct {
   396  	stmtNode
   397  
   398  	Charset string
   399  	Collate string
   400  }
   401  
   402  // Accept implements Node Accept interface.
   403  func (n *SetCharsetStmt) Accept(v Visitor) (Node, bool) {
   404  	newNode, skipChildren := v.Enter(n)
   405  	if skipChildren {
   406  		return v.Leave(newNode)
   407  	}
   408  	n = newNode.(*SetCharsetStmt)
   409  	return v.Leave(n)
   410  }
   411  */
   412  
   413  // SetPwdStmt is a statement to assign a password to user account.
   414  // See https://dev.mysql.com/doc/refman/5.7/en/set-password.html
   415  type SetPwdStmt struct {
   416  	stmtNode
   417  
   418  	User     *auth.UserIdentity
   419  	Password string
   420  }
   421  
   422  // SecureText implements SensitiveStatement interface.
   423  func (n *SetPwdStmt) SecureText() string {
   424  	return fmt.Sprintf("set password for user %s", n.User)
   425  }
   426  
   427  // Accept implements Node Accept interface.
   428  func (n *SetPwdStmt) Accept(v Visitor) (Node, bool) {
   429  	newNode, skipChildren := v.Enter(n)
   430  	if skipChildren {
   431  		return v.Leave(newNode)
   432  	}
   433  	n = newNode.(*SetPwdStmt)
   434  	return v.Leave(n)
   435  }
   436  
   437  // UserSpec is used for parsing create user statement.
   438  type UserSpec struct {
   439  	User    *auth.UserIdentity
   440  	AuthOpt *AuthOption
   441  }
   442  
   443  // SecurityString formats the UserSpec without password information.
   444  func (u *UserSpec) SecurityString() string {
   445  	withPassword := false
   446  	if opt := u.AuthOpt; opt != nil {
   447  		if len(opt.AuthString) > 0 || len(opt.HashString) > 0 {
   448  			withPassword = true
   449  		}
   450  	}
   451  	if withPassword {
   452  		return fmt.Sprintf("{%s password = ***}", u.User)
   453  	}
   454  	return u.User.String()
   455  }
   456  
   457  // EncodedPassword returns the encoded password (which is the real data mysql.user).
   458  // The boolean value indicates input's password format is legal or not.
   459  func (u *UserSpec) EncodedPassword() (string, bool) {
   460  	if u.AuthOpt == nil {
   461  		return "", true
   462  	}
   463  
   464  	opt := u.AuthOpt
   465  	if opt.ByAuthString {
   466  		return auth.EncodePassword(opt.AuthString), true
   467  	}
   468  
   469  	// Not a legal password string.
   470  	if len(opt.HashString) != 41 || !strings.HasPrefix(opt.HashString, "*") {
   471  		return "", false
   472  	}
   473  	return opt.HashString, true
   474  }
   475  
   476  // CreateUserStmt creates user account.
   477  // See https://dev.mysql.com/doc/refman/5.7/en/create-user.html
   478  type CreateUserStmt struct {
   479  	stmtNode
   480  
   481  	IfNotExists bool
   482  	Specs       []*UserSpec
   483  }
   484  
   485  // Accept implements Node Accept interface.
   486  func (n *CreateUserStmt) Accept(v Visitor) (Node, bool) {
   487  	newNode, skipChildren := v.Enter(n)
   488  	if skipChildren {
   489  		return v.Leave(newNode)
   490  	}
   491  	n = newNode.(*CreateUserStmt)
   492  	return v.Leave(n)
   493  }
   494  
   495  // SecureText implements SensitiveStatement interface.
   496  func (n *CreateUserStmt) SecureText() string {
   497  	var buf bytes.Buffer
   498  	buf.WriteString("create user")
   499  	for _, user := range n.Specs {
   500  		buf.WriteString(" ")
   501  		buf.WriteString(user.SecurityString())
   502  	}
   503  	return buf.String()
   504  }
   505  
   506  // AlterUserStmt modifies user account.
   507  // See https://dev.mysql.com/doc/refman/5.7/en/alter-user.html
   508  type AlterUserStmt struct {
   509  	stmtNode
   510  
   511  	IfExists    bool
   512  	CurrentAuth *AuthOption
   513  	Specs       []*UserSpec
   514  }
   515  
   516  // SecureText implements SensitiveStatement interface.
   517  func (n *AlterUserStmt) SecureText() string {
   518  	var buf bytes.Buffer
   519  	buf.WriteString("alter user")
   520  	for _, user := range n.Specs {
   521  		buf.WriteString(" ")
   522  		buf.WriteString(user.SecurityString())
   523  	}
   524  	return buf.String()
   525  }
   526  
   527  // Accept implements Node Accept interface.
   528  func (n *AlterUserStmt) Accept(v Visitor) (Node, bool) {
   529  	newNode, skipChildren := v.Enter(n)
   530  	if skipChildren {
   531  		return v.Leave(newNode)
   532  	}
   533  	n = newNode.(*AlterUserStmt)
   534  	return v.Leave(n)
   535  }
   536  
   537  // DropUserStmt creates user account.
   538  // See http://dev.mysql.com/doc/refman/5.7/en/drop-user.html
   539  type DropUserStmt struct {
   540  	stmtNode
   541  
   542  	IfExists bool
   543  	UserList []*auth.UserIdentity
   544  }
   545  
   546  // Accept implements Node Accept interface.
   547  func (n *DropUserStmt) Accept(v Visitor) (Node, bool) {
   548  	newNode, skipChildren := v.Enter(n)
   549  	if skipChildren {
   550  		return v.Leave(newNode)
   551  	}
   552  	n = newNode.(*DropUserStmt)
   553  	return v.Leave(n)
   554  }
   555  
   556  // DoStmt is the struct for DO statement.
   557  type DoStmt struct {
   558  	stmtNode
   559  
   560  	Exprs []ExprNode
   561  }
   562  
   563  // Accept implements Node Accept interface.
   564  func (n *DoStmt) Accept(v Visitor) (Node, bool) {
   565  	newNode, skipChildren := v.Enter(n)
   566  	if skipChildren {
   567  		return v.Leave(newNode)
   568  	}
   569  	n = newNode.(*DoStmt)
   570  	for i, val := range n.Exprs {
   571  		node, ok := val.Accept(v)
   572  		if !ok {
   573  			return n, false
   574  		}
   575  		n.Exprs[i] = node.(ExprNode)
   576  	}
   577  	return v.Leave(n)
   578  }
   579  
   580  // AdminStmtType is the type for admin statement.
   581  type AdminStmtType int
   582  
   583  // Admin statement types.
   584  const (
   585  	AdminShowDDL = iota + 1
   586  	AdminCheckTable
   587  	AdminShowDDLJobs
   588  	AdminCancelDDLJobs
   589  	AdminCheckIndex
   590  )
   591  
   592  // AdminStmt is the struct for Admin statement.
   593  type AdminStmt struct {
   594  	stmtNode
   595  
   596  	Tp     AdminStmtType
   597  	Index  string
   598  	Tables []*TableName
   599  	JobIDs []int64
   600  }
   601  
   602  // Accept implements Node Accpet interface.
   603  func (n *AdminStmt) Accept(v Visitor) (Node, bool) {
   604  	newNode, skipChildren := v.Enter(n)
   605  	if skipChildren {
   606  		return v.Leave(newNode)
   607  	}
   608  
   609  	n = newNode.(*AdminStmt)
   610  	for i, val := range n.Tables {
   611  		node, ok := val.Accept(v)
   612  		if !ok {
   613  			return n, false
   614  		}
   615  		n.Tables[i] = node.(*TableName)
   616  	}
   617  
   618  	return v.Leave(n)
   619  }
   620  
   621  // PrivElem is the privilege type and optional column list.
   622  type PrivElem struct {
   623  	node
   624  
   625  	Priv mysql.PrivilegeType
   626  	Cols []*ColumnName
   627  }
   628  
   629  // Accept implements Node Accept interface.
   630  func (n *PrivElem) Accept(v Visitor) (Node, bool) {
   631  	newNode, skipChildren := v.Enter(n)
   632  	if skipChildren {
   633  		return v.Leave(newNode)
   634  	}
   635  	n = newNode.(*PrivElem)
   636  	for i, val := range n.Cols {
   637  		node, ok := val.Accept(v)
   638  		if !ok {
   639  			return n, false
   640  		}
   641  		n.Cols[i] = node.(*ColumnName)
   642  	}
   643  	return v.Leave(n)
   644  }
   645  
   646  // ObjectTypeType is the type for object type.
   647  type ObjectTypeType int
   648  
   649  const (
   650  	// ObjectTypeNone is for empty object type.
   651  	ObjectTypeNone ObjectTypeType = iota + 1
   652  	// ObjectTypeTable means the following object is a table.
   653  	ObjectTypeTable
   654  )
   655  
   656  // GrantLevelType is the type for grant level.
   657  type GrantLevelType int
   658  
   659  const (
   660  	// GrantLevelNone is the dummy const for default value.
   661  	GrantLevelNone GrantLevelType = iota + 1
   662  	// GrantLevelGlobal means the privileges are administrative or apply to all databases on a given server.
   663  	GrantLevelGlobal
   664  	// GrantLevelDB means the privileges apply to all objects in a given database.
   665  	GrantLevelDB
   666  	// GrantLevelTable means the privileges apply to all columns in a given table.
   667  	GrantLevelTable
   668  )
   669  
   670  // GrantLevel is used for store the privilege scope.
   671  type GrantLevel struct {
   672  	Level     GrantLevelType
   673  	DBName    string
   674  	TableName string
   675  }
   676  
   677  // RevokeStmt is the struct for REVOKE statement.
   678  type RevokeStmt struct {
   679  	stmtNode
   680  
   681  	Privs      []*PrivElem
   682  	ObjectType ObjectTypeType
   683  	Level      *GrantLevel
   684  	Users      []*UserSpec
   685  }
   686  
   687  // Accept implements Node Accept interface.
   688  func (n *RevokeStmt) Accept(v Visitor) (Node, bool) {
   689  	newNode, skipChildren := v.Enter(n)
   690  	if skipChildren {
   691  		return v.Leave(newNode)
   692  	}
   693  	n = newNode.(*RevokeStmt)
   694  	for i, val := range n.Privs {
   695  		node, ok := val.Accept(v)
   696  		if !ok {
   697  			return n, false
   698  		}
   699  		n.Privs[i] = node.(*PrivElem)
   700  	}
   701  	return v.Leave(n)
   702  }
   703  
   704  // GrantStmt is the struct for GRANT statement.
   705  type GrantStmt struct {
   706  	stmtNode
   707  
   708  	Privs      []*PrivElem
   709  	ObjectType ObjectTypeType
   710  	Level      *GrantLevel
   711  	Users      []*UserSpec
   712  	WithGrant  bool
   713  }
   714  
   715  // SecureText implements SensitiveStatement interface.
   716  func (n *GrantStmt) SecureText() string {
   717  	text := n.text
   718  	// Filter "identified by xxx" because it would expose password information.
   719  	idx := strings.Index(strings.ToLower(text), "identified")
   720  	if idx > 0 {
   721  		text = text[:idx]
   722  	}
   723  	return text
   724  }
   725  
   726  // Accept implements Node Accept interface.
   727  func (n *GrantStmt) Accept(v Visitor) (Node, bool) {
   728  	newNode, skipChildren := v.Enter(n)
   729  	if skipChildren {
   730  		return v.Leave(newNode)
   731  	}
   732  	n = newNode.(*GrantStmt)
   733  	for i, val := range n.Privs {
   734  		node, ok := val.Accept(v)
   735  		if !ok {
   736  			return n, false
   737  		}
   738  		n.Privs[i] = node.(*PrivElem)
   739  	}
   740  	return v.Leave(n)
   741  }
   742  
   743  // Ident is the table identifier composed of schema name and table name.
   744  type Ident struct {
   745  	Schema model.CIStr
   746  	Name   model.CIStr
   747  }
   748  
   749  // String implements fmt.Stringer interface.
   750  func (i Ident) String() string {
   751  	if i.Schema.O == "" {
   752  		return i.Name.O
   753  	}
   754  	return fmt.Sprintf("%s.%s", i.Schema, i.Name)
   755  }
   756  
   757  // SelectStmtOpts wrap around select hints and switches
   758  type SelectStmtOpts struct {
   759  	Distinct      bool
   760  	SQLCache      bool
   761  	CalcFoundRows bool
   762  	Priority      mysql.PriorityEnum
   763  	TableHints    []*TableOptimizerHint
   764  }
   765  
   766  // TableOptimizerHint is Table level optimizer hint
   767  type TableOptimizerHint struct {
   768  	node
   769  	// HintName is the name or alias of the table(s) which the hint will affect.
   770  	// Table hints has no schema info
   771  	// It allows only table name or alias (if table has an alias)
   772  	HintName model.CIStr
   773  	Tables   []model.CIStr
   774  }
   775  
   776  // Accept implements Node Accept interface.
   777  func (n *TableOptimizerHint) Accept(v Visitor) (Node, bool) {
   778  	newNode, skipChildren := v.Enter(n)
   779  	if skipChildren {
   780  		return v.Leave(newNode)
   781  	}
   782  	n = newNode.(*TableOptimizerHint)
   783  	return v.Leave(n)
   784  }