1 26 package org.objectweb.speedo.query.parser; 27 28 import java.io.Serializable ; 29 import java.math.BigDecimal ; 30 import java.math.BigInteger ; 31 import java.util.ArrayList ; 32 import java.util.Date ; 33 import java.util.HashMap ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.util.Stack ; 37 import java.util.StringTokenizer ; 38 39 import org.objectweb.jorm.api.PMapper; 40 import org.objectweb.jorm.metainfo.api.ClassRef; 41 import org.objectweb.jorm.metainfo.api.GenClassRef; 42 import org.objectweb.jorm.metainfo.api.Reference; 43 import org.objectweb.jorm.type.api.PType; 44 import org.objectweb.medor.api.Field; 45 import org.objectweb.medor.api.MedorException; 46 import org.objectweb.medor.expression.api.Expression; 47 import org.objectweb.medor.expression.api.ExpressionException; 48 import org.objectweb.medor.expression.api.Operator; 49 import org.objectweb.medor.filter.api.FieldOperand; 50 import org.objectweb.medor.filter.lib.Avg; 51 import org.objectweb.medor.filter.lib.BasicFieldOperand; 52 import org.objectweb.medor.filter.lib.Count; 53 import org.objectweb.medor.filter.lib.Max; 54 import org.objectweb.medor.filter.lib.Min; 55 import org.objectweb.medor.filter.lib.Sum; 56 import org.objectweb.medor.query.api.PropagatedField; 57 import org.objectweb.medor.query.api.QueryNode; 58 import org.objectweb.medor.query.api.QueryTree; 59 import org.objectweb.medor.query.api.QueryTreeField; 60 import org.objectweb.medor.query.jorm.lib.ClassExtent; 61 import org.objectweb.medor.query.jorm.lib.JormQueryTreeHelper; 62 import org.objectweb.medor.query.jorm.lib.PNameField; 63 import org.objectweb.medor.query.lib.Nest; 64 import org.objectweb.medor.query.lib.SelectProject; 65 import org.objectweb.speedo.api.SpeedoException; 66 import org.objectweb.speedo.mim.api.SpeedoHome; 67 import org.objectweb.speedo.query.api.QueryDefinition; 68 import org.objectweb.speedo.query.lib.QueryDefinitionImpl; 69 import org.objectweb.speedo.query.lib.QueryEvalContext; 70 71 77 public class SelectGroupByVisitor { 78 79 82 private static final String COUNT = "count"; 83 84 87 private static final String SUM = "sum"; 88 89 92 private static final String MIN = "min"; 93 94 97 private static final String MAX = "max"; 98 99 102 private static final String AVG = "avg"; 103 104 107 private static final String DISTINCT = "distinct"; 108 109 112 private static final String UNIQUE = "unique"; 113 114 117 private static final String [] keywords = new String [] { 118 COUNT.toLowerCase(), COUNT.toUpperCase(), SUM.toLowerCase(), SUM.toUpperCase(), MIN.toLowerCase(), MIN.toUpperCase(), MAX.toLowerCase(), MAX.toUpperCase(), AVG.toLowerCase(), AVG.toUpperCase(), DISTINCT.toLowerCase(), DISTINCT.toUpperCase(), "(", ")", ",", "as", "AS", UNIQUE.toLowerCase(), UNIQUE.toUpperCase() }; 138 139 142 private final static String getFunctionAsString(int functionIdx) { 143 switch (functionIdx / 2) { 144 case 0: 145 return "COUNT"; 146 case 1: 147 return "SUM"; 148 case 2: 149 return "MIN"; 150 case 3: 151 return "MAX"; 152 case 4: 153 return "AVG"; 154 default: 155 return "UNKNOWN"; 156 } 157 158 } 159 160 164 private QueryNode top; 165 166 169 private QueryTree qt; 170 171 174 private PMapper mapper; 175 176 private ClassLoader classloader; 177 178 183 private SpeedoQLVariableVisitor sqvv; 184 185 192 private QueryEvalContext qec; 193 194 198 private boolean unique = false; 199 200 204 private boolean distinct = false; 205 206 210 private boolean hasAggregate = false; 211 212 221 private ArrayList selectfields = new ArrayList (); 222 223 230 private ArrayList aliases = new ArrayList (); 231 232 238 private ArrayList groupedFields = new ArrayList (); 239 240 245 private ArrayList groupByFields = new ArrayList (); 246 247 private ArrayList usedFields = new ArrayList (); 248 249 private ArrayList selectFieldTypes = new ArrayList (); 250 251 259 public SelectGroupByVisitor(SelectProject sp, QueryTree qt, PMapper mapper, 260 SpeedoQLVariableVisitor sqvv, QueryDefinitionImpl qd, 261 QueryEvalContext qec, ClassLoader classloader) { 262 super(); 263 this.qt = qt; 264 this.top = sp; 265 this.mapper = mapper; 266 this.sqvv = sqvv; 267 this.qec = qec; 268 this.classloader = classloader; 269 } 270 271 public Class [] getSelectFieldTypes() { 272 return (Class []) selectFieldTypes.toArray(new Class [selectFieldTypes.size()]); 273 } 274 275 279 public void visit(QueryDefinition qd) 280 throws SpeedoException { 281 try { 282 _visit(qd); 283 } catch (ExpressionException e) { 284 throw new SpeedoException(e); 285 } catch (MedorException e) { 286 throw new SpeedoException(e); 287 } 288 } 289 290 294 private void _visit(QueryDefinition qd) 295 throws SpeedoException, MedorException, ExpressionException { 296 String select = qd.getResult(); 297 String groupby = qd.getGrouping(); 298 boolean withPrefetch = qd.withPrefetch(); 299 if (select == null || select.length() == 0) { 300 select = "this"; 301 } 302 parseSelect(select); 303 parseGroupBy(groupby); 304 305 if (!hasAggregate && withPrefetch && selectfields.size() == 1 ) { 310 addPrefetchField(qd); 311 } 312 if (hasAggregate) { 313 top = addAggregateNode(); 314 } 315 top.setDistinct(distinct); 316 projectFields(); 317 qec.query = top; 318 } 319 320 324 private void addPrefetchField(QueryDefinition qd) throws MedorException { 325 Field f = ((PropagatedField) selectfields.get(0)).getOriginFields()[0]; 326 if (f instanceof PNameField) { 327 PNameField pnf = (PNameField) f; 328 if (pnf.isClassPName() && !pnf.isInGenClass()) { 329 ClassExtent ce = (ClassExtent) pnf.getQueryTree(); 331 String prefetchedClassName = ce.getJormName(); 332 SpeedoHome sh = (SpeedoHome) mapper.lookup(prefetchedClassName); 333 if (sh.getPrefetchOnQuery()) { 334 qec.pcm = sh; 335 JormQueryTreeHelper.addPrefetchFields(ce, qt, top, 336 qd.getIncludeSubClasses()); 337 qec.pnIndex = top.getTupleStructure().getSize() + 1; 338 } 339 } } } 342 343 347 private Nest addAggregateNode() throws SpeedoException, MedorException { 348 Map old2newFields = new HashMap (); 349 for (int i = 0; i < usedFields.size(); i++) { 351 QueryTreeField qtf = (QueryTreeField) usedFields.get(i); 352 Field newf = top.addPropagatedField(qtf.getName(), qtf 353 .getType(), new QueryTreeField[] { qtf }); 354 old2newFields.put(qtf, newf); 355 } 356 replaceFieldsInList(groupedFields, old2newFields); 358 replaceFieldsInList(groupByFields, old2newFields); 360 replaceFieldsInList(selectfields, old2newFields); 362 return new Nest((QueryTreeField[]) groupedFields 363 .toArray(new QueryTreeField[groupedFields.size()]), 364 "grouped_fields", (QueryTreeField[]) groupByFields 365 .toArray(new QueryTreeField[groupByFields 366 .size()]), "aggregate_node"); 367 } 369 370 373 private void projectFields() 374 throws SpeedoException, MedorException, ExpressionException { 375 for (int i = 0; i < selectfields.size(); i++) { 377 Object o = selectfields.get(i); 378 Field fieldOnTop = null; 379 String fieldName = (String ) aliases.get(i); 380 if (o instanceof Expression) { 381 if (fieldName == null || fieldName.length() == 0) { 382 fieldName = "field_" + i; 383 } 384 Expression e = (Expression) o; 385 e.compileExpression(); 386 fieldOnTop = top.addCalculatedField(fieldName, e.getType(), e); 387 } else if (o instanceof Field) { 388 Field f = (Field) o; 389 if (fieldName == null || fieldName.length() == 0) { 390 fieldName = f.getName(); 391 } 392 if (!groupByFields.contains(f) || (top instanceof Nest)) { 393 fieldOnTop = top.addPropagatedField(fieldName, f.getType(), 394 new QueryTreeField[] { (QueryTreeField) f }); 395 } else { 396 String fn = top.getName(); 397 if (fn == null || fn.length() == 0) { 398 fn = ""; 399 } else { 400 fn += "."; 401 } 402 fn += f.getName(); 403 fieldOnTop = top.getTupleStructure().getField(fn); 404 } 405 } 406 selectFieldTypes.add(getFieldClass(fieldOnTop)); 408 } 409 } 410 411 414 private Class getFieldClass(Field field) throws SpeedoException { 415 PType ptype = field.getType(); 416 String className = null; 417 switch(ptype.getTypeCode()) { 418 case PType.TYPECODE_BIGDECIMAL: 419 return BigDecimal .class; 420 case PType.TYPECODE_BIGINTEGER: 421 return BigInteger .class; 422 case PType.TYPECODE_BOOLEAN: 423 case PType.TYPECODE_OBJBOOLEAN: 424 return Boolean .class; 425 case PType.TYPECODE_BYTE: 426 case PType.TYPECODE_OBJBYTE: 427 return Byte .class; 428 case PType.TYPECODE_BYTEARRAY: 429 return Byte [].class; 430 case PType.TYPECODE_CHAR: 431 case PType.TYPECODE_OBJCHAR: 432 return Character .class; 433 case PType.TYPECODE_CHARARRAY: 434 return Character [].class; 435 case PType.TYPECODE_DATE: 436 return Date .class; 437 case PType.TYPECODE_DOUBLE: 438 case PType.TYPECODE_OBJDOUBLE: 439 return Double .class; 440 case PType.TYPECODE_FLOAT: 441 case PType.TYPECODE_OBJFLOAT: 442 return Float .class; 443 case PType.TYPECODE_INT: 444 case PType.TYPECODE_OBJINT: 445 return Integer .class; 446 case PType.TYPECODE_LONG: 447 case PType.TYPECODE_OBJLONG: 448 return Integer .class; 449 case PType.TYPECODE_SERIALIZED: 450 return Serializable .class; 451 case PType.TYPECODE_SHORT: 452 case PType.TYPECODE_OBJSHORT: 453 return Integer .class; 454 case PType.TYPECODE_STRING: 455 return String .class; 456 457 case PType.TYPECODE_REFERENCE: 458 if (field instanceof PropagatedField) { 459 Field f = ((PropagatedField) field).getOriginFields()[0]; 460 if (f instanceof PNameField) { 461 PNameField pnf = (PNameField) f; 462 if (pnf.isClassPName()) { 463 if (pnf.isInGenClass()) { 464 className = pnf.getGenClassRef().getGenClassId(); 466 } else { 467 className = pnf.getMetaObjectClass().getFQName(); 469 } 470 } else { 471 Reference ref = pnf.getReference(); 472 if (ref instanceof ClassRef) { 473 className = ((ClassRef) ref).getMOClass().getFQName(); 475 } else if (ref instanceof GenClassRef) { 476 className = ((GenClassRef) ref).getGenClassId(); 478 } 479 } 480 } 481 } 482 break; 483 default: 484 className = ptype.getJavaName(); 485 } 486 if (className == null) { 487 throw new SpeedoException( 488 "Type '" + ptype.getJavaName() 489 + "' not found for projected field:" 490 + field.getName()); 491 } else { 492 try { 493 return classloader.loadClass(className); 494 } catch (ClassNotFoundException e) { 495 throw new SpeedoException( 496 "Type '" + className 497 + "' not found for projected field:" 498 + field.getName(), e); 499 } 500 } 501 } 502 503 513 private void replaceFieldsInList(ArrayList list, Map old2newElement) 514 throws SpeedoException { 515 for (int i = 0; i < list.size(); i++) { 516 Object old = list.get(i); 517 Object neo = old2newElement.get(old); 518 if (neo != null && old != neo) { 519 list.set(i, neo); 520 } else if (old instanceof Expression) { 521 replaceFieldsInExpression((Expression) old, old2newElement); 522 } 523 } 524 } 525 526 534 private void replaceFieldsInExpression(Expression e, Map old2newElement) 535 throws SpeedoException { 536 if (e instanceof FieldOperand) { 537 FieldOperand fo = (FieldOperand) e; 538 Field old = fo.getField(); 539 Field neo = (Field) old2newElement.get(old); 540 if (neo != null && old != neo) { 541 ((FieldOperand) e).setField(neo); 542 } 543 } else if (e instanceof Operator) { 544 Operator operator = (Operator) e; 545 for (int i = 0; i < operator.getOperandNumber(); i++) { 546 replaceFieldsInExpression(operator.getExpression(i), 547 old2newElement); 548 } 549 } 550 } 551 552 560 private void parseSelect(String select) throws SpeedoException { 561 StringTokenizer st = new StringTokenizer (select, " (,)", true); 562 Stack stack = new Stack (); 563 while (st.hasMoreTokens()) { 564 String token = st.nextToken().trim(); 565 if (token.length() == 0) { 566 continue; 567 } 568 if (token.equalsIgnoreCase("select")) { 569 continue; 570 } 571 int keywordIdx = isKeyword(token); 572 if (keywordIdx < 0) { 573 parseFieldExpression(token, stack); 574 } else if (keywordIdx < 10) { 575 stack.push(new Integer (keywordIdx)); 577 } else if (keywordIdx == 10 || keywordIdx == 11) { 578 if (stack.size() > 0) { 580 stack.push(new Boolean (true)); 582 } else { 583 distinct = true; 584 } 585 } else if (keywordIdx == 17 || keywordIdx == 18) { 586 unique = true; 588 } else if (keywordIdx == 14) { 589 parseComma(stack); 590 } else if (keywordIdx == 12) { 591 stack.push(new Integer (keywordIdx)); 593 } else if (keywordIdx == 13) { 594 parseRightParenthesis(stack); 596 } 597 } 598 if (stack.size() == 1) { 599 selectfields.add(stack.pop()); 601 aliases.add(null); 602 } 603 } 604 private void parseFieldExpression(String token, Stack stack) throws SpeedoException { 605 if (token.equals("*")) { 607 token = "this"; 608 } 609 Field f = sqvv.getField(token); 610 if (!usedFields.contains(f)) { 611 usedFields.add(f); 612 } 613 stack.push(f); 614 } 615 616 private void parseComma(Stack stack) throws SpeedoException { 617 if (stack.size() > 0) { 618 Object o1 = stack.pop(); 619 if (stack.size() > 1) { 620 Object o2 = stack.pop(); 622 if (stack.size() > 2) { 623 stack.push(o2); 625 stack.push(o1); 626 } else if (!(o1 instanceof String ) 627 || !(o2 instanceof Expression)) { 628 throw new SpeedoException( 629 "Malformed selected field " 630 + (selectfields.size() + 1)); 631 } else { 632 selectfields.add(o2); 633 aliases.add(o1); 634 } 635 } else { 636 selectfields.add(o1); 638 aliases.add(null); 639 } 640 } else { 641 throw new SpeedoException( 642 "Empty definition of the selected field " 643 + (selectfields.size() + 1)); 644 } 645 } 646 647 private void parseRightParenthesis(Stack stack) throws SpeedoException { 648 ArrayList operands = new ArrayList (); 649 boolean isOperand = true; 650 Integer functionIdx = null; 651 boolean distinctOnOperand = false; 654 do { 655 Object o = stack.pop(); 656 isOperand = !new Integer (12).equals(o); 657 if (isOperand) { 658 operands.add(o); 660 } else { 661 if (stack.peek() instanceof Boolean ) { 662 distinctOnOperand = ((Boolean ) stack.pop()) 663 .booleanValue(); 664 } 665 functionIdx = (Integer ) stack.pop(); 667 } 668 } while (isOperand); 669 Expression e; 670 if (functionIdx.intValue() > 0 && functionIdx.intValue() < 10) { 672 if (operands.size() != 1) { 673 throw new SpeedoException( 674 "Bad number of operand for the function " 675 + getFunctionAsString(functionIdx 676 .intValue()) 677 + ", expected 1 operand, found " 678 + operands.size()); 679 } 680 } 681 Object operand = operands.get(0); 683 if (operand instanceof Expression) { 684 e = (Expression) operand; 685 } else if (operand instanceof Field) { 686 e = new BasicFieldOperand((Field) operand); 687 } else { 688 throw new SpeedoException("Unexpect operand: " + operand); 689 } 690 getFieldsFromExpression(e, groupedFields); 691 hasAggregate = true; 692 switch (functionIdx.intValue() / 2) { 693 case 0: 694 e = new Count(e, distinctOnOperand); 695 break; 696 case 1: 697 e = new Sum(e, distinctOnOperand); 698 break; 699 case 2: 700 e = new Min(e, distinctOnOperand); 701 break; 702 case 3: 703 e = new Max(e, distinctOnOperand); 704 break; 705 case 4: 706 e = new Avg(e, distinctOnOperand); 707 break; 708 default: 709 throw new SpeedoException("Unknown function identifier: " 710 + functionIdx.intValue()); 711 } 712 stack.push(e); 713 } 714 715 723 private void parseGroupBy(String groupby) throws SpeedoException { 724 if (groupby == null || groupby.length() == 0) { 725 return; 726 } 727 StringTokenizer st = new StringTokenizer (groupby, ",", false); 728 while (st.hasMoreTokens()) { 729 groupByFields.add(sqvv.getField(st.nextToken().trim())); 730 } 731 for (int i = 0; i < groupByFields.size(); i++) { 732 Field f = (Field) groupByFields.get(i); 733 if (!usedFields.contains(f)) { 734 usedFields.add(f); 735 } 736 } 737 } 738 739 748 private void getFieldsFromExpression(Expression e, List result) { 749 if (e instanceof FieldOperand) { 750 Field f = ((FieldOperand) e).getField(); 751 if (!result.contains(f)) { 752 result.add(f); 753 } 754 } else if (e instanceof Operator) { 755 Operator operator = (Operator) e; 756 for (int i = 0; i < operator.getOperandNumber(); i++) { 757 getFieldsFromExpression(operator.getExpression(i), result); 758 } 759 } 760 } 761 762 private int isKeyword(String str) { 763 if (str == null || str.length() == 0) { 764 return -1; 765 } 766 for (int i = 0; i < keywords.length; i++) { 767 if (keywords[i].equals(str)) { 768 return i; 769 } 770 } 771 return -1; 772 } 773 } | Popular Tags |