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.MySqlExprParser; 17 18 import hunt.sql.ast; 19 import hunt.sql.ast.expr.SQLAggregateExpr; 20 import hunt.sql.ast.expr.SQLBinaryOpExpr; 21 import hunt.sql.ast.expr.SQLBinaryOperator; 22 import hunt.sql.ast.expr.SQLCharExpr; 23 import hunt.sql.ast.expr.SQLHexExpr; 24 import hunt.sql.ast.expr.SQLIdentifierExpr; 25 import hunt.sql.ast.expr.SQLMethodInvokeExpr; 26 import hunt.sql.ast.expr.SQLUnaryExpr; 27 import hunt.sql.ast.expr.SQLUnaryOperator; 28 import hunt.sql.ast.expr.SQLVariantRefExpr; 29 import hunt.sql.ast.statement.SQLAssignItem; 30 import hunt.sql.ast.statement.SQLColumnDefinition; 31 import hunt.sql.ast.statement.SQLForeignKeyImpl; 32 import hunt.sql.dialect.mysql.ast.MySqlPrimaryKey; 33 import hunt.sql.dialect.mysql.ast.MySqlUnique; 34 import hunt.sql.dialect.mysql.ast.MysqlForeignKey; 35 import hunt.sql.ast.statement.SQLForeignKeyImpl; 36 import hunt.sql.dialect.mysql.ast.expr.MySqlCharExpr; 37 import hunt.sql.dialect.mysql.ast.expr.MySqlExtractExpr; 38 import hunt.sql.ast.expr.SQLIntervalExpr; 39 import hunt.sql.ast.expr.SQLIntervalUnit; 40 import hunt.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; 41 // import hunt.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr.SearchModifier; 42 import hunt.sql.dialect.mysql.ast.expr.MySqlOrderingExpr; 43 import hunt.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; 44 import hunt.sql.dialect.mysql.ast.expr.MySqlUserName; 45 import hunt.sql.parser; 46 import hunt.sql.util.FnvHash; 47 import hunt.sql.util.DBType; 48 import hunt.sql.dialect.mysql.parser.MySqlLexer; 49 import hunt.String; 50 import std.string; 51 import hunt.sql.util.Utils; 52 import hunt.String; 53 import hunt.sql.dialect.mysql.parser.MySqlSelectParser; 54 import hunt.text; 55 56 import std.concurrency : initOnce; 57 58 public class MySqlExprParser : SQLExprParser { 59 60 private enum string[] strings = ["AVG", "COUNT", "GROUP_CONCAT", "MAX", "MIN", "STDDEV", "SUM"]; 61 62 static string[] AGGREGATE_FUNCTIONS() { 63 __gshared string[] inst; 64 return initOnce!inst({ 65 long[] codes = AGGREGATE_FUNCTIONS_CODES(); 66 string[] r = new string[codes.length]; 67 68 foreach(string str ; strings) { 69 long hash = FnvHash.fnv1a_64_lower(str); 70 int index = search(codes, hash); 71 r[index] = str; 72 } 73 return r; 74 }()); 75 } 76 77 static long[] AGGREGATE_FUNCTIONS_CODES() { 78 __gshared long[] inst; 79 return initOnce!inst({ 80 return FnvHash.fnv1a_64_lower(strings, true); 81 }()); 82 } 83 84 // public static string[] AGGREGATE_FUNCTIONS; 85 86 // public static long[] AGGREGATE_FUNCTIONS_CODES; 87 88 // static this() { 89 // string[] strings = [ "AVG", "COUNT", "GROUP_CONCAT", "MAX", "MIN", "STDDEV", "SUM" ]; 90 // AGGREGATE_FUNCTIONS_CODES = FnvHash.fnv1a_64_lower(strings, true); 91 // AGGREGATE_FUNCTIONS = new string[AGGREGATE_FUNCTIONS_CODES.length]; 92 // foreach(string str ; strings) { 93 // long hash = FnvHash.fnv1a_64_lower(str); 94 // int index = search(AGGREGATE_FUNCTIONS_CODES, hash); 95 // AGGREGATE_FUNCTIONS[index] = str; 96 // } 97 // } 98 99 public this(Lexer lexer){ 100 super(lexer, DBType.MYSQL.name); 101 this.aggregateFunctions = AGGREGATE_FUNCTIONS; 102 this.aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES; 103 } 104 105 public this(string sql){ 106 this(new MySqlLexer(sql)); 107 this.lexer.nextToken(); 108 import std.stdio; 109 } 110 111 public this(string sql, SQLParserFeature[] features...){ 112 super(new MySqlLexer(sql, features), DBType.MYSQL.name); 113 this.aggregateFunctions = AGGREGATE_FUNCTIONS; 114 this.aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES; 115 if (sql.length > 6) { 116 char c0 = charAt(sql, 0); 117 char c1 = charAt(sql, 1); 118 char c2 = charAt(sql, 2); 119 char c3 = charAt(sql, 3); 120 char c4 = charAt(sql, 4); 121 char c5 = charAt(sql, 5); 122 char c6 = charAt(sql, 6); 123 124 if (c0 == 'S' && c1 == 'E' && c2 == 'L' && c3 == 'E' && c4 == 'C' && c5 == 'T' && c6 == ' ') { 125 lexer.reset(6, ' ', Token.SELECT); 126 return; 127 } 128 129 if (c0 == 's' && c1 == 'e' && c2 == 'l' && c3 == 'e' && c4 == 'c' && c5 == 't' && c6 == ' ') { 130 lexer.reset(6, ' ', Token.SELECT); 131 return; 132 } 133 134 if (c0 == 'I' && c1 == 'N' && c2 == 'S' && c3 == 'E' && c4 == 'R' && c5 == 'T' && c6 == ' ') { 135 lexer.reset(6, ' ', Token.INSERT); 136 return; 137 } 138 139 if (c0 == 'i' && c1 == 'n' && c2 == 's' && c3 == 'e' && c4 == 'r' && c5 == 't' && c6 == ' ') { 140 lexer.reset(6, ' ', Token.INSERT); 141 return; 142 } 143 144 if (c0 == 'U' && c1 == 'P' && c2 == 'D' && c3 == 'A' && c4 == 'T' && c5 == 'E' && c6 == ' ') { 145 lexer.reset(6, ' ', Token.UPDATE); 146 return; 147 } 148 149 if (c0 == 'u' && c1 == 'p' && c2 == 'd' && c3 == 'a' && c4 == 't' && c5 == 'e' && c6 == ' ') { 150 lexer.reset(6, ' ', Token.UPDATE); 151 return; 152 } 153 154 if (c0 == '/' && c1 == '*' && isEnabled(SQLParserFeature.OptimizedForParameterized)) { 155 MySqlLexer mySqlLexer = cast(MySqlLexer) lexer; 156 mySqlLexer.skipFirstHintsOrMultiCommentAndNextToken(); 157 return; 158 } 159 } 160 this.lexer.nextToken(); 161 162 } 163 164 public this(string sql, bool keepComments){ 165 this(new MySqlLexer(sql, true, keepComments)); 166 this.lexer.nextToken(); 167 } 168 169 170 public this(string sql, bool skipComment,bool keepComments){ 171 this(new MySqlLexer(sql, skipComment, keepComments)); 172 this.lexer.nextToken(); 173 } 174 175 override public SQLExpr primary() { 176 Token tok = lexer.token(); 177 178 if (lexer.identifierEquals(FnvHash.Constants.OUTFILE)) { 179 lexer.nextToken(); 180 SQLExpr file = primary(); 181 SQLExpr expr = new MySqlOutFileExpr(file); 182 183 return primaryRest(expr); 184 185 } 186 187 switch (tok) { 188 case Token.VARIANT: 189 SQLVariantRefExpr varRefExpr = new SQLVariantRefExpr(lexer.stringVal()); 190 lexer.nextToken(); 191 if (varRefExpr.getName().equalsIgnoreCase("@@global")) { 192 accept(Token.DOT); 193 varRefExpr = new SQLVariantRefExpr(lexer.stringVal(), true); 194 lexer.nextToken(); 195 } else if (varRefExpr.getName() == "@" && lexer.token() == Token.LITERAL_CHARS) { 196 varRefExpr.setName("@'" ~ lexer.stringVal() ~ "'"); 197 lexer.nextToken(); 198 } else if (varRefExpr.getName() == "@@" && lexer.token() == Token.LITERAL_CHARS) { 199 varRefExpr.setName("@@'" ~ lexer.stringVal() ~ "'"); 200 lexer.nextToken(); 201 } 202 return primaryRest(varRefExpr); 203 case Token.VALUES: 204 lexer.nextToken(); 205 if (lexer.token() != Token.LPAREN) { 206 throw new ParserException("syntax error, illegal values clause. " ~ lexer.info()); 207 } 208 return this.methodRest(new SQLIdentifierExpr("VALUES"), true); 209 case Token.BINARY: 210 lexer.nextToken(); 211 if (lexer.token() == Token.COMMA || lexer.token() == Token.SEMI || lexer.token() == Token.EOF) { 212 return new SQLIdentifierExpr("BINARY"); 213 } else { 214 SQLUnaryExpr binaryExpr = new SQLUnaryExpr(SQLUnaryOperator.BINARY, expr()); 215 return primaryRest(binaryExpr); 216 } 217 default: 218 return super.primary(); 219 } 220 221 } 222 223 override public SQLExpr primaryRest(SQLExpr expr) { 224 if (expr is null) { 225 throw new Exception("expr"); 226 } 227 228 if (lexer.token() == Token.LITERAL_CHARS) { 229 if (cast(SQLIdentifierExpr)(expr) !is null) { 230 SQLIdentifierExpr identExpr = cast(SQLIdentifierExpr) expr; 231 string ident = identExpr.getName(); 232 233 if (equalsIgnoreCase(ident, "x")) { 234 string charValue = lexer.stringVal(); 235 lexer.nextToken(); 236 expr = new SQLHexExpr(charValue); 237 238 return primaryRest(expr); 239 // } else if (equalsIgnoreCase(ident, "b")) { 240 // string charValue = lexer.stringVal(); 241 // lexer.nextToken(); 242 // expr = new SQLBinaryExpr(charValue); 243 // 244 // return primaryRest(expr); 245 } else if (ident.startsWith("_")) { 246 string charValue = lexer.stringVal(); 247 lexer.nextToken(); 248 249 MySqlCharExpr mysqlCharExpr = new MySqlCharExpr(charValue); 250 mysqlCharExpr.setCharset(identExpr.getName()); 251 if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) { 252 lexer.nextToken(); 253 254 string collate = lexer.stringVal(); 255 mysqlCharExpr.setCollate(collate); 256 accept(Token.IDENTIFIER); 257 } 258 259 expr = mysqlCharExpr; 260 261 return primaryRest(expr); 262 } 263 } else if (cast(SQLCharExpr)(expr) !is null) { 264 string text2 = (cast(SQLCharExpr) expr).getText.value(); 265 do { 266 string chars = lexer.stringVal(); 267 text2 ~= chars; 268 lexer.nextToken(); 269 } while (lexer.token() == Token.LITERAL_CHARS || lexer.token() == Token.LITERAL_ALIAS); 270 expr = new SQLCharExpr(text2); 271 } else if (cast(SQLVariantRefExpr)(expr) !is null) { 272 SQLMethodInvokeExpr concat = new SQLMethodInvokeExpr("CONCAT"); 273 concat.addArgument(expr); 274 concat.addArgument(this.primary()); 275 expr = concat; 276 277 return primaryRest(expr); 278 } 279 } else if (lexer.token() == Token.IDENTIFIER) { 280 if (cast(SQLHexExpr)(expr) !is null) { 281 if ("USING".equalsIgnoreCase(lexer.stringVal())) { 282 lexer.nextToken(); 283 if (lexer.token() != Token.IDENTIFIER) { 284 throw new ParserException("syntax error, illegal hex. " ~ lexer.info()); 285 } 286 string charSet = lexer.stringVal(); 287 lexer.nextToken(); 288 expr.getAttributes().put("USING", new String(charSet)); 289 290 return primaryRest(expr); 291 } 292 } else if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) { 293 lexer.nextToken(); 294 295 if (lexer.token() == Token.EQ) { 296 lexer.nextToken(); 297 } 298 299 if (lexer.token() != Token.IDENTIFIER 300 && lexer.token() != Token.LITERAL_CHARS) { 301 throw new ParserException("syntax error. " ~ lexer.info()); 302 } 303 304 string collate = lexer.stringVal(); 305 lexer.nextToken(); 306 307 SQLBinaryOpExpr binaryExpr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.COLLATE, 308 new SQLIdentifierExpr(collate), DBType.MYSQL.name); 309 310 expr = binaryExpr; 311 312 return primaryRest(expr); 313 } else if (cast(SQLVariantRefExpr)(expr) !is null) { 314 if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) { 315 lexer.nextToken(); 316 317 if (lexer.token() != Token.IDENTIFIER 318 && lexer.token() != Token.LITERAL_CHARS) { 319 throw new ParserException("syntax error. " ~ lexer.info()); 320 } 321 322 string collate = lexer.stringVal(); 323 lexer.nextToken(); 324 325 expr.putAttribute("COLLATE", new String(collate)); 326 327 return primaryRest(expr); 328 } 329 } 330 } 331 332 // if (lexer.token() == Token.LPAREN && cast(SQLIdentifierExpr)(expr) !is null) { 333 // SQLIdentifierExpr identExpr = cast(SQLIdentifierExpr) expr; 334 // string ident = identExpr.getName(); 335 // 336 // if ("POSITION".equalsIgnoreCase(ident)) { 337 // return parsePosition(); 338 // } 339 // } 340 341 if (lexer.token() == Token.VARIANT && "@" == lexer.stringVal()) { 342 return userNameRest(expr); 343 } 344 345 if (lexer.token() == Token.ERROR) { 346 throw new ParserException("syntax error. " ~ lexer.info()); 347 } 348 349 return super.primaryRest(expr); 350 } 351 352 public SQLName userName() { 353 SQLName name = this.name(); 354 if (lexer.token() == Token.LPAREN && name.hashCode64() == FnvHash.Constants.CURRENT_USER) { 355 lexer.nextToken(); 356 accept(Token.RPAREN); 357 return name; 358 } 359 360 return cast(SQLName) userNameRest(name); 361 } 362 363 private SQLExpr userNameRest(SQLExpr expr) { 364 if (lexer.token() != Token.VARIANT || !lexer.stringVal().startsWith("@")) { 365 return expr; 366 } 367 368 MySqlUserName userName = new MySqlUserName(); 369 if (cast(SQLCharExpr)(expr) !is null) { 370 userName.setUserName((cast(SQLCharExpr) expr).toString()); 371 } else { 372 userName.setUserName((cast(SQLIdentifierExpr) expr).getName()); 373 } 374 375 376 string strVal = lexer.stringVal(); 377 lexer.nextToken(); 378 379 if (strVal.length > 1) { 380 userName.setHost(strVal.substring(1)); 381 return userName; 382 } 383 384 if (lexer.token() == Token.LITERAL_CHARS) { 385 userName.setHost("'" ~ lexer.stringVal() ~ "'"); 386 } else { 387 userName.setHost(lexer.stringVal()); 388 } 389 lexer.nextToken(); 390 391 if (lexer.token() == Token.IDENTIFIED) { 392 Lexer.SavePoint mark = lexer.mark(); 393 394 lexer.nextToken(); 395 if (lexer.token() == Token.BY) { 396 lexer.nextToken(); 397 if (lexer.identifierEquals(FnvHash.Constants.PASSWORD)) { 398 lexer.reset(mark); 399 } else { 400 userName.setIdentifiedBy(lexer.stringVal()); 401 lexer.nextToken(); 402 } 403 } else { 404 lexer.reset(mark); 405 } 406 } 407 408 return userName; 409 } 410 411 override protected SQLExpr parsePosition() { 412 413 SQLExpr subStr = this.primary(); 414 accept(Token.IN); 415 SQLExpr str = this.expr(); 416 accept(Token.RPAREN); 417 418 SQLMethodInvokeExpr locate = new SQLMethodInvokeExpr("LOCATE"); 419 locate.addParameter(subStr); 420 locate.addParameter(str); 421 422 return primaryRest(locate); 423 } 424 425 override protected SQLExpr parseExtract() { 426 SQLExpr _expr; 427 if (lexer.token() != Token.IDENTIFIER) { 428 throw new ParserException("syntax error. " ~ lexer.info()); 429 } 430 431 string unitVal = lexer.stringVal(); 432 SQLIntervalUnit unit = SQLIntervalUnit(toUpper(unitVal)); 433 lexer.nextToken(); 434 435 accept(Token.FROM); 436 437 SQLExpr value = expr(); 438 439 MySqlExtractExpr extract = new MySqlExtractExpr(); 440 extract.setValue(value); 441 extract.setUnit(unit); 442 accept(Token.RPAREN); 443 444 _expr = extract; 445 446 return primaryRest(_expr); 447 } 448 449 override protected SQLExpr parseMatch() { 450 451 MySqlMatchAgainstExpr matchAgainstExpr = new MySqlMatchAgainstExpr(); 452 453 if (lexer.token() == Token.RPAREN) { 454 lexer.nextToken(); 455 } else { 456 exprList(matchAgainstExpr.getColumns(), matchAgainstExpr); 457 accept(Token.RPAREN); 458 } 459 460 acceptIdentifier("AGAINST"); 461 462 accept(Token.LPAREN); 463 SQLExpr against = primary(); 464 matchAgainstExpr.setAgainst(against); 465 466 if (lexer.token() == Token.IN) { 467 lexer.nextToken(); 468 if (lexer.identifierEquals(FnvHash.Constants.NATURAL)) { 469 lexer.nextToken(); 470 acceptIdentifier("LANGUAGE"); 471 acceptIdentifier("MODE"); 472 if (lexer.token() == Token.WITH) { 473 lexer.nextToken(); 474 acceptIdentifier("QUERY"); 475 acceptIdentifier("EXPANSION"); 476 matchAgainstExpr.setSearchModifier(MySqlMatchAgainstExpr.SearchModifier.IN_NATURAL_LANGUAGE_MODE_WITH_QUERY_EXPANSION); 477 } else { 478 matchAgainstExpr.setSearchModifier(MySqlMatchAgainstExpr.SearchModifier.IN_NATURAL_LANGUAGE_MODE); 479 } 480 } else if (lexer.identifierEquals(FnvHash.Constants.BOOLEAN)) { 481 lexer.nextToken(); 482 acceptIdentifier("MODE"); 483 matchAgainstExpr.setSearchModifier(MySqlMatchAgainstExpr.SearchModifier.IN_BOOLEAN_MODE); 484 } else { 485 throw new ParserException("syntax error. " ~ lexer.info()); 486 } 487 } else if (lexer.token() == Token.WITH) { 488 throw new ParserException("TODO. " ~ lexer.info()); 489 } 490 491 accept(Token.RPAREN); 492 493 return primaryRest(matchAgainstExpr); 494 } 495 496 override public SQLSelectParser createSelectParser() { 497 return new MySqlSelectParser(this); 498 } 499 500 override protected SQLExpr parseInterval() { 501 accept(Token.INTERVAL); 502 503 if (lexer.token() == Token.LPAREN) { 504 lexer.nextToken(); 505 506 SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr("INTERVAL"); 507 if (lexer.token() != Token.RPAREN) { 508 exprList(methodInvokeExpr.getParameters(), methodInvokeExpr); 509 } 510 511 accept(Token.RPAREN); 512 513 // 514 515 if (methodInvokeExpr.getParameters().size() == 1 // 516 && lexer.token() == Token.IDENTIFIER) { 517 SQLExpr value = methodInvokeExpr.getParameters().get(0); 518 string unit = lexer.stringVal(); 519 lexer.nextToken(); 520 521 SQLIntervalExpr intervalExpr = new SQLIntervalExpr(); 522 intervalExpr.setValue(value); 523 intervalExpr.setUnit(SQLIntervalUnit(toUpper(unit))); 524 return intervalExpr; 525 } else { 526 return primaryRest(methodInvokeExpr); 527 } 528 } else { 529 SQLExpr value = expr(); 530 531 if (lexer.token() != Token.IDENTIFIER) { 532 throw new ParserException("Syntax error. " ~ lexer.info()); 533 } 534 535 string unit = lexer.stringVal(); 536 lexer.nextToken(); 537 538 SQLIntervalExpr intervalExpr = new SQLIntervalExpr(); 539 intervalExpr.setValue(value); 540 intervalExpr.setUnit(SQLIntervalUnit(toUpper(unit))); 541 542 return intervalExpr; 543 } 544 } 545 546 override public SQLColumnDefinition parseColumn() { 547 SQLColumnDefinition column = new SQLColumnDefinition(); 548 column.setDbType(dbType); 549 column.setName(name()); 550 column.setDataType(parseDataType()); 551 552 return parseColumnRest(column); 553 } 554 555 override public SQLColumnDefinition parseColumnRest(SQLColumnDefinition column) { 556 if (lexer.token() == Token.ON) { 557 lexer.nextToken(); 558 accept(Token.UPDATE); 559 SQLExpr expr = this.expr(); 560 column.setOnUpdate(expr); 561 } 562 563 if (lexer.identifierEquals(FnvHash.Constants.CHARACTER)) { 564 lexer.nextToken(); 565 accept(Token.SET); 566 MySqlCharExpr charSetCollateExpr=new MySqlCharExpr(); 567 charSetCollateExpr.setCharset(lexer.stringVal()); 568 lexer.nextToken(); 569 if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) { 570 lexer.nextToken(); 571 charSetCollateExpr.setCollate(lexer.stringVal()); 572 lexer.nextToken(); 573 } 574 column.setCharsetExpr(charSetCollateExpr); 575 return parseColumnRest(column); 576 } 577 578 if (lexer.identifierEquals(FnvHash.Constants.CHARSET)) { 579 lexer.nextToken(); 580 MySqlCharExpr charSetCollateExpr=new MySqlCharExpr(); 581 charSetCollateExpr.setCharset(lexer.stringVal()); 582 lexer.nextToken(); 583 if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) { 584 lexer.nextToken(); 585 charSetCollateExpr.setCollate(lexer.stringVal()); 586 lexer.nextToken(); 587 } 588 column.setCharsetExpr(charSetCollateExpr); 589 return parseColumnRest(column); 590 } 591 if (lexer.identifierEquals(FnvHash.Constants.AUTO_INCREMENT)) { 592 lexer.nextToken(); 593 column.setAutoIncrement(true); 594 return parseColumnRest(column); 595 } 596 597 if (lexer.identifierEquals(FnvHash.Constants.PRECISION) 598 && column.getDataType().nameHashCode64() ==FnvHash.Constants.DOUBLE) { 599 lexer.nextToken(); 600 } 601 602 if (lexer.token() == Token.PARTITION) { 603 throw new ParserException("syntax error " ~ lexer.info()); 604 } 605 606 if (lexer.identifierEquals(FnvHash.Constants.STORAGE)) { 607 lexer.nextToken(); 608 SQLExpr expr = expr(); 609 column.setStorage(expr); 610 } 611 612 if (lexer.token() == Token.AS) { 613 lexer.nextToken(); 614 accept(Token.LPAREN); 615 SQLExpr expr = expr(); 616 column.setAsExpr(expr); 617 accept(Token.RPAREN); 618 } 619 620 if (lexer.identifierEquals(FnvHash.Constants.STORED)) { 621 lexer.nextToken(); 622 column.setSorted(true); 623 } 624 625 if (lexer.identifierEquals(FnvHash.Constants.VIRTUAL)) { 626 lexer.nextToken(); 627 column.setVirtual(true); 628 } 629 630 super.parseColumnRest(column); 631 632 return column; 633 } 634 635 override protected SQLDataType parseDataTypeRest(SQLDataType dataType) { 636 super.parseDataTypeRest(dataType); 637 638 for (;;) { 639 if (lexer.identifierEquals(FnvHash.Constants.UNSIGNED)) { 640 lexer.nextToken(); 641 (cast(SQLDataTypeImpl) dataType).setUnsigned(true); 642 } else if (lexer.identifierEquals(FnvHash.Constants.ZEROFILL)) { 643 lexer.nextToken(); 644 (cast(SQLDataTypeImpl) dataType).setZerofill(true); 645 } else { 646 break; 647 } 648 } 649 650 return dataType; 651 } 652 653 override public SQLAssignItem parseAssignItem() { 654 SQLAssignItem item = new SQLAssignItem(); 655 656 SQLExpr var = primary(); 657 658 string ident = null; 659 long identHash = 0; 660 if (cast(SQLIdentifierExpr)(var) !is null) { 661 SQLIdentifierExpr identExpr = cast(SQLIdentifierExpr) var; 662 ident = identExpr.getName(); 663 identHash = identExpr.hashCode64(); 664 665 if (identHash == FnvHash.Constants.GLOBAL) { 666 ident = lexer.stringVal(); 667 lexer.nextToken(); 668 var = new SQLVariantRefExpr(ident, true); 669 } else if (identHash == FnvHash.Constants.SESSION) { 670 ident = lexer.stringVal(); 671 lexer.nextToken(); 672 var = new SQLVariantRefExpr(ident, false, true); 673 } else { 674 var = new SQLVariantRefExpr(ident); 675 } 676 } 677 678 if (identHash == FnvHash.Constants.NAMES) { 679 string charset = lexer.stringVal(); 680 681 SQLExpr varExpr = null; 682 bool chars = false; 683 Token token = lexer.token(); 684 if (token == Token.IDENTIFIER) { 685 lexer.nextToken(); 686 } else if (token == Token.DEFAULT) { 687 charset = "DEFAULT"; 688 lexer.nextToken(); 689 } else if (token == Token.QUES) { 690 varExpr = new SQLVariantRefExpr("?"); 691 lexer.nextToken(); 692 } else { 693 chars = true; 694 accept(Token.LITERAL_CHARS); 695 } 696 697 if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) { 698 MySqlCharExpr charsetExpr = new MySqlCharExpr(charset); 699 lexer.nextToken(); 700 701 string collate = lexer.stringVal(); 702 lexer.nextToken(); 703 charsetExpr.setCollate(collate); 704 705 item.setValue(charsetExpr); 706 } else { 707 if (varExpr !is null) { 708 item.setValue(varExpr); 709 } else { 710 item.setValue(chars 711 ? new SQLCharExpr(charset) 712 : new SQLIdentifierExpr(charset) 713 ); 714 } 715 } 716 717 item.setTarget(var); 718 return item; 719 } else if (identHash == FnvHash.Constants.CHARACTER) { 720 var = new SQLIdentifierExpr("CHARACTER SET"); 721 accept(Token.SET); 722 if (lexer.token() == Token.EQ) { 723 lexer.nextToken(); 724 } 725 } else { 726 if (lexer.token() == Token.COLONEQ) { 727 lexer.nextToken(); 728 } else { 729 accept(Token.EQ); 730 } 731 } 732 733 if (lexer.token() == Token.ON) { 734 lexer.nextToken(); 735 item.setValue(new SQLIdentifierExpr("ON")); 736 } else { 737 item.setValue(this.expr()); 738 } 739 740 item.setTarget(var); 741 return item; 742 } 743 744 override public SQLName nameRest(SQLName name) { 745 if (lexer.token() == Token.VARIANT && "@" == lexer.stringVal()) { 746 lexer.nextToken(); 747 MySqlUserName userName = new MySqlUserName(); 748 userName.setUserName((cast(SQLIdentifierExpr) name).getName()); 749 750 if (lexer.token() == Token.LITERAL_CHARS) { 751 userName.setHost("'" ~ lexer.stringVal() ~ "'"); 752 } else { 753 userName.setHost(lexer.stringVal()); 754 } 755 lexer.nextToken(); 756 757 if (lexer.token() == Token.IDENTIFIED) { 758 lexer.nextToken(); 759 accept(Token.BY); 760 userName.setIdentifiedBy(lexer.stringVal()); 761 lexer.nextToken(); 762 } 763 764 return userName; 765 } 766 return super.nameRest(name); 767 } 768 769 override 770 public MySqlPrimaryKey parsePrimaryKey() { 771 accept(Token.PRIMARY); 772 accept(Token.KEY); 773 774 MySqlPrimaryKey primaryKey = new MySqlPrimaryKey(); 775 776 if (lexer.identifierEquals(FnvHash.Constants.USING)) { 777 lexer.nextToken(); 778 primaryKey.setIndexType(lexer.stringVal()); 779 lexer.nextToken(); 780 } 781 782 if (lexer.token() != Token.LPAREN) { 783 SQLName name = this.name(); 784 primaryKey.setName(name); 785 } 786 787 accept(Token.LPAREN); 788 for (;;) { 789 SQLExpr expr; 790 if (lexer.token() == Token.LITERAL_ALIAS) { 791 expr = this.name(); 792 } else { 793 expr = this.expr(); 794 } 795 primaryKey.addColumn(expr); 796 if (!(lexer.token() == (Token.COMMA))) { 797 break; 798 } else { 799 lexer.nextToken(); 800 } 801 } 802 accept(Token.RPAREN); 803 804 if (lexer.identifierEquals(FnvHash.Constants.USING)) { 805 lexer.nextToken(); 806 primaryKey.setIndexType(lexer.stringVal()); 807 lexer.nextToken(); 808 } 809 810 return primaryKey; 811 } 812 813 override public MySqlUnique parseUnique() { 814 accept(Token.UNIQUE); 815 816 if (lexer.token() == Token.KEY) { 817 lexer.nextToken(); 818 } 819 820 if (lexer.token() == Token.INDEX) { 821 lexer.nextToken(); 822 } 823 824 MySqlUnique unique = new MySqlUnique(); 825 826 if (lexer.token() != Token.LPAREN) { 827 SQLName indexName = name(); 828 unique.setName(indexName); 829 } 830 831 //5.5语法 USING BTREE 放在index 名字后 832 if (lexer.identifierEquals(FnvHash.Constants.USING)) { 833 lexer.nextToken(); 834 unique.setIndexType(lexer.stringVal()); 835 lexer.nextToken(); 836 } 837 838 accept(Token.LPAREN); 839 for (;;) { 840 SQLExpr column = this.expr(); 841 if (lexer.token() == Token.ASC) { 842 column = new MySqlOrderingExpr(column, SQLOrderingSpecification.ASC); 843 lexer.nextToken(); 844 } else if (lexer.token() == Token.DESC) { 845 column = new MySqlOrderingExpr(column, SQLOrderingSpecification.DESC); 846 lexer.nextToken(); 847 } 848 unique.addColumn(column); 849 if (!(lexer.token() == (Token.COMMA))) { 850 break; 851 } else { 852 lexer.nextToken(); 853 } 854 } 855 accept(Token.RPAREN); 856 857 if (lexer.identifierEquals(FnvHash.Constants.USING)) { 858 lexer.nextToken(); 859 unique.setIndexType(lexer.stringVal()); 860 lexer.nextToken(); 861 } 862 863 if (lexer.identifierEquals(FnvHash.Constants.KEY_BLOCK_SIZE)) { 864 lexer.nextToken(); 865 if (lexer.token() == Token.EQ) { 866 lexer.nextToken(); 867 } 868 SQLExpr value = this.primary(); 869 unique.setKeyBlockSize(value); 870 } 871 872 return unique; 873 } 874 875 override public MysqlForeignKey parseForeignKey() { 876 accept(Token.FOREIGN); 877 accept(Token.KEY); 878 879 MysqlForeignKey fk = new MysqlForeignKey(); 880 881 if (lexer.token() != Token.LPAREN) { 882 SQLName indexName = name(); 883 fk.setIndexName(indexName); 884 } 885 886 accept(Token.LPAREN); 887 this.names(fk.getReferencingColumns(), fk); 888 accept(Token.RPAREN); 889 890 accept(Token.REFERENCES); 891 892 fk.setReferencedTableName(this.name()); 893 894 accept(Token.LPAREN); 895 this.names(fk.getReferencedColumns()); 896 accept(Token.RPAREN); 897 898 if (lexer.identifierEquals(FnvHash.Constants.MATCH)) { 899 lexer.nextToken(); 900 if (lexer.identifierEquals("FULL") || lexer.token() == Token.FULL) { 901 fk.setReferenceMatch(SQLForeignKeyImpl.Match.FULL); 902 lexer.nextToken(); 903 } else if (lexer.identifierEquals(FnvHash.Constants.PARTIAL)) { 904 fk.setReferenceMatch(SQLForeignKeyImpl.Match.PARTIAL); 905 lexer.nextToken(); 906 } else if (lexer.identifierEquals(FnvHash.Constants.SIMPLE)) { 907 fk.setReferenceMatch(SQLForeignKeyImpl.Match.SIMPLE); 908 lexer.nextToken(); 909 } else { 910 throw new ParserException("TODO : " ~ lexer.info()); 911 } 912 } 913 914 while (lexer.token() == Token.ON) { 915 lexer.nextToken(); 916 917 if (lexer.token() == Token.DELETE) { 918 lexer.nextToken(); 919 920 SQLForeignKeyImpl.Option option = parseReferenceOption(); 921 fk.setOnDelete(option); 922 } else if (lexer.token() == Token.UPDATE) { 923 lexer.nextToken(); 924 925 SQLForeignKeyImpl.Option option = parseReferenceOption(); 926 fk.setOnUpdate(option); 927 } else { 928 throw new ParserException("syntax error, expect DELETE or UPDATE, actual " ~ lexer.token() ~ " " 929 ~ lexer.info()); 930 } 931 } 932 return fk; 933 } 934 935 override protected SQLAggregateExpr parseAggregateExprRest(SQLAggregateExpr aggregateExpr) { 936 if (lexer.token() == Token.ORDER) { 937 SQLOrderBy orderBy = this.parseOrderBy(); 938 aggregateExpr.putAttribute("ORDER BY", orderBy); 939 } 940 if (lexer.identifierEquals(FnvHash.Constants.SEPARATOR)) { 941 lexer.nextToken(); 942 943 SQLExpr seperator = this.primary(); 944 seperator.setParent(aggregateExpr); 945 946 aggregateExpr.putAttribute("SEPARATOR", cast(Object)seperator); 947 } 948 return aggregateExpr; 949 } 950 951 public MySqlOrderingExpr parseSelectGroupByItem() { 952 MySqlOrderingExpr item = new MySqlOrderingExpr(); 953 954 item.setExpr(expr()); 955 956 if (lexer.token() == Token.ASC) { 957 lexer.nextToken(); 958 item.setType(SQLOrderingSpecification.ASC); 959 } else if (lexer.token() == Token.DESC) { 960 lexer.nextToken(); 961 item.setType(SQLOrderingSpecification.DESC); 962 } 963 964 return item; 965 } 966 967 override public SQLPartition parsePartition() { 968 accept(Token.PARTITION); 969 970 SQLPartition partitionDef = new SQLPartition(); 971 972 partitionDef.setName(this.name()); 973 974 SQLPartitionValue values = this.parsePartitionValues(); 975 if (values !is null) { 976 partitionDef.setValues(values); 977 } 978 979 for (;;) { 980 bool storage = false; 981 if (lexer.identifierEquals(FnvHash.Constants.DATA)) { 982 lexer.nextToken(); 983 acceptIdentifier("DIRECTORY"); 984 if (lexer.token() == Token.EQ) { 985 lexer.nextToken(); 986 } 987 partitionDef.setDataDirectory(this.expr()); 988 } else if (lexer.token() == Token.TABLESPACE) { 989 lexer.nextToken(); 990 if (lexer.token() == Token.EQ) { 991 lexer.nextToken(); 992 } 993 SQLName tableSpace = this.name(); 994 partitionDef.setTablespace(tableSpace); 995 } else if (lexer.token() == Token.INDEX) { 996 lexer.nextToken(); 997 acceptIdentifier("DIRECTORY"); 998 if (lexer.token() == Token.EQ) { 999 lexer.nextToken(); 1000 } 1001 partitionDef.setIndexDirectory(this.expr()); 1002 } else if (lexer.identifierEquals(FnvHash.Constants.MAX_ROWS)) { 1003 lexer.nextToken(); 1004 if (lexer.token() == Token.EQ) { 1005 lexer.nextToken(); 1006 } 1007 SQLExpr maxRows = this.primary(); 1008 partitionDef.setMaxRows(maxRows); 1009 } else if (lexer.identifierEquals(FnvHash.Constants.MIN_ROWS)) { 1010 lexer.nextToken(); 1011 if (lexer.token() == Token.EQ) { 1012 lexer.nextToken(); 1013 } 1014 SQLExpr minRows = this.primary(); 1015 partitionDef.setMaxRows(minRows); 1016 } else if (lexer.identifierEquals(FnvHash.Constants.ENGINE) // 1017 ) { 1018 storage = (lexer.token() == Token.STORAGE || lexer.identifierEquals(FnvHash.Constants.STORAGE)); 1019 if (storage) { 1020 lexer.nextToken(); 1021 } 1022 acceptIdentifier("ENGINE"); 1023 1024 if (lexer.token() == Token.EQ) { 1025 lexer.nextToken(); 1026 } 1027 1028 SQLName engine = this.name(); 1029 partitionDef.setEngine(engine); 1030 } else if (lexer.token() == Token.COMMENT) { 1031 lexer.nextToken(); 1032 if (lexer.token() == Token.EQ) { 1033 lexer.nextToken(); 1034 } 1035 SQLExpr comment = this.primary(); 1036 partitionDef.setComment(comment); 1037 } else { 1038 break; 1039 } 1040 } 1041 1042 if (lexer.token() == Token.LPAREN) { 1043 lexer.nextToken(); 1044 1045 for (;;) { 1046 acceptIdentifier("SUBPARTITION"); 1047 1048 SQLName subPartitionName = this.name(); 1049 SQLSubPartition subPartition = new SQLSubPartition(); 1050 subPartition.setName(subPartitionName); 1051 1052 partitionDef.addSubPartition(subPartition); 1053 1054 if (lexer.token() == Token.COMMA) { 1055 lexer.nextToken(); 1056 continue; 1057 } 1058 break; 1059 } 1060 1061 accept(Token.RPAREN); 1062 } 1063 return partitionDef; 1064 } 1065 1066 override protected SQLExpr parseAliasExpr(string alias_p) { 1067 string chars = alias_p.substring(1, cast(int)(alias_p.length - 1)); 1068 return new SQLCharExpr(chars); 1069 } 1070 }