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.parser.SQLSelectParser; 17 18 import hunt.collection; 19 20 import hunt.sql.ast; 21 import hunt.sql.ast.expr; 22 import hunt.sql.ast.statement; 23 // import hunt.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock; 24 import hunt.sql.dialect.mysql.ast.expr.MySqlOrderingExpr; 25 import hunt.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; 26 import hunt.sql.util.FnvHash; 27 import hunt.sql.util.DBType; 28 import hunt.sql.parser.SQLParser; 29 import hunt.sql.parser.SQLExprParser; 30 import hunt.sql.parser.SQLSelectListCache; 31 import hunt.sql.parser.Lexer; 32 import hunt.sql.parser.SQLExprParser; 33 import hunt.sql.parser.Token; 34 import hunt.Float; 35 import hunt.sql.parser.ParserException; 36 import hunt.String; 37 import hunt.text; 38 import hunt.sql.ast.SQLCommentHint; 39 40 public class SQLSelectParser : SQLParser { 41 protected SQLExprParser exprParser; 42 protected SQLSelectListCache selectListCache; 43 44 public this(string sql){ 45 super(sql); 46 } 47 48 public this(Lexer lexer){ 49 super(lexer); 50 } 51 52 public this(SQLExprParser exprParser){ 53 this(exprParser, null); 54 } 55 56 public this(SQLExprParser exprParser, SQLSelectListCache selectListCache){ 57 super(exprParser.getLexer(), exprParser.getDbType()); 58 this.exprParser = exprParser; 59 this.selectListCache = selectListCache; 60 } 61 62 public SQLSelect select() { 63 SQLSelect select = new SQLSelect(); 64 65 if (lexer.token == Token.WITH) { 66 SQLWithSubqueryClause _with = this.parseWith(); 67 select.setWithSubQuery(_with); 68 } 69 70 SQLSelectQuery query = query(); 71 select.setQuery(query); 72 73 SQLOrderBy orderBy = this.parseOrderBy(); 74 75 if (cast(SQLSelectQueryBlock)(query) !is null) { 76 SQLSelectQueryBlock queryBlock = cast(SQLSelectQueryBlock) query; 77 78 if (queryBlock.getOrderBy() is null) { 79 queryBlock.setOrderBy(orderBy); 80 } else { 81 select.setOrderBy(orderBy); 82 } 83 84 if (orderBy !is null) { 85 parseFetchClause(queryBlock); 86 } 87 } else { 88 select.setOrderBy(orderBy); 89 } 90 91 while (lexer.token == Token.HINT) { 92 this.exprParser.parseHints!(SQLHint)((select.getHints())); 93 } 94 95 return select; 96 } 97 98 protected SQLUnionQuery createSQLUnionQuery() { 99 SQLUnionQuery _union = new SQLUnionQuery(); 100 _union.setDbType(getDbType()); 101 return _union; 102 } 103 104 public SQLUnionQuery unionRest(SQLUnionQuery _union) { 105 if (lexer.token == Token.ORDER) { 106 SQLOrderBy orderBy = this.exprParser.parseOrderBy(); 107 _union.setOrderBy(orderBy); 108 return unionRest(_union); 109 } 110 return _union; 111 } 112 113 public SQLSelectQuery queryRest(SQLSelectQuery selectQuery) { 114 return queryRest(selectQuery, true); 115 } 116 117 public SQLSelectQuery queryRest(SQLSelectQuery selectQuery, bool acceptUnion) { 118 if (!acceptUnion) { 119 return selectQuery; 120 } 121 122 if (lexer.token == Token.UNION) { 123 do { 124 lexer.nextToken(); 125 126 SQLUnionQuery _union = createSQLUnionQuery(); 127 if (_union.getLeft() is null) { 128 _union.setLeft(selectQuery); 129 } 130 131 bool paren = lexer.token == Token.LPAREN; 132 133 if (lexer.token == Token.ALL) { 134 _union.setOperator(SQLUnionOperator.UNION_ALL); 135 lexer.nextToken(); 136 } else if (lexer.token == Token.DISTINCT) { 137 _union.setOperator(SQLUnionOperator.DISTINCT); 138 lexer.nextToken(); 139 } 140 SQLSelectQuery right = this.query(paren ? null : _union, false); 141 _union.setRight(right); 142 143 if (!paren) { 144 if (cast(SQLSelectQueryBlock)(right) !is null) { 145 SQLSelectQueryBlock rightQuery = cast(SQLSelectQueryBlock) right; 146 SQLOrderBy orderBy = rightQuery.getOrderBy(); 147 SQLLimit limit = rightQuery.getLimit(); 148 if (orderBy !is null && limit is null) { 149 _union.setOrderBy(orderBy); 150 rightQuery.setOrderBy(null); 151 } 152 } else if (cast(SQLUnionQuery)(right) !is null) { 153 SQLUnionQuery rightUnion = cast(SQLUnionQuery) right; 154 if (rightUnion.getOrderBy() !is null) { 155 _union.setOrderBy(rightUnion.getOrderBy()); 156 rightUnion.setOrderBy(null); 157 } 158 } 159 } 160 161 _union = unionRest(_union); 162 163 selectQuery = _union; 164 165 } while (lexer.token() == Token.UNION); 166 167 selectQuery = queryRest(selectQuery, true); 168 169 return selectQuery; 170 } 171 172 if (lexer.token == Token.EXCEPT) { 173 lexer.nextToken(); 174 175 SQLUnionQuery _union = new SQLUnionQuery(); 176 _union.setLeft(selectQuery); 177 178 _union.setOperator(SQLUnionOperator.EXCEPT); 179 180 SQLSelectQuery right = this.query(_union, false); 181 _union.setRight(right); 182 183 return queryRest(_union, true); 184 } 185 186 if (lexer.token == Token.INTERSECT) { 187 lexer.nextToken(); 188 189 SQLUnionQuery _union = new SQLUnionQuery(); 190 _union.setLeft(selectQuery); 191 192 _union.setOperator(SQLUnionOperator.INTERSECT); 193 194 SQLSelectQuery right = this.query(_union, false); 195 _union.setRight(right); 196 197 return queryRest(_union, true); 198 } 199 200 if (acceptUnion && lexer.token == Token.MINUS) { 201 lexer.nextToken(); 202 203 SQLUnionQuery _union = new SQLUnionQuery(); 204 _union.setLeft(selectQuery); 205 206 _union.setOperator(SQLUnionOperator.MINUS); 207 208 SQLSelectQuery right = this.query(_union, false); 209 _union.setRight(right); 210 211 return queryRest(_union, true); 212 } 213 214 return selectQuery; 215 } 216 217 public SQLSelectQuery query() { 218 return query(null, true); 219 } 220 221 public SQLSelectQuery query(SQLObject parent) { 222 return query(parent, true); 223 } 224 225 public SQLSelectQuery query(SQLObject parent, bool acceptUnion) { 226 if (lexer.token == Token.LPAREN) { 227 lexer.nextToken(); 228 229 SQLSelectQuery select = query(); 230 accept(Token.RPAREN); 231 232 return queryRest(select, acceptUnion); 233 } 234 235 SQLSelectQueryBlock queryBlock = new SQLSelectQueryBlock(); 236 237 if (lexer.hasComment() && lexer.isKeepComments()) { 238 queryBlock.addBeforeComment(lexer.readAndResetComments()); 239 } 240 241 accept(Token.SELECT); 242 243 if (lexer.token() == Token.HINT) { 244 this.exprParser.parseHints!(SQLCommentHint)((queryBlock.getHints())); 245 } 246 247 if (lexer.token == Token.COMMENT) { 248 lexer.nextToken(); 249 } 250 251 if (DBType.INFORMIX.opEquals(dbType)) { 252 if (lexer.identifierEquals(FnvHash.Constants.SKIP)) { 253 lexer.nextToken(); 254 SQLExpr offset = this.exprParser.primary(); 255 queryBlock.setOffset(offset); 256 } 257 258 if (lexer.identifierEquals(FnvHash.Constants.FIRST)) { 259 lexer.nextToken(); 260 SQLExpr first = this.exprParser.primary(); 261 queryBlock.setFirst(first); 262 } 263 } 264 265 if (lexer.token == Token.DISTINCT) { 266 queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT); 267 lexer.nextToken(); 268 } else if (lexer.token == Token.UNIQUE) { 269 queryBlock.setDistionOption(SQLSetQuantifier.UNIQUE); 270 lexer.nextToken(); 271 } else if (lexer.token == Token.ALL) { 272 queryBlock.setDistionOption(SQLSetQuantifier.ALL); 273 lexer.nextToken(); 274 } 275 276 parseSelectList(queryBlock); 277 278 parseFrom(queryBlock); 279 280 parseWhere(queryBlock); 281 282 parseGroupBy(queryBlock); 283 284 parseSortBy(queryBlock); 285 286 parseFetchClause(queryBlock); 287 288 if (lexer.token() == Token.FOR) { 289 lexer.nextToken(); 290 accept(Token.UPDATE); 291 292 queryBlock.setForUpdate(true); 293 294 if (lexer.identifierEquals(FnvHash.Constants.NO_WAIT) || lexer.identifierEquals(FnvHash.Constants.NOWAIT)) { 295 lexer.nextToken(); 296 queryBlock.setNoWait(true); 297 } else if (lexer.identifierEquals(FnvHash.Constants.WAIT)) { 298 lexer.nextToken(); 299 SQLExpr waitTime = this.exprParser.primary(); 300 queryBlock.setWaitTime(waitTime); 301 } 302 } 303 304 return queryRest(queryBlock, acceptUnion); 305 } 306 307 protected void parseSortBy(SQLSelectQueryBlock queryBlock) { 308 309 } 310 311 protected void withSubquery(SQLSelect s_select) { 312 if (lexer.token == Token.WITH) { 313 lexer.nextToken(); 314 315 SQLWithSubqueryClause withQueryClause = new SQLWithSubqueryClause(); 316 317 if (lexer.token == Token.RECURSIVE || lexer.identifierEquals(FnvHash.Constants.RECURSIVE)) { 318 lexer.nextToken(); 319 withQueryClause.setRecursive(true); 320 } 321 322 for (;;) { 323 SQLWithSubqueryClause.Entry entry = new SQLWithSubqueryClause.Entry(); 324 entry.setParent(withQueryClause); 325 326 string _alias = this.lexer.stringVal(); 327 lexer.nextToken(); 328 entry.setAlias(_alias); 329 330 if (lexer.token == Token.LPAREN) { 331 lexer.nextToken(); 332 exprParser.names(entry.getColumns()); 333 accept(Token.RPAREN); 334 } 335 336 accept(Token.AS); 337 accept(Token.LPAREN); 338 entry.setSubQuery(select()); 339 accept(Token.RPAREN); 340 341 withQueryClause.addEntry(entry); 342 343 if (lexer.token == Token.COMMA) { 344 lexer.nextToken(); 345 continue; 346 } 347 348 break; 349 } 350 351 s_select.setWithSubQuery(withQueryClause); 352 } 353 } 354 355 public SQLWithSubqueryClause parseWith() { 356 accept(Token.WITH); 357 358 SQLWithSubqueryClause withQueryClause = new SQLWithSubqueryClause(); 359 360 if (lexer.token == Token.RECURSIVE || lexer.identifierEquals(FnvHash.Constants.RECURSIVE)) { 361 lexer.nextToken(); 362 withQueryClause.setRecursive(true); 363 } 364 365 for (;;) { 366 SQLWithSubqueryClause.Entry entry = new SQLWithSubqueryClause.Entry(); 367 entry.setParent(withQueryClause); 368 369 string _alias = this.lexer.stringVal(); 370 lexer.nextToken(); 371 entry.setAlias(_alias); 372 373 if (lexer.token == Token.LPAREN) { 374 lexer.nextToken(); 375 exprParser.names(entry.getColumns()); 376 accept(Token.RPAREN); 377 } 378 379 accept(Token.AS); 380 accept(Token.LPAREN); 381 382 switch (lexer.token) { 383 case Token.SELECT: 384 entry.setSubQuery(select()); 385 break; 386 default: 387 break; 388 } 389 390 accept(Token.RPAREN); 391 392 withQueryClause.addEntry(entry); 393 394 if (lexer.token == Token.COMMA) { 395 lexer.nextToken(); 396 continue; 397 } 398 399 break; 400 } 401 402 return withQueryClause; 403 } 404 405 public void parseWhere(SQLSelectQueryBlock queryBlock) { 406 if (lexer.token == Token.WHERE) { 407 lexer.nextTokenIdent(); 408 409 List!(string) beforeComments = null; 410 if (lexer.hasComment() && lexer.isKeepComments()) { 411 beforeComments = lexer.readAndResetComments(); 412 } 413 414 SQLExpr where; 415 416 if (lexer.token == Token.IDENTIFIER) { 417 string ident = lexer.stringVal(); 418 long hash_lower = lexer.hash_lower(); 419 lexer.nextTokenEq(); 420 421 SQLExpr identExpr; 422 if (lexer.token == Token.LITERAL_CHARS) { 423 string literal = lexer.stringVal; 424 if (hash_lower == FnvHash.Constants.TIMESTAMP) { 425 identExpr = new SQLTimestampExpr(literal); 426 lexer.nextToken(); 427 } else if (hash_lower == FnvHash.Constants.DATE) { 428 identExpr = new SQLDateExpr(literal); 429 lexer.nextToken(); 430 } else if (hash_lower == FnvHash.Constants.REAL) { 431 identExpr = new SQLRealExpr(Float.parseFloat(literal)); 432 lexer.nextToken(); 433 } else { 434 identExpr = new SQLIdentifierExpr(ident, hash_lower); 435 } 436 } else { 437 identExpr = new SQLIdentifierExpr(ident, hash_lower); 438 } 439 440 if (lexer.token == Token.DOT) { 441 identExpr = this.exprParser.primaryRest(identExpr); 442 } 443 444 if (lexer.token == Token.EQ) { 445 SQLExpr rightExp; 446 447 lexer.nextToken(); 448 449 try { 450 rightExp = this.exprParser.bitOr(); 451 } catch (ParserException e) { 452 throw new ParserException("EOF, " ~ ident ~ "=", e); 453 } 454 455 where = new SQLBinaryOpExpr(identExpr, SQLBinaryOperator.Equality, rightExp, dbType); 456 switch (lexer.token) { 457 case Token.BETWEEN: 458 case Token.IS: 459 case Token.EQ: 460 case Token.IN: 461 case Token.CONTAINS: 462 case Token.BANG_TILDE_STAR: 463 case Token.TILDE_EQ: 464 case Token.LT: 465 case Token.LTEQ: 466 case Token.LTEQGT: 467 case Token.GT: 468 case Token.GTEQ: 469 case Token.LTGT: 470 case Token.BANGEQ: 471 case Token.LIKE: 472 case Token.NOT: 473 where = this.exprParser.relationalRest(where); 474 break; 475 default: 476 break; 477 } 478 479 where = this.exprParser.andRest(where); 480 where = this.exprParser.xorRest(where); 481 where = this.exprParser.orRest(where); 482 } else { 483 identExpr = this.exprParser.primaryRest(identExpr); 484 where = this.exprParser.exprRest(identExpr); 485 } 486 } else { 487 where = this.exprParser.expr(); 488 } 489 // where = this.exprParser.expr(); 490 491 if (beforeComments !is null) { 492 where.addBeforeComment(beforeComments); 493 } 494 495 if (lexer.hasComment() && lexer.isKeepComments() // 496 && lexer.token != Token.INSERT // odps multi-insert 497 ) { 498 where.addAfterComment(lexer.readAndResetComments()); 499 } 500 501 queryBlock.setWhere(where); 502 } 503 } 504 505 protected void parseWindow(SQLSelectQueryBlock queryBlock) { 506 if (!(lexer.identifierEquals(FnvHash.Constants.WINDOW) || lexer.token == Token.WINDOW)) { 507 return; 508 } 509 510 lexer.nextToken(); 511 512 for (;;) { 513 SQLName name = this.exprParser.name(); 514 accept(Token.AS); 515 SQLOver s_over = new SQLOver(); 516 this.exprParser.over(s_over); 517 queryBlock.addWindow(new SQLWindow(name, s_over)); 518 519 if (lexer.token == Token.COMMA) { 520 lexer.nextToken(); 521 continue; 522 } 523 524 break; 525 } 526 } 527 528 protected void parseGroupBy(SQLSelectQueryBlock queryBlock) { 529 if (lexer.token == (Token.GROUP)) { 530 lexer.nextTokenBy(); 531 accept(Token.BY); 532 533 SQLSelectGroupByClause groupBy = new SQLSelectGroupByClause(); 534 if (lexer.identifierEquals(FnvHash.Constants.ROLLUP)) { 535 lexer.nextToken(); 536 accept(Token.LPAREN); 537 groupBy.setWithRollUp(true); 538 } 539 if (lexer.identifierEquals(FnvHash.Constants.CUBE)) { 540 lexer.nextToken(); 541 accept(Token.LPAREN); 542 groupBy.setWithCube(true); 543 } 544 545 for (;;) { 546 SQLExpr item = parseGroupByItem(); 547 548 item.setParent(groupBy); 549 groupBy.addItem(item); 550 551 if (!(lexer.token == (Token.COMMA))) { 552 break; 553 } 554 555 lexer.nextToken(); 556 } 557 if (groupBy.isWithRollUp() || groupBy.isWithCube()) { 558 accept(Token.RPAREN); 559 } 560 561 if (lexer.token == (Token.HAVING)) { 562 lexer.nextToken(); 563 564 SQLExpr having = this.exprParser.expr(); 565 groupBy.setHaving(having); 566 } 567 568 if (lexer.token == Token.WITH) { 569 lexer.nextToken(); 570 571 if (lexer.identifierEquals(FnvHash.Constants.CUBE)) { 572 lexer.nextToken(); 573 groupBy.setWithCube(true); 574 } else if(lexer.identifierEquals(FnvHash.Constants.ROLLUP)) { 575 lexer.nextToken(); 576 groupBy.setWithRollUp(true); 577 // } else if (lexer.identifierEquals(FnvHash.Constants.RS) 578 // && DBType.DB2.opEquals(dbType)) { 579 // lexer.nextToken(); 580 // ((DB2SelectQueryBlock) queryBlock).setIsolation(DB2SelectQueryBlock.Isolation.RS); 581 // } else if (lexer.identifierEquals(FnvHash.Constants.RR) 582 // && DBType.DB2.opEquals(dbType)) { 583 // lexer.nextToken(); 584 // ((DB2SelectQueryBlock) queryBlock).setIsolation(DB2SelectQueryBlock.Isolation.RR); 585 // } else if (lexer.identifierEquals(FnvHash.Constants.CS) 586 // && DBType.DB2.opEquals(dbType)) { 587 // lexer.nextToken(); 588 // ((DB2SelectQueryBlock) queryBlock).setIsolation(DB2SelectQueryBlock.Isolation.CS); 589 // } else if (lexer.identifierEquals(FnvHash.Constants.UR) 590 // && DBType.DB2.opEquals(dbType)) { 591 // lexer.nextToken(); 592 // ((DB2SelectQueryBlock) queryBlock).setIsolation(DB2SelectQueryBlock.Isolation.UR); 593 } else { 594 throw new ParserException("TODO " ~ lexer.info()); 595 } 596 } 597 598 queryBlock.setGroupBy(groupBy); 599 } else if (lexer.token == (Token.HAVING)) { 600 lexer.nextToken(); 601 602 SQLSelectGroupByClause groupBy = new SQLSelectGroupByClause(); 603 groupBy.setHaving(this.exprParser.expr()); 604 605 if (lexer.token == (Token.GROUP)) { 606 lexer.nextToken(); 607 accept(Token.BY); 608 609 for (;;) { 610 SQLExpr item = parseGroupByItem(); 611 612 item.setParent(groupBy); 613 groupBy.addItem(item); 614 615 if (!(lexer.token == (Token.COMMA))) { 616 break; 617 } 618 619 lexer.nextToken(); 620 } 621 } 622 623 if (lexer.token == Token.WITH) { 624 lexer.nextToken(); 625 acceptIdentifier("ROLLUP"); 626 627 groupBy.setWithRollUp(true); 628 } 629 630 if(DBType.MYSQL.opEquals(getDbType()) 631 && lexer.token == Token.DESC) { 632 lexer.nextToken(); // skip 633 } 634 635 queryBlock.setGroupBy(groupBy); 636 } 637 } 638 639 protected SQLExpr parseGroupByItem() { 640 SQLExpr item = this.exprParser.expr(); 641 642 if(DBType.MYSQL.opEquals(getDbType())) { 643 if (lexer.token == Token.DESC) { 644 lexer.nextToken(); // skip 645 item =new MySqlOrderingExpr(item, SQLOrderingSpecification.DESC); 646 } else if (lexer.token == Token.ASC) { 647 lexer.nextToken(); // skip 648 item =new MySqlOrderingExpr(item, SQLOrderingSpecification.ASC); 649 } 650 } 651 return item; 652 } 653 654 public void parseSelectList(SQLSelectQueryBlock queryBlock) { 655 List!(SQLSelectItem) selectList = queryBlock.getSelectList(); 656 for (;;) { 657 SQLSelectItem selectItem = this.exprParser.parseSelectItem(); 658 selectList.add(selectItem); 659 selectItem.setParent(queryBlock); 660 661 if (lexer.token != Token.COMMA) { 662 break; 663 } 664 665 lexer.nextToken(); 666 } 667 } 668 669 public void parseFrom(SQLSelectQueryBlock queryBlock) { 670 if (lexer.token != Token.FROM) { 671 return; 672 } 673 674 lexer.nextToken(); 675 676 queryBlock.setFrom( 677 parseTableSource()); 678 } 679 680 public SQLTableSource parseTableSource() { 681 if (lexer.token == Token.LPAREN) { 682 lexer.nextToken(); 683 SQLTableSource tableSource; 684 if (lexer.token == Token.SELECT || lexer.token == Token.WITH 685 || lexer.token == Token.SEL) { 686 SQLSelect select = select(); 687 accept(Token.RPAREN); 688 SQLSelectQuery query = queryRest(select.getQuery(), true); 689 if (cast(SQLUnionQuery)(query) !is null) { 690 tableSource = new SQLUnionQueryTableSource(cast(SQLUnionQuery) query); 691 } else { 692 tableSource = new SQLSubqueryTableSource(select); 693 } 694 } else if (lexer.token == Token.LPAREN) { 695 tableSource = parseTableSource(); 696 accept(Token.RPAREN); 697 } else { 698 tableSource = parseTableSource(); 699 accept(Token.RPAREN); 700 } 701 702 if (lexer.token == Token.AS 703 && cast(SQLValuesTableSource)(tableSource) !is null 704 && (cast(SQLValuesTableSource) tableSource).getColumns().size() == 0) 705 { 706 lexer.nextToken(); 707 708 string _alias = this.tableAlias(); 709 tableSource.setAlias(_alias); 710 711 SQLValuesTableSource values = cast(SQLValuesTableSource) tableSource; 712 accept(Token.LPAREN); 713 this.exprParser.names(values.getColumns(), values); 714 accept(Token.RPAREN); 715 } 716 717 return parseTableSourceRest(tableSource); 718 } 719 720 if (lexer.token() == Token.VALUES) { 721 lexer.nextToken(); 722 SQLValuesTableSource tableSource = new SQLValuesTableSource(); 723 724 for (;;) { 725 accept(Token.LPAREN); 726 SQLListExpr listExpr = new SQLListExpr(); 727 this.exprParser.exprList(listExpr.getItems(), listExpr); 728 accept(Token.RPAREN); 729 730 listExpr.setParent(tableSource); 731 732 tableSource.getValues().add(listExpr); 733 734 if (lexer.token == Token.COMMA) { 735 lexer.nextToken(); 736 continue; 737 } 738 break; 739 } 740 741 if (lexer.token == Token.RPAREN) { 742 return tableSource; 743 } 744 745 string _alias = this.tableAlias(); 746 if (_alias !is null) { 747 tableSource.setAlias(_alias); 748 } 749 750 accept(Token.LPAREN); 751 this.exprParser.names(tableSource.getColumns(), tableSource); 752 accept(Token.RPAREN); 753 754 return tableSource; 755 } 756 757 if (lexer.token == Token.SELECT) { 758 throw new ParserException("TODO " ~ lexer.info()); 759 } 760 761 SQLExprTableSource tableReference = new SQLExprTableSource(); 762 763 parseTableSourceQueryTableExpr(tableReference); 764 765 SQLTableSource tableSrc = parseTableSourceRest(tableReference); 766 767 if (lexer.hasComment() && lexer.isKeepComments()) { 768 tableSrc.addAfterComment(lexer.readAndResetComments()); 769 } 770 771 return tableSrc; 772 } 773 774 protected void parseTableSourceQueryTableExpr(SQLExprTableSource tableReference) { 775 if (lexer.token == Token.LITERAL_ALIAS || lexer.token == Token.IDENTIFIED 776 || lexer.token == Token.LITERAL_CHARS) { 777 tableReference.setExpr(this.exprParser.name()); 778 return; 779 } 780 781 tableReference.setExpr(expr()); 782 } 783 784 protected SQLTableSource primaryTableSourceRest(SQLTableSource tableSource) { 785 return tableSource; 786 } 787 788 protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) { 789 if (tableSource.getAlias() is null || tableSource.getAlias().length == 0) { 790 Token token = lexer.token; 791 long hash; 792 if (token != Token.LEFT 793 && token != Token.RIGHT 794 && token != Token.FULL 795 && token != Token.OUTER 796 && !(token == Token.IDENTIFIER 797 && ((hash = lexer.hash_lower()) == FnvHash.Constants.STRAIGHT_JOIN 798 || hash == FnvHash.Constants.CROSS))) 799 { 800 string _alias = tableAlias(); 801 if (_alias !is null) { 802 tableSource.setAlias(_alias); 803 804 if (lexer.token == Token.WHERE) { 805 return tableSource; 806 } 807 808 return parseTableSourceRest(tableSource); 809 } 810 } 811 } 812 813 SQLJoinTableSource.JoinType joinType = null; 814 815 bool natural = lexer.identifierEquals(FnvHash.Constants.NATURAL) && DBType.MYSQL.opEquals(dbType); 816 if (natural) { 817 lexer.nextToken(); 818 } 819 820 if (lexer.token == Token.LEFT) { 821 lexer.nextToken(); 822 823 if (lexer.identifierEquals(FnvHash.Constants.SEMI)) { 824 lexer.nextToken(); 825 joinType = SQLJoinTableSource.JoinType.LEFT_SEMI_JOIN; 826 } else if (lexer.identifierEquals(FnvHash.Constants.ANTI)) { 827 lexer.nextToken(); 828 joinType = SQLJoinTableSource.JoinType.LEFT_ANTI_JOIN; 829 } else if (lexer.token == Token.OUTER) { 830 lexer.nextToken(); 831 joinType = SQLJoinTableSource.JoinType.LEFT_OUTER_JOIN; 832 } else { 833 joinType = SQLJoinTableSource.JoinType.LEFT_OUTER_JOIN; 834 } 835 836 accept(Token.JOIN); 837 838 } else if (lexer.token == Token.RIGHT) { 839 lexer.nextToken(); 840 if (lexer.token == Token.OUTER) { 841 lexer.nextToken(); 842 } 843 accept(Token.JOIN); 844 joinType = SQLJoinTableSource.JoinType.RIGHT_OUTER_JOIN; 845 } else if (lexer.token == Token.FULL) { 846 lexer.nextToken(); 847 if (lexer.token == Token.OUTER) { 848 lexer.nextToken(); 849 } 850 accept(Token.JOIN); 851 joinType = SQLJoinTableSource.JoinType.FULL_OUTER_JOIN; 852 } else if (lexer.token == Token.INNER) { 853 lexer.nextToken(); 854 accept(Token.JOIN); 855 joinType = SQLJoinTableSource.JoinType.INNER_JOIN; 856 } else if (lexer.token == Token.JOIN) { 857 lexer.nextToken(); 858 joinType = SQLJoinTableSource.JoinType.JOIN; 859 } else if (lexer.token == Token.COMMA) { 860 lexer.nextToken(); 861 joinType = SQLJoinTableSource.JoinType.COMMA; 862 } else if (lexer.identifierEquals(FnvHash.Constants.STRAIGHT_JOIN)) { 863 lexer.nextToken(); 864 joinType = SQLJoinTableSource.JoinType.STRAIGHT_JOIN; 865 } else if (lexer.identifierEquals(FnvHash.Constants.CROSS)) { 866 lexer.nextToken(); 867 if (lexer.token == Token.JOIN) { 868 lexer.nextToken(); 869 joinType = SQLJoinTableSource.JoinType.CROSS_JOIN; 870 } else if (lexer.identifierEquals(FnvHash.Constants.APPLY)) { 871 lexer.nextToken(); 872 joinType = SQLJoinTableSource.JoinType.CROSS_APPLY; 873 } 874 } else if (lexer.token == Token.OUTER) { 875 lexer.nextToken(); 876 if (lexer.identifierEquals(FnvHash.Constants.APPLY)) { 877 lexer.nextToken(); 878 joinType = SQLJoinTableSource.JoinType.OUTER_APPLY; 879 } 880 } 881 882 if (joinType.name.length != 0) { 883 SQLJoinTableSource join = new SQLJoinTableSource(); 884 join.setLeft(tableSource); 885 join.setJoinType(joinType); 886 887 888 SQLTableSource rightTableSource; 889 if (lexer.token == Token.LPAREN) { 890 lexer.nextToken(); 891 if (lexer.token == Token.SELECT) { 892 SQLSelect select = this.select(); 893 rightTableSource = new SQLSubqueryTableSource(select); 894 } else { 895 rightTableSource = this.parseTableSource(); 896 } 897 accept(Token.RPAREN); 898 } else { 899 SQLExpr expr = this.expr(); 900 rightTableSource = new SQLExprTableSource(expr); 901 primaryTableSourceRest(rightTableSource); 902 } 903 904 if (lexer.token == Token.USING 905 ||lexer.identifierEquals(FnvHash.Constants.USING)) 906 { 907 Lexer.SavePoint savePoint = lexer.mark(); 908 lexer.nextToken(); 909 910 if (lexer.token == Token.LPAREN) { 911 lexer.nextToken(); 912 join.setRight(rightTableSource); 913 this.exprParser.exprList(join.getUsing(), join); 914 accept(Token.RPAREN); 915 } else if (lexer.token == Token.IDENTIFIER) { 916 lexer.reset(savePoint); 917 join.setRight(rightTableSource); 918 return join; 919 } else { 920 join.setAlias(this.tableAlias()); 921 } 922 } else { 923 rightTableSource.setAlias(this.tableAlias()); 924 925 primaryTableSourceRest(rightTableSource); 926 } 927 928 if (lexer.token == Token.WITH) { 929 lexer.nextToken(); 930 accept(Token.LPAREN); 931 932 for (;;) { 933 SQLExpr hintExpr = this.expr(); 934 SQLExprHint hint = new SQLExprHint(hintExpr); 935 hint.setParent(tableSource); 936 rightTableSource.getHints().add(hint); 937 if (lexer.token == Token.COMMA) { 938 lexer.nextToken(); 939 continue; 940 } else { 941 break; 942 } 943 } 944 945 accept(Token.RPAREN); 946 } 947 948 join.setRight(rightTableSource); 949 950 if (!natural) { 951 if (tableSource.aliasHashCode64() == FnvHash.Constants.NATURAL && DBType.MYSQL.opEquals(dbType)) { 952 tableSource.setAlias(null); 953 natural = true; 954 } 955 } 956 join.setNatural(natural); 957 958 if (lexer.token == Token.ON) { 959 lexer.nextToken(); 960 join.setCondition(expr()); 961 } else if (lexer.token == Token.USING 962 || lexer.identifierEquals(FnvHash.Constants.USING)) { 963 Lexer.SavePoint savePoint = lexer.mark(); 964 lexer.nextToken(); 965 if (lexer.token == Token.LPAREN) { 966 lexer.nextToken(); 967 this.exprParser.exprList(join.getUsing(), join); 968 accept(Token.RPAREN); 969 } else { 970 lexer.reset(savePoint); 971 } 972 } 973 974 return parseTableSourceRest(join); 975 } 976 977 if (tableSource.aliasHashCode64() == FnvHash.Constants.LATERAL 978 && lexer.token() == Token.VIEW) { 979 return parseLateralView(tableSource); 980 } 981 982 if (lexer.identifierEquals(FnvHash.Constants.LATERAL)) { 983 lexer.nextToken(); 984 return parseLateralView(tableSource); 985 } 986 987 return tableSource; 988 } 989 990 public SQLExpr expr() { 991 return this.exprParser.expr(); 992 } 993 994 public SQLOrderBy parseOrderBy() { 995 return this.exprParser.parseOrderBy(); 996 } 997 998 public void acceptKeyword(string ident) { 999 if (lexer.token == Token.IDENTIFIER && equalsIgnoreCase(ident, lexer.stringVal())) { 1000 lexer.nextToken(); 1001 } else { 1002 setErrorEndPos(lexer.pos()); 1003 throw new ParserException("syntax error, expect " ~ ident ~ ", actual " ~ lexer.token ~ ", " ~ lexer.info()); 1004 } 1005 } 1006 1007 public void parseFetchClause(SQLSelectQueryBlock queryBlock) { 1008 if (lexer.token == Token.LIMIT) { 1009 SQLLimit limit = this.exprParser.parseLimit(); 1010 queryBlock.setLimit(limit); 1011 return; 1012 } 1013 1014 if (lexer.identifierEquals(FnvHash.Constants.OFFSET) || lexer.token == Token.OFFSET) { 1015 lexer.nextToken(); 1016 SQLExpr offset = this.exprParser.primary(); 1017 queryBlock.setOffset(offset); 1018 if (lexer.identifierEquals(FnvHash.Constants.ROW) || lexer.identifierEquals(FnvHash.Constants.ROWS)) { 1019 lexer.nextToken(); 1020 } 1021 } 1022 1023 if (lexer.token == Token.FETCH) { 1024 lexer.nextToken(); 1025 if (lexer.token == Token.FIRST 1026 || lexer.token == Token.NEXT 1027 || lexer.identifierEquals(FnvHash.Constants.NEXT)) { 1028 lexer.nextToken(); 1029 } else { 1030 acceptIdentifier("FIRST"); 1031 } 1032 SQLExpr first = this.exprParser.primary(); 1033 queryBlock.setFirst(first); 1034 if (lexer.identifierEquals(FnvHash.Constants.ROW) || lexer.identifierEquals(FnvHash.Constants.ROWS)) { 1035 lexer.nextToken(); 1036 } 1037 1038 if (lexer.token == Token.ONLY) { 1039 lexer.nextToken(); 1040 } else { 1041 acceptIdentifier("ONLY"); 1042 } 1043 } 1044 } 1045 1046 protected void parseHierachical(SQLSelectQueryBlock queryBlock) { 1047 if (lexer.token == Token.CONNECT || lexer.identifierEquals(FnvHash.Constants.CONNECT)) { 1048 lexer.nextToken(); 1049 accept(Token.BY); 1050 1051 if (lexer.token == Token.PRIOR || lexer.identifierEquals(FnvHash.Constants.PRIOR)) { 1052 lexer.nextToken(); 1053 queryBlock.setPrior(true); 1054 } 1055 1056 if (lexer.identifierEquals(FnvHash.Constants.NOCYCLE)) { 1057 queryBlock.setNoCycle(true); 1058 lexer.nextToken(); 1059 1060 if (lexer.token == Token.PRIOR) { 1061 lexer.nextToken(); 1062 queryBlock.setPrior(true); 1063 } 1064 } 1065 queryBlock.setConnectBy(this.exprParser.expr()); 1066 } 1067 1068 if (lexer.token == Token.START || lexer.identifierEquals(FnvHash.Constants.START)) { 1069 lexer.nextToken(); 1070 accept(Token.WITH); 1071 1072 queryBlock.setStartWith(this.exprParser.expr()); 1073 } 1074 1075 if (lexer.token == Token.CONNECT || lexer.identifierEquals(FnvHash.Constants.CONNECT)) { 1076 lexer.nextToken(); 1077 accept(Token.BY); 1078 1079 if (lexer.token == Token.PRIOR || lexer.identifierEquals(FnvHash.Constants.PRIOR)) { 1080 lexer.nextToken(); 1081 queryBlock.setPrior(true); 1082 } 1083 1084 if (lexer.identifierEquals(FnvHash.Constants.NOCYCLE)) { 1085 queryBlock.setNoCycle(true); 1086 lexer.nextToken(); 1087 1088 if (lexer.token == Token.PRIOR || lexer.identifierEquals(FnvHash.Constants.PRIOR)) { 1089 lexer.nextToken(); 1090 queryBlock.setPrior(true); 1091 } 1092 } 1093 queryBlock.setConnectBy(this.exprParser.expr()); 1094 } 1095 } 1096 1097 protected SQLTableSource parseLateralView(SQLTableSource tableSource) { 1098 accept(Token.VIEW); 1099 if ("LATERAL".equalsIgnoreCase(tableSource.getAlias())) { 1100 tableSource.setAlias(null); 1101 } 1102 SQLLateralViewTableSource lateralViewTabSrc = new SQLLateralViewTableSource(); 1103 lateralViewTabSrc.setTableSource(tableSource); 1104 1105 SQLMethodInvokeExpr udtf = cast(SQLMethodInvokeExpr) this.exprParser.expr(); 1106 lateralViewTabSrc.setMethod(udtf); 1107 1108 string _alias = as(); 1109 lateralViewTabSrc.setAlias(_alias); 1110 1111 accept(Token.AS); 1112 1113 this.exprParser.names(lateralViewTabSrc.getColumns()); 1114 1115 return parseTableSourceRest(lateralViewTabSrc); 1116 } 1117 }