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