1 29 30 package com.caucho.ejb.ql; 31 32 import com.caucho.bytecode.JClass; 33 import com.caucho.bytecode.JMethod; 34 import com.caucho.config.ConfigException; 35 import com.caucho.config.LineConfigException; 36 import com.caucho.ejb.cfg.EjbConfig; 37 import com.caucho.ejb.cfg.EjbEntityBean; 38 import com.caucho.ejb.cfg.FunctionSignature; 39 import com.caucho.util.CharBuffer; 40 import com.caucho.util.IntMap; 41 import com.caucho.util.L10N; 42 import com.caucho.util.Log; 43 44 import javax.ejb.EJBLocalObject ; 45 import javax.ejb.EntityBean ; 46 import javax.ejb.FinderException ; 47 import java.util.ArrayList ; 48 import java.util.HashMap ; 49 import java.util.logging.Logger ; 50 51 56 public class QLParser extends Query { 57 static final Logger log = Log.open(QLParser.class); 58 static final L10N L = new L10N(QLParser.class); 59 60 final static int IDENTIFIER = 128; 61 final static int INTEGER = IDENTIFIER + 1; 62 final static int LONG = INTEGER + 1; 63 final static int DOUBLE = LONG + 1; 64 final static int STRING = DOUBLE + 1; 65 final static int TRUE = STRING + 1; 66 final static int FALSE = TRUE + 1; 67 final static int UNKNOWN = FALSE + 1; 68 final static int MEMBER = UNKNOWN + 1; 69 final static int OF = MEMBER + 1; 70 final static int EMPTY = OF + 1; 71 final static int NULL = EMPTY + 1; 72 73 final static int FROM = NULL + 1; 74 final static int IN = FROM + 1; 75 final static int SELECT = IN + 1; 76 final static int DISTINCT = SELECT + 1; 77 final static int WHERE = SELECT + 1; 78 final static int AS = WHERE + 1; 79 final static int ORDER = AS + 1; 80 final static int BY = ORDER + 1; 81 final static int ASC = BY + 1; 82 final static int DESC = ASC + 1; 83 final static int LIMIT = DESC + 1; 84 final static int OFFSET = LIMIT + 1; 85 86 final static int BETWEEN = OFFSET + 1; 87 final static int LIKE = BETWEEN + 1; 88 final static int ESCAPE = LIKE + 1; 89 final static int IS = ESCAPE + 1; 90 91 final static int EQ = IS + 1; 92 final static int NE = EQ + 1; 93 final static int LT = NE + 1; 94 final static int LE = LT + 1; 95 final static int GT = LE + 1; 96 final static int GE = GT + 1; 97 98 final static int AND = GE + 1; 99 final static int OR = AND + 1; 100 final static int NOT = OR + 1; 101 102 final static int EXTERNAL_DOT = NOT + 1; 103 104 final static int ARG = EXTERNAL_DOT + 1; 105 final static int THIS = ARG + 1; 106 107 private static IntMap _reserved; 108 109 private String _location; 110 111 private EjbEntityBean _bean; 113 114 private EjbEntityBean _target; 116 117 private ArrayList <FunctionSignature> _functions; 119 120 private String _methodName; 122 private JClass _returnType; 124 private String _returnEJB; 126 private String _query; 128 129 private ArrayList <FromItem> _fromList; 131 private ArrayList <PathExpr> _fromIds = new ArrayList <PathExpr>(); 133 134 private Expr _selectExpr; 138 private boolean _isDistinct; 140 141 private String _fromTable; 143 private String _fromId; 145 private IdExpr _thisExpr; 147 private Expr _whereExpr; 149 private ArrayList <Expr> _argList; 151 private ArrayList <Expr> _orderExprList; 153 private ArrayList <Boolean > _orderAscendingList; 155 private Expr _limitMax; 157 private Expr _limitOffset; 159 160 private AndExpr _andExpr; 161 private boolean _isWhere; 162 163 private HashMap <String ,PathExpr> _idMap; 164 private HashMap <Expr,Expr> _pathMap; 165 166 private int _parseIndex; 168 private int _token; 170 private String lexeme; 172 173 private int _unique; 174 175 private String _booleanTrue = "1"; 176 private String _booleanFalse = "0"; 177 178 private boolean _addArgToQuery = true; 179 180 private boolean _queryLoadsBean = true; 181 182 private int _maxArg; 183 184 private QLParser(EjbEntityBean bean) 185 { 186 _bean = bean; 187 188 _functions = bean.getConfig().getFunctions(); 190 } 191 192 199 public QLParser(EjbEntityBean bean, 200 String methodName, 201 JMethod method, 202 JClass returnType) 203 throws ConfigException 204 { 205 this(bean); 206 207 setMethod(method); 208 209 _methodName = methodName; 210 _returnType = returnType; 211 212 JClass []exn = method.getExceptionTypes(); 213 for (int i = 0; i < exn.length; i++) 214 if (exn[i].isAssignableTo(FinderException .class)) 215 return; 216 217 throw new ConfigException(L.l("{0}: `{1}' must throw javax.ejb.FinderException.", 218 method.getDeclaringClass().getName(), 219 getFullMethodName(method))); 220 } 221 222 public static void parseOrderBy(EjbEntityBean bean, 223 String orderBy, 224 ArrayList <String > orderList, 225 ArrayList <Boolean > orderAscendingList) 226 throws ConfigException 227 { 228 QLParser query = new QLParser(bean); 229 230 query.parseOrderBy(orderBy, orderList, orderAscendingList); 231 } 232 233 236 public void setLocation(String location) 237 { 238 _location = location; 239 } 240 241 244 public EjbEntityBean getPersistentBean() 245 { 246 return _bean; 247 } 248 249 252 public EjbEntityBean getBeanByName(String ejbName) 253 { 254 throw new UnsupportedOperationException (); 256 } 257 258 261 public EjbEntityBean getBeanByType(JClass type) 262 { 263 throw new UnsupportedOperationException (); 265 } 266 267 270 public String getName() 271 { 272 return _methodName; 273 } 274 275 278 public ArrayList <FunctionSignature> getFunctions() 279 { 280 return _functions; 281 } 282 283 286 public void setFunctions(ArrayList <FunctionSignature> functions) 287 { 288 _functions = functions; 289 } 290 291 294 public void setBooleanTrue(String literal) 295 { 296 _booleanTrue = literal; 297 } 298 299 302 public void setBooleanFalse(String literal) 303 { 304 _booleanFalse = literal; 305 } 306 307 310 public JClass getReturnType() 311 { 312 return _returnType; 313 } 314 315 318 public String getReturnEJB() 319 { 320 return _selectExpr.getReturnEJB(); 321 } 322 323 326 void setReturnType(JClass returnType) 327 { 328 _returnType = returnType; 329 } 330 331 334 public String getQuery() 335 { 336 return _query; 337 } 338 339 342 public Expr getSelectExpr() 343 { 344 return _selectExpr; 345 } 346 347 public boolean isDistinct() 348 { 349 return _isDistinct; 350 } 351 352 public boolean getQueryLoadsBean() 353 { 354 return _queryLoadsBean; 355 } 356 357 public void setQueryLoadsBean(boolean loadBean) 358 { 359 _queryLoadsBean = loadBean; 360 } 361 362 365 IdExpr getThisExpr() 366 { 367 return _thisExpr; 368 } 369 370 373 Expr getWhereExpr() 374 { 375 return _whereExpr; 376 } 377 378 381 ArrayList <Expr> getOrderExprList() 382 { 383 return _orderExprList; 384 } 385 386 389 ArrayList <Boolean > getAscendingList() 390 { 391 return _orderAscendingList; 392 } 393 394 397 Expr getLimitMax() 398 { 399 return _limitMax; 400 } 401 402 405 Expr getLimitOffset() 406 { 407 return _limitOffset; 408 } 409 410 413 ArrayList <FromItem> getFromList() 414 { 415 return _fromList; 416 } 417 418 void addFromItem(String id, String table) 419 { 420 _fromList.add(new FromItem(id, table)); 421 } 422 423 public int getUnique() 424 { 425 return _unique++; 426 } 427 428 431 442 443 446 461 462 465 478 479 482 488 489 492 public void addArg(Expr expr) 493 { 494 _argList.add(expr); 495 } 496 497 500 ArrayList <Expr> getArgList() 501 { 502 return _argList; 503 } 504 505 510 public void parseOrderBy(String orderBy, 511 ArrayList <String > orderList, 512 ArrayList <Boolean > orderAscendingList) 513 throws ConfigException 514 { 515 _query = orderBy; 516 517 _parseIndex = 0; 518 _unique = 0; 519 _token = -1; 520 521 int token = -1; 522 523 do { 524 token = scanToken(); 525 526 if (token == IDENTIFIER) 527 orderList.add(lexeme.toString()); 528 else 529 throw error(L.l("unexpected token `{0}' in order-by", 530 tokenName(token))); 531 532 token = scanToken(); 533 if (token == DESC) { 534 token = scanToken(); 535 orderAscendingList.add(Boolean.FALSE); 536 } 537 else if (token == ASC) { 538 token = scanToken(); 539 orderAscendingList.add(Boolean.TRUE); 540 } 541 else 542 orderAscendingList.add(Boolean.TRUE); 543 } while (token == ','); 544 545 if (token >= 0) 546 throw error(L.l("extra token {0} at end of order-by", 547 tokenName(peekToken()))); 548 } 549 550 555 public EjbQuery parseQuery(String query) 556 throws ConfigException 557 { 558 int token; 559 560 _query = query; 561 _fromList = new ArrayList <FromItem>(); 562 _pathMap = new HashMap <Expr,Expr>(); 563 _idMap = new HashMap <String ,PathExpr>(); 564 _argList = new ArrayList <Expr>(); 565 567 _parseIndex = 0; 568 _unique = 0; 569 _token = -1; 570 571 setConfig(_bean.getConfig()); 572 573 for (; (token = peekToken()) >= 0 && token != FROM; token = scanToken()) { 575 } 576 577 if (token != FROM) 578 throw error(L.l("expected FROM at {0}", 579 tokenName(token))); 580 581 scanToken(); 582 583 parseFrom(); 584 585 token = peekToken(); 586 if (token >= 0 && token != WHERE && token != ORDER) 587 throw error(L.l("expected WHERE or ORDER at {0}", 588 tokenName(token))); 589 590 _parseIndex = 0; 591 _token = -1; 592 token = scanToken(); 593 594 if (token != SELECT) 595 throw error(L.l("expected SELECT at {0}", tokenName(token))); 596 597 if (peekToken() == DISTINCT) { 598 scanToken(); 599 _isDistinct = true; 600 } 601 602 _selectExpr = parseExpr(); 603 604 611 612 if (_selectExpr instanceof PathExpr) 613 ((PathExpr) _selectExpr).setUsesField(); 614 615 620 621 token = peekToken(); 622 if (token != FROM) 623 throw error(L.l("expected FROM at {0}", 624 tokenName(token))); 625 626 for (; 628 (token = peekToken()) >= 0 && token != WHERE && token != ORDER; 629 token = scanToken()) { 630 } 631 632 _addArgToQuery = true; 633 634 if ((token = scanToken()) == WHERE) { 635 _isWhere = true; 636 _whereExpr = parseExpr(); 637 _isWhere = false; 638 token = scanToken(); 639 } 640 641 if (_whereExpr != null && ! _whereExpr.isBoolean()) 642 throw error(L.l("WHERE must be a boolean expression at {0}", 643 _whereExpr)); 644 645 _addArgToQuery = false; 646 647 int oldMaxArg = _maxArg; 648 if (token == ORDER) { 649 if (peekToken() == BY) 650 scanToken(); 651 if (_orderExprList == null) 652 _orderExprList = new ArrayList <Expr>(); 653 654 if (_orderAscendingList == null) 655 _orderAscendingList = new ArrayList <Boolean >(); 656 657 do { 658 _orderExprList.add(parseExpr()); 659 660 token = peekToken(); 661 if (token == DESC) { 662 token = scanToken(); 663 _orderAscendingList.add(Boolean.FALSE); 664 } 665 else if (token == ASC) { 666 token = scanToken(); 667 _orderAscendingList.add(Boolean.TRUE); 668 } 669 else 670 _orderAscendingList.add(Boolean.TRUE); 671 } while ((token = scanToken()) == ','); 672 } 673 674 if (token == OFFSET) { 675 _limitOffset = parseExpr(); 676 token = scanToken(); 677 678 if (! _limitOffset.getJavaType().getName().equals("int")) 679 throw error(L.l("OFFSET `{0}' must be an integer expression", 680 _limitMax)); 681 } 682 683 if (token == LIMIT) { 684 _limitMax = parseExpr(); 685 token = scanToken(); 686 687 if (! _limitMax.getJavaType().getName().equals("int")) 688 throw error(L.l("LIMIT `{0}' must be an integer expression", 689 _limitMax)); 690 } 691 692 if (token >= 0) 693 throw error(L.l("extra token {0} at end of query", 694 tokenName(peekToken()))); 695 _maxArg = oldMaxArg; 696 697 EjbSelectQuery ejbQuery = new EjbSelectQuery(_query); 698 699 ejbQuery.setDistinct(_isDistinct); 700 ejbQuery.setFromList(_fromIds); 701 ejbQuery.setSelectExpr(_selectExpr); 702 ejbQuery.setWhereExpr(_whereExpr); 703 704 ejbQuery.setMaxArg(_maxArg); 705 ejbQuery.setThisExpr(_thisExpr); 706 707 ejbQuery.setOrderBy(_orderExprList, _orderAscendingList); 708 709 ejbQuery.setOffset(_limitOffset); 710 ejbQuery.setLimit(_limitMax); 711 712 return ejbQuery; 713 } 714 715 727 private void parseFrom() 728 throws ConfigException 729 { 730 boolean moreTables = true; 731 732 while (moreTables) { 733 int token = scanToken(); 734 735 if (token == IN) { 736 if (scanToken() != '(') 737 throw error(L.l("expected `(' at {0} while parsing IN(<collection-path>).", 738 tokenName(token))); 739 740 parseFromCollection(); 741 } 742 else if (token == IDENTIFIER) { 743 String id = lexeme; 744 if (peekToken() == AS) 745 scanToken(); 746 747 parseFromTable(id); 748 } 749 else 750 throw error(L.l("expected identifier at {0} while parsing FROM", 751 tokenName(token))); 752 753 if (peekToken() == ',') { 754 scanToken(); 755 moreTables = true; 756 } 757 else 758 moreTables = false; 759 } 760 } 761 762 765 private void parseFromTable(String table) 766 throws ConfigException 767 { 768 int token = scanToken(); 769 770 if (token != IDENTIFIER) { 771 throw error(L.l("expected identifier at {0} while parsing FROM {1} [AS] var", tokenName(token), table)); 772 } 773 774 String name = lexeme; 775 776 EjbConfig ejbConfig = _bean.getConfig(); 777 778 EjbEntityBean entity = ejbConfig.findEntityBySchema(table); 779 780 if (entity == null) 781 throw error(L.l("`{0}' is an unknown entity-bean schema in `FROM {0} AS {1}'", 782 table, name)); 783 784 786 IdExpr id = new IdExpr(this, name, entity); 787 788 addIdentifier(name, id); 789 addFromItem(name, entity.getSQLTable()); 790 791 _fromIds.add(id); 792 } 793 794 797 private void parseFromCollection() 798 throws ConfigException 799 { 800 Expr expr = parseDotExpr(); 801 802 if (scanToken() != ')') 803 throw error(L.l("expected `)' at {0} while parsing IN(<collection-path>).", 804 tokenName(_token))); 805 806 if (! (expr instanceof CollectionExpr)) 807 throw error(L.l("expected <collection-path> expression at `{0}'", expr)); 808 809 CollectionExpr collectionExpr = (CollectionExpr) expr; 810 811 if (peekToken() == AS) 812 scanToken(); 813 814 int token = scanToken(); 815 if (token != IDENTIFIER) 816 throw error(L.l("expected identifier expression at {0} while parsing `IN({1}) AS id'", 817 tokenName(token), expr)); 818 819 String name = lexeme; 820 821 CollectionIdExpr idExpr; 822 idExpr = new CollectionIdExpr(this, name, collectionExpr); 823 824 addIdentifier(name, idExpr); 825 826 _fromIds.add(idExpr); 827 } 828 829 838 private Expr parseExpr() 839 throws ConfigException 840 { 841 return parseOrExpr(); 842 } 843 844 854 private Expr parseOrExpr() 855 throws ConfigException 856 { 857 Expr expr = parseAndExpr(); 858 859 int token = peekToken(); 860 while ((token = peekToken()) == OR) { 861 scanToken(); 862 863 expr = new BinaryExpr(this, token, expr, parseAndExpr()); 864 } 865 866 return expr; 867 } 868 869 879 private Expr parseAndExpr() 880 throws ConfigException 881 { 882 AndExpr oldAnd = _andExpr; 883 884 AndExpr andExpr = new AndExpr(this); 885 886 if (_isWhere) 887 _andExpr = andExpr; 888 889 Expr expr = parseNotExpr(); 890 891 andExpr.add(expr); 892 893 int token = peekToken(); 894 while ((token = peekToken()) == AND) { 895 scanToken(); 896 897 expr = parseNotExpr(); 898 899 andExpr.add(expr); 900 } 901 902 _andExpr = oldAnd; 903 904 return andExpr.getSingleExpr(); 905 } 906 907 916 private Expr parseNotExpr() 917 throws ConfigException 918 { 919 int token = peekToken(); 920 if (token == NOT) { 921 scanToken(); 922 923 Expr expr = parseCmpExpr(); 924 925 return new UnaryExpr(NOT, expr); 926 } 927 else 928 return parseCmpExpr(); 929 } 930 931 944 private Expr parseCmpExpr() 945 throws ConfigException 946 { 947 int token = peekToken(); 948 boolean isNot = false; 949 950 Expr expr = parseArithmeticExpr(); 951 952 token = peekToken(); 953 954 if (token == NOT) { 955 scanToken(); 956 isNot = true; 957 token = peekToken(); 958 } 959 960 if (token >= EQ && token <= GE) { 961 scanToken(); 962 963 return parseIs(new BinaryExpr(this, token, expr, parseAddExpr())); 964 } 965 else if (token == BETWEEN) { 966 scanToken(); 967 968 Expr a = parseArithmeticExpr(); 969 970 if ((token = scanToken()) != AND) 971 throw error(L.l("Expected 'AND' at {0}", tokenName(token))); 972 973 Expr b = parseArithmeticExpr(); 974 975 return parseIs(new BetweenExpr(expr, a, b, isNot)); 976 } 977 else if (token == LIKE) { 978 scanToken(); 979 980 Expr pattern = parseArithmeticExpr(); 981 982 String escape = null; 983 if (peekToken() == ESCAPE) { 984 scanToken(); 985 986 if ((token = scanToken()) != STRING) 987 throw error(L.l("Expected string at {0}", tokenName(token))); 988 989 escape = lexeme.toString(); 990 } 991 992 return parseIs(new LikeExpr(expr, pattern, escape, isNot)); 993 } 994 else if (token == IN) { 995 scanToken(); 996 token = scanToken(); 997 998 if (token != '(') 999 throw error(L.l("Expected '(' after IN at {0}", tokenName(token))); 1000 1001 ArrayList <Expr> args = new ArrayList <Expr>(); 1002 while ((token = peekToken()) > 0 && token != ')') { 1003 Expr arg = parseArithmeticExpr(); 1004 1005 args.add(arg); 1006 1007 token = peekToken(); 1008 if (token == ',') { 1009 scanToken(); 1010 token = peekToken(); 1011 } 1012 } 1013 1014 if (peekToken() != ')') 1015 throw error(L.l("Expected ')' after IN at {0}", tokenName(token))); 1016 1017 scanToken(); 1018 1019 return new InExpr(this, expr, args, isNot); 1020 } 1021 else if (token == IS) { 1022 scanToken(); 1023 1024 if (isNot) 1025 throw error(L.l("'NOT IS' is an invalid expression.")); 1026 1027 token = scanToken(); 1028 if (token == NOT) { 1029 isNot = true; 1030 token = scanToken(); 1031 } 1032 1033 if (token == NULL) 1034 return parseIs(new IsExpr(this, expr, NULL, isNot)); 1035 else if (token == EMPTY) { 1036 if (! (expr instanceof CollectionExpr)) 1037 throw error(L.l("IS EMPTY requires collection path at `{0}'", 1038 expr)); 1039 return parseIs(new EmptyExpr(expr, isNot)); 1040 } 1041 else 1042 throw error(L.l("`{0}' unexpected after IS.", tokenName(token))); 1043 } 1044 else if (token == MEMBER) { 1045 scanToken(); 1046 1047 token = peekToken(); 1048 if (token == OF) 1049 token = scanToken(); 1050 1051 Expr collection = parseDotExpr(); 1052 1053 return parseIs(new MemberExpr(isNot, expr, collection)); 1054 } 1055 else 1056 return expr; 1057 } 1058 1059 1066 private Expr parseIs(Expr base) 1067 throws ConfigException 1068 { 1069 if (peekToken() != IS) 1070 return base; 1071 1072 scanToken(); 1073 boolean isNot = peekToken() == NOT; 1074 if (isNot) 1075 scanToken(); 1076 1077 int token = scanToken(); 1078 if (token == UNKNOWN) 1079 return new IsExpr(this, base, NULL, isNot); 1080 else if (token == TRUE) 1081 return isNot ? new UnaryExpr(NOT, base) : base; 1082 else if (token == FALSE) 1083 return isNot ? base : new UnaryExpr(NOT, base); 1084 1085 throw error(L.l("expected TRUE or FALSE at {0}", tokenName(token))); 1086 } 1087 1088 1095 private Expr parseArithmeticExpr() 1096 throws ConfigException 1097 { 1098 return parseAddExpr(); 1099 } 1100 1101 1111 private Expr parseAddExpr() 1112 throws ConfigException 1113 { 1114 Expr expr = parseMulExpr(); 1115 1116 int token = peekToken(); 1117 while ((token = peekToken()) == '-' || token == '+') { 1118 scanToken(); 1119 1120 expr = new BinaryExpr(this, token, expr, parseMulExpr()); 1121 } 1122 1123 return expr; 1124 } 1125 1126 1136 private Expr parseMulExpr() 1137 throws ConfigException 1138 { 1139 Expr expr = parseUnaryExpr(); 1140 1141 int token = peekToken(); 1142 while ((token = peekToken()) == '*' || token == '/') { 1143 scanToken(); 1144 1145 expr = new BinaryExpr(this, token, expr, parseUnaryExpr()); 1146 } 1147 1148 return expr; 1149 } 1150 1151 1160 private Expr parseUnaryExpr() 1161 throws ConfigException 1162 { 1163 int token = peekToken(); 1164 1165 if (token == '+' || token == '-') { 1166 scanToken(); 1167 return new UnaryExpr(token, parseRefExpr()); 1168 } 1169 else 1170 return parseRefExpr(); 1171 } 1172 1173 1183 private Expr parseRefExpr() 1184 throws ConfigException 1185 { 1186 Expr expr = parseDotExpr(); 1187 1188 int token; 1189 if ((token = peekToken()) == EXTERNAL_DOT) { 1190 scanToken(); 1191 1192 token = scanToken(); 1193 1194 if (token != IDENTIFIER) 1195 throw error(L.l("expected field identifier at {0}", 1196 tokenName(token))); 1197 1198 expr = expr.newField(lexeme); 1199 expr.evalTypes(); 1200 1201 if (! expr.isExternal()) 1202 throw error(L.l("`{0}' must refer to an external entity bean", expr)); 1203 } 1204 1205 return expr; 1206 } 1207 1208 1218 private Expr parseDotExpr() 1219 throws ConfigException 1220 { 1221 Expr expr = parseTerm(); 1222 1223 int token; 1224 while ((token = peekToken()) == '.') { 1225 scanToken(); 1226 1227 token = scanToken(); 1228 1229 if (token != IDENTIFIER) 1230 throw error(L.l("expected field identifier at {0}", 1231 tokenName(token))); 1232 1233 expr.evalTypes(); 1234 if (expr.isExternal()) 1235 throw error(L.l("`{0}' must not refer to an external entity bean", expr)); 1236 Expr field = expr.newField(lexeme); 1237 expr = field; 1238 1239 Expr equiv = _pathMap.get(field); 1240 if (equiv != null) 1241 expr = equiv; 1242 else 1243 _pathMap.put(field, field); 1244 } 1245 1246 return expr; 1247 } 1248 1249 1259 private Expr parseTerm() 1260 throws ConfigException 1261 { 1262 int token = scanToken(); 1263 1264 switch (token) { 1265 case IDENTIFIER: 1266 String name = lexeme.toString(); 1267 if (peekToken() != '(') 1268 return getIdentifier(name); 1269 else 1270 return parseFunction(name); 1271 1272 case FALSE: 1273 return new LiteralExpr(_booleanFalse, boolean.class); 1274 1275 case TRUE: 1276 return new LiteralExpr(_booleanTrue, boolean.class); 1277 1278 case INTEGER: 1279 return new LiteralExpr(lexeme, int.class); 1280 1281 case LONG: 1282 return new LiteralExpr(lexeme, long.class); 1283 1284 case DOUBLE: 1285 return new LiteralExpr(lexeme, double.class); 1286 1287 case STRING: 1288 return new LiteralExpr(lexeme, String .class); 1289 1290 case ARG: 1291 { 1292 ArgExpr arg = new ArgExpr(this, Integer.parseInt(lexeme)); 1293 if (_addArgToQuery) 1294 addArg(arg); 1295 return arg; 1296 } 1297 1298 case THIS: 1299 { 1300 if (_thisExpr == null) { 1301 _thisExpr = new IdExpr(this, "caucho_this", _bean); 1302 addFromItem("caucho_this", _bean.getSQLTable()); 1303 _fromIds.add(_thisExpr); 1304 _argList.add(0, new ThisExpr(this, _bean)); 1305 } 1306 1307 return _thisExpr; 1308 } 1309 1310 case '(': 1311 Expr expr = parseExpr(); 1312 if ((token = scanToken()) != ')') 1313 throw error(L.l("expected `)' at {0}", tokenName(token))); 1314 1315 return expr; 1316 1317 1318 default: 1319 throw error(L.l("expected term at {0}", tokenName(token))); 1320 } 1321 } 1322 1323 1331 private Expr parseFunction(String name) 1332 throws ConfigException 1333 { 1334 ArrayList <Expr> args = new ArrayList <Expr>(); 1335 1336 int token; 1337 if ((token = scanToken()) != '(') 1338 throw error(L.l("expected `(' at {0} while parsing function {1}()", tokenName(token), name)); 1339 1340 while ((token = peekToken()) != ')' && token > 0) { 1341 Expr expr = parseExpr(); 1342 1343 args.add(expr); 1344 1345 if ((token = peekToken()) == ',') 1346 scanToken(); 1347 } 1348 1349 if (token != ')') 1350 throw error(L.l("expected `)' at {0} while parsing function {1}", tokenName(token), name)); 1351 1352 scanToken(); 1353 1354 if (name.equalsIgnoreCase("object")) { 1355 if (args.size() != 1) 1356 throw error(L.l("OBJECT() requires a single argument")); 1357 1358 Expr expr = args.get(0); 1359 1360 if (! expr.getJavaType().isAssignableTo(EntityBean.class) && 1361 ! expr.getJavaType().isAssignableTo(EJBLocalObject .class)) 1362 throw error(L.l("OBJECT({0}) requires an entity bean as its argument at `{1}'", 1363 expr, expr.getJavaType())); 1364 1365 return expr; 1366 } 1367 else { 1368 try { 1369 return new FunExpr(name, args, _functions); 1370 } catch (ConfigException e) { 1371 throw error(e.getMessage()); 1372 } 1373 } 1374 } 1375 1376 1383 void addIdentifier(String name, PathExpr expr) 1384 throws ConfigException 1385 { 1386 Expr oldExpr = _idMap.get(name); 1387 1388 if (oldExpr != null) 1389 throw error(L.l("`{0}' is defined twice", name)); 1390 1391 _idMap.put(name, expr); 1392 } 1393 1394 1401 PathExpr getIdentifier(String name) 1402 throws ConfigException 1403 { 1404 PathExpr expr = _idMap.get(name); 1405 1406 if (expr == null) 1407 throw error(L.l("`{0}' is an unknown identifier", name)); 1408 1409 return expr; 1410 } 1411 1412 1417 private int peekToken() 1418 throws ConfigException 1419 { 1420 if (_token > 0) 1421 return _token; 1422 1423 _token = scanToken(); 1424 1425 return _token; 1426 } 1427 1428 1434 private int scanToken() 1435 throws ConfigException 1436 { 1437 if (_token > 0) { 1438 int value = _token; 1439 _token = -1; 1440 return value; 1441 } 1442 1443 int sign = 1; 1444 int ch; 1445 1446 for (ch = read(); Character.isWhitespace((char) ch); ch = read()) { 1447 } 1448 1449 switch (ch) { 1450 case -1: 1451 case '(': 1452 case ')': 1453 case '.': 1454 case '*': 1455 case '/': 1456 case ',': 1457 return ch; 1458 1459 case '+': 1460 if ((ch = read()) >= '0' && ch <= '9') 1461 break; 1462 else { 1463 unread(ch); 1464 return '+'; 1465 } 1466 1467 case '-': 1468 if ((ch = read()) >= '0' && ch <= '9') { 1469 sign = -1; 1470 break; 1471 } 1472 else { 1473 unread(ch); 1474 return '-'; 1475 } 1476 1477 case '=': 1478 if ((ch = read()) == '>') 1479 return EXTERNAL_DOT; 1480 else { 1481 unread(ch); 1482 return EQ; 1483 } 1484 1485 case '<': 1486 if ((ch = read()) == '=') 1487 return LE; 1488 else if (ch == '>') 1489 return NE; 1490 else { 1491 unread(ch); 1492 return LT; 1493 } 1494 1495 case '>': 1496 if ((ch = read()) == '=') 1497 return GE; 1498 else { 1499 unread(ch); 1500 return GT; 1501 } 1502 1503 case '?': 1504 CharBuffer cb = CharBuffer.allocate(); 1505 int index = 0; 1506 for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) { 1507 cb.append((char) ch); 1508 index = 10 * index + ch - '0'; 1509 } 1510 unread(ch); 1511 1512 lexeme = cb.close(); 1513 1514 if (index <= 0) 1515 throw error(L.l("`{0}' must refer to a positive argument", 1516 "?" + lexeme)); 1517 1518 if (_maxArg < index) 1519 _maxArg = index; 1520 1521 return ARG; 1522 1523 case '@': 1525 if ((ch = read()) != '@') 1526 throw error(L.l("`@' expected at {0}", charName(ch))); 1527 return scanToken(); 1528 } 1529 1530 if (Character.isJavaIdentifierStart((char) ch)) { 1531 CharBuffer cb = CharBuffer.allocate(); 1532 1533 for (; ch > 0 && Character.isJavaIdentifierPart((char) ch); ch = read()) 1534 cb.append((char) ch); 1535 1536 unread(ch); 1537 1538 lexeme = cb.close(); 1539 String lower = lexeme.toLowerCase(); 1540 1541 int token = _reserved.get(lower); 1542 1543 if (token > 0) 1544 return token; 1545 else 1546 return IDENTIFIER; 1547 } 1548 else if (ch >= '0' && ch <= '9') { 1549 CharBuffer cb = CharBuffer.allocate(); 1550 1551 int type = INTEGER; 1552 1553 if (sign < 0) 1554 cb.append('-'); 1555 1556 for (; ch >= '0' && ch <= '9'; ch = read()) 1557 cb.append((char) ch); 1558 1559 if (ch == '.') { 1560 type = DOUBLE; 1561 1562 cb.append('.'); 1563 for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) 1564 cb.append((char) ch); 1565 } 1566 1567 if (ch == 'e' || ch == 'E') { 1568 type = DOUBLE; 1569 1570 cb.append('e'); 1571 if ((ch = read()) == '+' || ch == '-') { 1572 cb.append((char) ch); 1573 ch = read(); 1574 } 1575 1576 if (! (ch >= '0' && ch <= '9')) 1577 throw error(L.l("exponent needs digits at {0}", 1578 charName(ch))); 1579 1580 for (; ch >= '0' && ch <= '9'; ch = read()) 1581 cb.append((char) ch); 1582 } 1583 1584 if (ch == 'F' || ch == 'D') 1585 type = DOUBLE; 1586 else if (ch == 'L') { 1587 type = LONG; 1588 } 1589 else 1590 unread(ch); 1591 1592 lexeme = cb.close(); 1593 1594 return type; 1595 } 1596 else if (ch == '\'') { 1597 CharBuffer cb = CharBuffer.allocate(); 1598 1599 cb.append("'"); 1600 for (ch = read(); ch >= 0; ch = read()) { 1601 if (ch == '\'') { 1602 if ((ch = read()) == '\'') 1603 cb.append("''"); 1604 else { 1605 unread(ch); 1606 break; 1607 } 1608 } 1609 else 1610 cb.append((char) ch); 1611 } 1612 cb.append("'"); 1613 1614 lexeme = cb.close(); 1615 1616 return STRING; 1617 } 1618 1619 throw error(L.l("unexpected char at {0}", "" + (char) ch)); 1620 } 1621 1622 1625 private int read() 1626 { 1627 if (_parseIndex < _query.length()) 1628 return _query.charAt(_parseIndex++); 1629 else 1630 return -1; 1631 } 1632 1633 1636 private void unread(int ch) 1637 { 1638 if (ch >= 0) 1639 _parseIndex--; 1640 } 1641 1642 1645 private String getFullMethodName(JMethod method) 1646 { 1647 return method.getFullName(); 1648 } 1649 1650 1653 private String getFullMethodName(String methodName, JClass []params) 1654 { 1655 String name = methodName + "("; 1656 1657 for (int i = 0; i < params.length; i++) { 1658 if (i != 0) 1659 name += ", "; 1660 1661 name += params[i].getPrintName(); 1662 } 1663 1664 return name + ")"; 1665 } 1666 1667 1670 private String getClassName(Class cl) 1671 { 1672 if (cl.isArray()) 1673 return getClassName(cl.getComponentType()) + "[]"; 1674 else if (cl.getName().startsWith("java")) { 1675 int p = cl.getName().lastIndexOf('.'); 1676 1677 return cl.getName().substring(p + 1); 1678 } 1679 else 1680 return cl.getName(); 1681 } 1682 1683 1686 public ConfigException error(String msg) 1687 { 1688 msg += "\nin \"" + _query + "\""; 1689 1695 if (_location != null) 1696 return new LineConfigException(_location + msg); 1697 else 1698 return new ConfigException(msg); 1699 } 1700 1701 1704 private String charName(int ch) 1705 { 1706 if (ch < 0) 1707 return L.l("end of query"); 1708 else 1709 return String.valueOf((char) ch); 1710 } 1711 1712 1715 private String tokenName(int token) 1716 { 1717 switch (token) { 1718 case AS: return "AS"; 1719 case FROM: return "FROM"; 1720 case IN: return "IN"; 1721 case SELECT: return "SELECT"; 1722 case WHERE: return "WHERE"; 1723 case OR: return "OR"; 1724 case AND: return "AND"; 1725 case NOT: return "NOT"; 1726 case BETWEEN: return "BETWEEN"; 1727 case THIS: return "THIS"; 1728 case TRUE: return "FALSE"; 1729 case EMPTY: return "EMPTY"; 1730 case MEMBER: return "MEMBER"; 1731 case OF: return "OF"; 1732 case NULL: return "NULL"; 1733 case ORDER: return "ORDER"; 1734 case BY: return "BY"; 1735 case ASC: return "ASC"; 1736 case DESC: return "DESC"; 1737 case LIMIT: return "LIMIT"; 1738 1739 case EXTERNAL_DOT: return "=>"; 1740 1741 case -1: 1742 return L.l("end of query"); 1743 1744 default: 1745 if (token < 128) 1746 return "'" + String.valueOf((char) token) + "'"; 1747 else 1748 return "'" + lexeme + "'"; 1749 } 1750 } 1751 1752 public static ArrayList <FunctionSignature> getStandardFunctions() 1753 { 1754 return FunExpr.getStandardFunctions(); 1755 } 1756 1757 1760 public String toString() 1761 { 1762 return "QLParser[" + getMethod() + "]"; 1763 } 1764 1765 public boolean equals(Object b) 1766 { 1767 if (! (b instanceof QLParser)) 1768 return false; 1769 1770 QLParser bSel = (QLParser) b; 1771 1772 if (_bean != bSel._bean) 1773 return false; 1774 1775 return methodEquals(getMethod(), bSel.getMethod()); 1776 } 1777 1778 static boolean methodEquals(JMethod a, JMethod b) 1779 { 1780 if (! a.getName().equals(b.getName())) 1781 return false; 1782 1783 JClass []aParam = a.getParameterTypes(); 1784 JClass []bParam = b.getParameterTypes(); 1785 1786 if (aParam.length != bParam.length) 1787 return false; 1788 1789 for (int i = 0; i < aParam.length; i++) { 1790 if (! aParam[i].equals(bParam[i])) 1791 return false; 1792 } 1793 1794 return true; 1795 } 1796 1797 static class FromItem { 1798 String _id; 1799 String _table; 1800 1801 FromItem(String id, String table) 1802 { 1803 _id = id; 1804 _table = table; 1805 } 1806 } 1807 1808 static class LinkItem { 1809 String columnA; 1810 String tableA; 1811 1812 String columnB; 1813 String tableB; 1814 1815 LinkItem(String tableA, String columnA, 1816 String tableB, String columnB) 1817 { 1818 this.columnA = columnA; 1819 this.tableA = tableA; 1820 this.columnB = columnB; 1821 this.tableB = tableB; 1822 } 1823 1824 public boolean equals(Object o) 1825 { 1826 if (! (o instanceof LinkItem)) 1827 return false; 1828 1829 LinkItem link = (LinkItem) o; 1830 1831 if (tableA.equals(link.tableA) && columnA.equals(link.columnA) && 1832 tableB.equals(link.tableB) && columnB.equals(link.columnB)) 1833 return true; 1834 else if (tableA.equals(link.tableB) && columnA.equals(link.columnB) && 1835 tableB.equals(link.tableA) && columnB.equals(link.columnA)) 1836 return true; 1837 else 1838 return false; 1839 } 1840 } 1841 1842 static { 1843 _reserved = new IntMap(); 1844 _reserved.put("as", AS); 1845 _reserved.put("from", FROM); 1846 _reserved.put("in", IN); 1847 _reserved.put("select", SELECT); 1848 _reserved.put("distinct", DISTINCT); 1849 _reserved.put("where", WHERE); 1850 _reserved.put("order", ORDER); 1851 _reserved.put("by", BY); 1852 _reserved.put("asc", ASC); 1853 _reserved.put("desc", DESC); 1854 _reserved.put("limit", LIMIT); 1855 _reserved.put("offset", OFFSET); 1856 1857 _reserved.put("or", OR); 1858 _reserved.put("and", AND); 1859 _reserved.put("not", NOT); 1860 1861 _reserved.put("between", BETWEEN); 1862 _reserved.put("like", LIKE); 1863 _reserved.put("escape", ESCAPE); 1864 _reserved.put("is", IS); 1865 1866 _reserved.put("this", THIS); 1867 _reserved.put("true", TRUE); 1868 _reserved.put("false", FALSE); 1869 _reserved.put("unknown", UNKNOWN); 1870 _reserved.put("empty", EMPTY); 1871 _reserved.put("member", MEMBER); 1872 _reserved.put("of", OF); 1873 _reserved.put("null", NULL); 1874 } 1875} 1876 | Popular Tags |