1 9 package mondrian.rolap; 10 11 import java.util.*; 12 import java.sql.*; 13 14 import mondrian.calc.ExpCompiler.ResultStyle; 15 import mondrian.olap.*; 16 import mondrian.rolap.TupleReader.MemberBuilder; 17 import mondrian.rolap.cache.HardSmartCache; 18 import mondrian.rolap.cache.SmartCache; 19 import mondrian.rolap.cache.SoftSmartCache; 20 import mondrian.rolap.sql.MemberChildrenConstraint; 21 import mondrian.rolap.sql.SqlQuery; 22 import mondrian.rolap.sql.TupleConstraint; 23 import mondrian.mdx.*; 24 25 import org.apache.log4j.Logger; 26 27 import javax.sql.DataSource ; 28 29 41 public abstract class RolapNativeSet extends RolapNative { 42 protected static final Logger LOGGER = Logger.getLogger(RolapNativeSet.class); 43 44 private SmartCache<Object , List<List<RolapMember>>> cache = 45 new SoftSmartCache<Object , List<List<RolapMember>>>(); 46 47 55 protected abstract boolean isStrict(); 56 57 61 protected static abstract class SetConstraint extends SqlContextConstraint { 62 CrossJoinArg[] args; 63 64 SetConstraint(CrossJoinArg[] args, RolapEvaluator evaluator, boolean strict) { 65 super(evaluator, strict); 66 this.args = args; 67 } 68 69 73 protected boolean isJoinRequired() { 74 return args.length > 1 || super.isJoinRequired(); 75 } 76 77 public void addConstraint( 78 SqlQuery sqlQuery, 79 Map<RolapLevel, RolapStar.Column> levelToColumnMap) { 80 super.addConstraint(sqlQuery, levelToColumnMap); 81 for (CrossJoinArg arg : args) { 82 if (!(arg instanceof MemberListCrossJoinArg) || 87 !((MemberListCrossJoinArg) arg).hasCalcMembers()) { 88 arg.addConstraint(sqlQuery, levelToColumnMap); 89 } 90 } 91 } 92 93 98 public MemberChildrenConstraint getMemberChildrenConstraint(RolapMember parent) { 99 return null; 100 } 101 102 105 public Object getCacheKey() { 106 List<Object > key = new ArrayList<Object >(); 107 key.add(super.getCacheKey()); 108 for (CrossJoinArg arg : args) { 112 if (!(arg instanceof MemberListCrossJoinArg) || 113 !((MemberListCrossJoinArg) arg).hasCalcMembers()) { 114 key.add(arg); 115 } 116 } 117 return key; 118 } 119 } 120 121 protected class SetEvaluator implements NativeEvaluator { 122 private CrossJoinArg[] args; 123 private SchemaReader schemaReader; 124 private TupleConstraint constraint; 125 private int maxRows = 0; 126 127 public SetEvaluator( 128 CrossJoinArg[] args, 129 SchemaReader schemaReader, 130 TupleConstraint constraint) { 131 this.args = args; 132 this.schemaReader = schemaReader; 133 this.constraint = constraint; 134 } 135 136 public Object execute(ResultStyle desiredResultStyle) { 137 switch (desiredResultStyle) { 138 case ITERABLE : 139 return executeIterable(); 140 case MUTABLE_LIST : 141 case LIST : 142 return executeList(); 143 } 144 throw ResultStyleException.generate( 145 new ResultStyle[] { 146 ResultStyle.ITERABLE, 147 ResultStyle.MUTABLE_LIST, 148 ResultStyle.LIST 149 }, 150 new ResultStyle[] { 151 desiredResultStyle 152 } 153 ); 154 } 155 protected Object executeIterable() { 156 final List list = executeList(); 157 if (args.length == 1) { 158 return new Iterable <Member>() { 159 public Iterator<Member> iterator() { 160 return new Iterator<Member>() { 161 int index = 0; 162 public boolean hasNext() { 163 return (index < list.size()); 164 } 165 public Member next() { 166 return (Member) list.get(index++); 167 } 168 public void remove() { 169 throw new UnsupportedOperationException ("remove"); 170 } 171 }; 172 } 173 }; 174 } else { 175 return new Iterable <Member[]>() { 176 public Iterator<Member[]> iterator() { 177 return new Iterator<Member[]>() { 178 int index = 0; 179 public boolean hasNext() { 180 return (index < list.size()); 181 } 182 public Member[] next() { 183 return (Member[]) list.get(index++); 184 } 185 public void remove() { 186 throw new UnsupportedOperationException ("remove"); 187 } 188 }; 189 } 190 }; 191 } 192 } 193 protected List executeList() { 194 SqlTupleReader tr = new SqlTupleReader(constraint); 195 tr.setMaxRows(maxRows); 196 for (CrossJoinArg arg : args) { 197 addLevel(tr, arg); 198 } 199 200 Object key = tr.getCacheKey(); 206 List<List<RolapMember>> result = cache.get(key); 207 boolean hasEnumTargets = (tr.getEnumTargetCount() > 0); 208 if (result != null && !hasEnumTargets) { 209 if (listener != null) { 210 TupleEvent e = new TupleEvent(this, tr); 211 listener.foundInCache(e); 212 } 213 return copy(result); 214 } 215 216 if (result == null && listener != null) { 218 TupleEvent e = new TupleEvent(this, tr); 219 listener.excutingSql(e); 220 } 221 222 List<List<RolapMember>> partialResult = result; 225 result = null; 226 List<List<RolapMember>> newPartialResult = null; 227 if (hasEnumTargets && partialResult == null) { 228 newPartialResult = new ArrayList<List<RolapMember>>(); 229 } 230 DataSource dataSource = schemaReader.getDataSource(); 231 if (args.length == 1) { 232 result = (List) tr.readMembers(dataSource, partialResult, newPartialResult); 233 } else { 234 result = (List) tr.readTuples(dataSource, partialResult, newPartialResult); 235 } 236 237 if (hasEnumTargets) { 238 if (newPartialResult != null) { 239 cache.put(key, newPartialResult); 240 } 241 } else { 242 cache.put(key, result); 243 } 244 return copy(result); 245 } 246 247 250 private <T> List<T> copy(List<T> list) { 251 return new ArrayList<T>(list); 252 } 253 254 private void addLevel(TupleReader tr, CrossJoinArg arg) { 255 RolapLevel level = arg.getLevel(); 256 RolapHierarchy hierarchy = level.getHierarchy(); 257 MemberReader mr = hierarchy.getMemberReader(schemaReader.getRole()); 258 MemberBuilder mb = mr.getMemberBuilder(); 259 Util.assertTrue(mb != null, "MemberBuilder not found"); 260 261 if (arg instanceof MemberListCrossJoinArg && 262 ((MemberListCrossJoinArg) arg).hasCalcMembers()) 263 { 264 tr.addLevelMembers(level, mb, arg.getMembers()); 269 } else { 270 tr.addLevelMembers(level, mb, null); 271 } 272 } 273 274 int getMaxRows() { 275 return maxRows; 276 } 277 278 void setMaxRows(int maxRows) { 279 this.maxRows = maxRows; 280 } 281 } 282 283 290 protected interface CrossJoinArg { 291 RolapLevel getLevel(); 292 293 RolapMember[] getMembers(); 294 295 void addConstraint( 296 SqlQuery sqlQuery, 297 Map<RolapLevel, RolapStar.Column> levelToColumnMap); 298 299 boolean isPreferInterpreter(); 300 } 301 302 313 protected static class DescendantsCrossJoinArg implements CrossJoinArg { 314 RolapMember member; 315 RolapLevel level; 316 317 public DescendantsCrossJoinArg(RolapLevel level, RolapMember member) { 318 this.level = level; 319 this.member = member; 320 } 321 322 public RolapLevel getLevel() { 323 return level; 324 } 325 326 public RolapMember[] getMembers() { 327 if (member == null) { 328 return null; 329 } 330 return new RolapMember[] { member }; 331 } 332 333 public boolean isPreferInterpreter() { 334 return false; 335 } 336 337 private boolean equals(Object o1, Object o2) { 338 return o1 == null ? o2 == null : o1.equals(o2); 339 } 340 341 public boolean equals(Object obj) { 342 if (!(obj instanceof DescendantsCrossJoinArg)) { 343 return false; 344 } 345 DescendantsCrossJoinArg that = (DescendantsCrossJoinArg) obj; 346 if (!equals(this.level, that.level)) { 347 return false; 348 } 349 return equals(this.member, that.member); 350 } 351 352 public int hashCode() { 353 int c = 1; 354 if (level != null) { 355 c = level.hashCode(); 356 } 357 if (member != null) { 358 c = 31 * c + member.hashCode(); 359 } 360 return c; 361 } 362 363 public void addConstraint( 364 SqlQuery sqlQuery, 365 Map<RolapLevel, RolapStar.Column> levelToColumnMap) { 366 if (member != null) { 367 SqlConstraintUtils.addMemberConstraint( 368 sqlQuery, levelToColumnMap, null, member, true); 369 } 370 } 371 } 372 373 380 protected static class MemberListCrossJoinArg implements CrossJoinArg { 381 private RolapMember[] members; 382 private RolapLevel level = null; 383 private boolean strict; 384 private boolean hasCalcMembers; 385 386 private MemberListCrossJoinArg( 387 RolapLevel level, RolapMember[] members, boolean strict, 388 boolean hasCalcMembers) { 389 this.level = level; 390 this.members = members; 391 this.strict = strict; 392 this.hasCalcMembers = hasCalcMembers; 393 } 394 395 402 static CrossJoinArg create(Exp[] args, boolean strict) { 403 if (args.length == 0) { 404 return null; 405 } 406 RolapLevel level = null; 407 boolean hasCalcMembers = false; 408 for (int i = 0; i < args.length; i++) { 409 if (!(args[i] instanceof MemberExpr)) { 410 return null; 411 } 412 RolapMember m = (RolapMember) ((MemberExpr) args[i]).getMember(); 413 if (m.isCalculated()) { 414 if (strict) { 415 return null; 416 } 417 hasCalcMembers = true; 418 } 419 if (i == 0) { 420 level = m.getLevel(); 421 } else if (!level.equals(m.getLevel())) { 422 return null; 423 } 424 } 425 if (!isSimpleLevel(level)) { 426 return null; 427 } 428 RolapMember[] members = new RolapMember[args.length]; 429 for (int i = 0; i < members.length; i++) { 430 members[i] = (RolapMember) ((MemberExpr) args[i]).getMember(); 431 } 432 return new MemberListCrossJoinArg( 433 level, members, strict, hasCalcMembers); 434 } 435 436 public RolapLevel getLevel() { 437 return level; 438 } 439 440 public RolapMember[] getMembers() { 441 return members; 442 } 443 444 public boolean isPreferInterpreter() { 445 return true; 446 } 447 448 public boolean hasCalcMembers() { 449 return hasCalcMembers; 450 } 451 452 public int hashCode() { 453 int c = 12; 454 for (RolapMember member : members) { 455 c = 31 * c + member.hashCode(); 456 } 457 if (strict) { 458 c += 1; 459 } 460 return c; 461 } 462 463 public boolean equals(Object obj) { 464 if (!(obj instanceof MemberListCrossJoinArg)) { 465 return false; 466 } 467 MemberListCrossJoinArg that = (MemberListCrossJoinArg) obj; 468 if (this.strict != that.strict) { 469 return false; 470 } 471 for (int i = 0; i < members.length; i++) { 472 if (this.members[i] != that.members[i]) { 473 return false; 474 } 475 } 476 return true; 477 } 478 479 public void addConstraint( 480 SqlQuery sqlQuery, 481 Map<RolapLevel, RolapStar.Column> levelToColumnMap) { 482 SqlConstraintUtils.addMemberConstraint( 483 sqlQuery, levelToColumnMap, null, Arrays.asList(members), 484 strict, true); 485 } 486 } 487 488 494 protected CrossJoinArg checkDescendants(FunDef fun, Exp[] args) { 495 if (!"Descendants".equalsIgnoreCase(fun.getName())) { 496 return null; 497 } 498 if (args.length != 2) { 499 return null; 500 } 501 if (!(args[0] instanceof MemberExpr)) { 502 return null; 503 } 504 RolapMember member = (RolapMember) ((MemberExpr) args[0]).getMember(); 505 if (member.isCalculated()) { 506 return null; 507 } 508 if (!(args[1] instanceof LevelExpr)) { 509 return null; 510 } 511 RolapLevel level = (RolapLevel) ((LevelExpr) args[1]).getLevel(); 512 if (!isSimpleLevel(level)) { 513 return null; 514 } 515 return new DescendantsCrossJoinArg(level, member); 516 } 517 518 524 protected CrossJoinArg checkLevelMembers(FunDef fun, Exp[] args) { 525 if (!"Members".equalsIgnoreCase(fun.getName())) { 526 return null; 527 } 528 if (args.length != 1) { 529 return null; 530 } 531 if (!(args[0] instanceof LevelExpr)) { 532 return null; 533 } 534 RolapLevel level = (RolapLevel) ((LevelExpr) args[0]).getLevel(); 535 if (!isSimpleLevel(level)) { 536 return null; 537 } 538 return new DescendantsCrossJoinArg(level, null); 539 } 540 541 547 protected CrossJoinArg checkMemberChildren(FunDef fun, Exp[] args) { 548 if (!"Children".equalsIgnoreCase(fun.getName())) { 549 return null; 550 } 551 if (args.length != 1) { 552 return null; 553 } 554 if (!(args[0] instanceof MemberExpr)) { 555 return null; 556 } 557 RolapMember member = (RolapMember) ((MemberExpr) args[0]).getMember(); 558 if (member.isCalculated()) { 559 return null; 560 } 561 RolapLevel level = member.getLevel(); 562 level = (RolapLevel) level.getChildLevel(); 563 if (level == null || !isSimpleLevel(level)) { 564 return null; 566 } 567 return new DescendantsCrossJoinArg(level, member); 568 } 569 570 577 protected CrossJoinArg checkEnumeration(FunDef fun, Exp[] args) { 578 if (!"{}".equalsIgnoreCase(fun.getName())) { 579 return null; 580 } 581 return MemberListCrossJoinArg.create(args, isStrict()); 582 } 583 584 590 protected CrossJoinArg[] checkCrossJoin(FunDef fun, Exp[] args) { 591 if (!"Crossjoin".equalsIgnoreCase(fun.getName()) && 593 !"NonEmptyCrossJoin".equalsIgnoreCase(fun.getName())) 594 { 595 return null; 596 } 597 if (args.length != 2) { 598 return null; 599 } 600 CrossJoinArg[] arg0 = checkCrossJoinArg(args[0]); 601 if (arg0 == null) { 602 return null; 603 } 604 CrossJoinArg[] arg1 = checkCrossJoinArg(args[1]); 605 if (arg1 == null) { 606 return null; 607 } 608 CrossJoinArg[] ret = new CrossJoinArg[arg0.length + arg1.length]; 609 System.arraycopy(arg0, 0, ret, 0, arg0.length); 610 System.arraycopy(arg1, 0, ret, arg0.length, arg1.length); 611 return ret; 612 } 613 614 617 protected CrossJoinArg[] checkCrossJoinArg(Exp exp) { 618 if (exp instanceof NamedSetExpr) { 619 NamedSet namedSet = ((NamedSetExpr) exp).getNamedSet(); 620 exp = namedSet.getExp(); 621 } 622 if (!(exp instanceof ResolvedFunCall)) { 623 return null; 624 } 625 final ResolvedFunCall funCall = (ResolvedFunCall) exp; 626 FunDef fun = funCall.getFunDef(); 627 Exp[] args = funCall.getArgs(); 628 629 CrossJoinArg arg; 630 arg = checkMemberChildren(fun, args); 631 if (arg != null) { 632 return new CrossJoinArg[] {arg}; 633 } 634 arg = checkLevelMembers(fun, args); 635 if (arg != null) { 636 return new CrossJoinArg[] {arg}; 637 } 638 arg = checkDescendants(fun, args); 639 if (arg != null) { 640 return new CrossJoinArg[] {arg}; 641 } 642 arg = checkEnumeration(fun, args); 643 if (arg != null) { 644 return new CrossJoinArg[] {arg}; 645 } 646 return checkCrossJoin(fun, args); 647 } 648 649 652 protected static boolean isSimpleLevel(RolapLevel level) { 653 RolapHierarchy hier = level.getHierarchy(); 654 if (hier.isRagged()) { 656 return false; 657 } 658 if (level.isParentChild()) { 660 return false; 661 } 662 if (level.isMeasure()) { 664 return false; 665 } 666 return true; 667 } 668 669 675 protected boolean isPreferInterpreter(CrossJoinArg[] args) { 676 for (CrossJoinArg arg : args) { 677 if (!arg.isPreferInterpreter()) { 678 return false; 679 } 680 } 681 return true; 682 } 683 684 685 void useHardCache(boolean hard) { 686 if (hard) { 687 cache = new HardSmartCache(); 688 } else { 689 cache = new SoftSmartCache(); 690 } 691 } 692 693 705 protected RolapEvaluator overrideContext( 706 RolapEvaluator evaluator, 707 CrossJoinArg[] cargs, 708 RolapStoredMeasure storedMeasure) 709 { 710 SchemaReader schemaReader = evaluator.getSchemaReader(); 711 RolapEvaluator newEvaluator = (RolapEvaluator) evaluator.push(); 712 for (CrossJoinArg carg : cargs) { 713 Hierarchy hierarchy = carg.getLevel().getHierarchy(); 714 Member defaultMember = 715 schemaReader.getHierarchyDefaultMember(hierarchy); 716 newEvaluator.setContext(defaultMember); 717 } 718 if (storedMeasure != null) 719 newEvaluator.setContext(storedMeasure); 720 return newEvaluator; 721 } 722 } 723 724 | Popular Tags |