github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/preprocess.go (about)

     1  // Copyright 2020 WHTCORPS INC, 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 embedded
    15  
    16  import (
    17  	"fmt"
    18  	"math"
    19  	"strings"
    20  
    21  	"github.com/whtcorpsinc/BerolinaSQL"
    22  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    23  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    24  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    25  	"github.com/whtcorpsinc/errors"
    26  	"github.com/whtcorpsinc/milevadb/dbs"
    27  	"github.com/whtcorpsinc/milevadb/memex"
    28  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    29  	"github.com/whtcorpsinc/milevadb/soliton"
    30  	"github.com/whtcorpsinc/milevadb/soliton/petriutil"
    31  	"github.com/whtcorpsinc/milevadb/spacetime/autoid"
    32  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    33  	"github.com/whtcorpsinc/milevadb/types"
    34  	driver "github.com/whtcorpsinc/milevadb/types/BerolinaSQL_driver"
    35  )
    36  
    37  // PreprocessOpt presents optional parameters to `Preprocess` method.
    38  type PreprocessOpt func(*preprocessor)
    39  
    40  // InPrepare is a PreprocessOpt that indicates preprocess is executing under prepare memex.
    41  func InPrepare(p *preprocessor) {
    42  	p.flag |= inPrepare
    43  }
    44  
    45  // InTxnRetry is a PreprocessOpt that indicates preprocess is executing under transaction retry.
    46  func InTxnRetry(p *preprocessor) {
    47  	p.flag |= inTxnRetry
    48  }
    49  
    50  // TryAddExtraLimit trys to add an extra limit for SELECT or UNION memex when sql_select_limit is set.
    51  func TryAddExtraLimit(ctx stochastikctx.Context, node ast.StmtNode) ast.StmtNode {
    52  	if ctx.GetStochastikVars().SelectLimit == math.MaxUint64 || ctx.GetStochastikVars().InRestrictedALLEGROSQL {
    53  		return node
    54  	}
    55  	if explain, ok := node.(*ast.ExplainStmt); ok {
    56  		explain.Stmt = TryAddExtraLimit(ctx, explain.Stmt)
    57  		return explain
    58  	} else if sel, ok := node.(*ast.SelectStmt); ok {
    59  		if sel.Limit != nil || sel.SelectIntoOpt != nil {
    60  			return node
    61  		}
    62  		newSel := *sel
    63  		newSel.Limit = &ast.Limit{
    64  			Count: ast.NewValueExpr(ctx.GetStochastikVars().SelectLimit, "", ""),
    65  		}
    66  		return &newSel
    67  	} else if setOprStmt, ok := node.(*ast.SetOprStmt); ok {
    68  		if setOprStmt.Limit != nil {
    69  			return node
    70  		}
    71  		newSetOpr := *setOprStmt
    72  		newSetOpr.Limit = &ast.Limit{
    73  			Count: ast.NewValueExpr(ctx.GetStochastikVars().SelectLimit, "", ""),
    74  		}
    75  		return &newSetOpr
    76  	}
    77  	return node
    78  }
    79  
    80  // Preprocess resolves causet names of the node, and checks some memexs validation.
    81  func Preprocess(ctx stochastikctx.Context, node ast.Node, is schemareplicant.SchemaReplicant, preprocessOpt ...PreprocessOpt) error {
    82  	v := preprocessor{is: is, ctx: ctx, blockAliasInJoin: make([]map[string]interface{}, 0)}
    83  	for _, optFn := range preprocessOpt {
    84  		optFn(&v)
    85  	}
    86  	node.Accept(&v)
    87  	return errors.Trace(v.err)
    88  }
    89  
    90  type preprocessorFlag uint8
    91  
    92  const (
    93  	// inPrepare is set when visiting in prepare memex.
    94  	inPrepare preprocessorFlag = 1 << iota
    95  	// inTxnRetry is set when visiting in transaction retry.
    96  	inTxnRetry
    97  	// inCreateOrDropBlock is set when visiting create/drop causet memex.
    98  	inCreateOrDropBlock
    99  	// parentIsJoin is set when visiting node's parent is join.
   100  	parentIsJoin
   101  	// inRepairBlock is set when visiting a repair causet memex.
   102  	inRepairBlock
   103  	// inSequenceFunction is set when visiting a sequence function.
   104  	// This flag indicates the blockName in these function should be checked as sequence object.
   105  	inSequenceFunction
   106  )
   107  
   108  // preprocessor is an ast.Visitor that preprocess
   109  // ast Nodes parsed from BerolinaSQL.
   110  type preprocessor struct {
   111  	is   schemareplicant.SchemaReplicant
   112  	ctx  stochastikctx.Context
   113  	err  error
   114  	flag preprocessorFlag
   115  
   116  	// blockAliasInJoin is a stack that keeps the causet alias names for joins.
   117  	// len(blockAliasInJoin) may bigger than 1 because the left/right child of join may be subquery that contains `JOIN`
   118  	blockAliasInJoin []map[string]interface{}
   119  }
   120  
   121  func (p *preprocessor) Enter(in ast.Node) (out ast.Node, skipChildren bool) {
   122  	switch node := in.(type) {
   123  	case *ast.CreateBlockStmt:
   124  		p.flag |= inCreateOrDropBlock
   125  		p.resolveCreateBlockStmt(node)
   126  		p.checkCreateBlockGrammar(node)
   127  	case *ast.CreateViewStmt:
   128  		p.flag |= inCreateOrDropBlock
   129  		p.checkCreateViewGrammar(node)
   130  		p.checkCreateViewWithSelectGrammar(node)
   131  	case *ast.DropBlockStmt:
   132  		p.flag |= inCreateOrDropBlock
   133  		p.checkDropBlockGrammar(node)
   134  	case *ast.RenameBlockStmt:
   135  		p.flag |= inCreateOrDropBlock
   136  		p.checkRenameBlockGrammar(node)
   137  	case *ast.CreateIndexStmt:
   138  		p.checkCreateIndexGrammar(node)
   139  	case *ast.AlterBlockStmt:
   140  		p.resolveAlterBlockStmt(node)
   141  		p.checkAlterBlockGrammar(node)
   142  	case *ast.CreateDatabaseStmt:
   143  		p.checkCreateDatabaseGrammar(node)
   144  	case *ast.AlterDatabaseStmt:
   145  		p.checkAlterDatabaseGrammar(node)
   146  	case *ast.DroFIDelatabaseStmt:
   147  		p.checkDroFIDelatabaseGrammar(node)
   148  	case *ast.ShowStmt:
   149  		p.resolveShowStmt(node)
   150  	case *ast.SetOprSelectList:
   151  		p.checkSetOprSelectList(node)
   152  	case *ast.DeleteBlockList:
   153  		return in, true
   154  	case *ast.Join:
   155  		p.checkNonUniqBlockAlias(node)
   156  	case *ast.CreateBindingStmt:
   157  		EraseLastSemicolon(node.OriginSel)
   158  		EraseLastSemicolon(node.HintedSel)
   159  		p.checkBindGrammar(node.OriginSel, node.HintedSel)
   160  		return in, true
   161  	case *ast.DropBindingStmt:
   162  		EraseLastSemicolon(node.OriginSel)
   163  		if node.HintedSel != nil {
   164  			EraseLastSemicolon(node.HintedSel)
   165  			p.checkBindGrammar(node.OriginSel, node.HintedSel)
   166  		}
   167  		return in, true
   168  	case *ast.RecoverBlockStmt, *ast.FlashBackBlockStmt:
   169  		// The specified causet in recover causet memex maybe already been dropped.
   170  		// So skip check causet name here, otherwise, recover causet [block_name] syntax will return
   171  		// causet not exists error. But recover causet memex is use to recover the dropped causet. So skip children here.
   172  		return in, true
   173  	case *ast.RepairBlockStmt:
   174  		// The RepairBlock should consist of the logic for creating blocks and renaming blocks.
   175  		p.flag |= inRepairBlock
   176  		p.checkRepairBlockGrammar(node)
   177  	case *ast.CreateSequenceStmt:
   178  		p.flag |= inCreateOrDropBlock
   179  		p.resolveCreateSequenceStmt(node)
   180  	case *ast.DropSequenceStmt:
   181  		p.flag |= inCreateOrDropBlock
   182  		p.checkDropSequenceGrammar(node)
   183  	case *ast.FuncCallExpr:
   184  		if node.FnName.L == ast.NextVal || node.FnName.L == ast.LastVal || node.FnName.L == ast.SetVal {
   185  			p.flag |= inSequenceFunction
   186  		}
   187  	case *ast.BRIEStmt:
   188  		if node.HoTT == ast.BRIEHoTTRestore {
   189  			p.flag |= inCreateOrDropBlock
   190  		}
   191  	case *ast.CreateStatisticsStmt, *ast.DropStatisticsStmt:
   192  		p.checkStatisticsOpGrammar(in)
   193  	default:
   194  		p.flag &= ^parentIsJoin
   195  	}
   196  	return in, p.err != nil
   197  }
   198  
   199  // EraseLastSemicolon removes last semicolon of allegrosql.
   200  func EraseLastSemicolon(stmt ast.StmtNode) {
   201  	allegrosql := stmt.Text()
   202  	if len(allegrosql) > 0 && allegrosql[len(allegrosql)-1] == ';' {
   203  		stmt.SetText(allegrosql[:len(allegrosql)-1])
   204  	}
   205  }
   206  
   207  func (p *preprocessor) checkBindGrammar(originSel, hintedSel ast.StmtNode) {
   208  	originALLEGROSQL := BerolinaSQL.Normalize(originSel.(*ast.SelectStmt).Text())
   209  	hintedALLEGROSQL := BerolinaSQL.Normalize(hintedSel.(*ast.SelectStmt).Text())
   210  
   211  	if originALLEGROSQL != hintedALLEGROSQL {
   212  		p.err = errors.Errorf("hinted allegrosql and origin allegrosql don't match when hinted allegrosql erase the hint info, after erase hint info, originALLEGROSQL:%s, hintedALLEGROSQL:%s", originALLEGROSQL, hintedALLEGROSQL)
   213  	}
   214  }
   215  
   216  func (p *preprocessor) Leave(in ast.Node) (out ast.Node, ok bool) {
   217  	switch x := in.(type) {
   218  	case *ast.CreateBlockStmt:
   219  		p.flag &= ^inCreateOrDropBlock
   220  		p.checkAutoIncrement(x)
   221  		p.checkContainDotDeferredCauset(x)
   222  	case *ast.CreateViewStmt:
   223  		p.flag &= ^inCreateOrDropBlock
   224  	case *ast.DropBlockStmt, *ast.AlterBlockStmt, *ast.RenameBlockStmt:
   225  		p.flag &= ^inCreateOrDropBlock
   226  	case *driver.ParamMarkerExpr:
   227  		if p.flag&inPrepare == 0 {
   228  			p.err = BerolinaSQL.ErrSyntax.GenWithStack("syntax error, unexpected '?'")
   229  			return
   230  		}
   231  	case *ast.ExplainStmt:
   232  		if _, ok := x.Stmt.(*ast.ShowStmt); ok {
   233  			break
   234  		}
   235  		valid := false
   236  		for i, length := 0, len(ast.ExplainFormats); i < length; i++ {
   237  			if strings.ToLower(x.Format) == ast.ExplainFormats[i] {
   238  				valid = true
   239  				break
   240  			}
   241  		}
   242  		if !valid {
   243  			p.err = ErrUnknownExplainFormat.GenWithStackByArgs(x.Format)
   244  		}
   245  	case *ast.BlockName:
   246  		p.handleBlockName(x)
   247  	case *ast.Join:
   248  		if len(p.blockAliasInJoin) > 0 {
   249  			p.blockAliasInJoin = p.blockAliasInJoin[:len(p.blockAliasInJoin)-1]
   250  		}
   251  	case *ast.FuncCallExpr:
   252  		// The arguments for builtin NAME_CONST should be constants
   253  		// See https://dev.allegrosql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_name-const for details
   254  		if x.FnName.L == ast.NameConst {
   255  			if len(x.Args) != 2 {
   256  				p.err = memex.ErrIncorrectParameterCount.GenWithStackByArgs(x.FnName.L)
   257  			} else {
   258  				_, isValueExpr1 := x.Args[0].(*driver.ValueExpr)
   259  				isValueExpr2 := false
   260  				switch x.Args[1].(type) {
   261  				case *driver.ValueExpr, *ast.UnaryOperationExpr:
   262  					isValueExpr2 = true
   263  				}
   264  
   265  				if !isValueExpr1 || !isValueExpr2 {
   266  					p.err = ErrWrongArguments.GenWithStackByArgs("NAME_CONST")
   267  				}
   268  			}
   269  			break
   270  		}
   271  
   272  		// no need sleep when retry transaction and avoid unexpect sleep caused by retry.
   273  		if p.flag&inTxnRetry > 0 && x.FnName.L == ast.Sleep {
   274  			if len(x.Args) == 1 {
   275  				x.Args[0] = ast.NewValueExpr(0, "", "")
   276  			}
   277  		}
   278  
   279  		if x.FnName.L == ast.NextVal || x.FnName.L == ast.LastVal || x.FnName.L == ast.SetVal {
   280  			p.flag &= ^inSequenceFunction
   281  		}
   282  	case *ast.RepairBlockStmt:
   283  		p.flag &= ^inRepairBlock
   284  	case *ast.CreateSequenceStmt:
   285  		p.flag &= ^inCreateOrDropBlock
   286  	case *ast.BRIEStmt:
   287  		if x.HoTT == ast.BRIEHoTTRestore {
   288  			p.flag &= ^inCreateOrDropBlock
   289  		}
   290  	}
   291  
   292  	return in, p.err == nil
   293  }
   294  
   295  func checkAutoIncrementOp(colDef *ast.DeferredCausetDef, index int) (bool, error) {
   296  	var hasAutoIncrement bool
   297  
   298  	if colDef.Options[index].Tp == ast.DeferredCausetOptionAutoIncrement {
   299  		hasAutoIncrement = true
   300  		if len(colDef.Options) == index+1 {
   301  			return hasAutoIncrement, nil
   302  		}
   303  		for _, op := range colDef.Options[index+1:] {
   304  			if op.Tp == ast.DeferredCausetOptionDefaultValue {
   305  				if tmp, ok := op.Expr.(*driver.ValueExpr); ok {
   306  					if !tmp.Causet.IsNull() {
   307  						return hasAutoIncrement, errors.Errorf("Invalid default value for '%s'", colDef.Name.Name.O)
   308  					}
   309  				}
   310  			}
   311  		}
   312  	}
   313  	if colDef.Options[index].Tp == ast.DeferredCausetOptionDefaultValue && len(colDef.Options) != index+1 {
   314  		if tmp, ok := colDef.Options[index].Expr.(*driver.ValueExpr); ok {
   315  			if tmp.Causet.IsNull() {
   316  				return hasAutoIncrement, nil
   317  			}
   318  		}
   319  		for _, op := range colDef.Options[index+1:] {
   320  			if op.Tp == ast.DeferredCausetOptionAutoIncrement {
   321  				return hasAutoIncrement, errors.Errorf("Invalid default value for '%s'", colDef.Name.Name.O)
   322  			}
   323  		}
   324  	}
   325  
   326  	return hasAutoIncrement, nil
   327  }
   328  
   329  func isConstraintKeyTp(constraints []*ast.Constraint, colDef *ast.DeferredCausetDef) bool {
   330  	for _, c := range constraints {
   331  		if c.Keys[0].Expr != nil {
   332  			continue
   333  		}
   334  		// If the constraint as follows: primary key(c1, c2)
   335  		// we only support c1 column can be auto_increment.
   336  		if colDef.Name.Name.L != c.Keys[0].DeferredCauset.Name.L {
   337  			continue
   338  		}
   339  		switch c.Tp {
   340  		case ast.ConstraintPrimaryKey, ast.ConstraintKey, ast.ConstraintIndex,
   341  			ast.ConstraintUniq, ast.ConstraintUniqIndex, ast.ConstraintUniqKey:
   342  			return true
   343  		}
   344  	}
   345  
   346  	return false
   347  }
   348  
   349  func (p *preprocessor) checkAutoIncrement(stmt *ast.CreateBlockStmt) {
   350  	autoIncrementDefCauss := make(map[*ast.DeferredCausetDef]bool)
   351  
   352  	for _, colDef := range stmt.DefCauss {
   353  		var hasAutoIncrement bool
   354  		var isKey bool
   355  		for i, op := range colDef.Options {
   356  			ok, err := checkAutoIncrementOp(colDef, i)
   357  			if err != nil {
   358  				p.err = err
   359  				return
   360  			}
   361  			if ok {
   362  				hasAutoIncrement = true
   363  			}
   364  			switch op.Tp {
   365  			case ast.DeferredCausetOptionPrimaryKey, ast.DeferredCausetOptionUniqKey:
   366  				isKey = true
   367  			}
   368  		}
   369  		if hasAutoIncrement {
   370  			autoIncrementDefCauss[colDef] = isKey
   371  		}
   372  	}
   373  
   374  	if len(autoIncrementDefCauss) < 1 {
   375  		return
   376  	}
   377  	if len(autoIncrementDefCauss) > 1 {
   378  		p.err = autoid.ErrWrongAutoKey.GenWithStackByArgs()
   379  		return
   380  	}
   381  	// Only have one auto_increment col.
   382  	for col, isKey := range autoIncrementDefCauss {
   383  		if !isKey {
   384  			isKey = isConstraintKeyTp(stmt.Constraints, col)
   385  		}
   386  		autoIncrementMustBeKey := true
   387  		for _, opt := range stmt.Options {
   388  			if opt.Tp == ast.BlockOptionEngine && strings.EqualFold(opt.StrValue, "MyISAM") {
   389  				autoIncrementMustBeKey = false
   390  			}
   391  		}
   392  		if autoIncrementMustBeKey && !isKey {
   393  			p.err = autoid.ErrWrongAutoKey.GenWithStackByArgs()
   394  		}
   395  		switch col.Tp.Tp {
   396  		case allegrosql.TypeTiny, allegrosql.TypeShort, allegrosql.TypeLong,
   397  			allegrosql.TypeFloat, allegrosql.TypeDouble, allegrosql.TypeLonglong, allegrosql.TypeInt24:
   398  		default:
   399  			p.err = errors.Errorf("Incorrect column specifier for column '%s'", col.Name.Name.O)
   400  		}
   401  	}
   402  
   403  }
   404  
   405  // checkSetOprSelectList checks union's selectList.
   406  // refer: https://dev.allegrosql.com/doc/refman/5.7/en/union.html
   407  //        https://mariadb.com/kb/en/intersect/
   408  //        https://mariadb.com/kb/en/except/
   409  // "To apply ORDER BY or LIMIT to an individual SELECT, place the clause inside the parentheses that enclose the SELECT."
   410  func (p *preprocessor) checkSetOprSelectList(stmt *ast.SetOprSelectList) {
   411  	for _, sel := range stmt.Selects[:len(stmt.Selects)-1] {
   412  		if sel.IsInBraces {
   413  			continue
   414  		}
   415  		if sel.Limit != nil {
   416  			p.err = ErrWrongUsage.GenWithStackByArgs("UNION", "LIMIT")
   417  			return
   418  		}
   419  		if sel.OrderBy != nil {
   420  			p.err = ErrWrongUsage.GenWithStackByArgs("UNION", "ORDER BY")
   421  			return
   422  		}
   423  	}
   424  }
   425  
   426  func (p *preprocessor) checkCreateDatabaseGrammar(stmt *ast.CreateDatabaseStmt) {
   427  	if isIncorrectName(stmt.Name) {
   428  		p.err = dbs.ErrWrongDBName.GenWithStackByArgs(stmt.Name)
   429  	}
   430  }
   431  
   432  func (p *preprocessor) checkAlterDatabaseGrammar(stmt *ast.AlterDatabaseStmt) {
   433  	// for 'ALTER DATABASE' memex, database name can be empty to alter default database.
   434  	if isIncorrectName(stmt.Name) && !stmt.AlterDefaultDatabase {
   435  		p.err = dbs.ErrWrongDBName.GenWithStackByArgs(stmt.Name)
   436  	}
   437  }
   438  
   439  func (p *preprocessor) checkDroFIDelatabaseGrammar(stmt *ast.DroFIDelatabaseStmt) {
   440  	if isIncorrectName(stmt.Name) {
   441  		p.err = dbs.ErrWrongDBName.GenWithStackByArgs(stmt.Name)
   442  	}
   443  }
   444  
   445  func (p *preprocessor) checkCreateBlockGrammar(stmt *ast.CreateBlockStmt) {
   446  	tName := stmt.Block.Name.String()
   447  	if isIncorrectName(tName) {
   448  		p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(tName)
   449  		return
   450  	}
   451  	countPrimaryKey := 0
   452  	for _, colDef := range stmt.DefCauss {
   453  		if err := checkDeferredCauset(colDef); err != nil {
   454  			p.err = err
   455  			return
   456  		}
   457  		isPrimary, err := checkDeferredCausetOptions(colDef.Options)
   458  		if err != nil {
   459  			p.err = err
   460  			return
   461  		}
   462  		countPrimaryKey += isPrimary
   463  		if countPrimaryKey > 1 {
   464  			p.err = schemareplicant.ErrMultiplePriKey
   465  			return
   466  		}
   467  	}
   468  	for _, constraint := range stmt.Constraints {
   469  		switch tp := constraint.Tp; tp {
   470  		case ast.ConstraintKey, ast.ConstraintIndex, ast.ConstraintUniq, ast.ConstraintUniqKey, ast.ConstraintUniqIndex:
   471  			err := checHoTTexInfo(constraint.Name, constraint.Keys)
   472  			if err != nil {
   473  				p.err = err
   474  				return
   475  			}
   476  		case ast.ConstraintPrimaryKey:
   477  			if countPrimaryKey > 0 {
   478  				p.err = schemareplicant.ErrMultiplePriKey
   479  				return
   480  			}
   481  			countPrimaryKey++
   482  			err := checHoTTexInfo(constraint.Name, constraint.Keys)
   483  			if err != nil {
   484  				p.err = err
   485  				return
   486  			}
   487  		}
   488  	}
   489  	if p.err = checkUnsupportedBlockOptions(stmt.Options); p.err != nil {
   490  		return
   491  	}
   492  	if stmt.Select != nil {
   493  		// FIXME: a temp error noticing 'not implemented' (issue 4754)
   494  		p.err = errors.New("'CREATE TABLE ... SELECT' is not implemented yet")
   495  		return
   496  	} else if len(stmt.DefCauss) == 0 && stmt.ReferBlock == nil {
   497  		p.err = dbs.ErrBlockMustHaveDeferredCausets
   498  		return
   499  	}
   500  }
   501  
   502  func (p *preprocessor) checkCreateViewGrammar(stmt *ast.CreateViewStmt) {
   503  	vName := stmt.ViewName.Name.String()
   504  	if isIncorrectName(vName) {
   505  		p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(vName)
   506  		return
   507  	}
   508  	for _, col := range stmt.DefCauss {
   509  		if isIncorrectName(col.String()) {
   510  			p.err = dbs.ErrWrongDeferredCausetName.GenWithStackByArgs(col)
   511  			return
   512  		}
   513  	}
   514  }
   515  
   516  func (p *preprocessor) checkCreateViewWithSelect(stmt *ast.SelectStmt) {
   517  	if stmt.SelectIntoOpt != nil {
   518  		p.err = dbs.ErrViewSelectClause.GenWithStackByArgs("INFO")
   519  		return
   520  	}
   521  	if stmt.LockInfo != nil && stmt.LockInfo.LockType != ast.SelectLockNone {
   522  		stmt.LockInfo.LockType = ast.SelectLockNone
   523  		return
   524  	}
   525  }
   526  
   527  func (p *preprocessor) checkCreateViewWithSelectGrammar(stmt *ast.CreateViewStmt) {
   528  	switch stmt := stmt.Select.(type) {
   529  	case *ast.SelectStmt:
   530  		p.checkCreateViewWithSelect(stmt)
   531  	case *ast.SetOprStmt:
   532  		for _, selectStmt := range stmt.SelectList.Selects {
   533  			p.checkCreateViewWithSelect(selectStmt)
   534  			if p.err != nil {
   535  				return
   536  			}
   537  		}
   538  	}
   539  }
   540  
   541  func (p *preprocessor) checkDropSequenceGrammar(stmt *ast.DropSequenceStmt) {
   542  	p.checkDropBlockNames(stmt.Sequences)
   543  }
   544  
   545  func (p *preprocessor) checkDropBlockGrammar(stmt *ast.DropBlockStmt) {
   546  	p.checkDropBlockNames(stmt.Blocks)
   547  }
   548  
   549  func (p *preprocessor) checkDropBlockNames(blocks []*ast.BlockName) {
   550  	for _, t := range blocks {
   551  		if isIncorrectName(t.Name.String()) {
   552  			p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(t.Name.String())
   553  			return
   554  		}
   555  	}
   556  }
   557  
   558  func (p *preprocessor) checkNonUniqBlockAlias(stmt *ast.Join) {
   559  	if p.flag&parentIsJoin == 0 {
   560  		p.blockAliasInJoin = append(p.blockAliasInJoin, make(map[string]interface{}))
   561  	}
   562  	blockAliases := p.blockAliasInJoin[len(p.blockAliasInJoin)-1]
   563  	if err := isBlockAliasDuplicate(stmt.Left, blockAliases); err != nil {
   564  		p.err = err
   565  		return
   566  	}
   567  	if err := isBlockAliasDuplicate(stmt.Right, blockAliases); err != nil {
   568  		p.err = err
   569  		return
   570  	}
   571  	p.flag |= parentIsJoin
   572  }
   573  
   574  func isBlockAliasDuplicate(node ast.ResultSetNode, blockAliases map[string]interface{}) error {
   575  	if ts, ok := node.(*ast.BlockSource); ok {
   576  		tabName := ts.AsName
   577  		if tabName.L == "" {
   578  			if blockNode, ok := ts.Source.(*ast.BlockName); ok {
   579  				if blockNode.Schema.L != "" {
   580  					tabName = perceptron.NewCIStr(fmt.Sprintf("%s.%s", blockNode.Schema.L, blockNode.Name.L))
   581  				} else {
   582  					tabName = blockNode.Name
   583  				}
   584  			}
   585  		}
   586  		_, exists := blockAliases[tabName.L]
   587  		if len(tabName.L) != 0 && exists {
   588  			return ErrNonUniqBlock.GenWithStackByArgs(tabName)
   589  		}
   590  		blockAliases[tabName.L] = nil
   591  	}
   592  	return nil
   593  }
   594  
   595  func checkDeferredCausetOptions(ops []*ast.DeferredCausetOption) (int, error) {
   596  	isPrimary, isGenerated, isStored := 0, 0, false
   597  
   598  	for _, op := range ops {
   599  		switch op.Tp {
   600  		case ast.DeferredCausetOptionPrimaryKey:
   601  			isPrimary = 1
   602  		case ast.DeferredCausetOptionGenerated:
   603  			isGenerated = 1
   604  			isStored = op.Stored
   605  		}
   606  	}
   607  
   608  	if isPrimary > 0 && isGenerated > 0 && !isStored {
   609  		return isPrimary, ErrUnsupportedOnGeneratedDeferredCauset.GenWithStackByArgs("Defining a virtual generated column as primary key")
   610  	}
   611  
   612  	return isPrimary, nil
   613  }
   614  
   615  func (p *preprocessor) checkCreateIndexGrammar(stmt *ast.CreateIndexStmt) {
   616  	tName := stmt.Block.Name.String()
   617  	if isIncorrectName(tName) {
   618  		p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(tName)
   619  		return
   620  	}
   621  	p.err = checHoTTexInfo(stmt.IndexName, stmt.IndexPartSpecifications)
   622  }
   623  
   624  func (p *preprocessor) checkStatisticsOpGrammar(node ast.Node) {
   625  	var statsName string
   626  	switch stmt := node.(type) {
   627  	case *ast.CreateStatisticsStmt:
   628  		statsName = stmt.StatsName
   629  	case *ast.DropStatisticsStmt:
   630  		statsName = stmt.StatsName
   631  	}
   632  	if isIncorrectName(statsName) {
   633  		msg := fmt.Sprintf("Incorrect statistics name: %s", statsName)
   634  		p.err = ErrInternal.GenWithStack(msg)
   635  	}
   636  	return
   637  }
   638  
   639  func (p *preprocessor) checkRenameBlockGrammar(stmt *ast.RenameBlockStmt) {
   640  	oldBlock := stmt.OldBlock.Name.String()
   641  	newBlock := stmt.NewBlock.Name.String()
   642  
   643  	p.checkRenameBlock(oldBlock, newBlock)
   644  }
   645  
   646  func (p *preprocessor) checkRenameBlock(oldBlock, newBlock string) {
   647  	if isIncorrectName(oldBlock) {
   648  		p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(oldBlock)
   649  		return
   650  	}
   651  
   652  	if isIncorrectName(newBlock) {
   653  		p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(newBlock)
   654  		return
   655  	}
   656  }
   657  
   658  func (p *preprocessor) checkRepairBlockGrammar(stmt *ast.RepairBlockStmt) {
   659  	// Check create causet stmt whether it's is in REPAIR MODE.
   660  	if !petriutil.RepairInfo.InRepairMode() {
   661  		p.err = dbs.ErrRepairBlockFail.GenWithStackByArgs("MilevaDB is not in REPAIR MODE")
   662  		return
   663  	}
   664  	if len(petriutil.RepairInfo.GetRepairBlockList()) == 0 {
   665  		p.err = dbs.ErrRepairBlockFail.GenWithStackByArgs("repair list is empty")
   666  		return
   667  	}
   668  
   669  	// Check rename action as the rename memex does.
   670  	oldBlock := stmt.Block.Name.String()
   671  	newBlock := stmt.CreateStmt.Block.Name.String()
   672  	p.checkRenameBlock(oldBlock, newBlock)
   673  }
   674  
   675  func (p *preprocessor) checkAlterBlockGrammar(stmt *ast.AlterBlockStmt) {
   676  	tName := stmt.Block.Name.String()
   677  	if isIncorrectName(tName) {
   678  		p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(tName)
   679  		return
   680  	}
   681  	specs := stmt.Specs
   682  	for _, spec := range specs {
   683  		if spec.NewBlock != nil {
   684  			ntName := spec.NewBlock.Name.String()
   685  			if isIncorrectName(ntName) {
   686  				p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(ntName)
   687  				return
   688  			}
   689  		}
   690  		for _, colDef := range spec.NewDeferredCausets {
   691  			if p.err = checkDeferredCauset(colDef); p.err != nil {
   692  				return
   693  			}
   694  		}
   695  		if p.err = checkUnsupportedBlockOptions(spec.Options); p.err != nil {
   696  			return
   697  		}
   698  		switch spec.Tp {
   699  		case ast.AlterBlockAddConstraint:
   700  			switch spec.Constraint.Tp {
   701  			case ast.ConstraintKey, ast.ConstraintIndex, ast.ConstraintUniq, ast.ConstraintUniqIndex,
   702  				ast.ConstraintUniqKey, ast.ConstraintPrimaryKey:
   703  				p.err = checHoTTexInfo(spec.Constraint.Name, spec.Constraint.Keys)
   704  				if p.err != nil {
   705  					return
   706  				}
   707  			default:
   708  				// Nothing to do now.
   709  			}
   710  		default:
   711  			// Nothing to do now.
   712  		}
   713  	}
   714  }
   715  
   716  // checkDuplicateDeferredCausetName checks if index exists duplicated columns.
   717  func checkDuplicateDeferredCausetName(IndexPartSpecifications []*ast.IndexPartSpecification) error {
   718  	colNames := make(map[string]struct{}, len(IndexPartSpecifications))
   719  	for _, IndexDefCausNameWithExpr := range IndexPartSpecifications {
   720  		if IndexDefCausNameWithExpr.DeferredCauset != nil {
   721  			name := IndexDefCausNameWithExpr.DeferredCauset.Name
   722  			if _, ok := colNames[name.L]; ok {
   723  				return schemareplicant.ErrDeferredCausetExists.GenWithStackByArgs(name)
   724  			}
   725  			colNames[name.L] = struct{}{}
   726  		}
   727  	}
   728  	return nil
   729  }
   730  
   731  // checHoTTexInfo checks index name and index column names.
   732  func checHoTTexInfo(indexName string, IndexPartSpecifications []*ast.IndexPartSpecification) error {
   733  	if strings.EqualFold(indexName, allegrosql.PrimaryKeyName) {
   734  		return dbs.ErrWrongNameForIndex.GenWithStackByArgs(indexName)
   735  	}
   736  	if len(IndexPartSpecifications) > allegrosql.MaxKeyParts {
   737  		return schemareplicant.ErrTooManyKeyParts.GenWithStackByArgs(allegrosql.MaxKeyParts)
   738  	}
   739  	return checkDuplicateDeferredCausetName(IndexPartSpecifications)
   740  }
   741  
   742  // checkUnsupportedBlockOptions checks if there exists unsupported causet options
   743  func checkUnsupportedBlockOptions(options []*ast.BlockOption) error {
   744  	for _, option := range options {
   745  		switch option.Tp {
   746  		case ast.BlockOptionUnion:
   747  			return dbs.ErrBlockOptionUnionUnsupported
   748  		case ast.BlockOptionInsertMethod:
   749  			return dbs.ErrBlockOptionInsertMethodUnsupported
   750  		}
   751  	}
   752  	return nil
   753  }
   754  
   755  // checkDeferredCauset checks if the column definition is valid.
   756  // See https://dev.allegrosql.com/doc/refman/5.7/en/storage-requirements.html
   757  func checkDeferredCauset(colDef *ast.DeferredCausetDef) error {
   758  	// Check column name.
   759  	cName := colDef.Name.Name.String()
   760  	if isIncorrectName(cName) {
   761  		return dbs.ErrWrongDeferredCausetName.GenWithStackByArgs(cName)
   762  	}
   763  
   764  	if isInvalidDefaultValue(colDef) {
   765  		return types.ErrInvalidDefault.GenWithStackByArgs(colDef.Name.Name.O)
   766  	}
   767  
   768  	// Check column type.
   769  	tp := colDef.Tp
   770  	if tp == nil {
   771  		return nil
   772  	}
   773  	if tp.Flen > math.MaxUint32 {
   774  		return types.ErrTooBigDisplayWidth.GenWithStack("Display width out of range for column '%s' (max = %d)", colDef.Name.Name.O, math.MaxUint32)
   775  	}
   776  
   777  	switch tp.Tp {
   778  	case allegrosql.TypeString:
   779  		if tp.Flen != types.UnspecifiedLength && tp.Flen > allegrosql.MaxFieldCharLength {
   780  			return types.ErrTooBigFieldLength.GenWithStack("DeferredCauset length too big for column '%s' (max = %d); use BLOB or TEXT instead", colDef.Name.Name.O, allegrosql.MaxFieldCharLength)
   781  		}
   782  	case allegrosql.TypeVarchar:
   783  		if len(tp.Charset) == 0 {
   784  			// It's not easy to get the schemaReplicant charset and causet charset here.
   785  			// The charset is determined by the order DeferredCausetDefaultCharset --> BlockDefaultCharset-->DatabaseDefaultCharset-->SystemDefaultCharset.
   786  			// return nil, to make the check in the dbs.CreateBlock.
   787  			return nil
   788  		}
   789  		err := dbs.IsTooBigFieldLength(colDef.Tp.Flen, colDef.Name.Name.O, tp.Charset)
   790  		if err != nil {
   791  			return err
   792  		}
   793  	case allegrosql.TypeFloat, allegrosql.TypeDouble:
   794  		if tp.Decimal > allegrosql.MaxFloatingTypeScale {
   795  			return types.ErrTooBigScale.GenWithStackByArgs(tp.Decimal, colDef.Name.Name.O, allegrosql.MaxFloatingTypeScale)
   796  		}
   797  		if tp.Flen > allegrosql.MaxFloatingTypeWidth {
   798  			return types.ErrTooBigPrecision.GenWithStackByArgs(tp.Flen, colDef.Name.Name.O, allegrosql.MaxFloatingTypeWidth)
   799  		}
   800  	case allegrosql.TypeSet:
   801  		if len(tp.Elems) > allegrosql.MaxTypeSetMembers {
   802  			return types.ErrTooBigSet.GenWithStack("Too many strings for column %s and SET", colDef.Name.Name.O)
   803  		}
   804  		// Check set elements. See https://dev.allegrosql.com/doc/refman/5.7/en/set.html.
   805  		for _, str := range colDef.Tp.Elems {
   806  			if strings.Contains(str, ",") {
   807  				return types.ErrIllegalValueForType.GenWithStackByArgs(types.TypeStr(tp.Tp), str)
   808  			}
   809  		}
   810  	case allegrosql.TypeNewDecimal:
   811  		if tp.Decimal > allegrosql.MaxDecimalScale {
   812  			return types.ErrTooBigScale.GenWithStackByArgs(tp.Decimal, colDef.Name.Name.O, allegrosql.MaxDecimalScale)
   813  		}
   814  
   815  		if tp.Flen > allegrosql.MaxDecimalWidth {
   816  			return types.ErrTooBigPrecision.GenWithStackByArgs(tp.Flen, colDef.Name.Name.O, allegrosql.MaxDecimalWidth)
   817  		}
   818  	case allegrosql.TypeBit:
   819  		if tp.Flen <= 0 {
   820  			return types.ErrInvalidFieldSize.GenWithStackByArgs(colDef.Name.Name.O)
   821  		}
   822  		if tp.Flen > allegrosql.MaxBitDisplayWidth {
   823  			return types.ErrTooBigDisplayWidth.GenWithStackByArgs(colDef.Name.Name.O, allegrosql.MaxBitDisplayWidth)
   824  		}
   825  	default:
   826  		// TODO: Add more types.
   827  	}
   828  	return nil
   829  }
   830  
   831  // isDefaultValNowSymFunc checks whether default value is a NOW() builtin function.
   832  func isDefaultValNowSymFunc(expr ast.ExprNode) bool {
   833  	if funcCall, ok := expr.(*ast.FuncCallExpr); ok {
   834  		// Default value NOW() is transformed to CURRENT_TIMESTAMP() in BerolinaSQL.
   835  		if funcCall.FnName.L == ast.CurrentTimestamp {
   836  			return true
   837  		}
   838  	}
   839  	return false
   840  }
   841  
   842  func isInvalidDefaultValue(colDef *ast.DeferredCausetDef) bool {
   843  	tp := colDef.Tp
   844  	// Check the last default value.
   845  	for i := len(colDef.Options) - 1; i >= 0; i-- {
   846  		columnOpt := colDef.Options[i]
   847  		if columnOpt.Tp == ast.DeferredCausetOptionDefaultValue {
   848  			if !(tp.Tp == allegrosql.TypeTimestamp || tp.Tp == allegrosql.TypeDatetime) && isDefaultValNowSymFunc(columnOpt.Expr) {
   849  				return true
   850  			}
   851  			break
   852  		}
   853  	}
   854  
   855  	return false
   856  }
   857  
   858  // isIncorrectName checks if the identifier is incorrect.
   859  // See https://dev.allegrosql.com/doc/refman/5.7/en/identifiers.html
   860  func isIncorrectName(name string) bool {
   861  	if len(name) == 0 {
   862  		return true
   863  	}
   864  	if name[len(name)-1] == ' ' {
   865  		return true
   866  	}
   867  	return false
   868  }
   869  
   870  // checkContainDotDeferredCauset checks field contains the causet name.
   871  // for example :create causet t (c1.c2 int default null).
   872  func (p *preprocessor) checkContainDotDeferredCauset(stmt *ast.CreateBlockStmt) {
   873  	tName := stmt.Block.Name.String()
   874  	sName := stmt.Block.Schema.String()
   875  
   876  	for _, colDef := range stmt.DefCauss {
   877  		// check schemaReplicant and causet names.
   878  		if colDef.Name.Schema.O != sName && len(colDef.Name.Schema.O) != 0 {
   879  			p.err = dbs.ErrWrongDBName.GenWithStackByArgs(colDef.Name.Schema.O)
   880  			return
   881  		}
   882  		if colDef.Name.Block.O != tName && len(colDef.Name.Block.O) != 0 {
   883  			p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(colDef.Name.Block.O)
   884  			return
   885  		}
   886  	}
   887  }
   888  
   889  func (p *preprocessor) handleBlockName(tn *ast.BlockName) {
   890  	if tn.Schema.L == "" {
   891  		currentDB := p.ctx.GetStochastikVars().CurrentDB
   892  		if currentDB == "" {
   893  			p.err = errors.Trace(ErrNoDB)
   894  			return
   895  		}
   896  		tn.Schema = perceptron.NewCIStr(currentDB)
   897  	}
   898  	if p.flag&inCreateOrDropBlock > 0 {
   899  		// The causet may not exist in create causet or drop causet memex.
   900  		if p.flag&inRepairBlock > 0 {
   901  			// Create stmt is in repair stmt, skip resolving the causet to avoid error.
   902  			return
   903  		}
   904  		// Create stmt is not in repair stmt, check the causet not in repair list.
   905  		if petriutil.RepairInfo.InRepairMode() {
   906  			p.checkNotInRepair(tn)
   907  		}
   908  		return
   909  	}
   910  	// repairStmt: admin repair causet A create causet B ...
   911  	// repairStmt's blockName is whether `inCreateOrDropBlock` or `inRepairBlock` flag.
   912  	if p.flag&inRepairBlock > 0 {
   913  		p.handleRepairName(tn)
   914  		return
   915  	}
   916  
   917  	causet, err := p.is.BlockByName(tn.Schema, tn.Name)
   918  	if err != nil {
   919  		p.err = err
   920  		return
   921  	}
   922  	blockInfo := causet.Meta()
   923  	dbInfo, _ := p.is.SchemaByName(tn.Schema)
   924  	// blockName should be checked as sequence object.
   925  	if p.flag&inSequenceFunction > 0 {
   926  		if !blockInfo.IsSequence() {
   927  			p.err = schemareplicant.ErrWrongObject.GenWithStackByArgs(dbInfo.Name.O, blockInfo.Name.O, "SEQUENCE")
   928  			return
   929  		}
   930  	}
   931  	tn.BlockInfo = blockInfo
   932  	tn.DBInfo = dbInfo
   933  }
   934  
   935  func (p *preprocessor) checkNotInRepair(tn *ast.BlockName) {
   936  	blockInfo, dbInfo := petriutil.RepairInfo.GetRepairedBlockInfoByBlockName(tn.Schema.L, tn.Name.L)
   937  	if dbInfo == nil {
   938  		return
   939  	}
   940  	if blockInfo != nil {
   941  		p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(tn.Name.L, "this causet is in repair")
   942  	}
   943  }
   944  
   945  func (p *preprocessor) handleRepairName(tn *ast.BlockName) {
   946  	// Check the whether the repaired causet is system causet.
   947  	if soliton.IsMemOrSysDB(tn.Schema.L) {
   948  		p.err = dbs.ErrRepairBlockFail.GenWithStackByArgs("memory or system database is not for repair")
   949  		return
   950  	}
   951  	blockInfo, dbInfo := petriutil.RepairInfo.GetRepairedBlockInfoByBlockName(tn.Schema.L, tn.Name.L)
   952  	// blockName here only has the schemaReplicant rather than DBInfo.
   953  	if dbInfo == nil {
   954  		p.err = dbs.ErrRepairBlockFail.GenWithStackByArgs("database " + tn.Schema.L + " is not in repair")
   955  		return
   956  	}
   957  	if blockInfo == nil {
   958  		p.err = dbs.ErrRepairBlockFail.GenWithStackByArgs("causet " + tn.Name.L + " is not in repair")
   959  		return
   960  	}
   961  	p.ctx.SetValue(petriutil.RepairedBlock, blockInfo)
   962  	p.ctx.SetValue(petriutil.RepairedDatabase, dbInfo)
   963  }
   964  
   965  func (p *preprocessor) resolveShowStmt(node *ast.ShowStmt) {
   966  	if node.DBName == "" {
   967  		if node.Block != nil && node.Block.Schema.L != "" {
   968  			node.DBName = node.Block.Schema.O
   969  		} else {
   970  			node.DBName = p.ctx.GetStochastikVars().CurrentDB
   971  		}
   972  	} else if node.Block != nil && node.Block.Schema.L == "" {
   973  		node.Block.Schema = perceptron.NewCIStr(node.DBName)
   974  	}
   975  	if node.User != nil && node.User.CurrentUser {
   976  		// Fill the Username and Hostname with the current user.
   977  		currentUser := p.ctx.GetStochastikVars().User
   978  		if currentUser != nil {
   979  			node.User.Username = currentUser.Username
   980  			node.User.Hostname = currentUser.Hostname
   981  			node.User.AuthUsername = currentUser.AuthUsername
   982  			node.User.AuthHostname = currentUser.AuthHostname
   983  		}
   984  	}
   985  }
   986  
   987  func (p *preprocessor) resolveCreateBlockStmt(node *ast.CreateBlockStmt) {
   988  	for _, val := range node.Constraints {
   989  		if val.Refer != nil && val.Refer.Block.Schema.String() == "" {
   990  			val.Refer.Block.Schema = node.Block.Schema
   991  		}
   992  	}
   993  }
   994  
   995  func (p *preprocessor) resolveAlterBlockStmt(node *ast.AlterBlockStmt) {
   996  	for _, spec := range node.Specs {
   997  		if spec.Tp == ast.AlterBlockRenameBlock {
   998  			p.flag |= inCreateOrDropBlock
   999  			break
  1000  		}
  1001  		if spec.Tp == ast.AlterBlockAddConstraint && spec.Constraint.Refer != nil {
  1002  			causet := spec.Constraint.Refer.Block
  1003  			if causet.Schema.L == "" && node.Block.Schema.L != "" {
  1004  				causet.Schema = perceptron.NewCIStr(node.Block.Schema.L)
  1005  			}
  1006  		}
  1007  	}
  1008  }
  1009  
  1010  func (p *preprocessor) resolveCreateSequenceStmt(stmt *ast.CreateSequenceStmt) {
  1011  	sName := stmt.Name.Name.String()
  1012  	if isIncorrectName(sName) {
  1013  		p.err = dbs.ErrWrongBlockName.GenWithStackByArgs(sName)
  1014  		return
  1015  	}
  1016  }