1 /* 2 * Copyright 2015-2018 HuntLabs.cn 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 module hunt.sql.dialect.mysql.parser.MySqlCreateTableParser; 17 18 import hunt.sql.ast.SQLDataTypeImpl; 19 import hunt.sql.ast.SQLExpr; 20 import hunt.sql.ast.SQLName; 21 import hunt.sql.ast.SQLOrderingSpecification; 22 import hunt.sql.ast.SQLPartition; 23 import hunt.sql.ast.SQLPartitionBy; 24 import hunt.sql.ast.SQLPartitionByHash; 25 import hunt.sql.ast.SQLPartitionByList; 26 import hunt.sql.ast.SQLPartitionByRange; 27 import hunt.sql.ast.SQLSubPartitionBy; 28 import hunt.sql.ast.SQLSubPartitionByHash; 29 import hunt.sql.ast.expr.SQLIdentifierExpr; 30 import hunt.sql.ast.expr.SQLIntegerExpr; 31 import hunt.sql.ast.expr.SQLNumberExpr; 32 import hunt.sql.ast.statement; 33 import hunt.sql.dialect.mysql.ast.MySqlKey; 34 import hunt.sql.dialect.mysql.ast.MySqlPrimaryKey; 35 import hunt.sql.dialect.mysql.ast.MySqlUnique; 36 import hunt.sql.dialect.mysql.ast.MysqlForeignKey; 37 import hunt.sql.dialect.mysql.ast.expr.MySqlOrderingExpr; 38 import hunt.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; 39 // import hunt.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement.TableSpaceOption; 40 import hunt.sql.dialect.mysql.ast.statement.MySqlPartitionByKey; 41 import hunt.sql.dialect.mysql.ast.statement.MySqlSubPartitionByKey; 42 import hunt.sql.dialect.mysql.ast.statement.MySqlSubPartitionByList; 43 import hunt.sql.dialect.mysql.ast.statement.MySqlTableIndex; 44 import hunt.sql.parser; 45 import hunt.sql.util.FnvHash; 46 import hunt.sql.dialect.mysql.parser.MySqlExprParser; 47 import hunt.sql.dialect.mysql.parser.MySqlSelectParser; 48 import hunt.String; 49 import hunt.Boolean; 50 import hunt.collection; 51 import hunt.sql.ast.SQLObject; 52 import hunt.text; 53 import hunt.Number; 54 import hunt.sql.ast.SQLCommentHint; 55 56 public class MySqlCreateTableParser : SQLCreateTableParser { 57 58 public this(string sql){ 59 super(new MySqlExprParser(sql)); 60 } 61 62 public this(SQLExprParser exprParser){ 63 super(exprParser); 64 } 65 66 override public SQLCreateTableStatement parseCreateTable() { 67 return parseCreateTable(true); 68 } 69 70 override public MySqlExprParser getExprParser() { 71 return cast(MySqlExprParser) exprParser; 72 } 73 74 override public MySqlCreateTableStatement parseCreateTable(bool acceptCreate) { 75 MySqlCreateTableStatement stmt = new MySqlCreateTableStatement(); 76 if (acceptCreate) { 77 if (lexer.hasComment() && lexer.isKeepComments()) { 78 stmt.addBeforeComment(lexer.readAndResetComments()); 79 } 80 accept(Token.CREATE); 81 } 82 83 if (lexer.identifierEquals("TEMPORARY")) { 84 lexer.nextToken(); 85 stmt.setType(SQLCreateTableStatement.Type.GLOBAL_TEMPORARY); 86 } 87 88 accept(Token.TABLE); 89 90 if (lexer.token() == Token.IF || lexer.identifierEquals("IF")) { 91 lexer.nextToken(); 92 accept(Token.NOT); 93 accept(Token.EXISTS); 94 95 stmt.setIfNotExiists(true); 96 } 97 98 stmt.setName(this.exprParser.name()); 99 100 if (lexer.token() == Token.LIKE) { 101 lexer.nextTokenValue(); 102 SQLName name = this.exprParser.name(); 103 stmt.setLike(name); 104 } 105 106 if (lexer.token() == (Token.LPAREN)) { 107 lexer.nextToken(); 108 109 if (lexer.token() == Token.LIKE) { 110 lexer.nextTokenValue(); 111 SQLName name = this.exprParser.name(); 112 stmt.setLike(name); 113 } else if (lexer.token() == Token.SELECT) { 114 SQLSelect query = new MySqlSelectParser(this.exprParser).select(); 115 stmt.setSelect(query); 116 } else { 117 for (;;) { 118 if (lexer.token() == Token.FULLTEXT) { 119 Lexer.SavePoint mark = lexer.mark(); 120 lexer.nextToken(); 121 if (lexer.token() == Token.KEY) { 122 MySqlKey fulltextKey = cast(MySqlKey) parseConstraint(); 123 fulltextKey.setIndexType("FULLTEXT"); 124 stmt.getTableElementList().add(fulltextKey); 125 if (lexer.token() == Token.RPAREN) { 126 break; 127 } else if (lexer.token() == Token.COMMA) { 128 lexer.nextToken(); 129 continue; 130 } 131 } else if (lexer.token() == Token.INDEX) { 132 lexer.nextToken(); 133 MySqlTableIndex idx = new MySqlTableIndex(); 134 idx.setIndexType("FULLTEXT"); 135 idx.setName(this.exprParser.name()); 136 137 accept(Token.LPAREN); 138 for (; ; ) { 139 idx.addColumn(this.exprParser.parseSelectOrderByItem()); 140 if (!(lexer.token() == (Token.COMMA))) { 141 break; 142 } else { 143 lexer.nextToken(); 144 } 145 } 146 stmt.getTableElementList().add(idx); 147 accept(Token.RPAREN); 148 if (lexer.token() == Token.RPAREN) { 149 break; 150 } else if (lexer.token() == Token.COMMA) { 151 lexer.nextToken(); 152 continue; 153 } 154 } else { 155 MySqlTableIndex idx = new MySqlTableIndex(); 156 idx.setIndexType("FULLTEXT"); 157 idx.setName(this.exprParser.name()); 158 159 accept(Token.LPAREN); 160 for (; ; ) { 161 idx.addColumn(this.exprParser.parseSelectOrderByItem()); 162 if (!(lexer.token() == (Token.COMMA))) { 163 break; 164 } else { 165 lexer.nextToken(); 166 } 167 } 168 stmt.getTableElementList().add(idx); 169 accept(Token.RPAREN); 170 if (lexer.token() == Token.RPAREN) { 171 break; 172 } else if (lexer.token() == Token.COMMA) { 173 lexer.nextToken(); 174 continue; 175 } 176 } 177 } else if (lexer.identifierEquals(FnvHash.Constants.SPATIAL)) { 178 Lexer.SavePoint mark = lexer.mark(); 179 lexer.nextToken(); 180 if (lexer.token() == Token.INDEX) { 181 lexer.nextToken(); 182 MySqlTableIndex idx = new MySqlTableIndex(); 183 idx.setIndexType("SPATIAL"); 184 185 if (lexer.token() == Token.IDENTIFIER) { 186 if (!equalsIgnoreCase("USING",lexer.stringVal())) { 187 idx.setName(this.exprParser.name()); 188 } 189 } 190 191 if (lexer.identifierEquals("USING")) { 192 lexer.nextToken(); 193 idx.setIndexType(lexer.stringVal()); 194 lexer.nextToken(); 195 } 196 197 accept(Token.LPAREN); 198 for (;;) { 199 idx.addColumn(this.exprParser.parseSelectOrderByItem()); 200 if (!(lexer.token() == (Token.COMMA))) { 201 break; 202 } else { 203 lexer.nextToken(); 204 } 205 } 206 accept(Token.RPAREN); 207 208 if (lexer.identifierEquals("USING")) { 209 lexer.nextToken(); 210 idx.setIndexType(lexer.stringVal()); 211 lexer.nextToken(); 212 } 213 214 stmt.getTableElementList().add(idx); 215 216 if (lexer.token() == Token.RPAREN) { 217 break; 218 } else if (lexer.token() == Token.COMMA) { 219 lexer.nextToken(); 220 continue; 221 } 222 } else { 223 lexer.reset(mark); 224 } 225 } 226 227 SQLColumnDefinition column = null; 228 if (lexer.token() == Token.IDENTIFIER // 229 || lexer.token() == Token.LITERAL_CHARS) { 230 column = this.exprParser.parseColumn(); 231 stmt.getTableElementList().add(column); 232 233 if (lexer.isKeepComments() && lexer.hasComment()) { 234 column.addAfterComment(lexer.readAndResetComments()); 235 } 236 } else if (lexer.token() == Token.CONSTRAINT // 237 || lexer.token() == Token.PRIMARY // 238 || lexer.token() == Token.UNIQUE) { 239 SQLTableConstraint constraint = this.parseConstraint(); 240 constraint.setParent(stmt); 241 stmt.getTableElementList().add(constraint); 242 } else if (lexer.token() == (Token.INDEX)) { 243 lexer.nextToken(); 244 245 MySqlTableIndex idx = new MySqlTableIndex(); 246 247 if (lexer.token() == Token.IDENTIFIER) { 248 if (!equalsIgnoreCase("USING",lexer.stringVal())) { 249 idx.setName(this.exprParser.name()); 250 } 251 } 252 253 if (lexer.identifierEquals("USING")) { 254 lexer.nextToken(); 255 idx.setIndexType(lexer.stringVal()); 256 lexer.nextToken(); 257 } 258 259 accept(Token.LPAREN); 260 for (;;) { 261 idx.addColumn(this.exprParser.parseSelectOrderByItem()); 262 if (!(lexer.token() == (Token.COMMA))) { 263 break; 264 } else { 265 lexer.nextToken(); 266 } 267 } 268 accept(Token.RPAREN); 269 270 if (lexer.identifierEquals("USING")) { 271 lexer.nextToken(); 272 idx.setIndexType(lexer.stringVal()); 273 lexer.nextToken(); 274 } 275 276 stmt.getTableElementList().add(idx); 277 } else if (lexer.token() == (Token.KEY)) { 278 Lexer.SavePoint savePoint = lexer.mark(); 279 lexer.nextToken(); 280 281 bool isColumn = false; 282 if (lexer.identifierEquals(FnvHash.Constants.VARCHAR)) { 283 isColumn = true; 284 } 285 lexer.reset(savePoint); 286 287 if (isColumn) { 288 column = this.exprParser.parseColumn(); 289 stmt.getTableElementList().add(column); 290 } else { 291 stmt.getTableElementList().add(parseConstraint()); 292 } 293 } else if (lexer.token() == (Token.PRIMARY)) { 294 SQLTableConstraint pk = parseConstraint(); 295 pk.setParent(stmt); 296 stmt.getTableElementList().add(pk); 297 } else if (lexer.token() == (Token.FOREIGN)) { 298 SQLForeignKeyConstraint fk = this.getExprParser().parseForeignKey(); 299 fk.setParent(stmt); 300 stmt.getTableElementList().add(fk); 301 } else if (lexer.token() == Token.CHECK) { 302 SQLCheck check = this.exprParser.parseCheck(); 303 stmt.getTableElementList().add(check); 304 } else { 305 column = this.exprParser.parseColumn(); 306 stmt.getTableElementList().add(column); 307 } 308 309 if (lexer.token() != Token.COMMA) { 310 break; 311 } else { 312 lexer.nextToken(); 313 if (lexer.isKeepComments() && lexer.hasComment() && column !is null) { 314 column.addAfterComment(lexer.readAndResetComments()); 315 } 316 } 317 } 318 } 319 320 accept(Token.RPAREN); 321 } 322 323 for (;;) { 324 if (lexer.token() == Token.COMMA) { 325 lexer.nextToken(); 326 } 327 328 if (lexer.identifierEquals("ENGINE")) { 329 lexer.nextToken(); 330 if (lexer.token() == Token.EQ) { 331 lexer.nextToken(); 332 } 333 334 SQLExpr expr = null; 335 if (lexer.token() == Token.MERGE) { 336 expr = new SQLIdentifierExpr(lexer.stringVal()); 337 lexer.nextToken(); 338 } else { 339 expr = this.exprParser.expr(); 340 } 341 stmt.getTableOptions().put("ENGINE", expr); 342 continue; 343 } 344 345 if (lexer.identifierEquals("AUTO_INCREMENT")) { 346 lexer.nextToken(); 347 if (lexer.token() == Token.EQ) { 348 lexer.nextToken(); 349 } 350 stmt.getTableOptions().put("AUTO_INCREMENT", this.exprParser.expr()); 351 continue; 352 } 353 354 if (lexer.identifierEquals("AVG_ROW_LENGTH")) { 355 lexer.nextToken(); 356 if (lexer.token() == Token.EQ) { 357 lexer.nextToken(); 358 } 359 stmt.getTableOptions().put("AVG_ROW_LENGTH", this.exprParser.expr()); 360 continue; 361 } 362 363 if (lexer.token() == Token.DEFAULT) { 364 lexer.nextToken(); 365 parseTableOptionCharsetOrCollate(stmt); 366 continue; 367 } 368 369 if (parseTableOptionCharsetOrCollate(stmt)) { 370 continue; 371 } 372 373 if (lexer.identifierEquals("CHECKSUM")) { 374 lexer.nextToken(); 375 if (lexer.token() == Token.EQ) { 376 lexer.nextToken(); 377 } 378 stmt.getTableOptions().put("CHECKSUM", this.exprParser.expr()); 379 continue; 380 } 381 382 if (lexer.token() == Token.COMMENT) { 383 lexer.nextToken(); 384 if (lexer.token() == Token.EQ) { 385 lexer.nextToken(); 386 } 387 stmt.setComment(this.exprParser.expr()); 388 continue; 389 } 390 391 if (lexer.identifierEquals("CONNECTION")) { 392 lexer.nextToken(); 393 if (lexer.token() == Token.EQ) { 394 lexer.nextToken(); 395 } 396 stmt.getTableOptions().put("CONNECTION", this.exprParser.expr()); 397 continue; 398 } 399 400 if (lexer.identifierEquals("DATA")) { 401 lexer.nextToken(); 402 acceptIdentifier("DIRECTORY"); 403 if (lexer.token() == Token.EQ) { 404 lexer.nextToken(); 405 } 406 stmt.getTableOptions().put("DATA DIRECTORY", this.exprParser.expr()); 407 continue; 408 } 409 410 if (lexer.identifierEquals("DELAY_KEY_WRITE")) { 411 lexer.nextToken(); 412 if (lexer.token() == Token.EQ) { 413 lexer.nextToken(); 414 } 415 stmt.getTableOptions().put("DELAY_KEY_WRITE", this.exprParser.expr()); 416 continue; 417 } 418 419 if (lexer.identifierEquals("INDEX")) { 420 lexer.nextToken(); 421 acceptIdentifier("DIRECTORY"); 422 if (lexer.token() == Token.EQ) { 423 lexer.nextToken(); 424 } 425 stmt.getTableOptions().put("INDEX DIRECTORY", this.exprParser.expr()); 426 continue; 427 } 428 429 if (lexer.identifierEquals("INSERT_METHOD")) { 430 lexer.nextToken(); 431 if (lexer.token() == Token.EQ) { 432 lexer.nextToken(); 433 } 434 stmt.getTableOptions().put("INSERT_METHOD", this.exprParser.expr()); 435 continue; 436 } 437 438 if (lexer.identifierEquals("KEY_BLOCK_SIZE")) { 439 lexer.nextToken(); 440 if (lexer.token() == Token.EQ) { 441 lexer.nextToken(); 442 } 443 stmt.getTableOptions().put("KEY_BLOCK_SIZE", this.exprParser.expr()); 444 continue; 445 } 446 447 if (lexer.identifierEquals("MAX_ROWS")) { 448 lexer.nextToken(); 449 if (lexer.token() == Token.EQ) { 450 lexer.nextToken(); 451 } 452 stmt.getTableOptions().put("MAX_ROWS", this.exprParser.expr()); 453 continue; 454 } 455 456 if (lexer.identifierEquals("MIN_ROWS")) { 457 lexer.nextToken(); 458 if (lexer.token() == Token.EQ) { 459 lexer.nextToken(); 460 } 461 stmt.getTableOptions().put("MIN_ROWS", this.exprParser.expr()); 462 continue; 463 } 464 465 if (lexer.identifierEquals("PACK_KEYS")) { 466 lexer.nextToken(); 467 if (lexer.token() == Token.EQ) { 468 lexer.nextToken(); 469 } 470 stmt.getTableOptions().put("PACK_KEYS", this.exprParser.expr()); 471 continue; 472 } 473 474 if (lexer.identifierEquals("PASSWORD")) { 475 lexer.nextToken(); 476 if (lexer.token() == Token.EQ) { 477 lexer.nextToken(); 478 } 479 stmt.getTableOptions().put("PASSWORD", this.exprParser.expr()); 480 continue; 481 } 482 483 if (lexer.identifierEquals("ROW_FORMAT")) { 484 lexer.nextToken(); 485 if (lexer.token() == Token.EQ) { 486 lexer.nextToken(); 487 } 488 stmt.getTableOptions().put("ROW_FORMAT", this.exprParser.expr()); 489 continue; 490 } 491 492 if (lexer.identifierEquals("STATS_AUTO_RECALC")) { 493 lexer.nextToken(); 494 if (lexer.token() == Token.EQ) { 495 lexer.nextToken(); 496 } 497 498 stmt.getTableOptions().put("STATS_AUTO_RECALC", this.exprParser.expr()); 499 continue; 500 } 501 502 if (lexer.identifierEquals("STATS_PERSISTENT")) { 503 lexer.nextToken(); 504 if (lexer.token() == Token.EQ) { 505 lexer.nextToken(); 506 } 507 508 stmt.getTableOptions().put("STATS_PERSISTENT", this.exprParser.expr()); 509 continue; 510 } 511 512 if (lexer.identifierEquals("STATS_SAMPLE_PAGES")) { 513 lexer.nextToken(); 514 if (lexer.token() == Token.EQ) { 515 lexer.nextToken(); 516 } 517 518 stmt.getTableOptions().put("STATS_SAMPLE_PAGES", this.exprParser.expr()); 519 continue; 520 } 521 522 if (lexer.token() == Token.UNION) { 523 lexer.nextToken(); 524 if (lexer.token() == Token.EQ) { 525 lexer.nextToken(); 526 } 527 528 accept(Token.LPAREN); 529 SQLTableSource tableSrc = this.createSQLSelectParser().parseTableSource(); 530 stmt.getTableOptions().put("UNION", tableSrc); 531 accept(Token.RPAREN); 532 continue; 533 } 534 535 if (lexer.token() == Token.TABLESPACE) { 536 lexer.nextToken(); 537 538 MySqlCreateTableStatement.TableSpaceOption option = new MySqlCreateTableStatement.TableSpaceOption(); 539 option.setName(this.exprParser.name()); 540 541 if (lexer.identifierEquals("STORAGE")) { 542 lexer.nextToken(); 543 option.setStorage(this.exprParser.name()); 544 } 545 546 stmt.getTableOptions().put("TABLESPACE", option); 547 continue; 548 } 549 550 if (lexer.identifierEquals("TABLEGROUP")) { 551 lexer.nextToken(); 552 553 SQLName tableGroup = this.exprParser.name(); 554 stmt.setTableGroup(tableGroup); 555 continue; 556 } 557 558 if (lexer.identifierEquals("TYPE")) { 559 lexer.nextToken(); 560 accept(Token.EQ); 561 stmt.getTableOptions().put("TYPE", this.exprParser.expr()); 562 continue; 563 } 564 565 if (lexer.identifierEquals("ENCRYPTION")) { 566 lexer.nextToken(); 567 if (lexer.token() == Token.EQ) { 568 lexer.nextToken(); 569 } 570 stmt.getTableOptions().put("ENCRYPTION", this.exprParser.expr()); 571 continue; 572 } 573 574 if (lexer.identifierEquals(FnvHash.Constants.COMPRESSION)) { 575 lexer.nextToken(); 576 if (lexer.token() == Token.EQ) { 577 lexer.nextToken(); 578 } 579 stmt.getTableOptions().put("COMPRESSION", this.exprParser.expr()); 580 continue; 581 } 582 583 if (lexer.token() == Token.PARTITION) { 584 SQLPartitionBy partitionClause = parsePartitionBy(); 585 stmt.setPartitioning(partitionClause); 586 587 continue; 588 } 589 590 if (lexer.identifierEquals(FnvHash.Constants.DBPARTITION)) { 591 SQLPartitionBy partitionClause = parsePartitionBy(); 592 stmt.setDbPartitionBy(partitionClause); 593 continue; 594 } 595 596 if (lexer.identifierEquals(FnvHash.Constants.TBPARTITION)) { 597 SQLPartitionBy partitionClause = parsePartitionBy(); 598 stmt.setTablePartitionBy(partitionClause); 599 continue; 600 } 601 602 if (lexer.identifierEquals(FnvHash.Constants.TBPARTITIONS)) { 603 lexer.nextToken(); 604 SQLExpr tbpartitions = this.exprParser.expr(); 605 stmt.setTbpartitions(tbpartitions); 606 continue; 607 } 608 609 break; 610 } 611 612 if (lexer.token() == (Token.ON)) { 613 throw new ParserException("TODO. " ~ lexer.info()); 614 } 615 616 if (lexer.token() == (Token.AS)) { 617 lexer.nextToken(); 618 } 619 620 if (lexer.token() == (Token.SELECT)) { 621 SQLSelect query = new MySqlSelectParser(this.exprParser).select(); 622 stmt.setSelect(query); 623 } 624 625 while (lexer.token() == (Token.HINT)) { 626 this.exprParser.parseHints!(SQLCommentHint)((stmt.getOptionHints())); 627 } 628 return stmt; 629 } 630 631 private SQLPartitionBy parsePartitionBy() { 632 lexer.nextToken(); 633 accept(Token.BY); 634 635 SQLPartitionBy partitionClause; 636 637 bool linera = false; 638 if (lexer.identifierEquals("LINEAR")) { 639 lexer.nextToken(); 640 linera = true; 641 } 642 643 if (lexer.token() == Token.KEY) { 644 MySqlPartitionByKey clause = new MySqlPartitionByKey(); 645 lexer.nextToken(); 646 647 if (linera) { 648 clause.setLinear(true); 649 } 650 651 if (lexer.identifierEquals(FnvHash.Constants.ALGORITHM)) { 652 lexer.nextToken(); 653 accept(Token.EQ); 654 clause.setAlgorithm(lexer.integerValue().shortValue()); 655 lexer.nextToken(); 656 } 657 658 accept(Token.LPAREN); 659 if (lexer.token() != Token.RPAREN) { 660 for (;;) { 661 clause.addColumn(this.exprParser.name()); 662 if (lexer.token() == Token.COMMA) { 663 lexer.nextToken(); 664 continue; 665 } 666 break; 667 } 668 } 669 accept(Token.RPAREN); 670 671 partitionClause = clause; 672 673 partitionClauseRest(clause); 674 } else if (lexer.identifierEquals("HASH") || lexer.identifierEquals("UNI_HASH")) { 675 SQLPartitionByHash clause = new SQLPartitionByHash(); 676 677 if (lexer.identifierEquals("UNI_HASH")) { 678 clause.setUnique(true); 679 } 680 681 lexer.nextToken(); 682 683 if (linera) { 684 clause.setLinear(true); 685 } 686 687 if (lexer.token() == Token.KEY) { 688 lexer.nextToken(); 689 clause.setKey(true); 690 } 691 692 accept(Token.LPAREN); 693 this.exprParser.exprList(clause.getColumns(), clause); 694 accept(Token.RPAREN); 695 partitionClause = clause; 696 697 partitionClauseRest(clause); 698 699 } else if (lexer.identifierEquals("RANGE")) { 700 SQLPartitionByRange clause = partitionByRange(); 701 partitionClause = clause; 702 703 partitionClauseRest(clause); 704 705 } else if (lexer.identifierEquals("LIST")) { 706 lexer.nextToken(); 707 SQLPartitionByList clause = new SQLPartitionByList(); 708 709 if (lexer.token() == Token.LPAREN) { 710 lexer.nextToken(); 711 clause.addColumn(this.exprParser.expr()); 712 accept(Token.RPAREN); 713 } else { 714 acceptIdentifier("COLUMNS"); 715 accept(Token.LPAREN); 716 for (;;) { 717 clause.addColumn(this.exprParser.name()); 718 if (lexer.token() == Token.COMMA) { 719 lexer.nextToken(); 720 continue; 721 } 722 break; 723 } 724 accept(Token.RPAREN); 725 } 726 partitionClause = clause; 727 728 partitionClauseRest(clause); 729 } else { 730 throw new ParserException("TODO. " ~ lexer.info()); 731 } 732 733 if (lexer.token() == Token.LPAREN) { 734 lexer.nextToken(); 735 for (;;) { 736 SQLPartition partitionDef = this.getExprParser().parsePartition(); 737 738 partitionClause.addPartition(partitionDef); 739 740 if (lexer.token() == Token.COMMA) { 741 lexer.nextToken(); 742 continue; 743 } else { 744 break; 745 } 746 } 747 accept(Token.RPAREN); 748 } 749 return partitionClause; 750 } 751 752 753 protected SQLPartitionByRange partitionByRange() { 754 acceptIdentifier("RANGE"); 755 756 SQLPartitionByRange clause = new SQLPartitionByRange(); 757 758 if (lexer.token() == Token.LPAREN) { 759 lexer.nextToken(); 760 clause.addColumn(this.exprParser.expr()); 761 accept(Token.RPAREN); 762 } else { 763 acceptIdentifier("COLUMNS"); 764 accept(Token.LPAREN); 765 for (;;) { 766 clause.addColumn(this.exprParser.name()); 767 if (lexer.token() == Token.COMMA) { 768 lexer.nextToken(); 769 continue; 770 } 771 break; 772 } 773 accept(Token.RPAREN); 774 } 775 return clause; 776 } 777 778 protected void partitionClauseRest(SQLPartitionBy clause) { 779 if (lexer.identifierEquals("PARTITIONS")) { 780 lexer.nextToken(); 781 782 SQLIntegerExpr countExpr = this.exprParser.integerExpr(); 783 clause.setPartitionsCount(countExpr); 784 } 785 786 if (lexer.token() == Token.PARTITION) { 787 lexer.nextToken(); 788 789 if (lexer.identifierEquals("NUM")) { 790 lexer.nextToken(); 791 } 792 793 clause.setPartitionsCount(this.exprParser.expr()); 794 795 clause.putAttribute("ads.partition", Boolean.TRUE); 796 } 797 798 if (lexer.identifierEquals("SUBPARTITION")) { 799 lexer.nextToken(); 800 accept(Token.BY); 801 802 SQLSubPartitionBy subPartitionByClause = null; 803 804 bool linear = false; 805 if (lexer.identifierEquals("LINEAR")) { 806 lexer.nextToken(); 807 linear = true; 808 } 809 810 if (lexer.token() == Token.KEY) { 811 MySqlSubPartitionByKey subPartitionKey = new MySqlSubPartitionByKey(); 812 lexer.nextToken(); 813 814 if (linear) { 815 clause.setLinear(true); 816 } 817 818 if (lexer.identifierEquals(FnvHash.Constants.ALGORITHM)) { 819 lexer.nextToken(); 820 accept(Token.EQ); 821 subPartitionKey.setAlgorithm(lexer.integerValue().shortValue()); 822 lexer.nextToken(); 823 } 824 825 accept(Token.LPAREN); 826 for (;;) { 827 subPartitionKey.addColumn(this.exprParser.name()); 828 if (lexer.token() == Token.COMMA) { 829 lexer.nextToken(); 830 continue; 831 } 832 break; 833 } 834 accept(Token.RPAREN); 835 836 subPartitionByClause = subPartitionKey; 837 838 } else if (lexer.identifierEquals("HASH")) { 839 lexer.nextToken(); 840 SQLSubPartitionByHash subPartitionHash = new SQLSubPartitionByHash(); 841 842 if (linear) { 843 clause.setLinear(true); 844 } 845 846 if (lexer.token() == Token.KEY) { 847 lexer.nextToken(); 848 subPartitionHash.setKey(true); 849 } 850 851 accept(Token.LPAREN); 852 subPartitionHash.setExpr(this.exprParser.expr()); 853 accept(Token.RPAREN); 854 subPartitionByClause = subPartitionHash; 855 856 } else if (lexer.identifierEquals("LIST")) { 857 lexer.nextToken(); 858 MySqlSubPartitionByList subPartitionList = new MySqlSubPartitionByList(); 859 860 if (lexer.token() == Token.LPAREN) { 861 lexer.nextToken(); 862 SQLExpr expr = this.exprParser.expr(); 863 864 if (cast(SQLIdentifierExpr)(expr) !is null && (lexer.identifierEquals("bigint") || lexer.identifierEquals("long"))) { 865 string dataType = lexer.stringVal(); 866 lexer.nextToken(); 867 868 SQLColumnDefinition column = this.exprParser.createColumnDefinition(); 869 column.setName(cast(SQLIdentifierExpr) expr); 870 column.setDataType(new SQLDataTypeImpl(dataType)); 871 subPartitionList.addColumn(column); 872 873 subPartitionList.putAttribute("ads.subPartitionList", Boolean.TRUE); 874 } else { 875 subPartitionList.setExpr(expr); 876 } 877 accept(Token.RPAREN); 878 } else { 879 acceptIdentifier("COLUMNS"); 880 accept(Token.LPAREN); 881 for (;;) { 882 subPartitionList.addColumn(this.exprParser.parseColumn()); 883 if (lexer.token() == Token.COMMA) { 884 lexer.nextToken(); 885 continue; 886 } 887 break; 888 } 889 accept(Token.RPAREN); 890 } 891 subPartitionByClause = subPartitionList; 892 } 893 894 if (lexer.identifierEquals("SUBPARTITION")) { 895 lexer.nextToken(); 896 acceptIdentifier("OPTIONS"); 897 accept(Token.LPAREN); 898 899 SQLAssignItem option = this.exprParser.parseAssignItem(); 900 accept(Token.RPAREN); 901 902 option.setParent(subPartitionByClause); 903 904 subPartitionByClause.getOptions().add(option); 905 } 906 907 if (lexer.identifierEquals("SUBPARTITIONS")) { 908 lexer.nextToken(); 909 Number intValue = lexer.integerValue(); 910 SQLNumberExpr numExpr = new SQLNumberExpr(intValue); 911 subPartitionByClause.setSubPartitionsCount(numExpr); 912 lexer.nextToken(); 913 } 914 915 if (subPartitionByClause !is null) { 916 subPartitionByClause.setLinear(linear); 917 918 clause.setSubPartitionBy(subPartitionByClause); 919 } 920 } 921 } 922 923 private bool parseTableOptionCharsetOrCollate(MySqlCreateTableStatement stmt) { 924 if (lexer.identifierEquals("CHARACTER")) { 925 lexer.nextToken(); 926 accept(Token.SET); 927 if (lexer.token() == Token.EQ) { 928 lexer.nextToken(); 929 } 930 stmt.getTableOptions().put("CHARACTER SET", this.exprParser.expr()); 931 return true; 932 } 933 934 if (lexer.identifierEquals("CHARSET")) { 935 lexer.nextToken(); 936 if (lexer.token() == Token.EQ) { 937 lexer.nextToken(); 938 } 939 stmt.getTableOptions().put("CHARSET", this.exprParser.expr()); 940 return true; 941 } 942 943 if (lexer.identifierEquals("COLLATE")) { 944 lexer.nextToken(); 945 if (lexer.token() == Token.EQ) { 946 lexer.nextToken(); 947 } 948 stmt.getTableOptions().put("COLLATE", this.exprParser.expr()); 949 return true; 950 } 951 952 return false; 953 } 954 955 override protected SQLTableConstraint parseConstraint() { 956 SQLName name = null; 957 bool hasConstaint = false; 958 if (lexer.token() == (Token.CONSTRAINT)) { 959 hasConstaint = true; 960 lexer.nextToken(); 961 } 962 963 if (lexer.token() == Token.IDENTIFIER) { 964 name = this.exprParser.name(); 965 } 966 967 SQLTableConstraint constraint = null; 968 969 if (lexer.token() == (Token.KEY)) { 970 lexer.nextToken(); 971 972 MySqlKey key = new MySqlKey(); 973 key.setHasConstaint(hasConstaint); 974 975 // if (identifierEquals("USING")) { 976 // lexer.nextToken(); 977 // key.setIndexType(lexer.stringVal()); 978 // lexer.nextToken(); 979 // } 980 981 if (lexer.token() == Token.IDENTIFIER || lexer.token() == Token.LITERAL_ALIAS) { 982 SQLName indexName = this.exprParser.name(); 983 if (indexName !is null) { 984 key.setName(indexName); 985 } 986 } 987 988 // 5.5语法 USING BTREE 放在index 名字后 989 if (lexer.identifierEquals(FnvHash.Constants.USING)) { 990 lexer.nextToken(); 991 key.setIndexType(lexer.stringVal()); 992 lexer.nextToken(); 993 } 994 995 accept(Token.LPAREN); 996 for (;;) { 997 SQLExpr expr; 998 if (lexer.token() == Token.LITERAL_ALIAS) { 999 expr = this.exprParser.name(); 1000 expr = this.exprParser.primaryRest(expr); 1001 } else { 1002 expr = this.exprParser.expr(); 1003 } 1004 if (lexer.token() == Token.ASC) { 1005 lexer.nextToken(); 1006 expr = new MySqlOrderingExpr(expr, SQLOrderingSpecification.ASC); 1007 } else if (lexer.token() == Token.DESC) { 1008 lexer.nextToken(); 1009 expr = new MySqlOrderingExpr(expr, SQLOrderingSpecification.DESC); 1010 } 1011 1012 key.addColumn(expr); 1013 if (!(lexer.token() == (Token.COMMA))) { 1014 break; 1015 } else { 1016 lexer.nextToken(); 1017 } 1018 } 1019 accept(Token.RPAREN); 1020 1021 if (name !is null) { 1022 key.setName(name); 1023 } 1024 1025 if (lexer.identifierEquals(FnvHash.Constants.USING)) { 1026 lexer.nextToken(); 1027 key.setIndexType(lexer.stringVal()); 1028 lexer.nextToken(); 1029 } 1030 1031 constraint = key; 1032 } else if (lexer.token() == Token.PRIMARY) { 1033 MySqlPrimaryKey pk = this.getExprParser().parsePrimaryKey(); 1034 if (name !is null) { 1035 pk.setName(name); 1036 } 1037 pk.setHasConstaint(hasConstaint); 1038 constraint = pk; 1039 } else if (lexer.token() == Token.UNIQUE) { 1040 MySqlUnique uk = this.getExprParser().parseUnique(); 1041 if (name !is null) { 1042 uk.setName(name); 1043 } 1044 uk.setHasConstaint(hasConstaint); 1045 1046 constraint = uk; 1047 } else if (lexer.token() == Token.FOREIGN) { 1048 MysqlForeignKey fk = this.getExprParser().parseForeignKey(); 1049 fk.setName(name); 1050 fk.setHasConstraint(hasConstaint); 1051 constraint = fk; 1052 } else if (lexer.token() == Token.CHECK) { 1053 lexer.nextToken(); 1054 SQLCheck check = new SQLCheck(); 1055 check.setName(name); 1056 SQLExpr expr = this.exprParser.expr(); 1057 check.setExpr(expr); 1058 constraint = check; 1059 } 1060 1061 if (constraint !is null) { 1062 if (lexer.token() == Token.COMMENT) { 1063 lexer.nextToken(); 1064 SQLExpr comment = this.exprParser.primary(); 1065 constraint.setComment(comment); 1066 } 1067 1068 return constraint; 1069 } 1070 1071 throw new ParserException("TODO. " ~ lexer.info()); 1072 } 1073 }