1 28 29 package com.caucho.db.sql; 30 31 import com.caucho.db.Database; 32 import com.caucho.db.table.Column; 33 import com.caucho.db.table.Table; 34 import com.caucho.db.table.TableFactory; 35 import com.caucho.log.Log; 36 import com.caucho.util.CharBuffer; 37 import com.caucho.util.IntMap; 38 import com.caucho.util.L10N; 39 40 import java.sql.SQLException ; 41 import java.util.ArrayList ; 42 import java.util.HashSet ; 43 import java.util.logging.Level ; 44 import java.util.logging.Logger ; 45 46 public class Parser { 47 private static final Logger log = Log.open(Parser.class); 48 private static final L10N L = new L10N(Parser.class); 49 50 final static int IDENTIFIER = 128; 51 final static int INTEGER = IDENTIFIER + 1; 52 final static int LONG = INTEGER + 1; 53 final static int DOUBLE = LONG + 1; 54 final static int STRING = DOUBLE + 1; 55 final static int TRUE = STRING + 1; 56 final static int FALSE = TRUE + 1; 57 final static int UNKNOWN = FALSE + 1; 58 final static int NULL = UNKNOWN + 1; 59 final static int EXISTS = NULL + 1; 60 61 final static int FROM = EXISTS + 1; 62 final static int IN = FROM + 1; 63 final static int SELECT = IN + 1; 64 final static int DISTINCT = SELECT + 1; 65 final static int WHERE = SELECT + 1; 66 final static int AS = WHERE + 1; 67 final static int ORDER = AS + 1; 68 final static int GROUP = ORDER + 1; 69 final static int BY = GROUP + 1; 70 final static int ASC = BY + 1; 71 final static int DESC = ASC + 1; 72 final static int LIMIT = DESC + 1; 73 final static int OFFSET = LIMIT + 1; 74 75 final static int BETWEEN = OFFSET + 1; 76 final static int LIKE = BETWEEN + 1; 77 final static int ESCAPE = LIKE + 1; 78 final static int IS = ESCAPE + 1; 79 final static int CONCAT = IS + 1; 80 81 final static int EQ = CONCAT + 1; 82 final static int NE = EQ + 1; 83 final static int LT = NE + 1; 84 final static int LE = LT + 1; 85 final static int GT = LE + 1; 86 final static int GE = GT + 1; 87 88 final static int AND = GE + 1; 89 final static int OR = AND + 1; 90 final static int NOT = OR + 1; 91 92 final static int ARG = NOT + 1; 93 94 final static int CREATE = ARG + 1; 95 final static int TABLE = CREATE + 1; 96 final static int INSERT = TABLE + 1; 97 final static int INTO = INSERT + 1; 98 final static int VALUES = INTO + 1; 99 final static int DROP = VALUES + 1; 100 final static int UPDATE = DROP + 1; 101 final static int SET = UPDATE + 1; 102 final static int DELETE = SET + 1; 103 104 final static int CONSTRAINT = DELETE + 1; 105 final static int UNIQUE = CONSTRAINT + 1; 106 final static int PRIMARY = UNIQUE + 1; 107 final static int CHECK = PRIMARY + 1; 108 final static int FOREIGN = CHECK + 1; 109 final static int KEY = FOREIGN + 1; 110 111 private final static IntMap _reserved; 112 113 private Database _database; 114 115 private final String _sql; 116 private final char []_sqlChars; 117 private final int _sqlLength; 118 119 private int _parseIndex; 120 121 private final CharBuffer _cb = new CharBuffer(); 122 123 private String _lexeme; 124 private int _token; 125 126 private ArrayList <ParamExpr> _params = new ArrayList <ParamExpr>(); 127 128 private Query _query; 129 private AndExpr _andExpr; 130 131 private Parser(Database database, String sql) 132 { 133 _database = database; 134 _sql = sql; 135 _sqlLength = _sql.length(); 136 _sqlChars = new char[_sqlLength]; 137 _sql.getChars(0, _sqlLength, _sqlChars, 0); 138 } 139 140 public static Query parse(Database database, String sql) 141 throws SQLException 142 { 143 Parser parser = new Parser(database, sql); 144 145 Query query = parser.parse(); 146 147 query.bind(); 148 149 return query; 150 } 151 152 public static Expr parseExpr(Database database, String sql) 153 throws SQLException 154 { 155 Parser parser = new Parser(database, sql); 156 157 Expr expr = parser.parseExpr(); 158 159 return expr.bind(null); 160 } 161 162 165 private Query parse() 166 throws SQLException 167 { 168 int token = scanToken(); 169 170 switch (token) { 171 case SELECT: 172 return parseSelect(); 173 174 case CREATE: 175 return parseCreate(); 176 177 case INSERT: 178 return parseInsert(); 179 180 case DELETE: 181 return parseDelete(); 182 183 case DROP: 184 return parseDrop(); 185 186 case UPDATE: 187 return parseUpdate(); 188 189 default: 190 throw new SQLParseException(L.l("unknown query at `{0}'", 191 tokenName(token))); 192 } 193 } 194 195 198 private SelectQuery parseSelect() 199 throws SQLException 200 { 201 return parseSelect(new SelectQuery(_database, _sql)); 202 } 203 204 207 private SelectQuery parseSelect(SelectQuery query) 208 throws SQLException 209 { 210 boolean distinct = false; 211 212 int token = scanToken(); 213 214 if (token == DISTINCT) 215 distinct = true; 216 else 217 _token = token; 218 219 ArrayList <Expr> resultItems = new ArrayList <Expr>(); 220 221 int startToken = scanToken(); 222 String startLexeme = _lexeme; 223 int startOffset = _parseIndex; 224 225 while ((token = scanToken()) >= 0 && token != FROM) { 226 } 227 228 if (token != FROM) 229 throw error(L.l("expected FROM at `{0}'", tokenName(token))); 230 231 query.setParent(_query); 232 _query = query; 233 234 AndExpr oldAnd = _andExpr; 235 _andExpr = new AndExpr(); 236 237 ArrayList <FromItem> fromItems = parseFromItems(); 238 239 query.setFromItems(fromItems); 240 241 token = scanToken(); 242 243 int tailToken = token; 244 int tailOffset = _parseIndex; 245 246 _token = startToken; 247 _parseIndex = startOffset; 248 _lexeme = startLexeme; 249 250 Expr expr = parseSelectExpr(); 251 252 resultItems.add(expr); 253 254 while ((token = scanToken()) == ',') { 255 expr = parseSelectExpr(); 256 257 resultItems.add(expr); 258 } 259 260 _token = tailToken; 261 _parseIndex = tailOffset; 262 263 token = scanToken(); 264 265 if (token == WHERE) 266 _andExpr.add(parseExpr()); 267 else 268 _token = token; 269 270 ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]); 271 272 Expr whereExpr = _andExpr.getSingleExpr(); 273 _andExpr = null; 274 query.setWhereExpr(whereExpr); 275 query.setParams(params); 276 277 for (int i = resultItems.size() - 1; i >= 0; i--) { 278 Expr subExpr = resultItems.get(i); 279 280 if (subExpr instanceof UnboundStarExpr) { 281 UnboundStarExpr unboundExpr = (UnboundStarExpr) subExpr; 282 ArrayList <Expr> exprList = unboundExpr.expand(query.getFromItems()); 283 284 resultItems.remove(i); 285 resultItems.addAll(i, exprList); 286 } 287 } 288 289 ArrayList <Expr> groupItems = null; 290 token = scanToken(); 291 if (token == GROUP) { 292 token = scanToken(); 293 294 if (token != BY) 295 throw error(L.l("expected BY at `{0}'", tokenName(token))); 296 297 groupItems = parseGroup(query); 298 } 299 else 300 _token = token; 301 302 token = scanToken(); 303 if (token == ORDER) { 304 token = scanToken(); 305 306 if (token != BY) 307 throw error(L.l("expected BY at `{0}'", tokenName(token))); 308 309 Order order = parseOrder(query, resultItems); 310 } 311 else 312 _token = token; 313 314 Expr []resultArray = resultItems.toArray(new Expr[resultItems.size()]); 315 316 query.setResults(resultArray); 317 318 if (query.isGroup()) { 319 Expr []resultList = query.getResults(); 320 321 bindGroup(query, groupItems); 322 323 for (int i = 0; i < resultList.length; i++) { 324 Expr subExpr = resultList[i]; 325 326 if (! (subExpr instanceof GroupExpr)) { 327 resultList[i] = new GroupResultExpr(i, subExpr); 328 } 329 } 330 } 331 332 token = scanToken(); 333 _token = token; 334 if (query.getParent() == null && 335 token >= 0 && token != LIMIT && token != OFFSET) 336 throw error(L.l("unexpected token at end '{0}'", tokenName(token))); 337 338 _query = query.getParent(); 339 _andExpr = oldAnd; 340 341 return query; 342 } 343 344 private ArrayList <FromItem> parseFromItems() 345 throws SQLException 346 { 347 ArrayList <FromItem> fromItems = new ArrayList <FromItem>(); 348 349 int token; 350 351 while ((token = scanToken()) == '(') { 353 } 354 _token = token; 355 356 FromItem fromItem = parseFromItem(); 357 358 if (fromItem != null) 359 fromItems.add(fromItem); 360 361 while (true) { 362 token = scanToken(); 363 364 boolean isNatural = false; 365 boolean isOuter = false; 366 boolean isLeft = true; 367 boolean isRight = true; 368 369 if (token == ',') { 370 fromItem = parseFromItem(); 371 fromItems.add(fromItem); 372 continue; 373 } 374 else if (token == '(' || token == ')') 375 continue; 376 else if (token != IDENTIFIER) { 377 _token = token; 378 break; 379 } 380 else if ("join".equalsIgnoreCase(_lexeme)) { 381 } 382 else if ("inner".equalsIgnoreCase(_lexeme)) { 383 String join = parseIdentifier(); 384 385 if (! "join".equalsIgnoreCase(join)) 386 throw error(L.l("expected JOIN at '{0}'", join)); 387 } 388 else if ("left".equalsIgnoreCase(_lexeme)) { 389 String name = parseIdentifier(); 390 391 if ("outer".equalsIgnoreCase(name)) 392 name = parseIdentifier(); 393 394 if (! "join".equalsIgnoreCase(name)) 395 throw error(L.l("expected JOIN at '{0}'", name)); 396 397 isOuter = true; 398 } 399 else if ("right".equalsIgnoreCase(_lexeme)) { 400 String name = parseIdentifier(); 401 402 if ("outer".equalsIgnoreCase(name)) 403 name = parseIdentifier(); 404 405 if (! "join".equalsIgnoreCase(name)) 406 throw error(L.l("expected JOIN at '{0}'", name)); 407 408 isRight = true; 409 isOuter = true; 410 411 throw error(L.l("right outer joins are not supported")); 412 } 413 else if ("natural".equalsIgnoreCase(_lexeme)) { 414 String name = parseIdentifier(); 415 416 isNatural = true; 417 418 if ("left".equalsIgnoreCase(name)) { 419 name = parseIdentifier(); 420 421 if ("outer".equalsIgnoreCase(name)) 422 name = parseIdentifier(); 423 424 isOuter = true; 425 } 426 else if ("right".equalsIgnoreCase(name)) { 427 name = parseIdentifier(); 428 429 if ("outer".equalsIgnoreCase(name)) 430 name = parseIdentifier(); 431 432 isRight = true; 433 isOuter = true; 434 435 throw error(L.l("right outer joins are not supported")); 436 } 437 438 if (! "join".equalsIgnoreCase(name)) 439 throw error(L.l("expected JOIN at '{0}'", name)); 440 } 441 else { 442 _token = token; 443 break; 444 } 445 446 fromItem = parseFromItem(); 447 fromItems.add(fromItem); 448 449 _query.setFromItems(fromItems); 450 451 token = scanToken(); 452 if (token == IDENTIFIER && "on".equalsIgnoreCase(_lexeme)) { 453 Expr onExpr = parseExpr(); 454 455 if (isOuter) { 456 FromItem leftItem = fromItems.get(fromItems.size() - 2); 457 FromItem rightItem = fromItems.get(fromItems.size() - 1); 458 459 onExpr = new LeftOuterJoinExpr(rightItem, onExpr); 460 461 rightItem.setDependTable(leftItem); 462 } 463 464 _andExpr.add(onExpr); 465 } 466 else 467 _token = token; 468 } 469 470 return fromItems; 471 } 472 473 476 private Expr parseSelectExpr() 477 throws SQLException 478 { 479 int token = scanToken(); 480 481 if (token == '*') 482 return new UnboundStarExpr(); 483 else { 484 _token = token; 485 486 return parseExpr(); 487 } 488 } 489 490 493 private FromItem parseFromItem() 494 throws SQLException 495 { 496 String tableName = parseIdentifier(); 497 498 if (tableName.equalsIgnoreCase("DUAL")) 499 return null; 500 501 Table table = _database.getTable(tableName); 502 503 if (table == null) 504 throw error(L.l("'{0}' is an unknown table. 'FROM table' requires an existing table.", tableName)); 505 506 String name = table.getName(); 507 508 int token = scanToken(); 509 if (token == AS) 510 name = parseIdentifier(); 511 else if (token == IDENTIFIER) 512 name = _lexeme; 513 else 514 _token = token; 515 516 return new FromItem(table, name); 517 } 518 519 522 private Order parseOrder(SelectQuery query, 523 ArrayList <Expr> resultList) 524 throws SQLException 525 { 526 int token; 527 528 Order order = null; 529 530 do { 531 Expr expr = parseExpr(); 532 533 expr = expr.bind(query); 534 535 token = scanToken(); 536 boolean isAsc = true; 537 if (token == ASC) 538 isAsc = true; 539 else if (token == DESC) 540 isAsc = false; 541 else 542 _token = token; 543 544 int index; 545 for (index = 0; index < resultList.size(); index++) { 546 Expr resultExpr = resultList.get(index); 547 548 if (expr.equals(resultExpr)) 549 break; 550 } 551 552 if (resultList.size() <= index) { 553 resultList.add(expr); 554 } 555 556 Order tailOrder = expr.createOrder(index); 557 tailOrder.setAscending(isAsc); 558 559 order = Order.append(order, tailOrder); 560 561 } while ((token = scanToken()) == ','); 563 564 query.setOrder(order); 565 566 _token = token; 567 568 return order; 569 } 570 571 574 private ArrayList <Expr> parseGroup(SelectQuery query) 575 throws SQLException 576 { 577 query.setGroup(true); 578 int token; 579 580 ArrayList <Expr> groupList = new ArrayList <Expr>(); 581 582 do { 583 groupList.add(parseExpr()); 584 } while ((token = scanToken()) == ','); 585 586 _token = token; 587 588 return groupList; 589 } 590 591 594 private void bindGroup(SelectQuery query, ArrayList <Expr> groupList) 595 throws SQLException 596 { 597 query.setGroup(true); 598 599 Expr []resultList = query.getResults(); 600 601 for (int i = 0; i < groupList.size(); i++) { 602 Expr expr = groupList.get(i); 603 604 expr = expr.bind(query); 605 606 int index; 607 for (index = 0; index < resultList.length; index++) { 608 Expr resultExpr = resultList[index]; 609 610 if (expr.equals(resultExpr)) { 611 resultList[index] = new GroupResultExpr(index, resultExpr); 612 613 break; 614 } 615 } 616 617 if (resultList.length <= index) { 618 throw error(L.l("GROUP BY field '{0}' must refer to a result field.", 619 expr)); 620 } 621 622 query.setGroupResult(index); 623 } 624 } 625 626 629 private Query parseCreate() 630 throws SQLException 631 { 632 int token; 633 634 TableFactory factory = _database.createTableFactory(); 635 636 if ((token = scanToken()) != TABLE) 637 throw error(L.l("expected TABLE at `{0}'", tokenName(token))); 638 639 if ((token = scanToken()) != IDENTIFIER) 640 throw error(L.l("expected identifier at `{0}'", tokenName(token))); 641 642 factory.startTable(_lexeme); 643 644 if ((token = scanToken()) != '(') 645 throw error(L.l("expected '(' at `{0}'", tokenName(token))); 646 647 do { 648 token = scanToken(); 649 650 switch (token) { 651 case IDENTIFIER: 652 parseCreateColumn(factory, _lexeme); 653 break; 654 655 case UNIQUE: 656 factory.addUnique(parseColumnNames()); 657 break; 658 659 case PRIMARY: 660 token = scanToken(); 661 if (token != KEY) 662 throw error(L.l("expected 'key' at {0}", tokenName(token))); 663 664 factory.addPrimaryKey(parseColumnNames()); 665 break; 666 667 case KEY: 668 String key = parseIdentifier(); 669 670 parseColumnNames(); break; 672 673 case CHECK: 674 if ((token = scanToken()) != '(') 675 throw error(L.l("Expected '(' at '{0}'", tokenName(token))); 676 677 parseExpr(); 678 679 if ((token = scanToken()) != ')') 680 throw error(L.l("Expected ')' at '{0}'", tokenName(token))); 681 break; 682 683 default: 684 throw error(L.l("unexpected token `{0}'", tokenName(token))); 685 } 686 687 token = scanToken(); 688 } while (token == ','); 689 690 if (token != ')') 691 throw error(L.l("expected ')' at `{0}'", tokenName(token))); 692 693 return new CreateQuery(_database, _sql, factory); 694 } 695 696 699 private void parseCreateColumn(TableFactory factory, String name) 700 throws SQLException 701 { 702 int token; 703 704 if ((token = scanToken()) != IDENTIFIER) 705 throw error(L.l("expected column type at {0}", tokenName(token))); 706 707 String type = _lexeme; 708 int length = -1; 709 int scale = -1; 710 711 if (type.equalsIgnoreCase("double")) { 712 if ((token = scanToken()) == IDENTIFIER) { 713 if (_lexeme.equalsIgnoreCase("precision")) { 714 } 715 else 716 throw error(L.l("unexpected double type at {0}", _lexeme)); 717 } 718 else 719 _token = token; 720 } 721 722 if ((token = scanToken()) == '(') { 723 if ((token = scanToken()) != INTEGER) 724 throw error(L.l("expected column width at `{0}'", tokenName(token))); 725 726 length = Integer.parseInt(_lexeme); 727 728 if ((token = scanToken()) == ',') { 729 if ((token = scanToken()) != INTEGER) 730 throw error(L.l("expected column scale at `{0}'", tokenName(token))); 731 732 scale = Integer.parseInt(_lexeme); 733 734 token = scanToken(); 735 } 736 737 if (token != ')') 738 throw error(L.l("expected ')' at '{0}'", tokenName(token))); 739 } 740 else 741 _token = token; 742 743 if (type.equalsIgnoreCase("varchar")) { 744 if (length < 0) 745 throw error(L.l("VARCHAR needs a defined length")); 746 747 factory.addVarchar(name, length); 748 } 749 else if (type.equalsIgnoreCase("char")) { 750 if (length < 0) 751 length = 1; 752 753 factory.addVarchar(name, length); 754 } 755 else if (type.equalsIgnoreCase("blob")) { 756 factory.addBlob(name); 757 } 758 else if (type.equalsIgnoreCase("integer") || 759 type.equalsIgnoreCase("int") || 760 type.equalsIgnoreCase("smallint") || 761 type.equalsIgnoreCase("tinyint") || 762 type.equalsIgnoreCase("mediumint") || 763 type.equalsIgnoreCase("bit")) { 764 factory.addInteger(name); 765 } 766 else if (type.equalsIgnoreCase("bigint")) { 767 factory.addLong(name); 768 } 769 else if (type.equalsIgnoreCase("double") || 770 type.equalsIgnoreCase("float") || 771 type.equalsIgnoreCase("real")) { 772 factory.addDouble(name); 773 } 774 else if (type.equalsIgnoreCase("datetime") || 775 type.equalsIgnoreCase("timestamp")) { 776 factory.addDateTime(name); 777 } 778 else if (type.equalsIgnoreCase("text") || 779 type.equalsIgnoreCase("clob")) { 780 factory.addVarchar(name, 255); 781 } 782 else if (type.equalsIgnoreCase("decimal") || 783 type.equalsIgnoreCase("numeric")) { 784 factory.addNumeric(name, length, scale); 785 } 786 else 787 throw error(L.l("Unknown type {0}", type)); 788 789 token = scanToken(); 790 if (token == IDENTIFIER && _lexeme.equalsIgnoreCase("default")) { 791 Expr defaultExpr = parseExpr(); 792 793 factory.setDefault(name, defaultExpr); 794 } 795 else 796 _token = token; 797 798 while (true) { 799 token = scanToken(); 800 801 803 switch (token) { 804 case ')': 805 case ',': 806 _token = token; 807 return; 808 809 case UNIQUE: 810 factory.setUnique(name); 811 break; 812 813 case PRIMARY: 814 token = scanToken(); 815 if (token != KEY) 816 throw error(L.l("expected key at {0}", tokenName(token))); 817 818 factory.setPrimaryKey(name); 819 break; 820 821 case CHECK: 822 if ((token = scanToken()) != '(') 823 throw error(L.l("Expected '(' at '{0}'", tokenName(token))); 824 825 parseExpr(); 826 827 if ((token = scanToken()) != ')') 828 throw error(L.l("Expected ')' at '{0}'", tokenName(token))); 829 break; 830 831 case IDENTIFIER: 832 String id = _lexeme; 833 if (id.equalsIgnoreCase("references")) { 834 ArrayList <String > foreignKey = new ArrayList <String >(); 835 foreignKey.add(name); 836 parseReferences(foreignKey); 837 } 838 else if (id.equalsIgnoreCase("default")) { 839 Expr expr = parseExpr(); 840 } 841 else if (id.equalsIgnoreCase("auto_increment")) { 842 factory.setAutoIncrement(name, 1); 843 } 844 else if (id.equalsIgnoreCase("unsigned")) { 845 } 846 else if (id.equalsIgnoreCase("binary")) { 847 } 848 else 849 throw error(L.l("unexpected token '{0}'", tokenName(token))); 850 break; 851 852 case NULL: 853 break; 854 855 case NOT: 856 if ((token = scanToken()) == NULL) 857 factory.setNotNull(name); 858 else 859 throw error(L.l("unexpected token '{0}'", tokenName(token))); 860 break; 861 862 default: 863 throw error(L.l("unexpected token '{0}'", tokenName(token))); 864 } 865 } 866 } 867 868 871 private void parseKeyConstraint(TableFactory factory) 872 throws SQLException 873 { 874 String key = parseIdentifier(); 875 876 int token = scanToken(); 877 878 if (token == '(') { 879 parseIdentifier(); 880 881 token = scanToken(); 882 if (token != ')') 883 throw error("expected ')'"); 884 } 885 else 886 _token = token; 887 } 888 889 892 public void parseReferences(ArrayList <String > name) 893 throws SQLException 894 { 895 String foreignTable = parseIdentifier(); 896 897 int token = scanToken(); 898 899 ArrayList <String > foreignColumns = new ArrayList <String >(); 900 901 if (token == '(') { 902 _token = token; 903 904 foreignColumns = parseColumnNames(); 905 } 906 else 907 _token = token; 908 } 909 910 913 public ArrayList <String > parseColumnNames() 914 throws SQLException 915 { 916 ArrayList <String > columns = new ArrayList <String >(); 917 918 int token = scanToken(); 919 if (token == '(') { 920 do { 921 columns.add(parseIdentifier()); 922 923 token = scanToken(); 924 } while (token == ','); 925 926 if (token != ')') 927 throw error(L.l("expected ')' at '{0}'", tokenName(token))); 928 } 929 else if (token == IDENTIFIER) { 930 columns.add(_lexeme); 931 932 _token = token; 933 } 934 else 935 throw error(L.l("expected '(' at '{0}'", tokenName(token))); 936 937 return columns; 938 } 939 940 943 private Query parseInsert() 944 throws SQLException 945 { 946 int token; 947 948 if ((token = scanToken()) != INTO) 949 throw error(L.l("expected INTO at `{0}'", tokenName(token))); 950 951 if ((token = scanToken()) != IDENTIFIER) 952 throw error(L.l("expected identifier at `{0}'", tokenName(token))); 953 954 Table table = _database.getTable(_lexeme); 955 956 if (table == null) 957 throw error(L.l("unknown table `{0}'", tokenName(token))); 958 959 FromItem fromItem = new FromItem(table, table.getName()); 960 FromItem[] fromList = new FromItem[] { fromItem }; 961 962 ArrayList <Column> columns = new ArrayList <Column>(); 963 964 if ((token = scanToken()) == '(') { 965 do { 966 String columnName = parseIdentifier(); 967 968 Column column = table.getColumn(columnName); 969 970 if (column == null) 971 throw new SQLException (L.l("`{0}' is not a valid column in {1}", 972 columnName, table.getName())); 973 columns.add(column); 974 } while ((token = scanToken()) == ','); 975 976 if (token != ')') 977 throw error(L.l("expected ')' at `{0}'", tokenName(token))); 978 979 token = scanToken(); 980 } 981 else { 982 Column []columnArray = table.getColumns(); 983 984 for (int i = 0; i < columnArray.length; i++) 985 columns.add(columnArray[i]); 986 } 987 988 if (token != VALUES) 989 throw error(L.l("expected VALUES at `{0}'", tokenName(token))); 990 991 if ((token = scanToken()) != '(') 992 throw error(L.l("expected '(' at `{0}'", tokenName(token))); 993 994 ArrayList <Expr> values = new ArrayList <Expr>(); 995 996 InsertQuery query = new InsertQuery(_database, _sql, table, columns); 997 _query = query; 998 999 int i = 0; 1000 do { 1001 Expr expr = parseExpr(); 1002 1003 expr = expr.bind(new TempQuery(fromList)); 1004 1005 values.add(expr); 1006 1007 i++; 1008 } while ((token = scanToken()) == ','); 1009 1010 if (token != ')') 1011 throw error(L.l("expected ')' at {0}", tokenName(token))); 1012 1013 if (columns.size() != values.size()) 1014 throw error(L.l("number of columns does not match number of values")); 1015 1016 ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]); 1017 1018 query.setParams(params); 1019 query.setValues(values); 1020 query.init(); 1021 1022 return query; 1023 } 1024 1025 1028 private Query parseDelete() 1029 throws SQLException 1030 { 1031 int token; 1032 1033 if ((token = scanToken()) != FROM) 1034 throw error(L.l("expected FROM at `{0}'", tokenName(token))); 1035 1036 if ((token = scanToken()) != IDENTIFIER) 1037 throw error(L.l("expected identifier at `{0}'", tokenName(token))); 1038 1039 Table table = _database.getTable(_lexeme); 1040 1041 if (table == null) 1042 throw error(L.l("unknown table `{0}'", tokenName(token))); 1043 1044 DeleteQuery query = new DeleteQuery(_database, _sql, table); 1045 _query = query; 1046 1047 Expr whereExpr = null; 1048 1049 token = scanToken(); 1050 if (token == WHERE) 1051 whereExpr = parseExpr(); 1052 else if (token >= 0) 1053 throw error(L.l("expected WHERE at `{0}'", tokenName(token))); 1054 1055 ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]); 1056 1057 query.setParams(params); 1058 query.setWhereExpr(whereExpr); 1059 1060 return query; 1061 } 1062 1063 1066 private Query parseDrop() 1067 throws SQLException 1068 { 1069 int token; 1070 1071 if ((token = scanToken()) != TABLE) 1072 throw error(L.l("expected TABLE at `{0}'", tokenName(token))); 1073 1074 if ((token = scanToken()) != IDENTIFIER) 1075 throw error(L.l("expected identifier at `{0}'", tokenName(token))); 1076 1077 String table = _lexeme; 1078 1079 if ((token = scanToken()) >= 0) 1080 throw error(L.l("expected end of query at `{0}'", tokenName(token))); 1081 1082 return new DropQuery(_sql, _database, table); 1083 } 1084 1085 1088 private Query parseUpdate() 1089 throws SQLException 1090 { 1091 int token; 1092 1093 if ((token = scanToken()) != IDENTIFIER) 1094 throw error(L.l("expected identifier at `{0}'", tokenName(token))); 1095 1096 String name = _lexeme; 1097 1098 Table table = _database.getTable(name); 1099 1100 if (table == null) 1101 throw error(L.l("`{0}' is an unknown table in INSERT.", name)); 1102 1103 if ((token = scanToken()) != SET) 1104 throw error(L.l("expected SET at {0}", tokenName(token))); 1105 1106 UpdateQuery query = new UpdateQuery(_database, _sql, table); 1107 _query = query; 1108 1109 ArrayList <SetItem> setItemList = new ArrayList <SetItem>(); 1110 1111 do { 1112 SetItem item = parseSetItem(table); 1113 1114 setItemList.add(item); 1115 } while ((token = scanToken()) == ','); 1116 1117 Expr whereExpr = null; 1118 1119 if (token == WHERE) 1120 whereExpr = parseExpr(); 1121 1122 SetItem []setItems = new SetItem[setItemList.size()]; 1123 setItemList.toArray(setItems); 1124 1125 ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]); 1126 1127 query.setSetItems(setItems); 1128 query.setParams(params); 1129 query.setWhereExpr(whereExpr); 1130 1131 return query; 1132 } 1133 1134 1137 private SetItem parseSetItem(Table table) 1138 throws SQLException 1139 { 1140 int token; 1141 1142 if ((token = scanToken()) != IDENTIFIER) 1143 throw error(L.l("expected identifier at `{0}'", tokenName(token))); 1144 1145 Column column = table.getColumn(_lexeme); 1146 1147 if (column == null) 1148 throw error(L.l("`{0}' is an unknown column in table {1}.", 1149 _lexeme, table.getName())); 1150 1151 if ((token = scanToken()) != EQ) 1152 throw error(L.l("expected `=' at {0}", tokenName(token))); 1153 1154 Expr expr = parseExpr(); 1155 1156 return new SetItem(table, column, expr); 1157 } 1158 1159 1162 private Expr parseExpr() 1163 throws SQLException 1164 { 1165 int token = scanToken(); 1166 1167 if (token == SELECT) 1168 return parseSubSelect(); 1169 else { 1170 _token = token; 1171 return parseOrExpr(); 1172 } 1173 } 1174 1175 1178 private Expr parseSubSelect() 1179 throws SQLException 1180 { 1181 return parseSubSelect(new SelectQuery(_database, _sql)); 1182 } 1183 1184 1187 private Expr parseSubSelect(SelectQuery query) 1188 throws SQLException 1189 { 1190 parseSelect(query); 1191 1192 SubSelectExpr expr = new SubSelectExpr(query); 1193 1194 query.setSubSelect(expr); 1195 1196 _andExpr.add(new SubSelectEvalExpr(expr)); 1197 1198 return expr; 1199 } 1200 1201 1204 private Expr parseOrExpr() 1205 throws SQLException 1206 { 1207 Expr left = parseAndExpr(); 1208 1209 while (true) { 1210 int token = scanToken(); 1211 1212 switch (token) { 1213 case OR: 1214 left = new OrExpr(left, parseAndExpr()); 1215 break; 1216 1217 default: 1218 _token = token; 1219 return left; 1220 } 1221 } 1222 } 1223 1224 1227 private Expr parseAndExpr() 1228 throws SQLException 1229 { 1230 AndExpr oldAndExpr = _andExpr; 1231 AndExpr andExpr = new AndExpr(); 1232 _andExpr = andExpr; 1233 1234 andExpr.add(parseNotExpr()); 1235 1236 while (true) { 1237 int token = scanToken(); 1238 1239 switch (token) { 1240 case AND: 1241 andExpr.add(parseNotExpr()); 1242 break; 1243 1244 default: 1245 _token = token; 1246 1247 _andExpr = oldAndExpr; 1248 1249 return andExpr.getSingleExpr(); 1250 } 1251 } 1252 } 1253 1254 1257 private Expr parseNotExpr() 1258 throws SQLException 1259 { 1260 int token = scanToken(); 1261 1262 switch (token) { 1263 case NOT: 1264 return new NotExpr(parseNotExpr()); 1265 1266 default: 1267 _token = token; 1268 return parseCmpExpr(); 1269 } 1270 } 1271 1272 1275 private Expr parseCmpExpr() 1276 throws SQLException 1277 { 1278 Expr left = parseConcatExpr(); 1279 1280 int token = scanToken(); 1281 boolean isNot = false; 1282 1283 if (token == NOT) { 1284 isNot = true; 1285 1286 token = scanToken(); 1287 1288 if (token != BETWEEN && token != LIKE && token != IN) { 1289 _token = token; 1290 1291 return left; 1292 } 1293 } 1294 1295 switch (token) { 1296 case EQ: 1297 return new EqExpr(left, parseConcatExpr()); 1298 1299 case LT: 1300 case LE: 1301 case GT: 1302 case GE: 1303 case NE: 1304 return new CmpExpr(left, parseConcatExpr(), token); 1305 1306 case BETWEEN: 1307 { 1308 Expr min = parseConcatExpr(); 1309 1310 token = scanToken(); 1311 if (token != AND) 1312 throw error(L.l("expected AND at '{0}'", tokenName(token))); 1313 1314 Expr max = parseConcatExpr(); 1315 1316 return new BetweenExpr(left, min, max, isNot); 1317 } 1318 1319 case IS: 1320 { 1321 token = scanToken(); 1322 isNot = false; 1323 if (token == NOT) { 1324 token = scanToken(); 1325 isNot = true; 1326 } 1327 1328 if (token == NULL) 1329 return new IsNullExpr(left, isNot); 1330 else 1331 throw error(L.l("expected NULL at '{0}'", tokenName(token))); 1332 } 1333 1334 case LIKE: 1335 { 1336 token = scanToken(); 1337 1338 if (token == STRING) 1339 return new LikeExpr(left, _lexeme, isNot); 1340 else 1341 throw error(L.l("expected string at '{0}'", tokenName(token))); 1342 } 1343 1344 case IN: 1345 { 1346 HashSet <String > values = parseInValues(); 1347 1348 return new InExpr(left, values, isNot); 1349 } 1350 1351 default: 1352 _token = token; 1353 return left; 1354 } 1355 } 1356 1357 1360 private HashSet <String > parseInValues() 1361 throws SQLException 1362 { 1363 int token = scanToken(); 1364 1365 if (token != '(') 1366 throw error(L.l("Expected '('")); 1367 1368 HashSet <String > values = new HashSet <String >(); 1369 1370 while ((token = scanToken()) != ')') { 1371 if (token == STRING) { 1372 values.add(_lexeme); 1373 } 1374 else 1375 throw error(L.l("expected STRING at {0}", tokenName(token))); 1376 1377 if ((token = scanToken()) != ',') 1378 break; 1379 } 1380 1381 if (token != ')') 1382 throw error(L.l("expected ')' at {0}", tokenName(token))); 1383 1384 return values; 1385 } 1386 1387 1390 private Expr parseConcatExpr() 1391 throws SQLException 1392 { 1393 Expr left = parseAddExpr(); 1394 1395 while (true) { 1396 int token = scanToken(); 1397 1398 switch (token) { 1399 case CONCAT: 1400 left = new ConcatExpr(left, parseAddExpr()); 1401 break; 1402 1403 default: 1404 _token = token; 1405 return left; 1406 } 1407 } 1408 } 1409 1410 1413 private Expr parseAddExpr() 1414 throws SQLException 1415 { 1416 Expr left = parseMulExpr(); 1417 1418 while (true) { 1419 int token = scanToken(); 1420 1421 switch (token) { 1422 case '+': 1423 case '-': 1424 left = new BinaryExpr(left, parseMulExpr(), token); 1425 break; 1426 1427 default: 1428 _token = token; 1429 return left; 1430 } 1431 } 1432 } 1433 1434 1437 private Expr parseMulExpr() 1438 throws SQLException 1439 { 1440 Expr left = parseTerm(); 1441 1442 while (true) { 1443 int token = scanToken(); 1444 1445 switch (token) { 1446 case '*': 1447 case '/': 1448 case '%': 1449 left = new BinaryExpr(left, parseTerm(), token); 1450 break; 1451 1452 default: 1453 _token = token; 1454 return left; 1455 } 1456 } 1457 } 1458 1459 1462 private Expr parseTerm() 1463 throws SQLException 1464 { 1465 int token = scanToken(); 1466 1467 switch (token) { 1468 case '+': 1469 return parseTerm(); 1470 1471 case '-': 1472 return new UnaryExpr(parseTerm(), token); 1473 1474 case '(': 1475 Expr expr = parseExpr(); 1476 int peekToken; 1477 if ((peekToken = scanToken()) != ')') 1478 throw error(L.l("expected ')' at {0}", tokenName(peekToken))); 1479 return expr; 1480 1481 default: 1482 _token = token; 1483 return parseSimpleTerm(); 1484 } 1485 } 1486 1487 1490 private Expr parseSimpleTerm() 1491 throws SQLException 1492 { 1493 int token = scanToken(); 1494 1495 switch (token) { 1496 case IDENTIFIER: 1497 { 1498 String name = _lexeme; 1499 1500 token = scanToken(); 1501 if (token == '.') { 1502 token = scanToken(); 1503 1504 if (token == IDENTIFIER) { 1505 String column = _lexeme; 1506 return _query.bind(name, column); 1507 } 1508 else if (token == '*') { 1509 return new UnboundStarExpr(name); 1510 } 1511 else 1512 throw error("expected IDENTIFIER"); 1513 } 1514 else if (token == '(') { 1515 FunExpr fun = null; 1516 if (name.equalsIgnoreCase("max")) 1517 fun = new MaxExpr(); 1518 else if (name.equalsIgnoreCase("min")) 1519 fun = new MinExpr(); 1520 else if (name.equalsIgnoreCase("sum")) 1521 fun = new SumExpr(); 1522 else if (name.equalsIgnoreCase("avg")) 1523 fun = new AvgExpr(); 1524 else if (name.equalsIgnoreCase("count")) { 1525 fun = new CountExpr(); 1526 1527 token = scanToken(); 1528 if (token == '*') { 1529 fun.addArg(new UnboundStarExpr()); 1530 } 1531 else 1532 _token = token; 1533 } 1534 else if (name.equalsIgnoreCase("exists")) { 1535 token = scanToken(); 1536 1537 if (token != SELECT) 1538 throw error(L.l("exists requires SELECT at '{0}'", 1539 tokenName(token))); 1540 1541 ExistsQuery query = new ExistsQuery(_database, _sql); 1542 1543 parseSelect(query); 1544 1545 ExistsExpr expr = new ExistsExpr(query); 1546 1547 query.setSubSelect(expr); 1548 1549 _andExpr.add(new ExistsEvalExpr(expr)); 1550 1551 token = scanToken(); 1552 1553 if (token != ')') 1554 throw error(L.l("exists requires ')' at '{0}'", 1555 tokenName(token))); 1556 1557 return expr; 1558 } 1559 else { 1560 String funName = (Character.toUpperCase(name.charAt(0)) + 1561 name.substring(1).toLowerCase()); 1562 1563 funName = "com.caucho.db.fun." + funName + "Expr"; 1564 1565 try { 1566 Class cl = Class.forName(funName); 1567 1568 fun = (FunExpr) cl.newInstance(); 1569 } catch (ClassNotFoundException e) { 1570 log.finer(e.toString()); 1571 } catch (Throwable e) { 1572 log.log(Level.FINER, e.toString(), e); 1573 } 1574 1575 if (fun == null) 1576 throw error(L.l("`{0}' is an unknown function.", name)); 1577 } 1578 1579 token = scanToken(); 1580 while (token > 0 && token != ')') { 1581 _token = token; 1582 1583 Expr arg = parseExpr(); 1584 1585 fun.addArg(arg); 1586 1587 token = scanToken(); 1588 1589 if (token == ',') 1590 token = scanToken(); 1591 } 1592 1593 return fun; 1594 } 1595 else { 1596 _token = token; 1597 return _query.bind(null, name); 1598 } 1599 } 1600 1601 case STRING: 1602 return new StringExpr(_lexeme); 1603 1604 case DOUBLE: 1605 case INTEGER: 1606 case LONG: 1607 return NumberExpr.create(_lexeme); 1608 1609 case NULL: 1610 return new NullExpr(); 1611 1612 case TRUE: 1613 return BooleanLiteralExpr.create(true); 1614 1615 case FALSE: 1616 return BooleanLiteralExpr.create(false); 1617 1618 case '?': 1619 ParamExpr param = new ParamExpr(_params.size()); 1620 _params.add(param); 1621 return param; 1622 1623 default: 1624 throw error(L.l("unexpected term {0}", tokenName(token))); 1625 } 1626 } 1627 1628 1631 private String parseIdentifier() 1632 throws SQLException 1633 { 1634 int token = scanToken(); 1635 1636 if (token != IDENTIFIER) 1637 throw error(L.l("expected identifier at {0}", tokenName(token))); 1638 1639 return _lexeme; 1640 } 1641 1642 1648 private int scanToken() 1649 throws SQLException 1650 { 1651 if (_token > 0) { 1652 int value = _token; 1653 _token = -1; 1654 return value; 1655 } 1656 1657 int sign = 1; 1658 int ch; 1659 1660 for (ch = read(); Character.isWhitespace((char) ch); ch = read()) { 1661 } 1662 1663 switch (ch) { 1664 case -1: 1665 case '(': 1666 case ')': 1667 case '.': 1668 case '*': 1669 case '/': 1670 case '%': 1671 case ',': 1672 case '?': 1673 return ch; 1674 1675 case '+': 1676 if ((ch = read()) >= '0' && ch <= '9') 1677 break; 1678 else { 1679 unread(ch); 1680 return '+'; 1681 } 1682 1683 case '-': 1684 if ((ch = read()) >= '0' && ch <= '9') { 1685 sign = -1; 1686 break; 1687 } 1688 else { 1689 unread(ch); 1690 return '-'; 1691 } 1692 1693 case '=': 1694 return EQ; 1695 1696 case '<': 1697 if ((ch = read()) == '=') 1698 return LE; 1699 else if (ch == '>') 1700 return NE; 1701 else { 1702 unread(ch); 1703 return LT; 1704 } 1705 1706 case '>': 1707 if ((ch = read()) == '=') 1708 return GE; 1709 else { 1710 unread(ch); 1711 return GT; 1712 } 1713 1714 case '|': 1715 if ((ch = read()) == '|') 1716 return CONCAT; 1717 else { 1718 throw error(L.l("'|' expected at {0}", charName(ch))); 1719 } 1720 1721 case '@': 1723 if ((ch = read()) != '@') 1724 throw error(L.l("`@' expected at {0}", charName(ch))); 1725 return scanToken(); 1726 } 1727 1728 if (Character.isJavaIdentifierStart((char) ch)) { 1729 CharBuffer cb = _cb; 1730 cb.clear(); 1731 1732 for (; ch > 0 && Character.isJavaIdentifierPart((char) ch); ch = read()) 1733 cb.append((char) ch); 1734 1735 unread(ch); 1736 1737 _lexeme = cb.toString(); 1738 String lower = _lexeme.toLowerCase(); 1739 1740 int token = _reserved.get(lower); 1741 1742 if (token > 0) 1743 return token; 1744 else 1745 return IDENTIFIER; 1746 } 1747 else if (ch >= '0' && ch <= '9') { 1748 CharBuffer cb = _cb; 1749 cb.clear(); 1750 1751 int type = INTEGER; 1752 1753 if (sign < 0) 1754 cb.append('-'); 1755 1756 for (; ch >= '0' && ch <= '9'; ch = read()) 1757 cb.append((char) ch); 1758 1759 if (ch == '.') { 1760 type = DOUBLE; 1761 1762 cb.append('.'); 1763 for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) 1764 cb.append((char) ch); 1765 } 1766 1767 if (ch == 'e' || ch == 'E') { 1768 type = DOUBLE; 1769 1770 cb.append('e'); 1771 if ((ch = read()) == '+' || ch == '-') { 1772 cb.append((char) ch); 1773 ch = read(); 1774 } 1775 1776 if (! (ch >= '0' && ch <= '9')) 1777 throw error(L.l("exponent needs digits at {0}", 1778 charName(ch))); 1779 1780 for (; ch >= '0' && ch <= '9'; ch = read()) 1781 cb.append((char) ch); 1782 } 1783 1784 if (ch == 'F' || ch == 'D') 1785 type = DOUBLE; 1786 else if (ch == 'L') { 1787 type = LONG; 1788 } 1789 else 1790 unread(ch); 1791 1792 _lexeme = cb.toString(); 1793 1794 return type; 1795 } 1796 else if (ch == '\'') { 1797 CharBuffer cb = _cb; 1798 cb.clear(); 1799 1800 for (ch = read(); ch >= 0; ch = read()) { 1801 if (ch == '\'') { 1802 if ((ch = read()) == '\'') 1803 cb.append('\''); 1804 else { 1805 unread(ch); 1806 break; 1807 } 1808 } 1809 else if (ch == '\\') { 1810 ch = read(); 1811 1812 if (ch >= 0) 1813 cb.append(ch); 1814 } 1815 else 1816 cb.append((char) ch); 1817 } 1818 1819 _lexeme = cb.toString(); 1820 1821 return STRING; 1822 } 1823 else if (ch == '#') { 1824 while ((ch = read()) >= 0 && ch != '\n' && ch != '\r') { 1826 } 1827 1828 return scanToken(); 1830 } 1831 1832 throw error(L.l("unexpected char at {0} ({1})", "" + (char) ch, 1833 String.valueOf(ch))); 1834 } 1835 1836 1839 private int read() 1840 { 1841 if (_parseIndex < _sqlLength) 1842 return _sqlChars[_parseIndex++]; 1843 else 1844 return -1; 1845 } 1846 1847 1850 private void unread(int ch) 1851 { 1852 if (ch >= 0) 1853 _parseIndex--; 1854 } 1855 1856 1859 private String charName(int ch) 1860 { 1861 if (ch < 0) 1862 return L.l("end of query"); 1863 else 1864 return String.valueOf((char) ch); 1865 } 1866 1867 1870 private String tokenName(int token) 1871 { 1872 switch (token) { 1873 case AS: return "AS"; 1874 case ARG: return "?"; 1875 case FROM: return "FROM"; 1876 case IN: return "IN"; 1877 case SELECT: return "SELECT"; 1878 case WHERE: return "WHERE"; 1879 case OR: return "OR"; 1880 case AND: return "AND"; 1881 case NOT: return "NOT"; 1882 case BETWEEN: return "BETWEEN"; 1883 case TRUE: return "TRUE"; 1884 case FALSE: return "FALSE"; 1885 case NULL: return "NULL"; 1886 case GROUP: return "GROUP"; 1887 case ORDER: return "ORDER"; 1888 case BY: return "BY"; 1889 case ASC: return "ASC"; 1890 case DESC: return "DESC"; 1891 case LIMIT: return "LIMIT"; 1892 1893 case -1: 1894 return L.l("end of query"); 1895 1896 default: 1897 if (token < 128) 1898 return "'" + String.valueOf((char) token) + "'"; 1899 else 1900 return "'" + _lexeme + "'"; 1901 } 1902 } 1903 1904 private SQLException error(String msg) 1905 { 1906 return new SQLParseException(msg + "\n" + _sql); 1907 } 1908 1909 static { 1910 _reserved = new IntMap(); 1911 _reserved.put("as", AS); 1912 _reserved.put("from", FROM); 1913 _reserved.put("in", IN); 1914 _reserved.put("select", SELECT); 1915 _reserved.put("distinct", DISTINCT); 1916 _reserved.put("where", WHERE); 1917 _reserved.put("order", ORDER); 1918 _reserved.put("group", GROUP); 1919 _reserved.put("by", BY); 1920 _reserved.put("asc", ASC); 1921 _reserved.put("desc", DESC); 1922 _reserved.put("limit", LIMIT); 1923 _reserved.put("offset", OFFSET); 1924 1925 _reserved.put("or", OR); 1926 _reserved.put("and", AND); 1927 _reserved.put("not", NOT); 1928 1929 _reserved.put("between", BETWEEN); 1930 _reserved.put("like", LIKE); 1931 _reserved.put("escape", ESCAPE); 1932 _reserved.put("is", IS); 1933 1934 _reserved.put("true", TRUE); 1935 _reserved.put("false", FALSE); 1936 _reserved.put("unknown", UNKNOWN); 1937 _reserved.put("null", NULL); 1938 1939 _reserved.put("create", CREATE); 1940 _reserved.put("table", TABLE); 1941 _reserved.put("insert", INSERT); 1942 _reserved.put("into", INTO); 1943 _reserved.put("values", VALUES); 1944 _reserved.put("drop", DROP); 1945 _reserved.put("update", UPDATE); 1946 _reserved.put("set", SET); 1947 _reserved.put("delete", DELETE); 1948 1949 _reserved.put("constraint", CONSTRAINT); 1950 _reserved.put("unique", UNIQUE); 1951 _reserved.put("check", CHECK); 1952 _reserved.put("primary", PRIMARY); 1953 _reserved.put("key", KEY); 1954 _reserved.put("foreign", FOREIGN); 1955 } 1956} 1957 | Popular Tags |