1 13 14 package mondrian.rolap; 15 import mondrian.calc.Calc; 16 import mondrian.calc.ParameterSlot; 17 import mondrian.olap.*; 18 import mondrian.olap.fun.FunUtil; 19 import mondrian.resource.MondrianResource; 20 import mondrian.util.Format; 21 22 import org.apache.log4j.Logger; 23 24 import java.util.*; 25 26 41 public class RolapEvaluator implements Evaluator { 42 private static final Logger LOGGER = Logger.getLogger(RolapEvaluator.class); 43 44 47 private static final Object nullResult = new Object (); 48 49 private final Member[] currentMembers; 50 private final Evaluator parent; 51 protected CellReader cellReader; 52 private final int depth; 53 54 private Member expandingMember; 55 private boolean nonEmpty; 56 protected final RolapEvaluatorRoot root; 57 private int iterationLength; 58 private boolean evalAxes; 59 60 private final Member[] calcMembers; 61 private int calcMemberCount; 62 63 64 67 protected RolapEvaluator( 68 RolapEvaluatorRoot root, 69 RolapEvaluator parent, 70 CellReader cellReader, 71 Member[] currentMembers) { 72 this.root = root; 73 this.parent = parent; 74 if (parent == null) { 75 this.depth = 0; 76 this.nonEmpty = false; 77 } else { 78 this.depth = parent.depth + 1; 79 this.nonEmpty = parent.nonEmpty; 80 } 81 this.iterationLength = 1; 82 this.evalAxes = false; 83 84 this.cellReader = cellReader; 85 if (currentMembers == null) { 86 this.currentMembers = new Member[root.cube.getDimensions().length]; 87 } else { 88 this.currentMembers = currentMembers; 89 } 90 calcMembers = new Member[this.currentMembers.length]; 91 calcMemberCount = 0; 92 for (Member member : this.currentMembers) { 93 if (member != null && member.isCalculated()) { 94 addCalcMember(member); 95 } 96 } 97 } 98 99 104 public RolapEvaluator(RolapEvaluatorRoot root) { 105 this(root, null, null, null); 106 107 109 SchemaReader scr = this.root.connection.getSchemaReader(); 110 Dimension[] dimensions = this.root.cube.getDimensions(); 111 for (final Dimension dimension : dimensions) { 112 final int ordinal = dimension.getOrdinal(this.root.cube); 113 final Hierarchy hier = dimension.getHierarchy(); 114 115 Member member = scr.getHierarchyDefaultMember(hier); 116 117 if (member == null) { 119 throw MondrianResource.instance().InvalidHierarchyCondition 120 .ex(hier.getUniqueName()); 121 } 122 123 HierarchyUsage[] hierarchyUsages = this.root.cube.getUsages(hier); 124 if (hierarchyUsages.length != 0) { 125 ((RolapMember) member).makeUniqueName(hierarchyUsages[0]); 126 } 127 128 currentMembers[ordinal] = member; 129 if (member.isCalculated()) { 130 addCalcMember(member); 131 } 132 } 133 134 root.init(this); 135 } 136 137 140 public static Evaluator create(Query query) { 141 final RolapEvaluatorRoot root = new RolapEvaluatorRoot(query); 142 return new RolapEvaluator(root); 143 } 144 145 protected static class RolapEvaluatorRoot { 146 final Map<Object , Object > expResultCache = 147 new HashMap<Object , Object >(); 148 final RolapCube cube; 149 final RolapConnection connection; 150 final SchemaReader schemaReader; 151 final Map<Exp, Calc> compiledExps = new HashMap<Exp, Calc>(); 152 final private Query query; 153 154 public RolapEvaluatorRoot(Query query) { 155 this.query = query; 156 this.cube = (RolapCube) query.getCube(); 157 this.connection = (RolapConnection) query.getConnection(); 158 this.schemaReader = query.getSchemaReader(true); 159 } 160 161 167 Calc getCompiled(Exp exp, boolean scalar) { 168 Calc calc = compiledExps.get(exp); 169 if (calc == null) { 170 calc = query.compileExpression(exp, scalar); 171 compiledExps.put(exp, calc); 172 } 173 return calc; 174 } 175 176 182 protected Object evaluateNamedSet(String name, Exp exp) { 183 throw new UnsupportedOperationException (); 184 } 185 186 189 protected void clearNamedSets() { 190 } 191 192 195 protected void init(Evaluator evaluator) { 196 } 197 198 205 public Object getParameterValue(ParameterSlot slot) { 206 throw new UnsupportedOperationException (); 207 } 208 } 209 210 protected Logger getLogger() { 211 return LOGGER; 212 } 213 214 public Member[] getMembers() { 215 return currentMembers; 216 } 217 218 void setCellReader(CellReader cellReader) { 219 this.cellReader = cellReader; 220 } 221 222 public Cube getCube() { 223 return root.cube; 224 } 225 226 public Query getQuery() { 227 return root.query; 228 } 229 230 public int getDepth() { 231 return depth; 232 } 233 234 public Evaluator getParent() { 235 return parent; 236 } 237 238 public SchemaReader getSchemaReader() { 239 return root.schemaReader; 240 } 241 242 public Evaluator push(Member[] members) { 243 final RolapEvaluator evaluator = _push(); 244 evaluator.setContext(members); 245 return evaluator; 246 } 247 248 public Evaluator push(Member member) { 249 final RolapEvaluator evaluator = _push(); 250 evaluator.setContext(member); 251 return evaluator; 252 } 253 254 public Evaluator push() { 255 return _push(); 256 } 257 258 261 protected RolapEvaluator _push() { 262 getQuery().checkCancelOrTimeout(); 263 Member[] cloneCurrentMembers = currentMembers.clone(); 264 RolapEvaluator newEvaluator = 265 new RolapEvaluator( 266 root, 267 this, 268 cellReader, 269 cloneCurrentMembers); 270 newEvaluator.setEvalAxes(evalAxes); 271 return newEvaluator; 272 } 273 274 public Evaluator pop() { 275 return parent; 276 } 277 278 282 public boolean equals(Object obj) { 283 if (!(obj instanceof RolapEvaluator)) { 284 return false; 285 } 286 RolapEvaluator that = (RolapEvaluator) obj; 287 return Arrays.equals(this.currentMembers, that.currentMembers); 288 } 289 290 295 public void printCurrentMemberNames() { 296 for (int i = 0; i < currentMembers.length; i++) { 297 Member m = currentMembers[i]; 298 if (m == null) { 299 System.out.println("RolapEvaluator.printCurrentMemberNames: i="+i+", member NULL"); 300 } else { 301 System.out.println("RolapEvaluator.printCurrentMemberNames: i="+i+", member="+m.getUniqueName()); 302 } 303 } 304 } 305 306 320 Member setContextConditional(Member member) { 321 RolapMember m = (RolapMember) member; 322 int ordinal = m.getDimension().getOrdinal(root.cube); 323 if (ordinal >= currentMembers.length) { 325 return null; 326 } 327 Member previous = currentMembers[ordinal]; 328 if (previous.isNull()) { 329 return setContext(member); 331 } else if (previous.isMeasure()) { 332 return setContext(member); 334 } else if (previous.isAll()) { 335 return setContext(member); 337 } else { 338 Hierarchy heirarchy = m.getHierarchy(); 339 Member defaultMember = heirarchy.getDefaultMember(); 340 if (previous.equals(defaultMember) && ! previous.equals(member)) { 341 return setContext(member); 342 } else { 343 return null; 344 } 345 } 346 } 347 348 public Member setContext(Member member) { 349 RolapMember m = (RolapMember) member; 350 int ordinal = m.getDimension().getOrdinal(root.cube); 351 Member previous = currentMembers[ordinal]; 352 if (previous.isCalculated()) { 353 removeCalcMember(previous); 354 } 355 currentMembers[ordinal] = m; 356 if (m.isCalculated()) { 357 addCalcMember(m); 358 } 359 return previous; 360 } 361 362 public void setContext(List<Member> memberList) { 363 int i = 0; 364 for (Member member: memberList) { 365 if (member == null) { 367 if (getLogger().isDebugEnabled()) { 368 getLogger().debug( 369 "RolapEvaluator.setContext: member == null " 370 + " , count=" + i); 371 } 372 assert false; 373 } else { 374 setContext(member); 375 } 376 i++; 377 } 378 } 379 public void setContext(Member[] members) { 380 for (int i = 0; i < members.length; i++) { 381 Member member = members[i]; 382 383 if (member == null) { 385 if (getLogger().isDebugEnabled()) { 386 getLogger().debug( 387 "RolapEvaluator.setContext: member == null " 388 + " , count=" + i); 389 } 390 assert false; 391 continue; 392 } 393 394 setContext(member); 395 } 396 } 397 398 public Member getContext(Dimension dimension) { 399 return currentMembers[dimension.getOrdinal(root.cube)]; 400 } 401 402 public Object evaluateCurrent() { 403 Member maxSolveMember = peekCalcMember(); 407 if (maxSolveMember == null) { 408 Object o = cellReader.get(this); 409 if (o == Util.nullValue) { 410 o = null; 411 } 412 return o; 413 } 414 RolapMember defaultMember = (RolapMember) 415 maxSolveMember.getHierarchy().getDefaultMember(); 416 Util.assertTrue( 417 defaultMember != maxSolveMember, 418 "default member must not be calculated"); 419 RolapEvaluator evaluator = (RolapEvaluator) push(defaultMember); 420 evaluator.setExpanding(maxSolveMember); 421 final Exp exp = maxSolveMember.getExpression(); 422 Calc calc = root.getCompiled(exp, true); 423 Object o = calc.evaluate(evaluator); 424 if (o == Util.nullValue) { 425 o = null; 426 } 427 return o; 428 } 429 430 private void setExpanding(Member member) { 431 expandingMember = member; 432 int memberCount = currentMembers.length; 433 if (depth > memberCount) { 434 if (depth % memberCount == 0) { 435 checkRecursion((RolapEvaluator) parent); 436 } 437 } 438 } 439 440 446 private static void checkRecursion(RolapEvaluator eval) { 447 while (true) { 451 if (eval == null) { 452 return; 453 } 454 if (eval.expandingMember != null) { 455 break; 456 } 457 eval = (RolapEvaluator) eval.getParent(); 458 } 459 460 outer: 461 for (RolapEvaluator eval2 = (RolapEvaluator) eval.getParent(); 462 eval2 != null; 463 eval2 = (RolapEvaluator) eval2.getParent()) { 464 if (eval2.expandingMember != eval.expandingMember) { 465 continue; 466 } 467 for (int i = 0; i < eval.currentMembers.length; i++) { 468 Member member = eval2.currentMembers[i]; 469 470 if (member == null) { 472 if (LOGGER.isDebugEnabled()) { 473 LOGGER.debug( 474 "RolapEvaluator.checkRecursion: member == null " 475 + " , count=" + i); 476 } 477 continue; 478 } 479 480 Member parentMember = eval.getContext(member.getDimension()); 481 if (member != parentMember) { 482 continue outer; 483 } 484 } 485 throw FunUtil.newEvalException(null, 486 "Infinite loop while evaluating calculated member '" + 487 eval.expandingMember + "'; context stack is " + 488 eval.getContextString()); 489 } 490 } 491 492 private String getContextString() { 493 boolean skipDefaultMembers = true; 494 StringBuilder buf = new StringBuilder ("{"); 495 int frameCount = 0; 496 for (RolapEvaluator eval = this; eval != null; 497 eval = (RolapEvaluator) eval.getParent()) { 498 if (eval.expandingMember == null) { 499 continue; 500 } 501 if (frameCount++ > 0) { 502 buf.append(", "); 503 } 504 buf.append("("); 505 int memberCount = 0; 506 for (Member m : eval.currentMembers) { 507 if (skipDefaultMembers && 508 m == m.getHierarchy().getDefaultMember()) { 509 continue; 510 } 511 if (memberCount++ > 0) { 512 buf.append(", "); 513 } 514 buf.append(m.getUniqueName()); 515 } 516 buf.append(")"); 517 } 518 buf.append("}"); 519 return buf.toString(); 520 } 521 522 public Object getProperty(String name, Object defaultValue) { 523 Object o = defaultValue; 524 int maxSolve = Integer.MIN_VALUE; 525 for (int i = 0; i < currentMembers.length; i++) { 526 Member member = currentMembers[i]; 527 528 if (member == null) { 530 if (getLogger().isDebugEnabled()) { 531 getLogger().debug( 532 "RolapEvaluator.getProperty: member == null " 533 + " , count=" + i); 534 } 535 continue; 536 } 537 538 Object p = member.getPropertyValue(name); 539 if (p != null) { 540 int solve = member.getSolveOrder(); 541 if (solve > maxSolve) { 542 o = p; 543 maxSolve = solve; 544 } 545 } 546 } 547 return o; 548 } 549 550 557 public String getFormatString() { 558 Exp formatExp = (Exp) getProperty(Property.FORMAT_EXP.name, null); 559 if (formatExp == null) { 560 return "Standard"; 561 } 562 Calc formatCalc = root.getCompiled(formatExp, true); 563 Object o = formatCalc.evaluate(this); 564 if (o == null) { 565 return "Standard"; 566 } 567 return o.toString(); 568 } 569 570 private Format getFormat() { 571 String formatString = getFormatString(); 572 return getFormat(formatString); 573 } 574 575 private Format getFormat(String formatString) { 576 return Format.get(formatString, root.connection.getLocale()); 577 } 578 579 public Locale getConnectionLocale() { 580 return root.connection.getLocale(); 581 } 582 583 587 String format(Evaluator evaluator, Object o) { 588 return getFormat().format(o); 589 } 590 591 public String format(Object o) { 592 if (o == Util.nullValue) { 593 Format format = getFormat(); 594 return format.format(null); 595 } else if (o instanceof Throwable ) { 596 return "#ERR: " + o.toString(); 597 } else if (o instanceof String ) { 598 return (String ) o; 599 } else { 600 Format format = getFormat(); 601 return format.format(o); 602 } 603 } 604 605 public String format(Object o, String formatString) { 606 if (o == Util.nullValue) { 607 Format format = getFormat(formatString); 608 return format.format(null); 609 } else if (o instanceof Throwable ) { 610 return "#ERR: " + o.toString(); 611 } else if (o instanceof String ) { 612 return (String ) o; 613 } else { 614 Format format = getFormat(formatString); 615 return format.format(o); 616 } 617 } 618 619 624 private Object getExpResultCacheKey(ExpCacheDescriptor descriptor) { 625 List<Object > key = new ArrayList<Object >(); 626 key.add(descriptor.getExp()); 627 int[] dimensionOrdinals = descriptor.getDependentDimensionOrdinals(); 628 for (int i = 0; i < dimensionOrdinals.length; i++) { 629 int dimensionOrdinal = dimensionOrdinals[i]; 630 Member member = currentMembers[dimensionOrdinal]; 631 632 if (member == null) { 634 getLogger().debug( 635 "RolapEvaluator.getExpResultCacheKey: " + 636 "member == null; dimensionOrdinal=" + i); 637 continue; 638 } 639 640 key.add(member); 641 } 642 return key; 643 } 644 645 public Object getCachedResult(ExpCacheDescriptor cacheDescriptor) { 646 Object key = getExpResultCacheKey(cacheDescriptor); 649 Object result = root.expResultCache.get(key); 650 if (result == null) { 651 result = cacheDescriptor.evaluate(this); 652 root.expResultCache.put(key, result == null ? nullResult : result); 653 } else if (result == nullResult) { 654 result = null; 655 } 656 return result; 657 } 658 659 public void clearExpResultCache() { 660 root.expResultCache.clear(); 661 662 root.clearNamedSets(); 669 } 670 671 public boolean isNonEmpty() { 672 return nonEmpty; 673 } 674 675 public void setNonEmpty(boolean nonEmpty) { 676 this.nonEmpty = nonEmpty; 677 } 678 679 public RuntimeException newEvalException(Object context, String s) { 680 return FunUtil.newEvalException((FunDef) context, s); 681 } 682 683 public Object evaluateNamedSet(String name, Exp exp) { 684 return root.evaluateNamedSet(name, exp); 685 } 686 687 public int getMissCount() { 688 return cellReader.getMissCount(); 689 } 690 691 public Object getParameterValue(ParameterSlot slot) { 692 return root.getParameterValue(slot); 693 } 694 695 void addCalcMember(Member member) { 696 assert member != null; 697 assert member.isCalculated(); 698 calcMembers[calcMemberCount++] = member; 699 } 700 701 private Member peekCalcMember() { 702 switch (calcMemberCount) { 703 case 0: 704 return null; 705 706 case 1: 707 return calcMembers[0]; 708 709 default: 710 Member maxSolveMember = calcMembers[0]; 712 int maxSolve = maxSolveMember.getSolveOrder(); 713 for (int i = 1; i < calcMemberCount; i++) { 714 Member member = calcMembers[i]; 715 int solve = member.getSolveOrder(); 716 if (solve >= maxSolve) { 717 if (solve > maxSolve || 720 member.getDimension().getOrdinal(root.cube) < 721 maxSolveMember.getDimension().getOrdinal( 722 root.cube)) { 723 maxSolve = solve; 724 maxSolveMember = member; 725 } 726 } 727 } 728 return maxSolveMember; 729 } 730 } 731 732 private void removeCalcMember(Member previous) { 733 for (int i = 0; i < calcMemberCount; i++) { 734 Member calcMember = calcMembers[i]; 735 if (calcMember == previous) { 736 --calcMemberCount; 738 calcMembers[i] = calcMembers[calcMemberCount]; 739 calcMembers[calcMemberCount] = null; } 741 } 742 } 743 744 public int getIterationLength() { 745 return iterationLength; 746 } 747 748 public void setIterationLength(int length) { 749 iterationLength = length; 750 } 751 752 public boolean isEvalAxes() { 753 return evalAxes; 754 } 755 756 public void setEvalAxes(boolean evalAxes) { 757 this.evalAxes = evalAxes; 758 } 759 } 760 761 | Popular Tags |