1 29 30 package com.caucho.amber.query; 31 32 import com.caucho.amber.AmberException; 33 import com.caucho.amber.entity.AmberEntityHome; 34 import com.caucho.amber.expr.*; 35 import com.caucho.amber.expr.fun.*; 36 import com.caucho.amber.manager.AmberPersistenceUnit; 37 import com.caucho.amber.table.ForeignColumn; 38 import com.caucho.amber.table.LinkColumns; 39 import com.caucho.amber.table.Table; 40 import com.caucho.amber.type.EntityType; 41 import com.caucho.log.Log; 42 import com.caucho.util.CharBuffer; 43 import com.caucho.util.IntMap; 44 import com.caucho.util.L10N; 45 46 import javax.sql.DataSource ; 47 import java.sql.Connection ; 48 import java.sql.ResultSet ; 49 import java.sql.SQLException ; 50 import java.sql.Statement ; 51 import java.util.ArrayList ; 52 import java.util.HashMap ; 53 import java.util.Map ; 54 import java.util.logging.Level ; 55 import java.util.logging.Logger ; 56 57 61 public class QueryParser { 62 static final Logger log = Log.open(QueryParser.class); 63 static final L10N L = new L10N(QueryParser.class); 64 65 public final static int IDENTIFIER = 128; 66 public final static int INTEGER = IDENTIFIER + 1; 67 public final static int LONG = INTEGER + 1; 68 public final static int DOUBLE = LONG + 1; 69 public final static int STRING = DOUBLE + 1; 70 public final static int TRUE = STRING + 1; 71 public final static int FALSE = TRUE + 1; 72 public final static int UNKNOWN = FALSE + 1; 73 public final static int MEMBER = UNKNOWN + 1; 74 public final static int OF = MEMBER + 1; 75 public final static int EMPTY = OF + 1; 76 public final static int NULL = EMPTY + 1; 77 78 public final static int FROM = NULL + 1; 79 public final static int IN = FROM + 1; 80 public final static int SELECT = IN + 1; 81 public final static int UPDATE = SELECT + 1; 82 public final static int DELETE = UPDATE + 1; 83 public final static int DISTINCT = DELETE + 1; 84 public final static int WHERE = DISTINCT + 1; 85 public final static int AS = WHERE + 1; 86 public final static int SET = AS + 1; 87 public final static int ORDER = SET + 1; 88 public final static int GROUP = ORDER + 1; 89 public final static int BY = GROUP + 1; 90 public final static int ASC = BY + 1; 91 public final static int DESC = ASC + 1; 92 public final static int LIMIT = DESC + 1; 93 public final static int OFFSET = LIMIT + 1; 94 95 public final static int JOIN = OFFSET + 1; 96 public final static int INNER = JOIN + 1; 97 public final static int LEFT = INNER + 1; 98 public final static int OUTER = LEFT + 1; 99 public final static int FETCH = OUTER + 1; 100 101 public final static int BETWEEN = FETCH + 1; 102 public final static int LIKE = BETWEEN + 1; 103 public final static int ESCAPE = LIKE + 1; 104 public final static int IS = ESCAPE + 1; 105 106 public final static int CONCAT_OP = IS + 1; 107 108 public final static int EQ = CONCAT_OP + 1; 109 public final static int NE = EQ + 1; 110 public final static int LT = NE + 1; 111 public final static int LE = LT + 1; 112 public final static int GT = LE + 1; 113 public final static int GE = GT + 1; 114 115 public final static int AND = GE + 1; 116 public final static int OR = AND + 1; 117 public final static int NOT = OR + 1; 118 119 public final static int LENGTH = NOT + 1; 120 public final static int LOCATE = LENGTH + 1; 121 122 public final static int ABS = LOCATE + 1; 123 public final static int SQRT = ABS + 1; 124 public final static int MOD = SQRT + 1; 125 public final static int SIZE = MOD + 1; 126 127 public final static int MAX = SIZE + 1; 128 public final static int MIN = MAX + 1; 129 public final static int SUM = MIN + 1; 130 131 public final static int CONCAT = SUM + 1; 132 public final static int LOWER = CONCAT + 1; 133 public final static int UPPER = LOWER + 1; 134 public final static int SUBSTRING = UPPER + 1; 135 public final static int TRIM = SUBSTRING + 1; 136 137 public final static int BOTH = TRIM + 1; 138 public final static int LEADING = BOTH + 1; 139 public final static int TRAILING = LEADING + 1; 140 141 public final static int CURRENT_DATE = TRAILING + 1; 142 public final static int CURRENT_TIME = CURRENT_DATE + 1; 143 public final static int CURRENT_TIMESTAMP = CURRENT_TIME + 1; 144 145 public final static int EXTERNAL_DOT = CURRENT_TIMESTAMP + 1; 146 147 public final static int ARG = EXTERNAL_DOT + 1; 148 public final static int NAMED_ARG = ARG + 1; 149 150 public final static int NEW = NAMED_ARG + 1; 151 152 public final static int THIS = NEW + 1; 153 154 public final static int NOT_NULL = THIS + 1; 155 156 public final static int HAVING = NOT_NULL + 1; 157 158 private static IntMap _reserved; 159 160 private AmberPersistenceUnit _amberPersistenceUnit; 161 162 private String _sql; 164 165 173 174 private boolean _isLazyResult; 176 177 private AbstractQuery _query; 179 180 private HashMap <PathExpr,PathExpr> _pathMap 182 = new HashMap <PathExpr,PathExpr>(); 183 184 private int _parseIndex; 186 private int _token; 188 private int _unique; 190 private int _parameterCount; 192 private String _lexeme; 194 195 private ArrayList <ArgExpr> _argList = new ArrayList <ArgExpr>(); 196 197 private HashMap <AmberExpr, String > _joinFetchMap; 198 199 ArrayList <AmberExpr> _groupList = null; 200 201 private int _sqlArgCount; 202 203 private FromItem.JoinSemantics _joinSemantics 204 = FromItem.JoinSemantics.UNKNOWN; 205 206 private boolean _isJoinFetch = false; 207 208 private int _depth = 0; 211 212 private boolean _parsingResult; 213 private boolean _parsingFrom; 214 private boolean _parsingHaving; 215 216 private boolean _isSizeFunExpr; 218 private AmberExpr _havingExpr; 219 ArrayList <AmberExpr> _appendResultList = null; 221 222 private boolean _isDerbyDBMS; 223 private boolean _isPostgresDBMS; 224 225 228 public QueryParser(String query) 229 { 230 _sql = query; 231 } 232 233 236 public boolean isDerbyDBMS() 237 { 238 return _isDerbyDBMS; 239 } 240 241 244 public boolean isPostgresDBMS() 245 { 246 return _isPostgresDBMS; 247 } 248 249 252 public void setAmberManager(AmberPersistenceUnit amberPersistenceUnit) 253 { 254 _amberPersistenceUnit = amberPersistenceUnit; 255 256 _isDerbyDBMS = false; 257 _isPostgresDBMS = false; 258 259 if (amberPersistenceUnit == null) 260 return; 261 262 try { 263 Connection conn = null; 264 265 try { 266 DataSource ds = amberPersistenceUnit.getDataSource(); 267 conn = ds.getConnection(); 268 269 Statement stmt = conn.createStatement(); 270 271 try { 272 String sql = "select position('a' in 'abc')"; 273 274 ResultSet rs = stmt.executeQuery(sql); 275 rs.close(); 276 277 } catch (SQLException e) { 278 _isDerbyDBMS = true; 279 log.log(Level.FINER, e.toString(), e); 280 } 281 282 try { 283 String sql = "select false"; 284 285 ResultSet rs = stmt.executeQuery(sql); 286 rs.close(); 287 288 _isPostgresDBMS = true; 289 290 } catch (SQLException e) { 291 log.log(Level.FINER, e.toString(), e); 292 } 293 } catch (Exception e) { 294 log.log(Level.WARNING, e.toString(), e); 295 } finally { 296 if (conn != null) 297 conn.close(); 298 } 299 } catch (Exception e) { 300 log.log(Level.WARNING, e.toString(), e); 301 } 302 } 303 304 307 public void setLazyResult(boolean isLazy) 308 { 309 _isLazyResult = isLazy; 310 } 311 312 315 public String getQuery() 316 { 317 return _sql; 318 } 319 320 323 public AbstractQuery getSelectQuery() 324 { 325 return _query; 326 } 327 328 331 private void init() 332 { 333 _parseIndex = 0; 334 _unique = 0; 335 _token = -1; 336 _depth = 0; 337 _parsingResult = false; 338 _parsingFrom = false; 339 _parsingHaving = false; 340 _havingExpr = null; 341 _appendResultList = null; 342 _groupList = null; 343 _joinFetchMap = new HashMap <AmberExpr, String >(); 344 } 345 346 349 public int generateSQLArg() 350 { 351 return _sqlArgCount++; 352 } 353 354 357 public AbstractQuery parse() 358 throws AmberException 359 { 360 368 369 init(); 370 371 int token = scanToken(); 372 if (token == UPDATE) 373 return parseUpdate(); 374 else if (token == DELETE) 375 return parseDelete(); 376 377 _token = token; 378 return parseSelect(false); 379 } 380 381 private SelectQuery parseSelect(boolean innerSelect) 382 throws QueryParseException 383 { 384 int oldParseIndex = _parseIndex; 385 int oldToken = _token; 386 FromItem.JoinSemantics oldJoinSemantics = _joinSemantics; 387 boolean oldIsJoinFetch = _isJoinFetch; 388 AbstractQuery oldQuery = _query; 389 int oldDepth = _depth; 390 AmberExpr oldHavingExpr = _havingExpr; 391 ArrayList oldAppendResultList = _appendResultList; 392 393 _depth = 0; 395 396 _havingExpr = null; 397 _appendResultList = null; 398 399 SelectQuery query = new SelectQuery(_sql); 400 query.setParentQuery(_query); 401 _query = query; 402 403 int token; 404 while ((token = scanToken()) >= 0 && 405 ((token != FROM) || (_depth > 0))) { 406 } 407 408 boolean hasFrom = (token == FROM); 410 411 _token = token; 412 413 if (hasFrom) { 414 415 _parsingFrom = true; 416 417 do { 418 419 scanToken(); 420 421 _isJoinFetch = false; 422 423 if (token == JOIN) { 424 if ((token = peekToken()) == FETCH) { 425 scanToken(); 426 _isJoinFetch = true; 427 } 428 } 429 430 FromItem from = parseFrom(); 431 432 token = peekToken(); 433 434 _joinSemantics = FromItem.JoinSemantics.UNKNOWN; 435 436 if (token == INNER) { 437 scanToken(); 438 439 token = peekToken(); 440 441 if (token != JOIN) { 442 throw error(L.l("expected JOIN at {0}", tokenName(token))); 443 } 444 445 _joinSemantics = FromItem.JoinSemantics.INNER; 446 } 447 else if (token == LEFT) { 448 scanToken(); 449 450 token = peekToken(); 451 452 if (token == OUTER) { 453 scanToken(); 454 455 token = peekToken(); 456 } 457 458 if (token != JOIN) 459 throw error(L.l("expected JOIN at {0}", tokenName(token))); 460 461 _joinSemantics = FromItem.JoinSemantics.OUTER; 462 } 463 else if (token == JOIN) { 464 _joinSemantics = FromItem.JoinSemantics.INNER; 465 } 466 467 } while ((token == ',') || 468 (token == JOIN)); 469 470 _parsingFrom = false; 471 } 472 473 int fromParseIndex = _parseIndex; 474 int fromToken = _token; 475 476 _parseIndex = oldParseIndex; 477 _token = oldToken; 478 479 ArrayList <AmberExpr> resultList = new ArrayList <AmberExpr>(); 480 481 if (peekToken() == SELECT) { 482 scanToken(); 483 484 if (peekToken() == DISTINCT) { 485 scanToken(); 486 query.setDistinct(true); 487 } 488 489 String constructorName = null; 490 491 if (peekToken() == NEW) { 492 493 scanToken(); 494 495 497 String s = ""; 498 499 boolean isDot = false; 500 501 while ((token = scanToken()) != '(') { 502 503 if (! isDot) { 504 s += _lexeme; 505 isDot = true; 506 } 507 else if (token == '.') { 508 s += '.'; 509 isDot = false; 510 } 511 else 512 throw error(L.l("Constructor with SELECT NEW must be fully qualified. Expected '.' at {0}", tokenName(token))); 513 } 514 515 constructorName = s; 516 } 517 518 do { 519 520 AmberExpr expr = parseExpr(); 521 522 if (! hasFrom) { 523 if (! (expr instanceof DateTimeFunExpr)) 524 throw error(L.l("expected FROM clause when the select clause has not date/time functions only")); 525 } 526 else { 527 528 if (expr == null) 530 continue; 531 532 expr = expr.bindSelect(this); 533 534 if (_isLazyResult) { 535 } 536 else if (expr instanceof PathExpr) { 537 PathExpr pathExpr = (PathExpr) expr; 538 539 expr = LoadExpr.create(pathExpr); 540 541 expr = expr.bindSelect(this); 542 } 543 } 544 545 resultList.add(expr); 546 } while ((token = scanToken()) == ','); 547 548 query.setHasFrom(hasFrom); 549 550 if (hasFrom && (constructorName != null)) { 551 552 if (token != ')') 553 throw error(L.l("Expected ')' at {0} when calling constructor with SELECT NEW", tokenName(token))); 554 555 token = scanToken(); 556 557 try { 558 559 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 560 561 Class cl = Class.forName(constructorName, false, loader); 562 563 query.setConstructorClass(cl); 564 565 } catch (ClassNotFoundException ex) { 566 throw error(L.l("Unable to find class {0}. Make sure the class is fully qualified.", constructorName)); 567 } 568 } 569 570 _token = token; 571 } 572 573 if (hasFrom && (peekToken() != FROM)) 574 throw error(L.l("expected FROM at {0}", tokenName(token))); 575 576 _parsingResult = true; 577 578 if (resultList.size() == 0) { 579 580 if (_joinFetchMap.size() > 0) 581 throw error(L.l("All associations referenced by JOIN FETCH must belong to an entity that is returned as a result of the query")); 582 583 ArrayList <FromItem> fromList = _query.getFromList(); 584 585 if (fromList.size() > 0) { 586 FromItem fromItem = fromList.get(0); 587 588 AmberExpr expr = fromItem.getIdExpr(); 589 590 if (_isLazyResult) { 591 } 592 else if (expr instanceof PathExpr) { 593 PathExpr pathExpr = (PathExpr) expr; 594 595 expr = LoadExpr.create(pathExpr); 596 expr = expr.bindSelect(this); 597 } 598 599 resultList.add(expr); 600 } 601 } 602 else if (hasFrom) { 603 604 int size = resultList.size(); 605 606 int matches = 0; 607 608 for (int i = 0; i < size; i++) { 609 610 AmberExpr expr = resultList.get(i); 611 612 if (expr instanceof LoadEntityExpr) { 613 614 expr = ((LoadEntityExpr) expr).getExpr(); 615 616 if (_joinFetchMap.get(expr) != null) { 617 matches++; 618 } 619 } 620 } 621 622 if (matches < _joinFetchMap.size()) 623 throw error(L.l("All associations referenced by JOIN FETCH must belong to an entity that is returned as a result of the query")); 624 625 } 626 627 if (_appendResultList != null) 629 resultList.addAll(_appendResultList); 630 631 query.setResultList(resultList); 632 633 _parsingResult = false; 634 635 _parseIndex = fromParseIndex; 636 _token = fromToken; 637 638 token = peekToken(); 639 640 if (token == WHERE) { 641 scanToken(); 642 643 AmberExpr expr = parseExpr(); 644 645 if (expr != null) { 647 expr = expr.createBoolean(); 648 649 query.setWhere(expr.bindSelect(this)); 650 } 651 } 652 653 boolean hasGroupBy = false; 654 655 ArrayList <AmberExpr> groupList = _groupList; 656 657 token = peekToken(); 658 if (token == GROUP) { 659 scanToken(); 660 661 if (peekToken() == BY) { 662 scanToken(); 663 hasGroupBy = true; 664 } 665 666 if (groupList == null) 667 groupList = new ArrayList <AmberExpr>(); 668 669 while (true) { 670 AmberExpr groupExpr = parseExpr(); 672 673 groupExpr = groupExpr.bindSelect(this); 674 675 if (groupExpr instanceof PathExpr) { 676 678 PathExpr pathExpr = (PathExpr) groupExpr; 679 680 groupExpr = LoadExpr.create(pathExpr); 681 682 groupExpr = groupExpr.bindSelect(this); 683 } 684 685 groupList.add(groupExpr); 686 687 if (peekToken() == ',') 688 scanToken(); 689 else 690 break; 691 } 692 693 query.setGroupList(groupList); 694 695 _groupList = null; 697 } 698 699 token = peekToken(); 700 if (token == HAVING) { 701 702 if (! hasGroupBy) 703 throw error(L.l("Use of HAVING without GROUP BY is not currently supported")); 704 705 _parsingHaving = true; 706 707 scanToken(); 708 709 AmberExpr havingExpr = parseExpr(); 710 711 if (_havingExpr != null) 713 havingExpr = AndExpr.create(havingExpr, _havingExpr); 714 715 query.setHaving(havingExpr.createBoolean().bindSelect(this)); 716 717 _parsingHaving = false; 718 } 719 else if (_havingExpr != null) query.setHaving(_havingExpr.createBoolean().bindSelect(this)); 721 722 token = peekToken(); 723 if (token == ORDER) { 724 scanToken(); 725 726 if (peekToken() == BY) 727 scanToken(); 728 729 ArrayList <AmberExpr> orderList = new ArrayList <AmberExpr>(); 730 ArrayList <Boolean > ascList = new ArrayList <Boolean >(); 731 732 while (true) { 733 AmberExpr expr = parseExpr(); 734 expr = expr.bindSelect(this); 735 736 orderList.add(expr); 737 738 if (peekToken() == DESC) { 739 scanToken(); 740 ascList.add(Boolean.FALSE); 741 } 742 else if (peekToken() == ASC) { 743 scanToken(); 744 ascList.add(Boolean.TRUE); 745 } 746 else 747 ascList.add(Boolean.TRUE); 748 749 if (peekToken() == ',') 750 scanToken(); 751 else 752 break; 753 } 754 755 query.setOrderList(orderList, ascList); 756 } 757 758 token = peekToken(); 759 760 if (! innerSelect) { 761 762 query.setJoinFetchMap(_joinFetchMap); 763 764 if (token > 0) 765 throw error(L.l("expected end of query at {0}", tokenName(token))); 766 767 if (! query.setArgList(_argList.toArray(new ArgExpr[_argList.size()]))) 768 throw error(L.l("Unable to parse all query parameters. Make sure named parameters are not mixed with positional parameters")); 769 770 } 771 772 try { 773 query.init(); 774 } catch (SQLException e) { 775 throw new QueryParseException(e); 776 } 777 778 _joinSemantics = oldJoinSemantics; 779 _isJoinFetch = oldIsJoinFetch; 780 _query = oldQuery; 781 _depth = oldDepth; 782 _havingExpr = oldHavingExpr; 783 _appendResultList = oldAppendResultList; 784 785 return query; 786 } 787 788 private AbstractQuery parseUpdate() 789 throws QueryParseException 790 { 791 UpdateQuery query = new UpdateQuery(_sql); 792 _query = query; 793 794 FromItem fromItem = parseFrom(); 795 796 int token = scanToken(); 797 if (token != SET) 798 throw error(L.l("expected 'SET' at {0}", tokenName(token))); 799 800 ArrayList <AmberExpr> fields = new ArrayList <AmberExpr>(); 801 ArrayList <AmberExpr> values = new ArrayList <AmberExpr>(); 802 803 parseSetValues(fromItem, fields, values); 804 805 query.setFieldList(fields); 806 query.setValueList(values); 807 808 token = scanToken(); 809 if (token == WHERE) { 810 query.setWhere(parseExpr().createBoolean().bindSelect(this)); 811 812 token = scanToken(); 813 } 814 815 if (token >= 0) 816 throw error(L.l("'{0}' not expected at end of query.", tokenName(token))); 817 818 if (! query.setArgList(_argList.toArray(new ArgExpr[_argList.size()]))) 819 throw error(L.l("Unable to parse all query parameters. Make sure named parameters are not mixed with positional parameters")); 820 821 query.init(); 822 823 return query; 824 } 825 826 private AbstractQuery parseDelete() 827 throws QueryParseException 828 { 829 DeleteQuery query = new DeleteQuery(_sql); 830 _query = query; 831 832 int token = peekToken(); 833 if (token == FROM) 834 scanToken(); 835 836 FromItem fromItem = parseFrom(); 837 838 token = scanToken(); 839 if (token == WHERE) { 840 query.setWhere(parseExpr().createBoolean().bindSelect(this)); 841 842 token = scanToken(); 843 } 844 845 if (token >= 0) 846 throw error(L.l("'{0}' not expected at end of query.", tokenName(token))); 847 848 if (! query.setArgList(_argList.toArray(new ArgExpr[_argList.size()]))) 849 throw error(L.l("Unable to parse all query parameters. Make sure named parameters are not mixed with positional parameters")); 850 851 query.init(); 852 853 return query; 854 } 855 856 859 private void parseSetValues(FromItem fromItem, 860 ArrayList <AmberExpr> fields, 861 ArrayList <AmberExpr> values) 862 throws QueryParseException 863 { 864 EntityType entity = fromItem.getEntityType(); 865 866 int token = -1; 867 868 do { 869 870 token = scanToken(); 871 872 AmberExpr expr = null; 873 874 String name = _lexeme.toString(); 875 876 IdExpr tableExpr = getIdentifier(name); 877 878 if (tableExpr != null) { 879 expr = parsePath(tableExpr); 880 } 881 else { 882 883 tableExpr = fromItem.getIdExpr(); 884 885 AmberExpr next = tableExpr.createField(this, name); 886 887 if (next instanceof PathExpr) 888 expr = addPath((PathExpr) next); 889 else if (next != null) 890 expr = next; 891 } 892 893 expr = expr.bindSelect(this); 894 895 fields.add(expr); 896 897 if ((token = peekToken()) != EQ) 898 throw error(L.l("expected '=' at {0}", tokenName(token))); 899 900 scanToken(); 901 902 expr = parseConcatExpr(); 904 905 expr = expr.bindSelect(this); 906 907 values.add(expr); 908 909 } while ((token = scanToken()) == ','); 910 911 _token = token; 912 } 913 914 922 private FromItem parseFrom() 923 throws QueryParseException 924 { 925 SchemaExpr schema = parseSchema(); 926 927 String id; 928 929 int token = peekToken(); 930 if (token == AS) { 931 scanToken(); 932 token = peekToken(); 933 id = parseIdentifier(); 934 } 935 else if (token == IDENTIFIER) 936 id = parseIdentifier(); 937 else { 938 id = schema.getTailName(); 939 } 940 941 948 949 FromItem item = schema.addFromItem(this, id); 950 951 if (schema instanceof EmbeddedSchemaExpr) { 952 953 955 EmbeddedSchemaExpr embeddedSchema = (EmbeddedSchemaExpr) schema; 956 957 _query.addEmbeddedAlias(id, embeddedSchema.getExpr()); } 959 960 item.setJoinSemantics(_joinSemantics); 962 963 return item; 964 } 965 966 969 public FromItem addFromItem(Table table) 970 { 971 return addFromItem(table, createTableName()); 972 } 973 974 977 public String createTableName() 978 { 979 return "caucho" + _unique++; 980 } 981 982 985 public FromItem addFromItem(Table table, String id) 986 { 987 if (id == null) 988 id = createTableName(); 989 990 FromItem item = _query.createFromItem(table, id); 991 992 item.setJoinSemantics(_joinSemantics); 993 994 return item; 995 } 996 997 1000 public FromItem createDependentFromItem(FromItem item, 1001 LinkColumns link) 1002 { 1003 item = _query.createDependentFromItem(item, link, createTableName()); 1004 1005 item.setJoinSemantics(_joinSemantics); 1006 1007 return item; 1008 } 1009 1010 1013 void addLink(AmberExpr expr) 1014 { 1015 throw new IllegalStateException (); 1017 } 1018 1019 1022 public PathExpr addPath(PathExpr path) 1023 { 1024 PathExpr oldPath = _pathMap.get(path); 1025 1026 if (oldPath != null) 1027 return oldPath; 1028 1029 _pathMap.put(path, path); 1030 1031 return path; 1032 } 1033 1034 1037 public void addArg(ArgExpr arg) 1038 { 1039 _argList.add(arg); 1040 } 1041 1042 1045 private SchemaExpr parseSchema() 1046 throws QueryParseException 1047 { 1048 int token = peekToken(); 1049 boolean isIn = token == IN; 1050 1051 if (isIn) { 1052 1053 scanToken(); 1054 1055 _joinSemantics = FromItem.JoinSemantics.INNER; 1056 1057 if ((token = scanToken()) != '(') 1058 throw error(L.l("expected '(' at '{0}'", tokenName(token))); 1059 } 1060 1061 String name = parseIdentifier(); 1062 1063 SchemaExpr schema = null; 1064 1065 if (! isIn) { 1066 AmberEntityHome home = _amberPersistenceUnit.getHomeBySchema(name); 1067 1068 if (home != null) { 1069 EntityType type = home.getEntityType(); 1070 1071 schema = new TableIdExpr(home.getEntityType(), 1072 type.getTable().getName()); 1073 } 1074 } 1075 1076 IdExpr id = null; 1077 1078 if (schema == null) { 1079 id = getIdentifier(name); 1080 1081 if (id != null) 1082 schema = new FromIdSchemaExpr(id); 1083 } 1084 1085 if (! isIn && schema == null) { 1086 while (peekToken() == '.') { 1087 scanToken(); 1088 String segment = parseIdentifier(); 1089 1090 name = name + '.' + segment; 1091 1092 AmberEntityHome home = _amberPersistenceUnit.getHomeBySchema(name); 1093 1094 if (home != null) { 1095 schema = new TableIdExpr(home.getEntityType(), name); 1096 break; 1097 } 1098 } 1099 } 1100 1101 if (schema == null) { 1102 throw error(L.l("'{0}' is an unknown entity.", 1103 name)); 1104 } 1105 1106 name = ""; 1107 boolean isFirst = true; 1108 1109 while (peekToken() == '.') { 1110 scanToken(); 1111 String segment = parseIdentifier(); 1112 1113 if (isFirst) { 1114 name += segment; 1115 isFirst = false; 1116 } 1117 else 1118 name += "." + segment; 1119 1120 schema = schema.createField(this, segment); 1121 } 1122 1123 if (_isJoinFetch && (! name.equals(""))) { 1124 _joinFetchMap.put(id, name); 1125 } 1126 1127 if (isIn) { 1128 if ((token = scanToken()) != ')') 1129 throw error(L.l("expected ')' at '{0}'", tokenName(token))); 1130 } 1131 1132 return schema; 1133 } 1134 1135 1138 private AmberExpr parseExpr() 1139 throws QueryParseException 1140 { 1141 if (peekToken() == SELECT) { 1142 SelectQuery select = parseSelect(true); 1143 1144 return new SubSelectExpr(select); 1145 } 1146 1147 AmberExpr expr = parseOrExpr(); 1148 1149 return expr; } 1151 1152 1155 private AmberExpr parseOrExpr() 1156 throws QueryParseException 1157 { 1158 AmberExpr expr = parseAndExpr(); 1159 OrExpr orExpr = null; 1160 1161 while (peekToken() == OR) { 1162 scanToken(); 1163 1164 if (orExpr == null) { 1165 orExpr = new OrExpr(); 1166 orExpr.add(expr); 1167 } 1168 1169 AmberExpr andExpr = parseAndExpr(); 1170 1171 if (andExpr == null) 1172 continue; 1173 1174 orExpr.add(andExpr); 1175 } 1176 1177 return orExpr == null ? expr : orExpr; 1178 } 1179 1180 1183 private AmberExpr parseAndExpr() 1184 throws QueryParseException 1185 { 1186 AmberExpr expr = parseNotExpr(); 1187 AndExpr andExpr = null; 1188 1189 while (peekToken() == AND) { 1190 scanToken(); 1191 1192 if (andExpr == null) { 1193 andExpr = new AndExpr(); 1194 andExpr.add(expr); 1195 } 1196 1197 AmberExpr notExpr = parseNotExpr(); 1198 1199 if (notExpr == null) 1200 continue; 1201 1202 andExpr.add(notExpr); 1203 } 1204 1205 return andExpr == null ? expr : andExpr; 1206 } 1207 1208 1212 private AmberExpr parseNotExpr() 1213 throws QueryParseException 1214 { 1215 AmberExpr expr; 1216 1217 if (peekToken() == NOT) { 1218 scanToken(); 1219 1220 expr = new UnaryExpr(NOT, parseCmpExpr()); 1221 } 1222 else 1223 expr = parseCmpExpr(); 1224 1225 1227 if (_parsingResult || _parsingHaving) 1228 return expr; 1229 1230 if (! _isSizeFunExpr) 1231 return expr; 1232 1233 _isSizeFunExpr = false; 1234 1235 if (_havingExpr == null) 1236 _havingExpr = expr; 1237 else 1238 _havingExpr = AndExpr.create(_havingExpr, expr); 1239 1240 return null; 1241 } 1242 1243 1256 private AmberExpr parseCmpExpr() 1257 throws QueryParseException 1258 { 1259 AmberExpr expr = parseConcatExpr(); 1260 1261 int token = peekToken(); 1262 boolean isNot = false; 1263 1264 if (token == NOT) { 1265 scanToken(); 1266 isNot = true; 1267 token = peekToken(); 1268 1269 if (token != BETWEEN && 1270 token != LIKE && 1271 token != MEMBER && 1272 token != IN) 1273 throw error(L.l("'NOT' is not expected here.")); 1274 } 1275 1276 if (token >= EQ && token <= GE) { 1277 scanToken(); 1278 1279 return parseIs(new BinaryExpr(token, expr, parseConcatExpr())); 1280 } 1281 else if (token == BETWEEN) { 1282 scanToken(); 1283 1284 AmberExpr min = parseConcatExpr(); 1285 1286 if ((token = scanToken()) != AND) 1287 throw error(L.l("Expected 'AND' at {0}", tokenName(token))); 1288 1289 AmberExpr max = parseConcatExpr(); 1290 1291 return new BetweenExpr(expr, min, max, isNot); 1292 } 1293 else if (token == LIKE) { 1294 scanToken(); 1295 1296 AmberExpr pattern = parseConcatExpr(); 1297 1298 String escape = null; 1299 if (peekToken() == ESCAPE) { 1300 scanToken(); 1301 1302 if ((token = scanToken()) != STRING) 1303 throw error(L.l("Expected string at {0}", tokenName(token))); 1304 1305 escape = _lexeme.toString(); 1306 } 1307 1308 return parseIs(new LikeExpr(expr, pattern, escape, isNot)); 1309 } 1310 else if (token == IN) { 1311 scanToken(); 1312 token = scanToken(); 1313 1314 if (token != '(') 1315 throw error(L.l("Expected '(' after IN at {0}", tokenName(token))); 1316 1317 ArrayList <AmberExpr> args = new ArrayList <AmberExpr>(); 1318 while ((token = peekToken()) > 0 && token != ')') { 1319 AmberExpr arg = parseExpr(); 1320 1321 args.add(arg); 1322 1323 token = peekToken(); 1324 if (token == ',') { 1325 scanToken(); 1326 token = peekToken(); 1327 } 1328 } 1329 1330 if (peekToken() != ')') 1331 throw error(L.l("Expected ')' after IN at {0}", tokenName(token))); 1332 1333 scanToken(); 1334 1335 return new InExpr(expr, args, isNot); 1336 } 1337 else if (token == MEMBER) { 1338 scanToken(); 1339 1340 token = peekToken(); 1341 if (token == OF) 1342 token = scanToken(); 1343 1344 AmberExpr collection = parseExpr(); 1345 1346 if (expr instanceof ArgExpr) { 1348 addArg((ArgExpr) expr); 1349 } 1350 else if (! (expr instanceof PathExpr)) 1351 throw error(L.l("MEMBER OF requires an entity-valued item.")); 1352 1353 if ((collection instanceof ManyToOneExpr) && 1356 (((ManyToOneExpr) collection).getParent() instanceof OneToManyExpr)) { 1357 } 1358 else if (collection instanceof OneToManyExpr) { 1359 } 1360 else if (collection instanceof CollectionIdExpr) { 1361 } 1362 else { 1363 throw error(L.l("MEMBER OF requires an entity-valued collection at '{0}'.", 1364 collection.getClass().getName())); 1365 } 1366 1367 return parseIs(MemberExpr.create(this, 1368 expr, 1369 collection, 1370 isNot)); 1371 } 1372 else 1373 return parseIs(expr); 1374 } 1375 1376 private AmberExpr parseIs(AmberExpr expr) 1377 throws QueryParseException 1378 { 1379 int token = peekToken(); 1380 1381 if (token != IS) 1382 return expr; 1383 1384 scanToken(); 1385 1386 boolean isNot = false; 1387 token = scanToken(); 1388 1389 if (token == NOT) { 1390 isNot = true; 1391 token = scanToken(); 1392 } 1393 1394 if (token == NULL) { 1395 1396 if (expr instanceof KeyColumnExpr) 1397 expr = ((KeyColumnExpr) expr).getParent(); 1398 1399 if (isNot) 1400 return new UnaryExpr(NOT_NULL, expr); 1401 else 1402 return new UnaryExpr(NULL, expr); 1403 } 1404 else if (token == EMPTY) { 1405 1406 expr = new EmptyExpr(expr); 1407 1408 if (! isNot) 1409 expr = new UnaryExpr(NOT, expr); 1410 1411 return expr; 1412 } 1413 else 1414 throw error(L.l("expected NULL at '{0}'", tokenName(token))); 1415 } 1416 1417 1420 private AmberExpr parseConcatExpr() 1421 throws QueryParseException 1422 { 1423 AmberExpr expr = parseAddExpr(); 1424 1425 while (true) { 1426 int token = peekToken(); 1427 1428 switch (token) { 1429 case CONCAT_OP: 1430 scanToken(); 1431 1432 ArrayList <AmberExpr> args = new ArrayList <AmberExpr>(); 1433 1434 args.add(expr); 1435 args.add(parseAddExpr()); 1436 1437 expr = ConcatFunExpr.create(this, args); 1438 break; 1439 default: 1440 return expr; 1441 } 1442 } 1443 } 1444 1445 1448 private AmberExpr parseAddExpr() 1449 throws QueryParseException 1450 { 1451 AmberExpr expr = parseMulExpr(); 1452 1453 while (true) { 1454 int token = peekToken(); 1455 1456 switch (token) { 1457 case '+': 1458 case '-': 1459 scanToken(); 1460 expr = new BinaryExpr(token, expr, parseMulExpr()); 1461 break; 1462 default: 1463 return expr; 1464 } 1465 } 1466 } 1467 1468 1471 private AmberExpr parseMulExpr() 1472 throws QueryParseException 1473 { 1474 AmberExpr expr = parseTerm(); 1475 1476 while (true) { 1477 int token = peekToken(); 1478 1479 switch (token) { 1480 case '*': 1481 case '/': 1482 scanToken(); 1483 expr = new BinaryExpr(token, expr, parseTerm()); 1484 break; 1485 default: 1486 return expr; 1487 } 1488 } 1489 } 1490 1491 1500 private AmberExpr parseTerm() 1501 throws QueryParseException 1502 { 1503 int token = peekToken(); 1504 1505 switch (token) { 1506 case '+': 1507 case '-': 1508 case NOT: 1509 scanToken(); 1510 1511 return new UnaryExpr(token, parseTerm()); 1512 1513 default: 1514 return parseSimpleTerm(); 1515 } 1516 } 1517 1518 1529 private AmberExpr parseSimpleTerm() 1530 throws QueryParseException 1531 { 1532 int token = scanToken(); 1533 1534 switch (token) { 1535 case IDENTIFIER: 1536 case LOCATE: 1537 case LENGTH: 1538 case MAX: 1539 case MIN: 1540 case SUM: 1541 case ABS: 1542 case SQRT: 1543 case MOD: 1544 case SIZE: 1545 case CONCAT: 1546 case LOWER: 1547 case UPPER: 1548 case SUBSTRING: 1549 case TRIM: 1550 { 1551 String name = _lexeme.toString(); 1552 1553 if (peekToken() != '(') { 1554 AbstractPathExpr tableExpr = getIdentifier(name); 1556 1557 if (tableExpr == null) { 1558 tableExpr = getEmbeddedAlias(name); 1560 } 1561 1562 if (tableExpr == null) { 1563 AmberExpr amberExpr = parseEnum(name); 1565 1566 if (amberExpr != null) 1567 return amberExpr; 1568 } 1569 1570 if (tableExpr != null) { 1571 AmberExpr amberExpr = parsePath(tableExpr); 1572 1573 return amberExpr; 1574 } 1575 1576 if (_query.getFromList().size() == 0) 1577 throw error(L.l("Expected a FROM clause before '{0}'", name)); 1578 1579 FromItem fromItem = _query.getFromList().get(0); 1580 1581 tableExpr = fromItem.getIdExpr(); 1582 1583 AmberExpr next = tableExpr.createField(this, name); 1584 1585 if (next instanceof PathExpr) 1586 return addPath((PathExpr) next); 1587 else if (next != null) 1588 return next; 1589 1590 throw error(L.l("'{0}' is an unknown table or column", name)); 1591 } 1592 else { 1593 1594 name = name.toLowerCase(); 1595 1596 if (name.equals("exists") || 1598 name.equals("all") || 1599 name.equals("any") || 1600 name.equals("some")) { 1601 1602 scanToken(); 1603 1604 if (peekToken() != SELECT && peekToken() != FROM) 1605 throw error(L.l(name.toUpperCase() + " requires '(SELECT'")); 1606 1607 SelectQuery select = parseSelect(true); 1608 1609 if (peekToken() != ')') 1610 throw error(L.l(name.toUpperCase() + " requires ')'")); 1611 1612 scanToken(); 1613 1614 ArrayList <FromItem> parentFromList; 1615 parentFromList = select.getParentQuery().getFromList(); 1616 1617 select.getFromList().addAll(0, parentFromList); 1619 1620 if (name.equals("exists")) 1621 return new ExistsExpr(select); 1622 else if (name.equals("all")) 1623 return new AllExpr(select); 1624 else return new AnyExpr(select); 1626 } 1627 else { 1628 return parseFunction(name, token); 1629 } 1630 } 1631 } 1632 1633 case CURRENT_DATE: 1634 case CURRENT_TIME: 1635 case CURRENT_TIMESTAMP: 1636 { 1637 String name = _lexeme.toString(); 1638 1639 return parseFunction(name, token); 1640 } 1641 1642 case FALSE: 1643 return new LiteralExpr(this, _lexeme, boolean.class); 1644 1645 case TRUE: 1646 return new LiteralExpr(this, _lexeme, boolean.class); 1647 1648 case NULL: 1649 return new NullExpr(); 1650 1651 case INTEGER: 1652 return new LiteralExpr(this, _lexeme, int.class); 1653 1654 case LONG: 1655 return new LiteralExpr(this, _lexeme, long.class); 1656 1657 case DOUBLE: 1658 return new LiteralExpr(this, _lexeme, double.class); 1659 1660 case STRING: 1661 return new LiteralExpr(this, _lexeme, String .class); 1662 1663 case ARG: 1664 { 1665 ArgExpr arg = new ArgExpr(this, Integer.parseInt(_lexeme)); 1666 1670 return arg; 1671 } 1672 1673 case NAMED_ARG: 1674 { 1675 ArgExpr arg = new ArgExpr(this, _lexeme, _parameterCount); 1676 return arg; 1677 } 1678 1679 1691 1692 case '(': 1693 AmberExpr expr = parseExpr(); 1694 if ((token = scanToken()) != ')') 1695 throw error(L.l("expected `)' at {0}", tokenName(token))); 1696 1697 return expr; 1698 1699 1700 default: 1701 throw error(L.l("expected term at {0}", tokenName(token))); 1702 } 1703 } 1704 1705 1713 private AmberExpr parsePath(PathExpr path) 1714 throws QueryParseException 1715 { 1716 while (peekToken() == '.') { 1717 scanToken(); 1718 1719 String field = parseIdentifier(); 1720 1721 AmberExpr next = path.createField(this, field); 1722 1723 if (next == null) 1724 throw error(L.l("'{0}' does not have a field '{1}'", 1725 path, field)); 1726 1727 if (! (next instanceof PathExpr)) 1728 return next; 1729 1730 PathExpr nextPath = addPath((PathExpr) next); 1731 1732 if (peekToken() == '[') { 1733 scanToken(); 1734 1735 AmberExpr index = parseExpr(); 1736 1737 next = nextPath.createArray(index); 1738 1739 if (next == null) 1740 throw error(L.l("'{0}' does not have a map field '{1}'", 1741 path, field)); 1742 1743 if (peekToken() != ']') { 1744 throw error(L.l("expected ']' at '{0}'", tokenName(peekToken()))); 1745 } 1746 1747 scanToken(); 1748 } 1749 1750 if (next instanceof PathExpr) 1751 path = addPath((PathExpr) next); 1752 else 1753 return next; 1754 } 1755 1756 return path; 1757 } 1758 1759 1766 private EnumExpr parseEnum(String head) 1767 throws QueryParseException 1768 { 1769 CharBuffer cb = CharBuffer.allocate(); 1770 1771 int token; 1772 1773 while ((token = scanToken()) == '.') { 1774 1775 if (cb.length() > 0) 1776 cb.append('.'); 1777 1778 cb.append(head); 1779 1780 token = scanToken(); 1781 1782 if (token != IDENTIFIER) 1783 throw error(L.l("expected identifier for enumerated type {0} at {1}", 1784 cb.toString(), 1785 tokenName(token))); 1786 1787 head = _lexeme.toString(); 1788 } 1789 1790 int value = -1; 1791 Class cl = null; 1792 1793 try { 1794 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 1795 1796 cl = Class.forName(cb.toString(), false, loader); 1797 1798 Enum enumValue = Enum.valueOf(cl, head); 1799 1800 value = enumValue.ordinal(); 1801 } catch (ClassNotFoundException e) { 1802 return null; 1805 } 1806 1807 return new EnumExpr(cl, head, value); 1808 } 1809 1810 1818 private AmberExpr parseFunction(String id, 1819 int functionToken) 1820 throws QueryParseException 1821 { 1822 switch (functionToken) { 1824 1825 case CURRENT_DATE: 1826 return CurrentDateFunExpr.create(this); 1827 1828 case CURRENT_TIME: 1829 return CurrentTimeFunExpr.create(this); 1830 1831 case CURRENT_TIMESTAMP: 1832 return CurrentTimestampFunExpr.create(this); 1833 } 1834 1835 1837 scanToken(); 1838 1839 AmberExpr trimChar = null; 1841 TrimFunExpr.TrimSemantics trimSemantics 1842 = TrimFunExpr.TrimSemantics.BOTH; 1843 boolean distinct = false; 1844 1845 ArrayList <AmberExpr> args = new ArrayList <AmberExpr>(); 1846 1847 if (functionToken == TRIM) { 1848 1849 switch (peekToken()) { 1850 1851 case LEADING: 1852 trimSemantics = TrimFunExpr.TrimSemantics.LEADING; 1853 scanToken(); 1854 break; 1855 1856 case TRAILING: 1857 trimSemantics = TrimFunExpr.TrimSemantics.TRAILING; 1858 scanToken(); 1859 break; 1860 1861 case BOTH: 1862 scanToken(); 1863 break; 1864 1865 } 1867 1868 AmberExpr arg = null; 1869 1870 if (peekToken() != FROM) { 1871 1872 arg = parseExpr(); 1873 1874 if (arg instanceof LiteralExpr) { 1875 1876 String v = ((LiteralExpr) arg).getValue(); 1877 1878 if (v.length() != 3) throw error(L.l("expected a single char expression for TRIM at {0}", v)); 1880 } 1881 } 1882 1883 if (peekToken() == FROM) { 1884 scanToken(); 1885 1886 trimChar = arg; 1887 1888 arg = parseExpr(); 1889 } 1890 1891 args.add(arg); 1892 } 1893 else { 1894 1895 if (peekToken() == DISTINCT) { 1896 distinct = true; 1897 scanToken(); 1898 } 1899 1900 while ((peekToken() >= 0) && (peekToken() != ')')) { 1901 1902 AmberExpr arg = parseExpr(); 1903 1904 if (id.equalsIgnoreCase("object")) { 1905 if (arg instanceof PathExpr) { 1906 PathExpr pathExpr = (PathExpr) arg; 1907 1908 arg = LoadExpr.create(pathExpr); 1909 1910 arg = arg.bindSelect(this); 1911 1912 int token = scanToken(); 1913 1914 if (token != ')') 1915 throw error(L.l("expected ')' at '{0}'", tokenName(token))); 1916 1917 return arg; 1918 } 1919 } 1920 1921 args.add(arg); 1922 1923 if (peekToken() != ',') 1924 break; 1925 1926 scanToken(); 1927 } 1928 } 1929 1930 if (peekToken() != ')') 1931 throw error(L.l("expected ')' at '{0}'", tokenName(scanToken()))); 1932 1933 scanToken(); 1934 1935 FunExpr funExpr; 1936 1937 switch (functionToken) { 1938 1939 case LOCATE: 1940 funExpr = LocateFunExpr.create(this, args); 1941 break; 1942 1943 case LENGTH: 1944 funExpr = LengthFunExpr.create(this, args); 1945 break; 1946 1947 case MAX: 1948 funExpr = MaxFunExpr.create(this, id, args, distinct); 1949 break; 1950 1951 case MIN: 1952 funExpr = MinFunExpr.create(this, id, args, distinct); 1953 break; 1954 1955 case SUM: 1956 funExpr = SumFunExpr.create(this, id, args, distinct); 1957 break; 1958 1959 case ABS: 1960 funExpr = AbsFunExpr.create(this, args); 1961 break; 1962 1963 case SQRT: 1964 funExpr = SqrtFunExpr.create(this, args); 1965 break; 1966 1967 case MOD: 1968 funExpr = ModFunExpr.create(this, args); 1969 break; 1970 1971 case SIZE: 1972 if (! (_query instanceof SelectQuery)) 1973 throw error(L.l("The SIZE() function is only supported for SELECT or subselect queries")); 1974 1975 1977 AmberExpr arg = args.get(0); 1978 if (arg instanceof ManyToOneExpr) { 1979 arg = ((ManyToOneExpr) arg).getParent(); 1981 } 1982 1983 if (! (arg instanceof OneToManyExpr)) 1984 throw error(L.l("The SIZE() function is only supported for @ManyToMany or @OneToMany relationships")); 1985 1986 OneToManyExpr oneToMany = (OneToManyExpr) arg; 1987 1988 _groupList = new ArrayList <AmberExpr>(); 1989 1990 LinkColumns linkColumns = oneToMany.getLinkColumns(); 1991 ForeignColumn fkColumn = linkColumns.getColumns().get(0); 1992 1993 AmberExpr groupExpr = oneToMany.getParent(); 1994 1995 if (groupExpr instanceof PathExpr) { 1996 1998 PathExpr pathExpr = (PathExpr) groupExpr; 1999 2000 groupExpr = LoadExpr.create(pathExpr); 2001 2002 groupExpr = groupExpr.bindSelect(this); 2003 } 2004 2005 2008 _groupList.add(groupExpr); 2009 2010 ((SelectQuery) _query).setGroupList(_groupList); 2011 2012 funExpr = SizeFunExpr.create(this, args); 2013 2014 if (_appendResultList == null) 2015 _appendResultList = new ArrayList <AmberExpr>(); 2016 2017 _appendResultList.add(funExpr.bindSelect(this)); 2019 2020 _isSizeFunExpr = true; 2021 2022 break; 2023 2024 case CONCAT: 2025 funExpr = ConcatFunExpr.create(this, args); 2026 break; 2027 2028 case LOWER: 2029 funExpr = LowerFunExpr.create(this, args); 2030 break; 2031 2032 case UPPER: 2033 funExpr = UpperFunExpr.create(this, args); 2034 break; 2035 2036 case SUBSTRING: 2037 funExpr = SubstringFunExpr.create(this, args); 2038 break; 2039 2040 case TRIM: 2041 { 2042 TrimFunExpr trimFunExpr = TrimFunExpr.create(this, args); 2043 trimFunExpr.setTrimChar(trimChar); 2044 trimFunExpr.setTrimSemantics(trimSemantics); 2045 funExpr = trimFunExpr; 2046 break; 2047 } 2048 2049 default: 2050 funExpr = FunExpr.create(this, id, args, distinct); 2051 } 2052 2053 return funExpr; 2054 } 2055 2056 2059 private IdExpr getIdentifier(String name) 2060 throws QueryParseException 2061 { 2062 AbstractQuery query = _query; 2063 2064 for (; query != null; query = query.getParentQuery()) { 2065 ArrayList <FromItem> fromList = query.getFromList(); 2066 2067 for (int i = 0; i < fromList.size(); i++) { 2068 FromItem from = fromList.get(i); 2069 2070 if (from.getName().equalsIgnoreCase(name)) 2071 return from.getIdExpr(); 2072 } 2073 } 2074 2075 return null; 2076 2077 } 2079 2080 2083 private EmbeddedExpr getEmbeddedAlias(String name) 2084 throws QueryParseException 2085 { 2086 2088 AbstractQuery query = _query; 2089 2090 for (; query != null; query = query.getParentQuery()) { 2091 HashMap <String , EmbeddedExpr> embeddedAliases = 2092 query.getEmbeddedAliases(); 2093 2094 for (Map.Entry<String , EmbeddedExpr> entry : 2095 embeddedAliases.entrySet()) { 2096 2097 if (entry.getKey().equalsIgnoreCase(name)) 2098 return entry.getValue(); 2099 } 2100 } 2101 2102 return null; 2103 } 2104 2105 2108 private String parseIdentifier() 2109 throws QueryParseException 2110 { 2111 int token = scanToken(); 2112 2113 String identifier = _lexeme; 2114 2115 if (token == ORDER) { 2118 int parseIndex = _parseIndex; 2119 2120 scanToken(); 2121 2122 if (peekToken() != BY) { 2123 token = IDENTIFIER; 2124 2125 _parseIndex = parseIndex; 2127 _lexeme = identifier; 2128 _token = -1; 2129 } 2130 } else if (_parsingFrom && token == MEMBER) { 2132 token = IDENTIFIER; 2133 } 2134 2135 if (token != IDENTIFIER) { 2136 throw error(L.l("expected identifier at `{0}'", tokenName(token))); 2137 } 2138 2139 return identifier; 2140 } 2141 2142 2147 private int peekToken() 2148 throws QueryParseException 2149 { 2150 if (_token > 0) 2151 return _token; 2152 2153 _token = scanToken(); 2154 2155 return _token; 2156 } 2157 2158 2164 private int scanToken() 2165 throws QueryParseException 2166 { 2167 if (_token > 0) { 2168 int value = _token; 2169 _token = -1; 2170 return value; 2171 } 2172 2173 int sign = 1; 2174 int ch; 2175 2176 for (ch = read(); Character.isWhitespace((char) ch); ch = read()) { 2177 } 2178 2179 switch (ch) { 2180 case -1: 2181 case '.': 2182 case '*': 2183 case '/': 2184 case ',': 2185 case '+': 2186 case '-': 2187 case '[': 2188 case ']': 2189 return ch; 2190 2191 case '(': 2192 _depth++; 2193 return ch; 2194 2195 case ')': 2196 _depth--; 2197 return ch; 2198 2199 case '=': 2200 if ((ch = read()) == '>') 2201 return EXTERNAL_DOT; 2202 else { 2203 unread(ch); 2204 return EQ; 2205 } 2206 2207 case '!': 2208 if ((ch = read()) == '=') 2209 return NE; 2210 else { 2211 unread(ch); 2212 return '!'; 2213 } 2214 2215 case '<': 2216 if ((ch = read()) == '=') 2217 return LE; 2218 else if (ch == '>') 2219 return NE; 2220 else { 2221 unread(ch); 2222 return LT; 2223 } 2224 2225 case '>': 2226 if ((ch = read()) == '=') 2227 return GE; 2228 else { 2229 unread(ch); 2230 return GT; 2231 } 2232 2233 case '?': 2234 CharBuffer cb = CharBuffer.allocate(); 2235 int index = 0; 2236 for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) { 2237 cb.append((char) ch); 2238 index = 10 * index + ch - '0'; 2239 } 2240 unread(ch); 2241 2242 _lexeme = cb.close(); 2243 2244 if (_lexeme.length() == 0) { 2245 _lexeme = String.valueOf(++_parameterCount); 2246 } 2247 else if (index <= 0) 2248 throw error(L.l("`{0}' must refer to a positive argument", 2249 "?" + _lexeme)); 2250 2251 return ARG; 2252 2253 case ':': 2254 if (Character.isJavaIdentifierStart((char) (ch = read()))) { 2255 cb = CharBuffer.allocate(); 2256 2257 for (; ch > 0 && Character.isJavaIdentifierPart((char) ch); ch = read()) 2258 cb.append((char) ch); 2259 2260 unread(ch); 2261 2262 _lexeme = cb.close(); 2263 2264 _parameterCount++; 2265 } 2266 else 2267 throw error(L.l("`{0}' must be a valid parameter identifier", 2268 ":" + ((char) ch))); 2269 2270 return NAMED_ARG; 2271 2272 case '|': 2273 if ((ch = read()) == '|') 2274 return CONCAT_OP; 2275 else 2276 throw error(L.l("unexpected char at {0}", String.valueOf((char) ch))); 2277 2278 case '@': 2280 if ((ch = read()) != '@') 2281 throw error(L.l("`@' expected at {0}", charName(ch))); 2282 return scanToken(); 2283 } 2284 2285 if (Character.isJavaIdentifierStart((char) ch)) { 2286 CharBuffer cb = CharBuffer.allocate(); 2287 2288 for (; ch > 0 && Character.isJavaIdentifierPart((char) ch); ch = read()) 2289 cb.append((char) ch); 2290 2291 unread(ch); 2292 2293 _lexeme = cb.close(); 2294 String lower = _lexeme.toLowerCase(); 2295 2296 int token = _reserved.get(lower); 2297 2298 if (token > 0) 2299 return token; 2300 else 2301 return IDENTIFIER; 2302 } 2303 else if (ch >= '0' && ch <= '9') { 2304 CharBuffer cb = CharBuffer.allocate(); 2305 2306 int type = INTEGER; 2307 2308 if (sign < 0) 2309 cb.append('-'); 2310 2311 for (; ch >= '0' && ch <= '9'; ch = read()) 2312 cb.append((char) ch); 2313 2314 if (ch == '.') { 2315 type = DOUBLE; 2316 2317 cb.append('.'); 2318 for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) 2319 cb.append((char) ch); 2320 } 2321 2322 if (ch == 'e' || ch == 'E') { 2323 type = DOUBLE; 2324 2325 cb.append('e'); 2326 if ((ch = read()) == '+' || ch == '-') { 2327 cb.append((char) ch); 2328 ch = read(); 2329 } 2330 2331 if (! (ch >= '0' && ch <= '9')) 2332 throw error(L.l("exponent needs digits at {0}", 2333 charName(ch))); 2334 2335 for (; ch >= '0' && ch <= '9'; ch = read()) 2336 cb.append((char) ch); 2337 } 2338 2339 if (ch == 'F' || ch == 'D') 2340 type = DOUBLE; 2341 else if (ch == 'L') { 2342 type = LONG; 2343 } 2344 else 2345 unread(ch); 2346 2347 _lexeme = cb.close(); 2348 2349 return type; 2350 } 2351 else if (ch == '\'') { 2352 CharBuffer cb = CharBuffer.allocate(); 2353 2354 cb.append("'"); 2355 for (ch = read(); ch >= 0; ch = read()) { 2356 if (ch == '\'') { 2357 if ((ch = read()) == '\'') 2358 cb.append("''"); 2359 else { 2360 unread(ch); 2361 break; 2362 } 2363 } 2364 else 2365 cb.append((char) ch); 2366 } 2367 cb.append("'"); 2368 2369 _lexeme = cb.close(); 2370 2371 return STRING; 2372 } 2373 2374 throw error(L.l("unexpected char at {0}", "" + (char) ch)); 2375 } 2376 2377 2380 private int read() 2381 { 2382 if (_parseIndex < _sql.length()) 2383 return _sql.charAt(_parseIndex++); 2384 else 2385 return -1; 2386 } 2387 2388 2391 private void unread(int ch) 2392 { 2393 if (ch >= 0) 2394 _parseIndex--; 2395 } 2396 2397 2400 public QueryParseException error(String msg) 2401 { 2402 msg += "\nin \"" + _sql + "\""; 2403 2404 return new QueryParseException(msg); 2405 } 2406 2407 2410 private String charName(int ch) 2411 { 2412 if (ch < 0) 2413 return L.l("end of query"); 2414 else 2415 return String.valueOf((char) ch); 2416 } 2417 2418 2421 private String tokenName(int token) 2422 { 2423 switch (token) { 2424 case AS: return "AS"; 2425 case FROM: return "FROM"; 2426 case IN: return "IN"; 2427 case SELECT: return "SELECT"; 2428 case WHERE: return "WHERE"; 2429 case OR: return "OR"; 2430 case AND: return "AND"; 2431 case NOT: return "NOT"; 2432 case BETWEEN: return "BETWEEN"; 2433 case THIS: return "THIS"; 2434 case TRUE: return "FALSE"; 2435 case EMPTY: return "EMPTY"; 2436 case MEMBER: return "MEMBER"; 2437 case OF: return "OF"; 2438 case NULL: return "NULL"; 2439 case ORDER: return "ORDER"; 2440 case BY: return "BY"; 2441 case ASC: return "ASC"; 2442 case DESC: return "DESC"; 2443 case LIMIT: return "LIMIT"; 2444 2445 case EXTERNAL_DOT: return "=>"; 2446 2447 case -1: 2448 return L.l("end of query"); 2449 2450 default: 2451 if (token < 128) 2452 return "'" + String.valueOf((char) token) + "'"; 2453 else 2454 return "'" + _lexeme + "'"; 2455 } 2456 } 2457 2458 2461 public String toString() 2462 { 2463 return "QueryParser[]"; 2464 } 2465 2466 static { 2467 _reserved = new IntMap(); 2468 _reserved.put("as", AS); 2469 _reserved.put("from", FROM); 2470 _reserved.put("in", IN); 2471 _reserved.put("select", SELECT); 2472 _reserved.put("update", UPDATE); 2473 _reserved.put("delete", DELETE); 2474 _reserved.put("set", SET); 2475 _reserved.put("distinct", DISTINCT); 2476 _reserved.put("where", WHERE); 2477 _reserved.put("order", ORDER); 2478 _reserved.put("group", GROUP); 2479 _reserved.put("by", BY); 2480 _reserved.put("having", HAVING); 2481 _reserved.put("asc", ASC); 2482 _reserved.put("desc", DESC); 2483 _reserved.put("limit", LIMIT); 2484 _reserved.put("offset", OFFSET); 2485 2486 _reserved.put("join", JOIN); 2487 _reserved.put("inner", INNER); 2488 _reserved.put("left", LEFT); 2489 _reserved.put("outer", OUTER); 2490 _reserved.put("fetch", FETCH); 2491 2492 _reserved.put("or", OR); 2493 _reserved.put("and", AND); 2494 _reserved.put("not", NOT); 2495 2496 _reserved.put("length", LENGTH); 2497 _reserved.put("locate", LOCATE); 2498 2499 _reserved.put("abs", ABS); 2500 _reserved.put("sqrt", SQRT); 2501 _reserved.put("mod", MOD); 2502 _reserved.put("size", SIZE); 2503 2504 _reserved.put("max", MAX); 2505 _reserved.put("min", MIN); 2506 _reserved.put("sum", SUM); 2507 2508 _reserved.put("concat", CONCAT); 2509 _reserved.put("lower", LOWER); 2510 _reserved.put("upper", UPPER); 2511 _reserved.put("substring", SUBSTRING); 2512 _reserved.put("trim", TRIM); 2513 _reserved.put("both", BOTH); 2514 _reserved.put("leading", LEADING); 2515 _reserved.put("trailing", TRAILING); 2516 2517 _reserved.put("current_date", CURRENT_DATE); 2518 _reserved.put("current_time", CURRENT_TIME); 2519 _reserved.put("current_timestamp", CURRENT_TIMESTAMP); 2520 2521 _reserved.put("between", BETWEEN); 2522 _reserved.put("like", LIKE); 2523 _reserved.put("escape", ESCAPE); 2524 _reserved.put("is", IS); 2525 2526 _reserved.put("new", NEW); 2527 2528 _reserved.put("this", THIS); 2529 _reserved.put("true", TRUE); 2530 _reserved.put("false", FALSE); 2531 _reserved.put("unknown", UNKNOWN); 2532 _reserved.put("empty", EMPTY); 2533 _reserved.put("member", MEMBER); 2534 _reserved.put("of", OF); 2535 _reserved.put("null", NULL); 2536 } 2537} 2538 | Popular Tags |