001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/CrossJoinFunDef.java#59 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2002-2002 Kana Software, Inc. 007 // Copyright (C) 2003-2008 Julian Hyde and others 008 // All Rights Reserved. 009 // You must accept the terms of that agreement to use this software. 010 */ 011 package mondrian.olap.fun; 012 013 import mondrian.calc.*; 014 import mondrian.calc.impl.AbstractIterCalc; 015 import mondrian.calc.impl.AbstractListCalc; 016 import mondrian.mdx.*; 017 import mondrian.olap.*; 018 import mondrian.olap.type.SetType; 019 import mondrian.olap.type.TupleType; 020 import mondrian.olap.type.Type; 021 import mondrian.util.UnsupportedList; 022 import mondrian.rolap.*; 023 024 import java.util.*; 025 026 /** 027 * Definition of the <code>CrossJoin</code> MDX function. 028 * 029 * @author jhyde 030 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/CrossJoinFunDef.java#59 $ 031 * @since Mar 23, 2006 032 */ 033 public class CrossJoinFunDef extends FunDefBase { 034 static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver( 035 "Crossjoin", 036 "Crossjoin(<Set1>, <Set2>)", 037 "Returns the cross product of two sets.", 038 new String[]{"fxxx"}, 039 CrossJoinFunDef.class); 040 041 static final StarCrossJoinResolver StarResolver = new StarCrossJoinResolver(); 042 043 private static int counterTag = 0; 044 045 // used to tell the difference between crossjoin expressions. 046 private final int ctag = counterTag++; 047 048 public CrossJoinFunDef(FunDef dummyFunDef) { 049 super(dummyFunDef); 050 } 051 052 public Type getResultType(Validator validator, Exp[] args) { 053 // CROSSJOIN(<Set1>,<Set2>) has type [Hie1] x [Hie2]. 054 List<Type> list = new ArrayList<Type>(); 055 for (Exp arg : args) { 056 final Type type = arg.getType(); 057 if (type instanceof SetType) { 058 addTypes(type, list); 059 } else if (getName().equals("*")) { 060 // The "*" form of CrossJoin is lenient: args can be either 061 // members/tuples or sets. 062 addTypes(type, list); 063 } else { 064 throw Util.newInternal("arg to crossjoin must be a set"); 065 } 066 } 067 final Type[] types = list.toArray(new Type[list.size()]); 068 final TupleType tupleType = new TupleType(types); 069 return new SetType(tupleType); 070 } 071 072 /** 073 * Adds a type to a list of types. If type is a {@link TupleType}, does so 074 * recursively. 075 * 076 * @param type Type to add to list 077 * @param list List of types to add to 078 */ 079 private static void addTypes(final Type type, List<Type> list) { 080 if (type instanceof SetType) { 081 SetType setType = (SetType) type; 082 addTypes(setType.getElementType(), list); 083 } else if (type instanceof TupleType) { 084 TupleType tupleType = (TupleType) type; 085 for (Type elementType : tupleType.elementTypes) { 086 addTypes(elementType, list); 087 } 088 } else { 089 list.add(type); 090 } 091 } 092 093 public Calc compileCall(final ResolvedFunCall call, ExpCompiler compiler) { 094 // What is the desired return type? 095 for (ResultStyle r : compiler.getAcceptableResultStyles()) { 096 switch (r) { 097 case ITERABLE: 098 case ANY: 099 // Consumer wants ITERABLE or ANY 100 return compileCallIterable(call, compiler); 101 case LIST: 102 // Consumer wants (immutable) LIST 103 return compileCallImmutableList(call, compiler); 104 case MUTABLE_LIST: 105 // Consumer MUTABLE_LIST 106 return compileCallMutableList(call, compiler); 107 } 108 } 109 throw ResultStyleException.generate( 110 ResultStyle.ITERABLE_LIST_MUTABLELIST_ANY, 111 compiler.getAcceptableResultStyles()); 112 } 113 114 /////////////////////////////////////////////////////////////////////////// 115 /////////////////////////////////////////////////////////////////////////// 116 // Iterable 117 /////////////////////////////////////////////////////////////////////////// 118 /////////////////////////////////////////////////////////////////////////// 119 120 protected IterCalc compileCallIterable( 121 final ResolvedFunCall call, 122 ExpCompiler compiler) 123 { 124 final Calc calc1 = toIter(compiler, call.getArg(0)); 125 final Calc calc2 = toIter(compiler, call.getArg(1)); 126 Calc[] calcs = new Calc[] {calc1, calc2}; 127 // The Calcs, 1 and 2, can be of type: Member or Member[] and 128 // of ResultStyle: ITERABLE, LIST or MUTABLE_LIST, but 129 // LIST and MUTABLE_LIST are treated the same; so 130 // there are 16 possible combinations - sweet. 131 132 // Check returned calc ResultStyles 133 checkIterListResultStyles(calc1); 134 checkIterListResultStyles(calc2); 135 136 if (isMemberType(calc1)) { 137 // Member 138 if (isMemberType(calc2)) { 139 // Member 140 if (calc1.getResultStyle() == ResultStyle.ITERABLE) { 141 if (calc2.getResultStyle() == ResultStyle.ITERABLE) { 142 return new IterMemberIterMemberIterCalc(call, calcs); 143 } else { 144 return new IterMemberListMemberIterCalc(call, calcs); 145 } 146 } else { 147 if (calc2.getResultStyle() == ResultStyle.ITERABLE) { 148 return new ListMemberIterMemberIterCalc(call, calcs); 149 } else { 150 return new ListMemberListMemberIterCalc(call, calcs); 151 } 152 } 153 } else { 154 // Member[] 155 if (calc1.getResultStyle() == ResultStyle.ITERABLE) { 156 if (calc2.getResultStyle() == ResultStyle.ITERABLE) { 157 return new IterMemberIterMemberArrayIterCalc(call, calcs); 158 } else { 159 return new IterMemberListMemberArrayIterCalc(call, calcs); 160 } 161 } else { 162 if (calc2.getResultStyle() == ResultStyle.ITERABLE) { 163 return new ListMemberIterMemberArrayIterCalc(call, calcs); 164 } else { 165 return new ListMemberListMemberArrayIterCalc(call, calcs); 166 } 167 } 168 } 169 } else { 170 // Member[] 171 if (isMemberType(calc2)) { 172 // Member 173 if (calc1.getResultStyle() == ResultStyle.ITERABLE) { 174 if (calc2.getResultStyle() == ResultStyle.ITERABLE) { 175 return new IterMemberArrayIterMemberIterCalc(call, calcs); 176 } else { 177 return new IterMemberArrayListMemberIterCalc(call, calcs); 178 } 179 } else { 180 if (calc2.getResultStyle() == ResultStyle.ITERABLE) { 181 return new ListMemberArrayIterMemberIterCalc(call, calcs); 182 } else { 183 return new ListMemberArrayListMemberIterCalc(call, calcs); 184 } 185 } 186 } else { 187 // Member[] 188 if (calc1.getResultStyle() == ResultStyle.ITERABLE) { 189 if (calc2.getResultStyle() == ResultStyle.ITERABLE) { 190 return new IterMemberArrayIterMemberArrayIterCalc(call, calcs); 191 } else { 192 return new IterMemberArrayListMemberArrayIterCalc(call, calcs); 193 } 194 } else { 195 if (calc2.getResultStyle() == ResultStyle.ITERABLE) { 196 return new ListMemberArrayIterMemberArrayIterCalc(call, calcs); 197 } else { 198 return new ListMemberArrayListMemberArrayIterCalc(call, calcs); 199 } 200 } 201 } 202 } 203 } 204 private Calc toIter(ExpCompiler compiler, final Exp exp) { 205 // Want iterable, immutable list or mutable list in that order 206 // It is assumed that an immutable list is easier to get than 207 // a mutable list. 208 final Type type = exp.getType(); 209 if (type instanceof SetType) { 210 // this can return an IterCalc or ListCalc 211 return compiler.compileAs(exp, 212 null, ResultStyle.ITERABLE_LIST_MUTABLELIST); 213 } else { 214 // this always returns an IterCalc 215 return new SetFunDef.IterSetCalc( 216 new DummyExp(new SetType(type)), 217 new Exp[] {exp}, 218 compiler, 219 ResultStyle.ITERABLE_LIST_MUTABLELIST); 220 } 221 } 222 private abstract class BaseIterCalc extends AbstractIterCalc { 223 protected BaseIterCalc(ResolvedFunCall call, Calc[] calcs) { 224 super(call, calcs); 225 } 226 public Iterable evaluateIterable(Evaluator evaluator) { 227 ResolvedFunCall call = (ResolvedFunCall) exp; 228 // Use a native evaluator, if more efficient. 229 // TODO: Figure this out at compile time. 230 SchemaReader schemaReader = evaluator.getSchemaReader(); 231 NativeEvaluator nativeEvaluator = 232 schemaReader.getNativeSetEvaluator( 233 call.getFunDef(), call.getArgs(), evaluator, this); 234 if (nativeEvaluator != null) { 235 return (Iterable) nativeEvaluator.execute( 236 ResultStyle.ITERABLE); 237 } 238 239 Calc[] calcs = getCalcs(); 240 Calc calc1 = calcs[0]; 241 Calc calc2 = calcs[1]; 242 243 Evaluator oldEval = null; 244 assert (oldEval = evaluator.push()) != null; 245 246 Object o1 = calc1.evaluate(evaluator); 247 assert oldEval.equals(evaluator) : "calc1 changed context"; 248 249 if (o1 instanceof List) { 250 List l1 = (List) o1; 251 //l1 = checkList(evaluator, l1); 252 l1 = nonEmptyOptimizeList(evaluator, l1, call); 253 if (l1.isEmpty()) { 254 return Collections.EMPTY_LIST; 255 } 256 o1 = l1; 257 } 258 259 Object o2 = calc2.evaluate(evaluator); 260 assert oldEval.equals(evaluator) : "calc2 changed context"; 261 262 if (o2 instanceof List) { 263 List l2 = (List) o2; 264 //l2 = checkList(evaluator, l2); 265 l2 = nonEmptyOptimizeList(evaluator, l2, call); 266 if (l2.isEmpty()) { 267 return Collections.EMPTY_LIST; 268 } 269 o2 = l2; 270 } 271 272 return makeIterable(o1, o2); 273 } 274 275 /** 276 * Derived classes implement and create Iterable<Member[]> 277 * based upon the types of the parameters: 278 * List<Member>, 279 * List<Member[]>, 280 * Iterable<Member>, or 281 * Iterable<Member[]>. 282 * 283 * @param o1 List or Iterable of Member or Member[] 284 * @param o2 List or Iterable of Member or Member[] 285 * @return Iterable<Member[]> over contents of o1 and o2 286 */ 287 protected abstract Iterable<Member[]> makeIterable(Object o1, Object o2); 288 289 /** 290 * Derived classes implement depending upon the types of parameter 291 * o1 and o2. 292 * 293 * @param o1 Member or Member[] 294 * @param o2 Member or Member[] 295 * @return combining o1 and o2 into Member[] 296 */ 297 protected abstract Member[] makeNext(Object o1, Object o2); 298 299 protected Iterable<Member[]> makeIterableIterable( 300 final Iterable it1, 301 final Iterable it2) 302 { 303 // There is no knowledge about how large either it1 ore it2 304 // are or how many null members they might have, so all 305 // one can do is iterate across them: 306 // iterate across it1 and for each member iterate across it2 307 308 return new Iterable<Member[]>() { 309 public Iterator<Member[]> iterator() { 310 return new Iterator<Member[]>() { 311 Iterator i1 = it1.iterator(); 312 Object o1 = null; 313 Iterator i2 = it2.iterator(); 314 Object o2 = null; 315 public boolean hasNext() { 316 if (o2 != null) { 317 return true; 318 } 319 if (! hasNextO1()) { 320 return false; 321 } 322 if (! hasNextO2()) { 323 o1 = null; 324 // got to end of i2, get next m1 325 if (! hasNextO1()) { 326 return false; 327 } 328 // reset i2 329 i2 = it2.iterator(); 330 if (! hasNextO2()) { 331 return false; 332 } 333 } 334 return true; 335 } 336 public Member[] next() { 337 try { 338 return makeNext(o1, o2); 339 } finally { 340 o2 = null; 341 } 342 } 343 public void remove() { 344 throw new UnsupportedOperationException("remove"); 345 } 346 347 private boolean hasNextO1() { 348 while (o1 == null) { 349 if (! i1.hasNext()) { 350 return false; 351 } 352 o1 = i1.next(); 353 } 354 return true; 355 } 356 private boolean hasNextO2() { 357 o2 = null; 358 while (o2 == null) { 359 if (! i2.hasNext()) { 360 return false; 361 } 362 o2 = i2.next(); 363 } 364 return true; 365 } 366 }; 367 } 368 }; 369 } 370 371 protected Iterable<Member[]> makeIterableList( 372 final Iterable it1, 373 final List l2) 374 { 375 return new Iterable<Member[]>() { 376 public Iterator<Member[]> iterator() { 377 return new Iterator<Member[]>() { 378 Iterator i1 = it1.iterator(); 379 Object o1 = null; 380 int index2 = 0; 381 Object o2 = null; 382 public boolean hasNext() { 383 if (o2 != null) { 384 return true; 385 } 386 if (! hasNextO1()) { 387 return false; 388 } 389 if (! hasNextO2()) { 390 o1 = null; 391 // got to end of l2, get next m1 392 if (! hasNextO1()) { 393 return false; 394 } 395 // reset l2 396 index2 = 0; 397 if (! hasNextO2()) { 398 return false; 399 } 400 } 401 return true; 402 } 403 public Member[] next() { 404 try { 405 return makeNext(o1, o2); 406 } finally { 407 o2 = null; 408 } 409 } 410 public void remove() { 411 throw new UnsupportedOperationException("remove"); 412 } 413 414 private boolean hasNextO1() { 415 while (o1 == null) { 416 if (! i1.hasNext()) { 417 return false; 418 } 419 o1 = i1.next(); 420 } 421 return true; 422 } 423 private boolean hasNextO2() { 424 o2 = null; 425 while (o2 == null) { 426 if (index2 == l2.size()) { 427 return false; 428 } 429 o2 = l2.get(index2++); 430 } 431 return true; 432 } 433 }; 434 } 435 }; 436 } 437 438 protected Iterable<Member[]> makeListIterable( 439 final List l1, 440 final Iterable it2) 441 { 442 return new Iterable<Member[]>() { 443 public Iterator<Member[]> iterator() { 444 return new Iterator<Member[]>() { 445 int index1 = 0; 446 Object o1 = null; 447 Iterator i2 = it2.iterator(); 448 Object o2 = null; 449 public boolean hasNext() { 450 if (o2 != null) { 451 return true; 452 } 453 if (! hasNextO1()) { 454 return false; 455 } 456 if (! hasNextO2()) { 457 o1 = null; 458 // got to end of i2, get next o1 459 if (! hasNextO1()) { 460 return false; 461 } 462 // reset i2 463 i2 = it2.iterator(); 464 if (! hasNextO2()) { 465 return false; 466 } 467 } 468 return true; 469 } 470 public Member[] next() { 471 try { 472 return makeNext(o1, o2); 473 } finally { 474 o2 = null; 475 } 476 } 477 public void remove() { 478 throw new UnsupportedOperationException("remove"); 479 } 480 481 private boolean hasNextO1() { 482 while (o1 == null) { 483 if (index1 == l1.size()) { 484 return false; 485 } 486 o1 = l1.get(index1++); 487 } 488 return true; 489 } 490 private boolean hasNextO2() { 491 o2 = null; 492 while (o2 == null) { 493 if (! i2.hasNext()) { 494 return false; 495 } 496 o2 = i2.next(); 497 } 498 return true; 499 } 500 }; 501 } 502 }; 503 } 504 505 protected Iterable<Member[]> makeListList( 506 final List l1, 507 final List l2) 508 { 509 return new Iterable<Member[]>() { 510 public Iterator<Member[]> iterator() { 511 return new Iterator<Member[]>() { 512 int index1 = 0; 513 Object o1 = null; 514 int index2 = 0; 515 Object o2 = null; 516 public boolean hasNext() { 517 if (o2 != null) { 518 return true; 519 } 520 if (! hasNextO1()) { 521 return false; 522 } 523 if (! hasNextO2()) { 524 o1 = null; 525 // got to end of i2, get next o1 526 if (! hasNextO1()) { 527 return false; 528 } 529 // reset i2 530 index2 = 0; 531 if (! hasNextO2()) { 532 return false; 533 } 534 } 535 return true; 536 } 537 public Member[] next() { 538 try { 539 return makeNext(o1, o2); 540 } finally { 541 o2 = null; 542 } 543 } 544 public void remove() { 545 throw new UnsupportedOperationException("remove"); 546 } 547 548 private boolean hasNextO1() { 549 while (o1 == null) { 550 if (index1 == l1.size()) { 551 return false; 552 } 553 o1 = l1.get(index1++); 554 } 555 return true; 556 } 557 private boolean hasNextO2() { 558 o2 = null; 559 while (o2 == null) { 560 if (index2 == l2.size()) { 561 return false; 562 } 563 o2 = l2.get(index2++); 564 } 565 return true; 566 } 567 }; 568 } 569 }; 570 } 571 } 572 573 /////////////////////////////////////////////////////////////////////////// 574 575 // Member Member 576 abstract class BaseMemberMemberIterCalc 577 extends BaseIterCalc { 578 BaseMemberMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 579 super(call, calcs); 580 } 581 protected Member[] makeNext(Object o1, Object o2) { 582 return new Member[] {(Member) o1, (Member) o2}; 583 } 584 } 585 586 // Member Member[] 587 abstract class BaseMemberMemberArrayIterCalc 588 extends BaseIterCalc { 589 BaseMemberMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 590 super(call, calcs); 591 } 592 protected Member[] makeNext(Object o1, Object o2) { 593 Member m1 = (Member) o1; 594 Member[] ma2 = (Member[]) o2; 595 Member[] ma = new Member[ma2.length + 1]; 596 ma[0] = m1; 597 System.arraycopy(ma2, 0, ma, 1, ma2.length); 598 return ma; 599 } 600 } 601 602 // Member[] Member 603 abstract class BaseMemberArrayMemberIterCalc 604 extends BaseIterCalc { 605 BaseMemberArrayMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 606 super(call, calcs); 607 } 608 protected Member[] makeNext(Object o1, Object o2) { 609 Member[] ma1 = (Member[]) o1; 610 Member m2 = (Member) o2; 611 Member[] ma = new Member[ma1.length + 1]; 612 System.arraycopy(ma1, 0, ma, 0, ma1.length); 613 ma[ma1.length] = m2; 614 return ma; 615 } 616 } 617 618 // Member[] Member[] 619 abstract class BaseMemberArrayMemberArrayIterCalc 620 extends BaseIterCalc { 621 BaseMemberArrayMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 622 super(call, calcs); 623 } 624 protected Member[] makeNext(Object o1, Object o2) { 625 Member[] ma1 = (Member[]) o1; 626 Member[] ma2 = (Member[]) o2; 627 Member[] ma = new Member[ma1.length + ma2.length]; 628 System.arraycopy(ma1, 0, ma, 0, ma1.length); 629 System.arraycopy(ma2, 0, ma, ma1.length, ma2.length); 630 return ma; 631 } 632 } 633 634 /////////////////////////////////////////////////////////////////////////// 635 636 // ITERABLE Member ITERABLE Member 637 class IterMemberIterMemberIterCalc 638 extends BaseMemberMemberIterCalc { 639 IterMemberIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 640 super(call, calcs); 641 } 642 643 @SuppressWarnings({"unchecked"}) 644 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 645 Iterable<Member> it1 = (Iterable<Member>) o1; 646 Iterable<Member> it2 = (Iterable<Member>) o2; 647 return makeIterableIterable(it1, it2); 648 } 649 } 650 651 // ITERABLE Member LIST Member 652 class IterMemberListMemberIterCalc 653 extends BaseMemberMemberIterCalc { 654 IterMemberListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 655 super(call, calcs); 656 } 657 658 @SuppressWarnings({"unchecked"}) 659 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 660 Iterable<Member> it1 = (Iterable<Member>) o1; 661 List<Member> l2 = (List<Member>) o2; 662 663 if (l2 instanceof RandomAccess) { 664 // direct access faster 665 return makeIterableList(it1, l2); 666 } else { 667 // iteration faster 668 return makeIterableIterable(it1, l2); 669 } 670 } 671 } 672 673 // LIST Member ITERABLE Member 674 class ListMemberIterMemberIterCalc 675 extends BaseMemberMemberIterCalc { 676 ListMemberIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 677 super(call, calcs); 678 } 679 680 @SuppressWarnings({"unchecked"}) 681 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 682 List<Member> l1 = (List<Member>) o1; 683 Iterable<Member> it2 = (Iterable<Member>) o2; 684 685 if (l1 instanceof RandomAccess) { 686 // direct access faster 687 return makeListIterable(l1, it2); 688 } else { 689 // iteration faster 690 return makeIterableIterable(l1, it2); 691 } 692 } 693 } 694 695 // LIST Member LIST Member 696 class ListMemberListMemberIterCalc 697 extends BaseMemberMemberIterCalc { 698 ListMemberListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 699 super(call, calcs); 700 } 701 702 @SuppressWarnings({"unchecked"}) 703 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 704 List<Member> l1 = (List<Member>) o1; 705 List<Member> l2 = (List<Member>) o2; 706 707 if (l1 instanceof RandomAccess) { 708 // l1 direct access faster 709 if (l2 instanceof RandomAccess) { 710 // l2 direct access faster 711 return makeListList(l1, l2); 712 } else { 713 // l2 iteration faster 714 return makeListIterable(l1, l2); 715 } 716 } else { 717 // l1 iteration faster 718 if (l2 instanceof RandomAccess) { 719 // l2 direct access faster 720 return makeIterableList(l1, l2); 721 } else { 722 // l2 iteration faster 723 return makeIterableIterable(l1, l2); 724 } 725 } 726 } 727 } 728 729 /////////////////////////////////////////////////////////////////////////// 730 731 // ITERABLE Member ITERABLE Member[] 732 class IterMemberIterMemberArrayIterCalc 733 extends BaseMemberMemberArrayIterCalc { 734 IterMemberIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 735 super(call, calcs); 736 } 737 738 @SuppressWarnings({"unchecked"}) 739 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 740 Iterable<Member> it1 = (Iterable<Member>) o1; 741 Iterable<List<Member>> it2 = (Iterable<List<Member>>) o2; 742 return makeIterableIterable(it1, it2); 743 } 744 } 745 746 // ITERABLE Member LIST Member[] 747 class IterMemberListMemberArrayIterCalc 748 extends BaseMemberMemberArrayIterCalc { 749 IterMemberListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 750 super(call, calcs); 751 } 752 753 @SuppressWarnings({"unchecked"}) 754 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 755 Iterable<Member> it1 = (Iterable<Member>) o1; 756 List<List<Member>> l2 = (List<List<Member>>) o2; 757 758 if (l2 instanceof RandomAccess) { 759 // direct access faster 760 return makeIterableList(it1, l2); 761 } else { 762 // iteration faster 763 return makeIterableIterable(it1, l2); 764 } 765 } 766 } 767 768 // LIST Member ITERABLE Member[] 769 class ListMemberIterMemberArrayIterCalc 770 extends BaseMemberMemberArrayIterCalc { 771 ListMemberIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 772 super(call, calcs); 773 } 774 775 @SuppressWarnings({"unchecked"}) 776 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 777 List<Member> l1 = (List<Member>) o1; 778 Iterable<List<Member>> it2 = (Iterable<List<Member>>) o2; 779 780 if (l1 instanceof RandomAccess) { 781 // direct access faster 782 return makeListIterable(l1, it2); 783 } else { 784 // iteration faster 785 return makeIterableIterable(l1, it2); 786 } 787 } 788 } 789 790 // LIST Member LIST Member[] 791 class ListMemberListMemberArrayIterCalc 792 extends BaseMemberMemberArrayIterCalc { 793 ListMemberListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 794 super(call, calcs); 795 } 796 797 @SuppressWarnings({"unchecked"}) 798 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 799 List<Member> l1 = (List<Member>) o1; 800 List<List<Member>> l2 = (List<List<Member>>) o2; 801 802 if (l1 instanceof RandomAccess) { 803 // l1 direct access faster 804 if (l2 instanceof RandomAccess) { 805 // l2 direct access faster 806 return makeListList(l1, l2); 807 } else { 808 // l2 iteration faster 809 return makeListIterable(l1, l2); 810 } 811 } else { 812 // l1 iteration faster 813 if (l2 instanceof RandomAccess) { 814 // l2 direct access faster 815 return makeIterableList(l1, l2); 816 } else { 817 // l2 iteration faster 818 return makeIterableIterable(l1, l2); 819 } 820 } 821 } 822 } 823 824 /////////////////////////////////////////////////////////////////////////// 825 826 // ITERABLE Member[] ITERABLE Member 827 class IterMemberArrayIterMemberIterCalc 828 extends BaseMemberArrayMemberIterCalc { 829 IterMemberArrayIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 830 super(call, calcs); 831 } 832 833 @SuppressWarnings({"unchecked"}) 834 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 835 Iterable<List<Member>> it1 = (Iterable<List<Member>>) o1; 836 Iterable<Member> it2 = (Iterable<Member>) o2; 837 return makeIterableIterable(it1, it2); 838 } 839 } 840 841 // ITERABLE Member[] LIST Member 842 class IterMemberArrayListMemberIterCalc 843 extends BaseMemberArrayMemberIterCalc { 844 IterMemberArrayListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 845 super(call, calcs); 846 } 847 848 @SuppressWarnings({"unchecked"}) 849 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 850 Iterable<List<Member>> it1 = (Iterable<List<Member>>) o1; 851 List<Member> l2 = (List<Member>) o2; 852 853 if (l2 instanceof RandomAccess) { 854 // direct access faster 855 return makeIterableList(it1, l2); 856 } else { 857 // iteration faster 858 return makeIterableIterable(it1, l2); 859 } 860 } 861 } 862 863 // LIST Member[] ITERABLE Member 864 class ListMemberArrayIterMemberIterCalc 865 extends BaseMemberArrayMemberIterCalc { 866 ListMemberArrayIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 867 super(call, calcs); 868 } 869 870 @SuppressWarnings({"unchecked"}) 871 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 872 List<List<Member>> l1 = (List<List<Member>>) o1; 873 Iterable<Member> it2 = (Iterable<Member>) o2; 874 875 if (l1 instanceof RandomAccess) { 876 // direct access faster 877 return makeListIterable(l1, it2); 878 } else { 879 // iteration faster 880 return makeIterableIterable(l1, it2); 881 } 882 } 883 } 884 885 // LIST Member[] LIST Member 886 class ListMemberArrayListMemberIterCalc 887 extends BaseMemberArrayMemberIterCalc { 888 ListMemberArrayListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 889 super(call, calcs); 890 } 891 892 @SuppressWarnings({"unchecked"}) 893 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 894 List<List<Member>> l1 = (List<List<Member>>) o1; 895 List<Member> l2 = (List<Member>) o2; 896 897 if (l1 instanceof RandomAccess) { 898 // l1 direct access faster 899 if (l2 instanceof RandomAccess) { 900 // l2 direct access faster 901 return makeListList(l1, l2); 902 } else { 903 // l2 iteration faster 904 return makeListIterable(l1, l2); 905 } 906 } else { 907 // l1 iteration faster 908 if (l2 instanceof RandomAccess) { 909 // l2 direct access faster 910 return makeIterableList(l1, l2); 911 } else { 912 // l2 iteration faster 913 return makeIterableIterable(l1, l2); 914 } 915 } 916 } 917 } 918 919 /////////////////////////////////////////////////////////////////////////// 920 921 // ITERABLE Member[] ITERABLE Member[] 922 class IterMemberArrayIterMemberArrayIterCalc 923 extends BaseMemberArrayMemberArrayIterCalc { 924 IterMemberArrayIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 925 super(call, calcs); 926 } 927 928 @SuppressWarnings({"unchecked"}) 929 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 930 Iterable<List<Member>> it1 = (Iterable<List<Member>>) o1; 931 Iterable<List<Member>> it2 = (Iterable<List<Member>>) o2; 932 return makeIterableIterable(it1, it2); 933 } 934 } 935 936 // ITERABLE Member[] LIST Member[] 937 class IterMemberArrayListMemberArrayIterCalc 938 extends BaseMemberArrayMemberArrayIterCalc { 939 IterMemberArrayListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 940 super(call, calcs); 941 } 942 943 @SuppressWarnings({"unchecked"}) 944 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 945 Iterable<List<Member>> it1 = (Iterable<List<Member>>) o1; 946 List<List<Member>> l2 = (List<List<Member>>) o2; 947 948 if (l2 instanceof RandomAccess) { 949 // direct access faster 950 return makeIterableList(it1, l2); 951 } else { 952 // iteration faster 953 return makeIterableIterable(it1, l2); 954 } 955 } 956 } 957 958 // LIST Member[] ITERABLE Member[] 959 class ListMemberArrayIterMemberArrayIterCalc 960 extends BaseMemberArrayMemberArrayIterCalc { 961 ListMemberArrayIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 962 super(call, calcs); 963 } 964 965 @SuppressWarnings({"unchecked"}) 966 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 967 List<List<Member>> l1 = (List<List<Member>>) o1; 968 Iterable<List<Member>> it2 = (Iterable<List<Member>>) o2; 969 970 if (l1 instanceof RandomAccess) { 971 // direct access faster 972 return makeListIterable(l1, it2); 973 } else { 974 // iteration faster 975 return makeIterableIterable(l1, it2); 976 } 977 } 978 } 979 980 // LIST Member[] LIST Member[] 981 class ListMemberArrayListMemberArrayIterCalc 982 extends BaseMemberArrayMemberArrayIterCalc { 983 ListMemberArrayListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 984 super(call, calcs); 985 } 986 987 @SuppressWarnings({"unchecked"}) 988 protected Iterable<Member[]> makeIterable(Object o1, Object o2) { 989 List<List<Member>> l1 = (List<List<Member>>) o1; 990 List<List<Member>> l2 = (List<List<Member>>) o2; 991 992 if (l1 instanceof RandomAccess) { 993 // l1 direct access faster 994 if (l2 instanceof RandomAccess) { 995 // l2 direct access faster 996 return makeListList(l1, l2); 997 } else { 998 // l2 iteration faster 999 return makeListIterable(l1, l2); 1000 } 1001 } else { 1002 // l1 iteration faster 1003 if (l2 instanceof RandomAccess) { 1004 // l2 direct access faster 1005 return makeIterableList(l1, l2); 1006 } else { 1007 // l2 iteration faster 1008 return makeIterableIterable(l1, l2); 1009 } 1010 } 1011 } 1012 } 1013 1014 /////////////////////////////////////////////////////////////////////////// 1015 /////////////////////////////////////////////////////////////////////////// 1016 // Immutable List 1017 /////////////////////////////////////////////////////////////////////////// 1018 /////////////////////////////////////////////////////////////////////////// 1019 1020 protected ListCalc compileCallImmutableList(final ResolvedFunCall call, 1021 ExpCompiler compiler) { 1022 final ListCalc listCalc1 = toList(compiler, call.getArg(0)); 1023 final ListCalc listCalc2 = toList(compiler, call.getArg(1)); 1024 Calc[] calcs = new Calc[] {listCalc1, listCalc2}; 1025 // The Calcs, 1 and 2, can be of type: Member or Member[] and 1026 // of ResultStyle: LIST or MUTABLE_LIST. 1027 // Since we want an immutable list as the result, it does not 1028 // matter whether the Calc list are of type 1029 // LIST and MUTABLE_LIST - they are treated the same; so 1030 // there are 4 possible combinations - even sweeter. 1031 1032 // Check returned calc ResultStyles 1033 checkListResultStyles(listCalc1); 1034 checkListResultStyles(listCalc2); 1035 1036 if (isMemberType(listCalc1)) { 1037 // Member 1038 if (isMemberType(listCalc2)) { 1039 // Member 1040 return new ImmutableListMemberListMemberListCalc(call, calcs); 1041 } else { 1042 // Member[] 1043 return new ImmutableListMemberListMemberArrayListCalc(call, calcs); 1044 } 1045 } else { 1046 // Member[] 1047 if (isMemberType(listCalc2)) { 1048 // Member 1049 return new ImmutableListMemberArrayListMemberListCalc(call, calcs); 1050 } else { 1051 // Member[] 1052 return new ImmutableListMemberArrayListMemberArrayListCalc(call, calcs); 1053 } 1054 } 1055 } 1056 1057 private ListCalc toList(ExpCompiler compiler, final Exp exp) { 1058 // Want immutable list or mutable list in that order 1059 // It is assumed that an immutable list is easier to get than 1060 // a mutable list. 1061 final Type type = exp.getType(); 1062 if (type instanceof SetType) { 1063 return (ListCalc) compiler.compileAs(exp, 1064 null, ResultStyle.LIST_MUTABLELIST); 1065 } else { 1066 return new SetFunDef.ListSetCalc( 1067 new DummyExp(new SetType(type)), 1068 new Exp[] {exp}, 1069 compiler, 1070 ResultStyle.LIST_MUTABLELIST); 1071 } 1072 } 1073 1074 abstract class BaseListCalc extends AbstractListCalc { 1075 protected BaseListCalc(ResolvedFunCall call, 1076 Calc[] calcs, 1077 boolean mutable) { 1078 super(call, calcs, mutable); 1079 } 1080 1081 public List<Member[]> evaluateList(Evaluator evaluator) { 1082 ResolvedFunCall call = (ResolvedFunCall) exp; 1083 // Use a native evaluator, if more efficient. 1084 // TODO: Figure this out at compile time. 1085 SchemaReader schemaReader = evaluator.getSchemaReader(); 1086 NativeEvaluator nativeEvaluator = 1087 schemaReader.getNativeSetEvaluator( 1088 call.getFunDef(), call.getArgs(), evaluator, this); 1089 if (nativeEvaluator != null) { 1090 return (List) nativeEvaluator.execute( 1091 ResultStyle.LIST); 1092 } 1093 1094 Calc[] calcs = getCalcs(); 1095 ListCalc listCalc1 = (ListCalc) calcs[0]; 1096 ListCalc listCalc2 = (ListCalc) calcs[1]; 1097 1098 Evaluator oldEval = null; 1099 assert (oldEval = evaluator.push()) != null; 1100 1101 List l1 = listCalc1.evaluateList(evaluator); 1102 assert oldEval.equals(evaluator) : "listCalc1 changed context"; 1103 1104 List l2 = listCalc2.evaluateList(evaluator); 1105 assert oldEval.equals(evaluator) : "listCalc2 changed context"; 1106 1107 //l1 = checkList(evaluator, l1); 1108 l1 = nonEmptyOptimizeList(evaluator, l1, call); 1109 if (l1.isEmpty()) { 1110 return Collections.emptyList(); 1111 } 1112 //l2 = checkList(evaluator, l2); 1113 l2 = nonEmptyOptimizeList(evaluator, l2, call); 1114 if (l2.isEmpty()) { 1115 return Collections.emptyList(); 1116 } 1117 1118 return makeList(l1, l2); 1119 } 1120 1121 protected abstract List<Member[]> makeList(List l1, List l2); 1122 } 1123 1124 public abstract class BaseImmutableList 1125 extends UnsupportedList<Member[]> { 1126 protected BaseImmutableList() { 1127 } 1128 public abstract int size(); 1129 public abstract Member[] get(int index); 1130 1131 public Object[] toArray() { 1132 int size = size(); 1133 Object[] result = new Object[size]; 1134 for (int i = 0; i < size; i++) { 1135 result[i] = get(i); 1136 } 1137 return result; 1138 } 1139 1140 public <T> T[] toArray(T[] a) { 1141 int size = size(); 1142 if (a.length < size) { 1143 a = (T[]) java.lang.reflect.Array.newInstance( 1144 a.getClass().getComponentType(), size); 1145 } 1146 for (int i = 0; i < size; i++) { 1147 a[i] = (T) get(i); 1148 } 1149 if (a.length > size) { 1150 a[size] = null; 1151 } 1152 return a; 1153 } 1154 1155 public List<Member[]> toArrayList() { 1156 List<Member[]> l = new ArrayList<Member[]>(size()); 1157 Iterator<Member[]> i = iterator(); 1158 while (i.hasNext()) { 1159 l.add(i.next()); 1160 } 1161 return l; 1162 } 1163 public ListIterator<Member[]> listIterator() { 1164 return new ListItr(0); 1165 } 1166 public ListIterator<Member[]> listIterator(int index) { 1167 return new ListItr(index); 1168 } 1169 public Iterator<Member[]> iterator() { 1170 return new Itr(); 1171 } 1172 } 1173 1174 // LIST Member LIST Member 1175 class ImmutableListMemberListMemberListCalc 1176 extends BaseListCalc { 1177 ImmutableListMemberListMemberListCalc(ResolvedFunCall call, Calc[] calcs) { 1178 super(call, calcs, false); 1179 } 1180 protected List<Member[]> makeList(final List l1, final List l2) { 1181 final int size = l1.size() * l2.size(); 1182 // This is the mythical "local class" declaration. 1183 // Observer that in the subList method, there is another 1184 // such class declaration. The outer one can not be an 1185 // anonymous class because 1186 // the inner one must reference, have a name for, the 1187 // outer one. The inner one is needed because it includes 1188 // the offset into the outer one as instance variables. 1189 // The outer class has no explicit instance variables 1190 // though it does have the implicit List finals, l1 and l2. 1191 // One can call the inner class's subList method repeatedly 1192 // and each new Inner object return adds an additional 1193 // "fromIndex" to the "get" method calls. 1194 // 1195 // All of this works because the underlying lists are 1196 // immutable. 1197 // 1198 class Outer extends BaseImmutableList { 1199 Outer() { 1200 } 1201 public int size() { 1202 return size; 1203 } 1204 public Member[] get(int index) { 1205 int i = (index / l2.size()); 1206 int j = (index % l2.size()); 1207 Member m1 = (Member) l1.get(i); 1208 Member m2 = (Member) l2.get(j); 1209 return new Member[] { m1, m2 }; 1210 } 1211 public List<Member[]> subList(int fromIndex, int toIndex) { 1212 class Inner extends Outer { 1213 int fromIndex; 1214 int toIndex; 1215 Inner(int fromIndex, int toIndex) { 1216 this.fromIndex = fromIndex; 1217 this.toIndex = toIndex; 1218 } 1219 public int size() { 1220 return (this.toIndex - this.fromIndex); 1221 } 1222 public Member[] get(int index) { 1223 return Outer.this.get(index + this.fromIndex); 1224 } 1225 public List<Member[]> subList(int fromIndex, int toIndex) { 1226 return new Inner(this.fromIndex + fromIndex, this.fromIndex + toIndex); 1227 } 1228 } 1229 return new Inner(fromIndex, toIndex); 1230 } 1231 } 1232 return new Outer(); 1233 } 1234 } 1235 1236 // LIST Member LIST Member[] 1237 class ImmutableListMemberListMemberArrayListCalc 1238 extends BaseListCalc { 1239 ImmutableListMemberListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) { 1240 super(call, calcs, false); 1241 } 1242 protected List<Member[]> makeList(final List l1, final List l2) { 1243 final int len2 = ((Member[])l2.get(0)).length; 1244 final int size = (l1.size() * l2.size()); 1245 class Outer extends BaseImmutableList { 1246 Outer() { 1247 } 1248 public int size() { 1249 return size; 1250 } 1251 public Member[] get(int index) { 1252 int i = (index / l2.size()); 1253 int j = (index % l2.size()); 1254 Member[] ma = new Member[1 + len2]; 1255 Member m1 = (Member) l1.get(i); 1256 Member[] ma2 = (Member[]) l2.get(j); 1257 ma[0] = m1; 1258 System.arraycopy(ma2, 0, ma, 1, len2); 1259 return ma; 1260 } 1261 public List<Member[]> subList(int fromIndex, int toIndex) { 1262 class Inner extends Outer { 1263 int fromIndex; 1264 int toIndex; 1265 Inner(int fromIndex, int toIndex) { 1266 this.fromIndex = fromIndex; 1267 this.toIndex = toIndex; 1268 } 1269 public int size() { 1270 return (this.toIndex - this.fromIndex); 1271 } 1272 public Member[] get(int index) { 1273 return Outer.this.get(index + this.fromIndex); 1274 } 1275 public List<Member[]> subList(int fromIndex, int toIndex) { 1276 return new Inner(this.fromIndex + fromIndex, this.fromIndex + toIndex); 1277 } 1278 } 1279 return new Inner(fromIndex, toIndex); 1280 } 1281 } 1282 return new Outer(); 1283 } 1284 } 1285 // LIST Member[] LIST Member 1286 class ImmutableListMemberArrayListMemberListCalc 1287 extends BaseListCalc { 1288 ImmutableListMemberArrayListMemberListCalc(ResolvedFunCall call, Calc[] calcs) { 1289 super(call, calcs, false); 1290 } 1291 protected List<Member[]> makeList(final List l1, final List l2) { 1292 final int len1 = ((Member[])l1.get(0)).length; 1293 final int size = (l1.size() * l2.size()); 1294 class Outer extends BaseImmutableList { 1295 Outer() { 1296 } 1297 public int size() { 1298 return size; 1299 } 1300 public Member[] get(int index) { 1301 int i = (index / l2.size()); 1302 int j = (index % l2.size()); 1303 Member[] ma = new Member[len1 + 1]; 1304 Member[] ma1 = (Member[]) l1.get(i); 1305 Member m2 = (Member) l2.get(j); 1306 System.arraycopy(ma1, 0, ma, 0, len1); 1307 ma[len1] = m2; 1308 return ma; 1309 } 1310 public List<Member[]> subList(int fromIndex, int toIndex) { 1311 class Inner extends Outer { 1312 int fromIndex; 1313 int toIndex; 1314 Inner(int fromIndex, int toIndex) { 1315 this.fromIndex = fromIndex; 1316 this.toIndex = toIndex; 1317 } 1318 public int size() { 1319 return (this.toIndex - this.fromIndex); 1320 } 1321 public Member[] get(int index) { 1322 return Outer.this.get(index + this.fromIndex); 1323 } 1324 public List<Member[]> subList(int fromIndex, int toIndex) { 1325 return new Inner(this.fromIndex + fromIndex, this.fromIndex + toIndex); 1326 } 1327 } 1328 return new Inner(fromIndex, toIndex); 1329 } 1330 } 1331 return new Outer(); 1332 } 1333 } 1334 // LIST Member[] LIST Member[] 1335 class ImmutableListMemberArrayListMemberArrayListCalc 1336 extends BaseListCalc { 1337 ImmutableListMemberArrayListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) { 1338 super(call, calcs, false); 1339 } 1340 protected List<Member[]> makeList(final List l1, final List l2) { 1341 final int len1 = ((Member[])l1.get(0)).length; 1342 final int len2 = ((Member[])l2.get(0)).length; 1343 final int size = (l1.size() * l2.size()); 1344 1345 class Outer extends BaseImmutableList { 1346 Outer() { 1347 } 1348 public int size() { 1349 return size; 1350 } 1351 public Member[] get(int index) { 1352 int i = (index / l2.size()); 1353 int j = (index % l2.size()); 1354 Member[] ma = new Member[len1 + len2]; 1355 Member[] ma1 = (Member[]) l1.get(i); 1356 Member[] ma2 = (Member[]) l2.get(j); 1357 System.arraycopy(ma1, 0, ma, 0, len1); 1358 System.arraycopy(ma2, 0, ma, len1, len2); 1359 return ma; 1360 } 1361 public List<Member[]> subList(int fromIndex, int toIndex) { 1362 class Inner extends Outer { 1363 int fromIndex; 1364 int toIndex; 1365 Inner(int fromIndex, int toIndex) { 1366 this.fromIndex = fromIndex; 1367 this.toIndex = toIndex; 1368 } 1369 public int size() { 1370 return (this.toIndex - this.fromIndex); 1371 } 1372 public Member[] get(int index) { 1373 return Outer.this.get(index + this.fromIndex); 1374 } 1375 public List<Member[]> subList(int fromIndex, int toIndex) { 1376 return new Inner(this.fromIndex + fromIndex, this.fromIndex + toIndex); 1377 } 1378 } 1379 return new Inner(fromIndex, toIndex); 1380 } 1381 } 1382 return new Outer(); 1383 } 1384 } 1385 1386 /////////////////////////////////////////////////////////////////////////// 1387 /////////////////////////////////////////////////////////////////////////// 1388 // Mutable List 1389 /////////////////////////////////////////////////////////////////////////// 1390 /////////////////////////////////////////////////////////////////////////// 1391 1392 protected ListCalc compileCallMutableList(final ResolvedFunCall call, 1393 ExpCompiler compiler) { 1394 final ListCalc listCalc1 = toList(compiler, call.getArg(0)); 1395 final ListCalc listCalc2 = toList(compiler, call.getArg(1)); 1396 1397 Calc[] calcs = new Calc[] {listCalc1, listCalc2}; 1398 // The Calcs, 1 and 2, can be of type: Member or Member[] and 1399 // of ResultStyle: LIST or MUTABLE_LIST. 1400 // Since we want an mutable list as the result, it does not 1401 // matter whether the Calc list are of type 1402 // LIST and MUTABLE_LIST - they are treated the same, 1403 // regardless of type, one must materialize the result list; so 1404 // there are 4 possible combinations - even sweeter. 1405 1406 // Check returned calc ResultStyles 1407 checkListResultStyles(listCalc1); 1408 checkListResultStyles(listCalc2); 1409 1410 if (isMemberType(listCalc1)) { 1411 // Member 1412 if (isMemberType(listCalc2)) { 1413 // Member 1414 return new MutableListMemberListMemberListCalc(call, calcs); 1415 } else { 1416 // Member[] 1417 return new MutableListMemberListMemberArrayListCalc(call, calcs); 1418 } 1419 } else { 1420 // Member[] 1421 if (isMemberType(listCalc2)) { 1422 // Member 1423 return new MutableListMemberArrayListMemberListCalc(call, calcs); 1424 } else { 1425 // Member[] 1426 return new MutableListMemberArrayListMemberArrayListCalc(call, calcs); 1427 } 1428 } 1429 } 1430 1431 /** 1432 * A BaseMutableList can be sorted, its elements rearranged, but 1433 * its size can not be changed (the add or remove methods are not 1434 * supported). 1435 */ 1436 public abstract class BaseMutableList 1437 extends UnsupportedList<Member[]> { 1438 protected final List<Member> members; 1439 protected BaseMutableList(List<Member> members) { 1440 this.members = members; 1441 } 1442 public abstract int size(); 1443 public abstract Member[] get(int index); 1444 public abstract Member[] set(int index, Member[] element); 1445 public abstract Member[] remove(int index); 1446 public abstract List<Member[]> subList(int fromIndex, int toIndex); 1447 1448 public Object[] toArray() { 1449 int size = size(); 1450 Object[] result = new Object[size]; 1451 for (int i = 0; i < size; i++) { 1452 result[i] = get(i); 1453 } 1454 return result; 1455 } 1456 public List<Member[]> toArrayList() { 1457 List<Member[]> l = new ArrayList<Member[]>(size()); 1458 Iterator<Member[]> i = iterator(); 1459 while (i.hasNext()) { 1460 l.add(i.next()); 1461 } 1462 return l; 1463 } 1464 public ListIterator<Member[]> listIterator() { 1465 return new LocalListItr(0); 1466 } 1467 public ListIterator<Member[]> listIterator(int index) { 1468 return new LocalListItr(index); 1469 } 1470 public Iterator<Member[]> iterator() { 1471 return new LocalItr(); 1472 } 1473 private class LocalItr extends Itr { 1474 public LocalItr() { 1475 super(); 1476 } 1477 public void remove() { 1478 if (lastRet == -1) { 1479 throw new IllegalStateException(); 1480 } 1481 //checkForComodification(); 1482 1483 try { 1484 CrossJoinFunDef.BaseMutableList.this.remove(lastRet); 1485 if (lastRet < cursor) { 1486 cursor--; 1487 } 1488 lastRet = -1; 1489 //expectedModCount = modCount; 1490 } catch (IndexOutOfBoundsException e) { 1491 throw new ConcurrentModificationException(); 1492 } 1493 } 1494 } 1495 1496 private class LocalListItr extends ListItr { 1497 public LocalListItr(int index) { 1498 super(index); 1499 } 1500 1501 public void set(Member[] o) { 1502 if (lastRet == -1) { 1503 throw new IllegalStateException(); 1504 } 1505 try { 1506 CrossJoinFunDef.BaseMutableList.this.set(lastRet, o); 1507 } catch (IndexOutOfBoundsException e) { 1508 throw new ConcurrentModificationException(); 1509 } 1510 } 1511 } 1512 } 1513 1514 //LIST Member LIST Member 1515 class MutableListMemberListMemberListCalc extends BaseListCalc { 1516 MutableListMemberListMemberListCalc( 1517 final ResolvedFunCall call, final Calc[] calcs) 1518 { 1519 super(call, calcs, true); 1520 } 1521 1522 @SuppressWarnings({"unchecked"}) 1523 protected List<Member[]> makeList(final List _l1, final List _l2) { 1524 final List<Member> l1 = (List<Member>) _l1; 1525 final List<Member> l2 = (List<Member>) _l2; 1526 if (l1.isEmpty() || l2.isEmpty()) { 1527 return Collections.emptyList(); 1528 } 1529 1530 final Iterator<Member> it1 = l1.iterator(); 1531 final Member first = it1.next(); 1532 if (first.getDimension().isHighCardinality()) { 1533 return new AbstractSequentialList<Member []>() { 1534 public int size() { 1535 return l1.size() * l2.size(); 1536 } 1537 public ListIterator<Member[]> listIterator( 1538 final int index) 1539 { 1540 return new ListIterator<Member []>() { 1541 private int idx = 0; 1542 private Member m1 = first; 1543 private Iterator<Member> it2 = l2.iterator(); 1544 public boolean hasNext() { 1545 return it2.hasNext() || it1.hasNext(); 1546 } 1547 public Member[] next() { 1548 if (!it2.hasNext()) { 1549 it2 = l2.iterator(); 1550 m1 = it1.next(); 1551 } 1552 idx++; 1553 return new Member[] {m1, it2.next()}; 1554 } 1555 public int nextIndex() { 1556 return idx; 1557 } 1558 public void add(final Member[] t) { 1559 throw new UnsupportedOperationException(); 1560 } 1561 public void set(final Member[] t) { 1562 throw new UnsupportedOperationException(); 1563 } 1564 public boolean hasPrevious() { 1565 throw new UnsupportedOperationException(); 1566 } 1567 public Member[] previous() { 1568 throw new UnsupportedOperationException(); 1569 } 1570 public int previousIndex() { 1571 throw new UnsupportedOperationException(); 1572 } 1573 public void remove() { 1574 throw new UnsupportedOperationException(); 1575 } 1576 }; 1577 } 1578 }; 1579 } 1580 final List<Member[]> members = 1581 new ArrayList<Member[]>(l1.size() * l2.size()); 1582 for (final Member m1 : l1) { 1583 for (final Member m2 : l2) { 1584 members.add(new Member[] {m1, m2}); 1585 } 1586 } 1587 return members; 1588 } 1589 } 1590 1591 // LIST Member LIST Member[] 1592 class MutableListMemberListMemberArrayListCalc 1593 extends BaseListCalc { 1594 MutableListMemberListMemberArrayListCalc( 1595 ResolvedFunCall call, Calc[] calcs) 1596 { 1597 super(call, calcs, true); 1598 } 1599 1600 @SuppressWarnings({"unchecked"}) 1601 protected List<Member[]> makeList(final List _l1, final List _l2) { 1602 final List<Member> l1 = (List<Member>) _l1; 1603 final List<Member[]> l2 = (List<Member[]>) _l2; 1604 int size1 = l1.size(); 1605 // len1 == 1 1606 int size2 = l2.size(); 1607 int len2 = l2.get(0).length; 1608 int totalLen = 1 + len2; 1609 int arraySize = (totalLen * (size1 * size2)); 1610 1611 List<Member> memberList = new ArrayList<Member>(arraySize); 1612 for (int i = 0; i < size1; i++) { 1613 Member m1 = l1.get(i); 1614 for (int j = 0; j < size2; j++) { 1615 final Member[] ma2 = l2.get(j); 1616 memberList.add(m1); 1617 for (int k = 0; k < len2; k++) { 1618 final Member m2 = ma2[k]; 1619 memberList.add(m2); 1620 } 1621 } 1622 } 1623 return makeList(memberList, totalLen); 1624 } 1625 1626 protected List<Member[]> makeList( 1627 final List<Member> members, 1628 final int totalLen) 1629 { 1630 // l1: a,b 1631 // l2: {A,B,C},{D,E,F} 1632 // 1633 // externally looks like: 1634 // [] <- {a,A,B,C} 1635 // [] <- {a,D,E,F} 1636 // [] <- {b,A,B,C} 1637 // [] <- {b,D,E,F} 1638 // 1639 // but internally is: 1640 // a,A,B,C,a,D,E,F,b,A,B,C,b,D,E,F 1641 return new BaseMutableList(members) { 1642 int size = members.size() / totalLen; 1643 1644 public int size() { 1645 return size; 1646 } 1647 1648 public Member[] get(int index) { 1649 int base = totalLen * index; 1650 Member[] ma = new Member[totalLen]; 1651 for (int i = 0; i < totalLen; i++) { 1652 ma[i] = members.get(base + i); 1653 } 1654 return ma; 1655 } 1656 1657 public Member[] set(int index, Member[] element) { 1658 int base = totalLen * index; 1659 Member[] oldValue = new Member[totalLen]; 1660 for (int i = 0; i < totalLen; i++) { 1661 oldValue[i] = members.set(base + i, element[i]); 1662 } 1663 return oldValue; 1664 } 1665 1666 public Member[] remove(int index) { 1667 int base = totalLen * index; 1668 Member[] oldValue = new Member[totalLen]; 1669 for (int i = 0; i < totalLen; i++) { 1670 oldValue[i] = members.remove(base); 1671 } 1672 size--; 1673 return oldValue; 1674 } 1675 1676 public List<Member[]> subList(int fromIndex, int toIndex) { 1677 int from = totalLen * fromIndex; 1678 int to = totalLen * toIndex; 1679 List<Member> sublist = members.subList(from, to); 1680 return makeList(sublist, totalLen); 1681 } 1682 }; 1683 } 1684 } 1685 1686 // LIST Member[] LIST Member 1687 class MutableListMemberArrayListMemberListCalc 1688 extends BaseListCalc { 1689 MutableListMemberArrayListMemberListCalc( 1690 final ResolvedFunCall call, 1691 final Calc[] calcs) 1692 { 1693 super(call, calcs, true); 1694 } 1695 1696 @SuppressWarnings({"unchecked"}) 1697 protected List<Member[]> makeList(final List _l1, final List _l2) { 1698 final List<Member[]> l1 = (List<Member[]>) _l1; 1699 final List<Member> l2 = (List<Member>) _l2; 1700 int size1 = _l1.size(); 1701 int len1 = l1.get(0).length; 1702 int size2 = l2.size(); 1703 // len2 == 1 1704 int totalLen = 1 + len1; 1705 int arraySize = (totalLen * (size1 * size2)); 1706 1707 Member[] members = new Member[arraySize]; 1708 int x = 0; 1709 for (int i = 0; i < size1; i++) { 1710 Member[] ma1 = l1.get(i); 1711 int ii = i * size2; 1712 for (int j = 0; j < size2; j++) { 1713 for (int k = 0; k < len1; k++) { 1714 Member m1 = ma1[k]; 1715 members[x++] = m1; 1716 } 1717 Member m2 = l2.get(j); 1718 members[x++] = m2; 1719 } 1720 } 1721 assert x == arraySize; 1722 1723 // Use ArrayList, not Arrays.asList, because we want the remove() 1724 // operation. 1725 final List<Member> list = 1726 new ArrayList<Member>(Arrays.asList(members)); 1727 return makeList(list, totalLen); 1728 } 1729 1730 protected List<Member []> makeList( 1731 final List<Member> members, 1732 final int totalLen) 1733 { 1734 // l1: {A,B,C},{D,E,F} 1735 // l2: a,b 1736 // 1737 // externally looks like: 1738 // [] <- {A,B,C,a} 1739 // [] <- {A,B,C,b} 1740 // [] <- {D,E,F,a} 1741 // [] <- {D,E,F,b} 1742 // 1743 // but internally is: 1744 // A,B,C,a,A,B,C,b,D,E,F,a,D,E,F,b 1745 return new BaseMutableList(members) { 1746 int size = members.size() / totalLen; 1747 1748 public int size() { 1749 return size; 1750 } 1751 1752 public Member[] get(int index) { 1753 int base = totalLen * index; 1754 final List<Member> memberList = 1755 members.subList(base, totalLen + base); 1756 return memberList.toArray(new Member[totalLen]); 1757 } 1758 1759 public Member[] set(int index, Member[] element) { 1760 int base = totalLen * index; 1761 Member[] oldValue = new Member[totalLen]; 1762 for (int j = 0; j < totalLen; j++) { 1763 oldValue[j] = members.set(base + j, element[j]); 1764 } 1765 return oldValue; 1766 } 1767 1768 public Member[] remove(int index) { 1769 int base = totalLen * index; 1770 Member[] oldValue = new Member[totalLen]; 1771 for (int i = 0; i < totalLen; i++) { 1772 oldValue[i] = members.remove(base); 1773 } 1774 size--; 1775 return oldValue; 1776 } 1777 1778 public List<Member[]> subList(int fromIndex, int toIndex) { 1779 int from = totalLen * fromIndex; 1780 int to = totalLen * toIndex; 1781 List<Member> sublist = members.subList(from, to); 1782 return makeList(sublist, totalLen); 1783 } 1784 }; 1785 } 1786 } 1787 1788 // LIST Member[] LIST Member[] 1789 class MutableListMemberArrayListMemberArrayListCalc 1790 extends BaseListCalc { 1791 MutableListMemberArrayListMemberArrayListCalc( 1792 ResolvedFunCall call, Calc[] calcs) 1793 { 1794 super(call, calcs, true); 1795 } 1796 1797 @SuppressWarnings({"unchecked"}) 1798 protected List<Member[]> makeList(final List _l1, final List _l2) { 1799 final List<Member[]> l1 = (List<Member[]>) _l1; 1800 final List<Member[]> l2 = (List<Member[]>) _l2; 1801 int size1 = l1.size(); 1802 int len1 = l1.get(0).length; 1803 int size2 = l2.size(); 1804 int len2 = l2.get(0).length; 1805 int totalLen = len1 + len2; 1806 int arraySize = (totalLen * (size1 * size2)); 1807 1808 final List<Member> members = new ArrayList<Member>(arraySize); 1809 for (int i = 0; i < size1; i++) { 1810 Member[] ma1 = l1.get(i); 1811 for (int j = 0; j < size2; j++) { 1812 for (int k = 0; k < len1; k++) { 1813 Member m1 = ma1[k]; 1814 members.add(m1); 1815 } 1816 Member[] ma2 = l2.get(j); 1817 for (int k = 0; k < len2; k++) { 1818 Member m2 = ma2[k]; 1819 members.add(m2); 1820 } 1821 } 1822 } 1823 return makeList(members, totalLen); 1824 } 1825 1826 protected List<Member []> makeList( 1827 final List<Member> members, 1828 final int totalLen) 1829 { 1830 // l1: {A,B,C},{D,E,F} 1831 // l2: {a,b},{c,d},{e,f} 1832 // 1833 // externally looks like: 1834 // [] <- {A,B,C,a,b} 1835 // [] <- {A,B,C,c,d} 1836 // [] <- {A,B,C,e,f} 1837 // [] <- {D,E,F,a,b} 1838 // [] <- {D,E,F,c,d} 1839 // [] <- {D,E,F,e,d} 1840 // 1841 // but internally is: 1842 // A,B,C,a,b,A,B,C,c,d,A,B,C,e,f,D,E,F,a,b,D,E,F,c,d,D,E,F,e,d 1843 return new BaseMutableList(members) { 1844 int size = members.size() / totalLen; 1845 public int size() { 1846 return size; 1847 } 1848 1849 public Member[] get(int index) { 1850 int base = totalLen * index; 1851 Member[] m = new Member[totalLen]; 1852 for (int i = 0; i < totalLen; i++) { 1853 m[i] = members.get(base + i); 1854 } 1855 return m; 1856 } 1857 1858 public Member[] set(int index, Member[] element) { 1859 int base = totalLen * index; 1860 Member[] oldValue = new Member[totalLen]; 1861 for (int j = 0; j < totalLen; j++) { 1862 oldValue[j] = members.set(base + j, element[j]); 1863 } 1864 return oldValue; 1865 } 1866 1867 public Member[] remove(int index) { 1868 int base = totalLen * index; 1869 Member[] oldValue = new Member[totalLen]; 1870 for (int i = 0; i < totalLen; i++) { 1871 oldValue[i] = members.remove(base); 1872 } 1873 size--; 1874 return oldValue; 1875 } 1876 1877 public List<Member[]> subList(int fromIndex, int toIndex) { 1878 int from = totalLen * fromIndex; 1879 int to = totalLen * toIndex; 1880 List<Member> sublist = members.subList(from, to); 1881 return makeList(sublist, totalLen); 1882 } 1883 }; 1884 } 1885 } 1886 1887 protected List nonEmptyOptimizeList( 1888 Evaluator evaluator, 1889 List list, 1890 ResolvedFunCall call) { 1891 1892 int opSize = MondrianProperties.instance().CrossJoinOptimizerSize.get(); 1893 if (list.isEmpty()) { 1894 return list; 1895 } 1896 try { 1897 final Object o = list.get(0); 1898 if (o instanceof Member) { 1899 // Cannot optimize high cardinality dimensions 1900 if (((Member)o).getDimension().isHighCardinality()) { 1901 return list; 1902 } 1903 } 1904 } catch (IndexOutOfBoundsException ioobe) { 1905 return Collections.EMPTY_LIST; 1906 } 1907 int size = list.size(); 1908 1909 if (size > opSize && evaluator.isNonEmpty()) { 1910 // instead of overflow exception try to further 1911 // optimize nonempty(crossjoin(a,b)) == 1912 // nonempty(crossjoin(nonempty(a),nonempty(b)) 1913 final int missCount = evaluator.getMissCount(); 1914 1915 list = nonEmptyList(evaluator, list, call); 1916 size = list.size(); 1917 // list may be empty after nonEmpty optimization 1918 if (size == 0) { 1919 return Collections.EMPTY_LIST; 1920 } 1921 final int missCount2 = evaluator.getMissCount(); 1922 final int puntMissCountListSize = 1000; 1923 if (missCount2 > missCount && size > puntMissCountListSize) { 1924 // We've hit some cells which are not in the cache. They 1925 // registered as non-empty, but we won't really know until 1926 // we've populated the cache. The cartesian product is still 1927 // huge, so let's quit now, and try again after the cache 1928 // has been loaded. 1929 // Return an empty list short circuits higher level 1930 // evaluation poping one all the way to the top. 1931 return Collections.EMPTY_LIST; 1932 } 1933 } 1934 return list; 1935 } 1936 1937 public static List<Member[]> crossJoin( 1938 List list1, 1939 List list2) 1940 { 1941 if (list1.isEmpty() || list2.isEmpty()) { 1942 return Collections.emptyList(); 1943 } 1944 // Optimize nonempty(crossjoin(a,b)) == 1945 // nonempty(crossjoin(nonempty(a),nonempty(b)) 1946 1947 // FIXME: If we're going to apply a NON EMPTY constraint later, it's 1948 // possible that the ultimate result will be much smaller. 1949 1950 long size = (long)list1.size() * (long)list2.size(); 1951 Util.checkCJResultLimit(size); 1952 1953 // Now we can safely cast size to an integer. It still might be very 1954 // large - which means we're allocating a huge array which we might 1955 // pare down later by applying NON EMPTY constraints - which is a 1956 // concern. 1957 List<Member[]> result = new ArrayList<Member[]>((int) size); 1958 1959 boolean neitherSideIsTuple = true; 1960 int arity0 = 1; 1961 int arity1 = 1; 1962 if (list1.get(0) instanceof Member[]) { 1963 arity0 = ((Member[]) list1.get(0)).length; 1964 neitherSideIsTuple = false; 1965 } 1966 if (list2.get(0) instanceof Member[]) { 1967 arity1 = ((Member[]) list2.get(0)).length; 1968 neitherSideIsTuple = false; 1969 } 1970 1971 if (neitherSideIsTuple) { 1972 // Simpler routine if we know neither side contains tuples. 1973 for (Member o0 : (List<Member>) list1) { 1974 for (Member o1 : (List<Member>) list2) { 1975 result.add(new Member[]{o0, o1}); 1976 } 1977 } 1978 } else { 1979 // More complex routine if one or both sides are arrays 1980 // (probably the product of nested CrossJoins). 1981 Member[] row = new Member[arity0 + arity1]; 1982 for (int i = 0, m = list1.size(); i < m; i++) { 1983 int x = 0; 1984 Object o0 = list1.get(i); 1985 if (o0 instanceof Member) { 1986 row[x++] = (Member) o0; 1987 } else { 1988 assertTrue(o0 instanceof Member[]); 1989 final Member[] members = (Member[]) o0; 1990 for (Member member : members) { 1991 row[x++] = member; 1992 } 1993 } 1994 for (int j = 0, n = list2.size(); j < n; j++) { 1995 Object o1 = list2.get(j); 1996 if (o1 instanceof Member) { 1997 row[x++] = (Member) o1; 1998 } else { 1999 assertTrue(o1 instanceof Member[]); 2000 final Member[] members = (Member[]) o1; 2001 for (Member member : members) { 2002 row[x++] = member; 2003 } 2004 } 2005 result.add(row.clone()); 2006 x = arity0; 2007 } 2008 } 2009 } 2010 return result; 2011 } 2012 2013 /** 2014 * Visitor class used to locate a resolved function call within an 2015 * expression 2016 */ 2017 private static class ResolvedFunCallFinder 2018 extends MdxVisitorImpl 2019 { 2020 private final ResolvedFunCall call; 2021 public boolean found; 2022 private final Set<Member> activeMembers = new HashSet<Member>(); 2023 2024 public ResolvedFunCallFinder(ResolvedFunCall call) 2025 { 2026 this.call = call; 2027 found = false; 2028 } 2029 2030 public Object visit(ResolvedFunCall funCall) 2031 { 2032 if (funCall == call) { 2033 found = true; 2034 } 2035 return null; 2036 } 2037 2038 public Object visit(MemberExpr memberExpr) { 2039 Member member = memberExpr.getMember(); 2040 if (member.isCalculated()) { 2041 if (activeMembers.add(member)) { 2042 Exp memberExp = member.getExpression(); 2043 memberExp.accept(this); 2044 activeMembers.remove(member); 2045 } 2046 } 2047 return null; 2048 } 2049 } 2050 2051 /** 2052 * Traverses the function call tree of 2053 * the non empty crossjoin function and populates the queryMeasureSet 2054 * with base measures 2055 */ 2056 private static class MeasureVisitor extends MdxVisitorImpl { 2057 2058 private final Set<Member> queryMeasureSet; 2059 private final ResolvedFunCallFinder finder; 2060 private final Set<Member> activeMeasures = new HashSet<Member>(); 2061 2062 /** 2063 * Creates a MeasureVisitor. 2064 * 2065 * @param queryMeasureSet Set of measures in query 2066 * 2067 * @param crossJoinCall Measures referencing this call should be 2068 * excluded from the list of measures found 2069 */ 2070 MeasureVisitor( 2071 Set<Member> queryMeasureSet, 2072 ResolvedFunCall crossJoinCall) 2073 { 2074 this.queryMeasureSet = queryMeasureSet; 2075 finder = new ResolvedFunCallFinder(crossJoinCall); 2076 } 2077 2078 public Object visit(ResolvedFunCall funcall) { 2079 Exp[] exps = funcall.getArgs(); 2080 if (exps != null) { 2081 for (Exp exp : exps) { 2082 exp.accept(this); 2083 } 2084 } 2085 return null; 2086 } 2087 2088 public Object visit(ParameterExpr parameterExpr) { 2089 final Parameter parameter = parameterExpr.getParameter(); 2090 final Type type = parameter.getType(); 2091 if (type instanceof mondrian.olap.type.MemberType) { 2092 final Object value = parameter.getValue(); 2093 if (value instanceof Member) { 2094 final Member member = (Member) value; 2095 process(member); 2096 } 2097 } 2098 2099 return null; 2100 } 2101 2102 public Object visit(MemberExpr memberExpr) { 2103 Member member = memberExpr.getMember(); 2104 process(member); 2105 return null; 2106 } 2107 2108 private void process(final Member member) { 2109 if (member.isMeasure()) { 2110 if (member.isCalculated()) { 2111 if (activeMeasures.add(member)) { 2112 Exp exp = member.getExpression(); 2113 finder.found = false; 2114 exp.accept(finder); 2115 if (! finder.found) { 2116 exp.accept(this); 2117 // commented line out to fix bug #1696772 2118 // queryMeasureSet.add(member); 2119 } 2120 activeMeasures.remove(member); 2121 } 2122 } else { 2123 queryMeasureSet.add(member); 2124 } 2125 } 2126 } 2127 } 2128 2129 /** 2130 * This is the entry point to the crossjoin non-empty optimizer code. 2131 * 2132 * <p>What one wants to determine is for each individual Member of the input 2133 * parameter list, a 'List-Member', whether across a slice there is any 2134 * data. 2135 * 2136 * <p>But what data? 2137 * 2138 * <p>For Members other than those in the list, the 'non-List-Members', 2139 * one wants to consider 2140 * all data across the scope of these other Members. For instance, if 2141 * Time is not a List-Member, then one wants to consider data 2142 * across All Time. Or, if Customer is not a List-Member, then 2143 * look at data across All Customers. The theory here, is if there 2144 * is no data for a particular Member of the list where all other 2145 * Members not part of the list are span their complete hierarchy, then 2146 * there is certainly no data for Members of that Hierarchy at a 2147 * more specific Level (more on this below). 2148 * 2149 * <p>When a Member that is a non-List-Member is part of a Hierarchy 2150 * that has an 2151 * All Member (hasAll="true"), then its very easy to make sure that 2152 * the All Member is used during the optimization. 2153 * If a non-List-Member is part of a Hierarchy that does not have 2154 * an All Member, then one must, in fact, iterate over all top-level 2155 * Members of the Hierarchy!!! - otherwise a List-Member might 2156 * be excluded because the optimization code was not looking everywhere. 2157 * 2158 * <p>Concerning default Members for those Hierarchies for the 2159 * non-List-Members, ignore them. What is wanted is either the 2160 * All Member or one must iterate across all top-level Members, what 2161 * happens to be the default Member of the Hierarchy is of no relevant. 2162 * 2163 * <p>The Measures Hierarchy has special considerations. First, there is 2164 * no All Measure. But, certainly one need only involve Measures 2165 * that are actually in the query... yes and no. For Calculated Measures 2166 * one must also get all of the non-Calculated Measures that make up 2167 * each Calculated Measure. Thus, one ends up iterating across all 2168 * Calculated and non-Calculated Measures that are explicitly 2169 * mentioned in the query as well as all Calculated and non-Calculated 2170 * Measures that are used to define the Calculated Measures in 2171 * the query. Why all of these? because this represents the total 2172 * scope of possible Measures that might yield a non-null value 2173 * for the List-Members and that is what we what to find. It might 2174 * be a super set, but thats ok; we just do not want to miss anything. 2175 * 2176 * <p>For other Members, the default Member is used, but for Measures one 2177 * should look for that data for all Measures associated with the query, not 2178 * just one Measure. For a dense dataset this may not be a problem or even 2179 * apparent, but for a sparse dataset, the first Measure may, in fact, have 2180 * not data but other Measures associated with the query might. 2181 * Hence, the solution here is to identify all Measures associated with the 2182 * query and then for each Member of the list, determine if there is any 2183 * data iterating across all Measures until non-null data is found or the 2184 * end of the Measures is reached. 2185 * 2186 * <p>This is a non-optimistic implementation. This means that an 2187 * element of the input parameter List is only not included in the 2188 * returned result List if for no combination of Measures, non-All 2189 * Members (for Hierarchies that have no All Members) and evaluator 2190 * default Members did the element evaluate to non-null. 2191 * 2192 * 2193 * <p>This method can be applied to members or tuples. Accordingly, the 2194 * type parameter {@code T} can be either {@code Member} or 2195 * {@code Member[]}. 2196 * 2197 * @param evaluator Evaluator 2198 * 2199 * @param list List of members or tuples 2200 * 2201 * @param call Calling ResolvedFunCall used to determine what Measures 2202 * to use 2203 * 2204 * @return List of elements from the input parameter list that have 2205 * evaluated to non-null. 2206 */ 2207 protected <T> List<T> nonEmptyList( 2208 Evaluator evaluator, 2209 List<T> list, 2210 ResolvedFunCall call) 2211 { 2212 if (list.isEmpty()) { 2213 return list; 2214 } 2215 2216 List<T> result = new ArrayList<T>((list.size() + 2) >> 1); 2217 2218 // Get all of the Measures 2219 final Query query = evaluator.getQuery(); 2220 2221 final String measureSetKey = "MEASURE_SET-" + ctag; 2222 Set<Member> measureSet = 2223 (Set<Member>) query.getEvalCache(measureSetKey); 2224 // If not in query cache, then create and place into cache. 2225 // This information is used for each iteration so it makes 2226 // sense to create and cache it. 2227 if (measureSet == null) { 2228 measureSet = new HashSet<Member>(); 2229 Set<Member> queryMeasureSet = query.getMeasuresMembers(); 2230 MeasureVisitor visitor = new MeasureVisitor(measureSet, call); 2231 for (Member m : queryMeasureSet) { 2232 if (m.isCalculated()) { 2233 Exp exp = m.getExpression(); 2234 exp.accept(visitor); 2235 } else { 2236 measureSet.add(m); 2237 } 2238 } 2239 2240 Formula[] formula = query.getFormulas(); 2241 if (formula != null) { 2242 for (Formula f : formula) { 2243 f.accept(visitor); 2244 } 2245 } 2246 2247 query.putEvalCache(measureSetKey, measureSet); 2248 } 2249 2250 final String allMemberListKey = "ALL_MEMBER_LIST-" + ctag; 2251 List<Member> allMemberList = 2252 (List<Member>) query.getEvalCache(allMemberListKey); 2253 2254 final String nonAllMembersKey = "NON_ALL_MEMBERS-" + ctag; 2255 Member[][] nonAllMembers = 2256 (Member[][]) query.getEvalCache(nonAllMembersKey); 2257 if (nonAllMembers == null) { 2258 // 2259 // Get all of the All Members and those Hierarchies that 2260 // do not have All Members. 2261 // 2262 Member[] evalMembers = evaluator.getMembers().clone(); 2263 2264 Member[] listMembers = (list.get(0) instanceof Member[]) 2265 ? (Member[]) list.get(0) 2266 : new Member[] { (Member) list.get(0) }; 2267 2268 // Remove listMembers from evalMembers and independentSlicerMembers 2269 for (Member lm : listMembers) { 2270 Hierarchy h = lm.getHierarchy(); 2271 for (int i = 0; i < evalMembers.length; i++) { 2272 Member em = evalMembers[i]; 2273 if ((em != null) && h.equals(em.getHierarchy())) { 2274 evalMembers[i] = null; 2275 } 2276 } 2277 } 2278 2279 List<Member> slicerMembers = null; 2280 if (evaluator instanceof RolapEvaluator) { 2281 RolapEvaluator rev = (RolapEvaluator) evaluator; 2282 slicerMembers = rev.getSlicerMembers(); 2283 } 2284 2285 // Now we have the non-List-Members, but some of them may not be 2286 // All Members (default Member need not be the All Member) and 2287 // for some Hierarchies there may not be an All Member. 2288 // So we create an array of Objects some elements of which are 2289 // All Members and others elements will be an array of all top-level 2290 // Members when there is not an All Member. 2291 SchemaReader schemaReader = evaluator.getSchemaReader(); 2292 allMemberList = new ArrayList<Member>(); 2293 List<Member[]> nonAllMemberList = new ArrayList<Member[]>(); 2294 2295 Member em; 2296 boolean isSlicerMember; 2297 for (Member evalMember : evalMembers) { 2298 em = evalMember; 2299 2300 isSlicerMember = 2301 slicerMembers != null 2302 && slicerMembers.contains(em); 2303 2304 if (em == null) { 2305 // Above we might have removed some by setting them 2306 // to null. These are the CrossJoin axes. 2307 continue; 2308 } 2309 if (em.isMeasure()) { 2310 continue; 2311 } 2312 2313 // 2314 // The unconstrained members need to be replaced by the "All" 2315 // member based on its usage and property. This is currently 2316 // also the behavior of native cross join evaluation. See 2317 // SqlConstraintUtils.addContextConstraint() 2318 // 2319 // on slicer? | calculated? | replace with All? 2320 // ----------------------------------------------- 2321 // Y | Y | Y always 2322 // Y | N | N 2323 // N | Y | N 2324 // N | N | Y if not "All" 2325 // ----------------------------------------------- 2326 // 2327 if ((isSlicerMember && !em.isCalculated()) || 2328 (!isSlicerMember && em.isCalculated())) { 2329 continue; 2330 } 2331 2332 // If the member is not the All member; 2333 // or if it is a slicer member, 2334 // replace with the "all" member. 2335 if (isSlicerMember || !em.isAll()) { 2336 Hierarchy h = em.getHierarchy(); 2337 final List<Member> rootMemberList = 2338 schemaReader.getHierarchyRootMembers(h); 2339 if (h.hasAll()) { 2340 // The Hierarchy has an All member 2341 boolean found = false; 2342 for (Member m : rootMemberList) { 2343 if (m.isAll()) { 2344 allMemberList.add(m); 2345 found = true; 2346 break; 2347 } 2348 } 2349 if (!found) { 2350 System.out 2351 .println( 2352 "CrossJoinFunDef.nonEmptyListNEW: ERROR"); 2353 } 2354 } else { 2355 // The Hierarchy does NOT have an All member 2356 Member[] rootMembers = 2357 rootMemberList.toArray( 2358 new Member[rootMemberList.size()]); 2359 nonAllMemberList.add(rootMembers); 2360 } 2361 } 2362 } 2363 nonAllMembers = 2364 nonAllMemberList.toArray( 2365 new Member[nonAllMemberList.size()][]); 2366 2367 query.putEvalCache(allMemberListKey, allMemberList); 2368 query.putEvalCache(nonAllMembersKey, nonAllMembers); 2369 } 2370 2371 // 2372 // Determine if there is any data. 2373 // 2374 evaluator = evaluator.push(); 2375 2376 // Put all of the All Members into Evaluator 2377 evaluator.setContext(allMemberList); 2378 2379 // Iterate over elements of the input list (whether it contains 2380 // Member[] or Member elements). If for any combination of 2381 // Measure and non-All Members evaluation is non-null, then 2382 // add it to the result List. 2383 if (list.get(0) instanceof Member[]) { 2384 for (Member[] ms : ((List<Member[]>) list)) { 2385 evaluator.setContext(ms); 2386 if (checkData(nonAllMembers, nonAllMembers.length - 1, 2387 measureSet, evaluator)) { 2388 result.add((T) ms); 2389 } 2390 } 2391 } else { 2392 for (Member m : ((List<Member>) list)) { 2393 evaluator.setContext(m); 2394 if (checkData(nonAllMembers, nonAllMembers.length - 1, 2395 measureSet, evaluator)) { 2396 result.add((T) m); 2397 } 2398 } 2399 } 2400 2401 return result; 2402 } 2403 2404 /** 2405 * Return <code>true</code> if for some combination of Members 2406 * from the nonAllMembers array of Member arrays and Measures from 2407 * the Set of Measures evaluate to a non-null value. Even if a 2408 * particular combination is non-null, all combinations are tested 2409 * just to make sure that the data is loaded. 2410 * 2411 * @param nonAllMembers array of Member arrays of top-level Members 2412 * for Hierarchies that have no All Member. 2413 * @param cnt which Member array is to be processed. 2414 * @param measureSet Set of all that should be tested against. 2415 * @param evaluator the Evaluator. 2416 * @return True if at least one combination evaluated to non-null. 2417 */ 2418 private static boolean checkData( 2419 Member[][] nonAllMembers, 2420 int cnt, 2421 Set<Member> measureSet, 2422 Evaluator evaluator) { 2423 2424 if (cnt < 0) { 2425 // no measures found, use standard algorithm 2426 if (measureSet.isEmpty()) { 2427 Object value = evaluator.evaluateCurrent(); 2428 if (value != null && !(value instanceof Throwable)) { 2429 return true; 2430 } 2431 } else { 2432 // Here we evaluate across all measures just to 2433 // make sure that the data is all loaded 2434 boolean found = false; 2435 for (Member measure : measureSet) { 2436 evaluator.setContext(measure); 2437 Object value = evaluator.evaluateCurrent(); 2438 if (value != null && !(value instanceof Throwable)) { 2439 found = true; 2440 } 2441 } 2442 return found; 2443 } 2444 } else { 2445 boolean found = false; 2446 for (Member m : nonAllMembers[cnt]) { 2447 evaluator.setContext(m); 2448 if (checkData(nonAllMembers, cnt - 1, measureSet, evaluator)) { 2449 found = true; 2450 } 2451 } 2452 return found; 2453 } 2454 return false; 2455 } 2456 2457 private static class StarCrossJoinResolver extends MultiResolver { 2458 public StarCrossJoinResolver() { 2459 super( 2460 "*", 2461 "<Set1> * <Set2>", 2462 "Returns the cross product of two sets.", 2463 new String[]{"ixxx", "ixmx", "ixxm", "ixmm"}); 2464 } 2465 2466 public FunDef resolve( 2467 Exp[] args, Validator validator, int[] conversionCount) { 2468 // This function only applies in contexts which require a set. 2469 // Elsewhere, "*" is the multiplication operator. 2470 // This means that [Measures].[Unit Sales] * [Gender].[M] is 2471 // well-defined. 2472 if (validator.requiresExpression()) { 2473 return null; 2474 } 2475 return super.resolve(args, validator, conversionCount); 2476 } 2477 2478 protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) { 2479 return new CrossJoinFunDef(dummyFunDef); 2480 } 2481 } 2482 2483 2484 } 2485 2486 // End CrossJoinFunDef.java