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 }