KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > olap > fun > CrossJoinFunDef


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/olap/fun/CrossJoinFunDef.java#46 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2002-2002 Kana Software, Inc.
7 // Copyright (C) 2003-2007 Julian Hyde and others
8 // All Rights Reserved.
9 // You must accept the terms of that agreement to use this software.
10 */

11 package mondrian.olap.fun;
12
13 import mondrian.calc.*;
14 import mondrian.calc.ExpCompiler.ResultStyle;
15 import mondrian.calc.impl.AbstractIterCalc;
16 import mondrian.calc.impl.AbstractListCalc;
17 import mondrian.mdx.MdxVisitorImpl;
18 import mondrian.mdx.ResolvedFunCall;
19 import mondrian.olap.*;
20 import mondrian.olap.type.SetType;
21 import mondrian.olap.type.TupleType;
22 import mondrian.olap.type.Type;
23 import mondrian.resource.MondrianResource;
24 import mondrian.util.Bug;
25 import mondrian.util.UnsupportedList;
26
27 import java.util.*;
28
29 /**
30  * Definition of the <code>CrossJoin</code> MDX function.
31  *
32  * @author jhyde
33  * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/CrossJoinFunDef.java#46 $
34  * @since Mar 23, 2006
35  */

36 class CrossJoinFunDef extends FunDefBase {
37     static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver(
38             "Crossjoin",
39             "Crossjoin(<Set1>, <Set2>)",
40             "Returns the cross product of two sets.",
41             new String JavaDoc[]{"fxxx"},
42             CrossJoinFunDef.class);
43
44     static final StarCrossJoinResolver StarResolver = new StarCrossJoinResolver();
45
46     private static int counterTag = 0;
47
48     // used to tell the difference between crossjoin expressions.
49
private final int ctag = counterTag++;
50
51     public CrossJoinFunDef(FunDef dummyFunDef) {
52         super(dummyFunDef);
53     }
54
55     public Type getResultType(Validator validator, Exp[] args) {
56         // CROSSJOIN(<Set1>,<Set2>) has type [Hie1] x [Hie2].
57
List<Type> list = new ArrayList<Type>();
58         for (Exp arg : args) {
59             final Type type = arg.getType();
60             if (type instanceof SetType) {
61                 addTypes(type, list);
62             } else if (getName().equals("*")) {
63                 // The "*" form of CrossJoin is lenient: args can be either
64
// members/tuples or sets.
65
addTypes(type, list);
66             } else {
67                 throw Util.newInternal("arg to crossjoin must be a set");
68             }
69         }
70         final Type[] types = list.toArray(new Type[list.size()]);
71         final TupleType tupleType = new TupleType(types);
72         return new SetType(tupleType);
73     }
74
75     /**
76      * Adds a type to a list of types. If type is a {@link TupleType}, does so
77      * recursively.
78      */

79     private static void addTypes(final Type type, List<Type> list) {
80         if (type instanceof SetType) {
81             SetType setType = (SetType) type;
82             addTypes(setType.getElementType(), list);
83         } else if (type instanceof TupleType) {
84             TupleType tupleType = (TupleType) type;
85             for (Type elementType : tupleType.elementTypes) {
86                 addTypes(elementType, list);
87             }
88         } else {
89             list.add(type);
90         }
91     }
92     public Calc compileCall(final ResolvedFunCall call, ExpCompiler compiler) {
93         ResultStyle[] rs = compiler.getAcceptableResultStyles();
94         // What is the desired return type?
95
for (ResultStyle r : rs) {
96             switch (r) {
97             case ITERABLE:
98             case ANY:
99                 // 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             new ResultStyle[] {
111                 ResultStyle.ITERABLE,
112                 ResultStyle.LIST,
113                 ResultStyle.MUTABLE_LIST,
114                 ResultStyle.ANY
115             },
116             rs
117         );
118     }
119
120     ///////////////////////////////////////////////////////////////////////////
121
///////////////////////////////////////////////////////////////////////////
122
// Iterable
123
///////////////////////////////////////////////////////////////////////////
124
///////////////////////////////////////////////////////////////////////////
125

126     protected IterCalc compileCallIterable(
127         final ResolvedFunCall call,
128         ExpCompiler compiler)
129     {
130         final Calc calc1 = toIter(compiler, call.getArg(0));
131         final Calc calc2 = toIter(compiler, call.getArg(1));
132         Calc[] calcs = new Calc[] {calc1, calc2};
133         // The Calcs, 1 and 2, can be of type: Member or Member[] and
134
// of ResultStyle: ITERABLE, LIST or MUTABLE_LIST, but
135
// LIST and MUTABLE_LIST are treated the same; so
136
// there are 16 possible combinations - sweet.
137

138         // Check returned calc ResultStyles
139
checkIterListResultStyles(calc1);
140         checkIterListResultStyles(calc2);
141
142         if (isMemberType(calc1)) {
143             // Member
144
if (isMemberType(calc2)) {
145                 // Member
146
if (calc1.getResultStyle() == ResultStyle.ITERABLE) {
147                     if (calc2.getResultStyle() == ResultStyle.ITERABLE) {
148                         return new IterMemberIterMemberIterCalc(call, calcs);
149                     } else {
150                         return new IterMemberListMemberIterCalc(call, calcs);
151                     }
152                 } else {
153                     if (calc2.getResultStyle() == ResultStyle.ITERABLE) {
154                         return new ListMemberIterMemberIterCalc(call, calcs);
155                     } else {
156                         return new ListMemberListMemberIterCalc(call, calcs);
157                     }
158                 }
159             } else {
160                 // Member[]
161
if (calc1.getResultStyle() == ResultStyle.ITERABLE) {
162                     if (calc2.getResultStyle() == ResultStyle.ITERABLE) {
163                         return new IterMemberIterMemberArrayIterCalc(call, calcs);
164                     } else {
165                         return new IterMemberListMemberArrayIterCalc(call, calcs);
166                     }
167                 } else {
168                     if (calc2.getResultStyle() == ResultStyle.ITERABLE) {
169                         return new ListMemberIterMemberArrayIterCalc(call, calcs);
170                     } else {
171                         return new ListMemberListMemberArrayIterCalc(call, calcs);
172                     }
173                 }
174             }
175         } else {
176             // Member[]
177
if (isMemberType(calc2)) {
178                 // Member
179
if (calc1.getResultStyle() == ResultStyle.ITERABLE) {
180                     if (calc2.getResultStyle() == ResultStyle.ITERABLE) {
181                         return new IterMemberArrayIterMemberIterCalc(call, calcs);
182                     } else {
183                         return new IterMemberArrayListMemberIterCalc(call, calcs);
184                     }
185                 } else {
186                     if (calc2.getResultStyle() == ResultStyle.ITERABLE) {
187                         return new ListMemberArrayIterMemberIterCalc(call, calcs);
188                     } else {
189                         return new ListMemberArrayListMemberIterCalc(call, calcs);
190                     }
191                 }
192             } else {
193                 // Member[]
194
if (calc1.getResultStyle() == ResultStyle.ITERABLE) {
195                     if (calc2.getResultStyle() == ResultStyle.ITERABLE) {
196                         return new IterMemberArrayIterMemberArrayIterCalc(call, calcs);
197                     } else {
198                         return new IterMemberArrayListMemberArrayIterCalc(call, calcs);
199                     }
200                 } else {
201                     if (calc2.getResultStyle() == ResultStyle.ITERABLE) {
202                         return new ListMemberArrayIterMemberArrayIterCalc(call, calcs);
203                     } else {
204                         return new ListMemberArrayListMemberArrayIterCalc(call, calcs);
205                     }
206                 }
207             }
208         }
209     }
210     private Calc toIter(ExpCompiler compiler, final Exp exp) {
211         // Want iterable, immutable list or mutable list in that order
212
// It is assumed that an immutable list is easier to get than
213
// a mutable list.
214
final Type type = exp.getType();
215         if (type instanceof SetType) {
216             // this can return an IterCalc or ListCalc
217
return compiler.compile(exp,
218                 ExpCompiler.ITERABLE_LIST_MUTABLE_LIST_RESULT_STYLE_ARRAY);
219         } else {
220             // this always returns an IterCalc
221
return new SetFunDef.IterSetCalc(
222                 new DummyExp(new SetType(type)),
223                 new Exp[] {exp},
224                 compiler,
225                 ExpCompiler.ITERABLE_LIST_MUTABLE_LIST_RESULT_STYLE_ARRAY);
226         }
227     }
228     private abstract class BaseIterCalc extends AbstractIterCalc {
229         protected BaseIterCalc(ResolvedFunCall call, Calc[] calcs) {
230             super(call, calcs);
231         }
232         public Iterable JavaDoc evaluateIterable(Evaluator evaluator) {
233             ResolvedFunCall call = (ResolvedFunCall) exp;
234             // Use a native evaluator, if more efficient.
235
// TODO: Figure this out at compile time.
236
SchemaReader schemaReader = evaluator.getSchemaReader();
237             NativeEvaluator nativeEvaluator =
238                 schemaReader.getNativeSetEvaluator(
239                     call.getFunDef(), call.getArgs(), evaluator, this);
240             if (nativeEvaluator != null) {
241                 return (Iterable JavaDoc) nativeEvaluator.execute(
242                             ResultStyle.ITERABLE);
243             }
244
245             Calc[] calcs = getCalcs();
246             Calc calc1 = calcs[0];
247             Calc calc2 = calcs[1];
248
249             Evaluator oldEval = null;
250             assert (oldEval = evaluator.push()) != null;
251
252             Object JavaDoc o1 = calc1.evaluate(evaluator);
253             assert oldEval.equals(evaluator) : "calc1 changed context";
254
255             if (o1 instanceof List) {
256                 List l1 = (List) o1;
257                 //l1 = checkList(evaluator, l1);
258
l1 = nonEmptyOptimizeList(evaluator, l1, call);
259                 if (l1.isEmpty()) {
260                     return Collections.EMPTY_LIST;
261                 }
262                 o1 = l1;
263             }
264
265             Object JavaDoc o2 = calc2.evaluate(evaluator);
266             assert oldEval.equals(evaluator) : "calc2 changed context";
267
268             if (o2 instanceof List) {
269                 List l2 = (List) o2;
270                 //l2 = checkList(evaluator, l2);
271
l2 = nonEmptyOptimizeList(evaluator, l2, call);
272                 if (l2.isEmpty()) {
273                     return Collections.EMPTY_LIST;
274                 }
275                 o2 = l2;
276             }
277
278             return makeIterable(o1, o2);
279         }
280
281         /**
282          * Derived classes implement and create Iterable&lt;Member[]&gt;
283          * based upon the types of the parameters:
284          * List&lt;Member&gt;,
285          * List&lt;Member[]&gt;,
286          * Iterable&lt;Member&gt;, or
287          * Iterable&lt;Member[]&gt;.
288          *
289          * @param o1 List or Iterable of Member or Member[]
290          * @param o2 List or Iterable of Member or Member[]
291          * @return Iterable&lt;Member[]&gt; over contents of o1 and o2
292          */

293         protected abstract Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2);
294
295         /**
296          * Derived classes implement depending upon the types of parameter
297          * o1 and o2.
298          *
299          * @param o1 Member or Member[]
300          * @param o2 Member or Member[]
301          * @return combining o1 and o2 into Member[]
302          */

303         protected abstract Member[] makeNext(Object JavaDoc o1, Object JavaDoc o2);
304
305         protected Iterable JavaDoc<Member[]> makeIterableIterable(
306             final Iterable JavaDoc it1,
307             final Iterable JavaDoc it2)
308         {
309             // There is no knowledge about how large either it1 ore it2
310
// are or how many null members they might have, so all
311
// one can do is iterate across them:
312
// iterate across it1 and for each member iterate across it2
313
Iterable JavaDoc<Member[]> iterable = new Iterable JavaDoc<Member[]>() {
314                 public Iterator<Member[]> iterator() {
315                     return new Iterator<Member[]>() {
316                         Iterator i1 = it1.iterator();
317                         Object JavaDoc o1 = null;
318                         Iterator i2 = it2.iterator();
319                         Object JavaDoc o2 = null;
320                         public boolean hasNext() {
321                             if (o2 != null) {
322                                 return true;
323                             }
324                             if (! hasNextO1()) {
325                                 return false;
326                             }
327                             if (! hasNextO2()) {
328                                  o1 = null;
329                                 // got to end of i2, get next m1
330
if (! hasNextO1()) {
331                                     return false;
332                                 }
333                                 // reset i2
334
i2 = it2.iterator();
335                                 if (! hasNextO2()) {
336                                     return false;
337                                 }
338                             }
339                             return true;
340                         }
341                         public Member[] next() {
342                             try {
343                                 return makeNext(o1, o2);
344                             } finally {
345                                 o2 = null;
346                             }
347                         }
348                         public void remove() {
349                             throw new UnsupportedOperationException JavaDoc("remove");
350                         }
351
352                         private boolean hasNextO1() {
353                             while (o1 == null) {
354                                 if (! i1.hasNext()) {
355                                     return false;
356                                 }
357                                 o1 = i1.next();
358                             }
359                             return true;
360                         }
361                         private boolean hasNextO2() {
362                             o2 = null;
363                             while (o2 == null) {
364                                 if (! i2.hasNext()) {
365                                     return false;
366                                 }
367                                 o2 = i2.next();
368                             }
369                             return true;
370                         }
371                     };
372                 }
373             };
374
375             return iterable;
376         }
377
378         protected Iterable JavaDoc<Member[]> makeIterableList(
379             final Iterable JavaDoc it1,
380             final List l2)
381         {
382             Iterable JavaDoc<Member[]> iterable = new Iterable JavaDoc<Member[]>() {
383                 public Iterator<Member[]> iterator() {
384                     return new Iterator<Member[]>() {
385                         Iterator i1 = it1.iterator();
386                         Object JavaDoc o1 = null;
387                         int index2 = 0;
388                         Object JavaDoc o2 = null;
389                         public boolean hasNext() {
390                             if (o2 != null) {
391                                 return true;
392                             }
393                             if (! hasNextO1()) {
394                                 return false;
395                             }
396                             if (! hasNextO2()) {
397                                  o1 = null;
398                                 // got to end of l2, get next m1
399
if (! hasNextO1()) {
400                                     return false;
401                                 }
402                                 // reset l2
403
index2 = 0;
404                                 if (! hasNextO2()) {
405                                     return false;
406                                 }
407                             }
408                             return true;
409                         }
410                         public Member[] next() {
411                             try {
412                                 return makeNext(o1, o2);
413                             } finally {
414                                 o2 = null;
415                             }
416                         }
417                         public void remove() {
418                             throw new UnsupportedOperationException JavaDoc("remove");
419                         }
420
421                         private boolean hasNextO1() {
422                             while (o1 == null) {
423                                 if (! i1.hasNext()) {
424                                     return false;
425                                 }
426                                 o1 = i1.next();
427                             }
428                             return true;
429                         }
430                         private boolean hasNextO2() {
431                             o2 = null;
432                             while (o2 == null) {
433                                 if (index2 == l2.size()) {
434                                     return false;
435                                 }
436                                 o2 = l2.get(index2++);
437                             }
438                             return true;
439                         }
440                     };
441                 }
442             };
443             return iterable;
444         }
445
446         protected Iterable JavaDoc<Member[]> makeListIterable(
447             final List l1,
448             final Iterable JavaDoc it2)
449         {
450             Iterable JavaDoc<Member[]> iterable = new Iterable JavaDoc<Member[]>() {
451                 public Iterator<Member[]> iterator() {
452                     return new Iterator<Member[]>() {
453                         int index1 = 0;
454                         Object JavaDoc o1 = null;
455                         Iterator i2 = it2.iterator();
456                         Object JavaDoc o2 = null;
457                         public boolean hasNext() {
458                             if (o2 != null) {
459                                 return true;
460                             }
461                             if (! hasNextO1()) {
462                                 return false;
463                             }
464                             if (! hasNextO2()) {
465                                  o1 = null;
466                                 // got to end of i2, get next o1
467
if (! hasNextO1()) {
468                                     return false;
469                                 }
470                                 // reset i2
471
i2 = it2.iterator();
472                                 if (! hasNextO2()) {
473                                     return false;
474                                 }
475                             }
476                             return true;
477                         }
478                         public Member[] next() {
479                             try {
480                                 return makeNext(o1, o2);
481                             } finally {
482                                 o2 = null;
483                             }
484                         }
485                         public void remove() {
486                             throw new UnsupportedOperationException JavaDoc("remove");
487                         }
488
489                         private boolean hasNextO1() {
490                             while (o1 == null) {
491                                 if (index1 == l1.size()) {
492                                     return false;
493                                 }
494                                 o1 = l1.get(index1++);
495                             }
496                             return true;
497                         }
498                         private boolean hasNextO2() {
499                             o2 = null;
500                             while (o2 == null) {
501                                 if (! i2.hasNext()) {
502                                     return false;
503                                 }
504                                 o2 = i2.next();
505                             }
506                             return true;
507                         }
508                     };
509                 }
510             };
511
512             return iterable;
513         }
514
515         protected Iterable JavaDoc<Member[]> makeListList(
516             final List l1,
517             final List l2)
518         {
519             Iterable JavaDoc<Member[]> iterable = new Iterable JavaDoc<Member[]>() {
520                 public Iterator<Member[]> iterator() {
521                     return new Iterator<Member[]>() {
522                         int index1 = 0;
523                         Object JavaDoc o1 = null;
524                         int index2 = 0;
525                         Object JavaDoc o2 = null;
526                         public boolean hasNext() {
527                             if (o2 != null) {
528                                 return true;
529                             }
530                             if (! hasNextO1()) {
531                                 return false;
532                             }
533                             if (! hasNextO2()) {
534                                  o1 = null;
535                                 // got to end of i2, get next o1
536
if (! hasNextO1()) {
537                                     return false;
538                                 }
539                                 // reset i2
540
index2 = 0;
541                                 if (! hasNextO2()) {
542                                     return false;
543                                 }
544                             }
545                             return true;
546                         }
547                         public Member[] next() {
548                             try {
549                                 return makeNext(o1, o2);
550                             } finally {
551                                 o2 = null;
552                             }
553                         }
554                         public void remove() {
555                             throw new UnsupportedOperationException JavaDoc("remove");
556                         }
557
558                         private boolean hasNextO1() {
559                             while (o1 == null) {
560                                 if (index1 == l1.size()) {
561                                     return false;
562                                 }
563                                 o1 = l1.get(index1++);
564                             }
565                             return true;
566                         }
567                         private boolean hasNextO2() {
568                             o2 = null;
569                             while (o2 == null) {
570                                 if (index2 == l2.size()) {
571                                     return false;
572                                 }
573                                 o2 = l2.get(index2++);
574                             }
575                             return true;
576                         }
577                     };
578                 }
579             };
580             return iterable;
581         }
582     }
583
584     ///////////////////////////////////////////////////////////////////////////
585

586     // Member Member
587
abstract class BaseMemberMemberIterCalc
588             extends BaseIterCalc {
589         BaseMemberMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
590             super(call, calcs);
591         }
592         protected Member[] makeNext(Object JavaDoc o1, Object JavaDoc o2) {
593             return new Member[] {(Member) o1, (Member) o2};
594         }
595     }
596
597     // Member Member[]
598
abstract class BaseMemberMemberArrayIterCalc
599                     extends BaseIterCalc {
600         BaseMemberMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
601             super(call, calcs);
602         }
603         protected Member[] makeNext(Object JavaDoc o1, Object JavaDoc o2) {
604             Member m1 = (Member) o1;
605             Member[] ma2 = (Member[]) o2;
606             Member[] ma = new Member[ma2.length+1];
607             ma[0] = m1;
608             System.arraycopy(ma2, 0, ma, 1, ma2.length);
609             return ma;
610         }
611     }
612
613     // Member[] Member
614
abstract class BaseMemberArrayMemberIterCalc
615                     extends BaseIterCalc {
616         BaseMemberArrayMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
617             super(call, calcs);
618         }
619         protected Member[] makeNext(Object JavaDoc o1, Object JavaDoc o2) {
620             Member[] ma1 = (Member[]) o1;
621             Member m2 = (Member) o2;
622             Member[] ma = new Member[ma1.length+1];
623             System.arraycopy(ma1, 0, ma, 0, ma1.length);
624             ma[ma1.length] = m2;
625             return ma;
626         }
627     }
628
629     // Member[] Member[]
630
abstract class BaseMemberArrayMemberArrayIterCalc
631                     extends BaseIterCalc {
632         BaseMemberArrayMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
633             super(call, calcs);
634         }
635         protected Member[] makeNext(Object JavaDoc o1, Object JavaDoc o2) {
636             Member[] ma1 = (Member[]) o1;
637             Member[] ma2 = (Member[]) o2;
638             Member[] ma = new Member[ma1.length+ma2.length];
639             System.arraycopy(ma1, 0, ma, 0, ma1.length);
640             System.arraycopy(ma2, 0, ma, ma1.length, ma2.length);
641             return ma;
642         }
643     }
644
645     ///////////////////////////////////////////////////////////////////////////
646

647     // ITERABLE Member ITERABLE Member
648
class IterMemberIterMemberIterCalc
649             extends BaseMemberMemberIterCalc {
650         IterMemberIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
651             super(call, calcs);
652         }
653         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
654             Iterable JavaDoc<Member> it1 = (Iterable JavaDoc<Member>) o1;
655             Iterable JavaDoc<Member> it2 = (Iterable JavaDoc<Member>) o2;
656             return makeIterableIterable(it1, it2);
657         }
658     }
659
660     // ITERABLE Member LIST Member
661
class IterMemberListMemberIterCalc
662             extends BaseMemberMemberIterCalc {
663         IterMemberListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
664             super(call, calcs);
665         }
666         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
667             Iterable JavaDoc<Member> it1 = (Iterable JavaDoc<Member>) o1;
668             List<Member> l2 = (List<Member>) o2;
669
670             if (l2 instanceof RandomAccess) {
671                 // direct access faster
672
return makeIterableList(it1, l2);
673             } else {
674                 // iteration faster
675
return makeIterableIterable(it1, l2);
676             }
677         }
678     }
679     // LIST Member ITERABLE Member
680
class ListMemberIterMemberIterCalc
681             extends BaseMemberMemberIterCalc {
682         ListMemberIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
683             super(call, calcs);
684         }
685         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
686             List<Member> l1 = (List<Member>) o1;
687             Iterable JavaDoc<Member> it2 = (Iterable JavaDoc<Member>) o2;
688
689             if (l1 instanceof RandomAccess) {
690                 // direct access faster
691
return makeListIterable(l1, it2);
692             } else {
693                 // iteration faster
694
return makeIterableIterable(l1, it2);
695             }
696         }
697     }
698
699     // LIST Member LIST Member
700
class ListMemberListMemberIterCalc
701             extends BaseMemberMemberIterCalc {
702         ListMemberListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
703             super(call, calcs);
704         }
705         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
706             List<Member> l1 = (List<Member>) o1;
707             List<Member> l2 = (List<Member>) o2;
708
709             if (l1 instanceof RandomAccess) {
710                 // l1 direct access faster
711
if (l2 instanceof RandomAccess) {
712                     // l2 direct access faster
713
return makeListList(l1, l2);
714                 } else {
715                     // l2 iteration faster
716
return makeListIterable(l1, l2);
717                 }
718             } else {
719                 // l1 iteration faster
720
if (l2 instanceof RandomAccess) {
721                     // l2 direct access faster
722
return makeIterableList(l1, l2);
723                 } else {
724                     // l2 iteration faster
725
return makeIterableIterable(l1, l2);
726                 }
727             }
728         }
729     }
730
731     ///////////////////////////////////////////////////////////////////////////
732

733     // ITERABLE Member ITERABLE Member[]
734
class IterMemberIterMemberArrayIterCalc
735                 extends BaseMemberMemberArrayIterCalc {
736         IterMemberIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
737             super(call, calcs);
738         }
739         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
740             Iterable JavaDoc<Member> it1 = (Iterable JavaDoc<Member>) o1;
741             Iterable JavaDoc<Member[]> it2 = (Iterable JavaDoc<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         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
753             Iterable JavaDoc<Member> it1 = (Iterable JavaDoc<Member>) o1;
754             List<Member[]> l2 = (List<Member[]>) o2;
755
756             if (l2 instanceof RandomAccess) {
757                 // direct access faster
758
return makeIterableList(it1, l2);
759             } else {
760                 // iteration faster
761
return makeIterableIterable(it1, l2);
762             }
763         }
764     }
765
766     // LIST Member ITERABLE Member[]
767
class ListMemberIterMemberArrayIterCalc
768                 extends BaseMemberMemberArrayIterCalc {
769         ListMemberIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
770             super(call, calcs);
771         }
772         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
773             List<Member> l1 = (List<Member>) o1;
774             Iterable JavaDoc<Member[]> it2 = (Iterable JavaDoc<Member[]>) o2;
775
776             if (l1 instanceof RandomAccess) {
777                 // direct access faster
778
return makeListIterable(l1, it2);
779             } else {
780                 // iteration faster
781
return makeIterableIterable(l1, it2);
782             }
783         }
784     }
785
786     // LIST Member LIST Member[]
787
class ListMemberListMemberArrayIterCalc
788                 extends BaseMemberMemberArrayIterCalc {
789         ListMemberListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
790             super(call, calcs);
791         }
792         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
793             List<Member> l1 = (List<Member>) o1;
794             List<Member[]> l2 = (List<Member[]>) o2;
795
796             if (l1 instanceof RandomAccess) {
797                 // l1 direct access faster
798
if (l2 instanceof RandomAccess) {
799                     // l2 direct access faster
800
return makeListList(l1, l2);
801                 } else {
802                     // l2 iteration faster
803
return makeListIterable(l1, l2);
804                 }
805             } else {
806                 // l1 iteration faster
807
if (l2 instanceof RandomAccess) {
808                     // l2 direct access faster
809
return makeIterableList(l1, l2);
810                 } else {
811                     // l2 iteration faster
812
return makeIterableIterable(l1, l2);
813                 }
814             }
815         }
816     }
817
818     ///////////////////////////////////////////////////////////////////////////
819

820     // ITERABLE Member[] ITERABLE Member
821
class IterMemberArrayIterMemberIterCalc
822                 extends BaseMemberArrayMemberIterCalc {
823         IterMemberArrayIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
824             super(call, calcs);
825         }
826         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
827             Iterable JavaDoc<Member[]> it1 = (Iterable JavaDoc<Member[]>) o1;
828             Iterable JavaDoc<Member> it2 = (Iterable JavaDoc<Member>) o2;
829             return makeIterableIterable(it1, it2);
830         }
831     }
832
833     // ITERABLE Member[] LIST Member
834
class IterMemberArrayListMemberIterCalc
835                 extends BaseMemberArrayMemberIterCalc {
836         IterMemberArrayListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
837             super(call, calcs);
838         }
839         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
840             Iterable JavaDoc<Member[]> it1 = (Iterable JavaDoc<Member[]>) o1;
841             List<Member> l2 = (List<Member>) o2;
842
843             if (l2 instanceof RandomAccess) {
844                 // direct access faster
845
return makeIterableList(it1, l2);
846             } else {
847                 // iteration faster
848
return makeIterableIterable(it1, l2);
849             }
850         }
851     }
852
853     // LIST Member[] ITERABLE Member
854
class ListMemberArrayIterMemberIterCalc
855                 extends BaseMemberArrayMemberIterCalc {
856         ListMemberArrayIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
857             super(call, calcs);
858         }
859         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
860             List<Member[]> l1 = (List<Member[]>) o1;
861             Iterable JavaDoc<Member> it2 = (Iterable JavaDoc<Member>) o2;
862
863             if (l1 instanceof RandomAccess) {
864                 // direct access faster
865
return makeListIterable(l1, it2);
866             } else {
867                 // iteration faster
868
return makeIterableIterable(l1, it2);
869             }
870         }
871     }
872
873     // LIST Member[] LIST Member
874
class ListMemberArrayListMemberIterCalc
875                 extends BaseMemberArrayMemberIterCalc {
876         ListMemberArrayListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
877             super(call, calcs);
878         }
879         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
880             List<Member[]> l1 = (List<Member[]>) o1;
881             List<Member> l2 = (List<Member>) o2;
882
883             if (l1 instanceof RandomAccess) {
884                 // l1 direct access faster
885
if (l2 instanceof RandomAccess) {
886                     // l2 direct access faster
887
return makeListList(l1, l2);
888                 } else {
889                     // l2 iteration faster
890
return makeListIterable(l1, l2);
891                 }
892             } else {
893                 // l1 iteration faster
894
if (l2 instanceof RandomAccess) {
895                     // l2 direct access faster
896
return makeIterableList(l1, l2);
897                 } else {
898                     // l2 iteration faster
899
return makeIterableIterable(l1, l2);
900                 }
901             }
902         }
903     }
904
905     ///////////////////////////////////////////////////////////////////////////
906

907     // ITERABLE Member[] ITERABLE Member[]
908
class IterMemberArrayIterMemberArrayIterCalc
909                 extends BaseMemberArrayMemberArrayIterCalc {
910         IterMemberArrayIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
911             super(call, calcs);
912         }
913         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
914             Iterable JavaDoc<Member[]> it1 = (Iterable JavaDoc<Member[]>) o1;
915             Iterable JavaDoc<Member[]> it2 = (Iterable JavaDoc<Member[]>) o2;
916             return makeIterableIterable(it1, it2);
917         }
918     }
919
920     // ITERABLE Member[] LIST Member[]
921
class IterMemberArrayListMemberArrayIterCalc
922                 extends BaseMemberArrayMemberArrayIterCalc {
923         IterMemberArrayListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
924             super(call, calcs);
925         }
926         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
927             Iterable JavaDoc<Member[]> it1 = (Iterable JavaDoc<Member[]>) o1;
928             List<Member[]> l2 = (List<Member[]>) o2;
929
930             if (l2 instanceof RandomAccess) {
931                 // direct access faster
932
return makeIterableList(it1, l2);
933             } else {
934                 // iteration faster
935
return makeIterableIterable(it1, l2);
936             }
937         }
938     }
939
940     // LIST Member[] ITERABLE Member[]
941
class ListMemberArrayIterMemberArrayIterCalc
942                 extends BaseMemberArrayMemberArrayIterCalc {
943         ListMemberArrayIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
944             super(call, calcs);
945         }
946         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
947             List<Member[]> l1 = (List<Member[]>) o1;
948             Iterable JavaDoc<Member[]> it2 = (Iterable JavaDoc<Member[]>) o2;
949
950             if (l1 instanceof RandomAccess) {
951                 // direct access faster
952
return makeListIterable(l1, it2);
953             } else {
954                 // iteration faster
955
return makeIterableIterable(l1, it2);
956             }
957         }
958     }
959
960     // LIST Member[] LIST Member[]
961
class ListMemberArrayListMemberArrayIterCalc
962                 extends BaseMemberArrayMemberArrayIterCalc {
963         ListMemberArrayListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
964             super(call, calcs);
965         }
966         protected Iterable JavaDoc<Member[]> makeIterable(Object JavaDoc o1, Object JavaDoc o2) {
967             List<Member[]> l1 = (List<Member[]>) o1;
968             List<Member[]> l2 = (List<Member[]>) o2;
969
970             if (l1 instanceof RandomAccess) {
971                 // l1 direct access faster
972
if (l2 instanceof RandomAccess) {
973                     // l2 direct access faster
974
return makeListList(l1, l2);
975                 } else {
976                     // l2 iteration faster
977
return makeListIterable(l1, l2);
978                 }
979             } else {
980                 // l1 iteration faster
981
if (l2 instanceof RandomAccess) {
982                     // l2 direct access faster
983
return makeIterableList(l1, l2);
984                 } else {
985                     // l2 iteration faster
986
return makeIterableIterable(l1, l2);
987                 }
988             }
989         }
990     }
991
992     ///////////////////////////////////////////////////////////////////////////
993
///////////////////////////////////////////////////////////////////////////
994
// Immutable List
995
///////////////////////////////////////////////////////////////////////////
996
///////////////////////////////////////////////////////////////////////////
997

998     protected ListCalc compileCallImmutableList(final ResolvedFunCall call,
999             ExpCompiler compiler) {
1000        final ListCalc listCalc1 = toList(compiler, call.getArg(0));
1001        final ListCalc listCalc2 = toList(compiler, call.getArg(1));
1002        Calc[] calcs = new Calc[] {listCalc1, listCalc2};
1003        // The Calcs, 1 and 2, can be of type: Member or Member[] and
1004
// of ResultStyle: LIST or MUTABLE_LIST.
1005
// Since we want an immutable list as the result, it does not
1006
// matter whether the Calc list are of type
1007
// LIST and MUTABLE_LIST - they are treated the same; so
1008
// there are 4 possible combinations - even sweeter.
1009

1010        // Check returned calc ResultStyles
1011
checkListResultStyles(listCalc1);
1012        checkListResultStyles(listCalc2);
1013
1014        if (isMemberType(listCalc1)) {
1015            // Member
1016
if (isMemberType(listCalc2)) {
1017                // Member
1018
return new ImmutableListMemberListMemberListCalc(call, calcs);
1019            } else {
1020                // Member[]
1021
return new ImmutableListMemberListMemberArrayListCalc(call, calcs);
1022            }
1023        } else {
1024            // Member[]
1025
if (isMemberType(listCalc2)) {
1026                // Member
1027
return new ImmutableListMemberArrayListMemberListCalc(call, calcs);
1028            } else {
1029                // Member[]
1030
return new ImmutableListMemberArrayListMemberArrayListCalc(call, calcs);
1031            }
1032        }
1033    }
1034
1035    private ListCalc toList(ExpCompiler compiler, final Exp exp) {
1036        // Want immutable list or mutable list in that order
1037
// It is assumed that an immutable list is easier to get than
1038
// a mutable list.
1039
final Type type = exp.getType();
1040        if (type instanceof SetType) {
1041            return (ListCalc) compiler.compile(exp,
1042                ExpCompiler.LIST_MUTABLE_LIST_RESULT_STYLE_ARRAY);
1043        } else {
1044            return new SetFunDef.ListSetCalc(
1045                    new DummyExp(new SetType(type)),
1046                    new Exp[] {exp},
1047                    compiler,
1048                    ExpCompiler.LIST_MUTABLE_LIST_RESULT_STYLE_ARRAY
1049                    );
1050        }
1051    }
1052
1053    abstract class BaseListCalc extends AbstractListCalc {
1054        protected BaseListCalc(ResolvedFunCall call,
1055                    Calc[] calcs,
1056                    boolean mutable) {
1057            super(call, calcs, mutable);
1058        }
1059        public List<Member[]> evaluateList(Evaluator evaluator) {
1060            ResolvedFunCall call = (ResolvedFunCall) exp;
1061            // Use a native evaluator, if more efficient.
1062
// TODO: Figure this out at compile time.
1063
SchemaReader schemaReader = evaluator.getSchemaReader();
1064            NativeEvaluator nativeEvaluator =
1065                schemaReader.getNativeSetEvaluator(
1066                    call.getFunDef(), call.getArgs(), evaluator, this);
1067            if (nativeEvaluator != null) {
1068                return (List) nativeEvaluator.execute(
1069                            ResultStyle.LIST);
1070            }
1071
1072            Calc[] calcs = getCalcs();
1073            ListCalc listCalc1 = (ListCalc) calcs[0];
1074            ListCalc listCalc2 = (ListCalc) calcs[1];
1075
1076            Evaluator oldEval = null;
1077            assert (oldEval = evaluator.push()) != null;
1078
1079            List l1 = listCalc1.evaluateList(evaluator);
1080            assert oldEval.equals(evaluator) : "listCalc1 changed context";
1081
1082            List l2 = listCalc2.evaluateList(evaluator);
1083            assert oldEval.equals(evaluator) : "listCalc2 changed context";
1084
1085            //l1 = checkList(evaluator, l1);
1086
l1 = nonEmptyOptimizeList(evaluator, l1, call);
1087            if (l1.isEmpty()) {
1088                return Collections.EMPTY_LIST;
1089            }
1090            //l2 = checkList(evaluator, l2);
1091
l2 = nonEmptyOptimizeList(evaluator, l2, call);
1092            if (l2.isEmpty()) {
1093                return Collections.EMPTY_LIST;
1094            }
1095
1096            return makeList(l1, l2);
1097        }
1098
1099        protected abstract List<Member[]> makeList(List l1, List l2);
1100    }
1101
1102    public abstract class BaseImmutableList
1103                            extends UnsupportedList<Member[]> {
1104        protected BaseImmutableList() {
1105        }
1106        public abstract int size();
1107        public abstract Member[] get(int index);
1108
1109        public Object JavaDoc[] toArray() {
1110            int size = size();
1111            Object JavaDoc[] result = new Object JavaDoc[size];
1112            for (int i = 0; i < size; i++) {
1113                result[i] = get(i);
1114            }
1115            return result;
1116        }
1117        public List<Member[]> toArrayList() {
1118            List<Member[]> l = new ArrayList<Member[]>(size());
1119            Iterator i = iterator();
1120            while (i.hasNext()) {
1121                l.add((Member[]) i.next());
1122            }
1123            return l;
1124        }
1125        public ListIterator<Member[]> listIterator() {
1126            return new ListItr(0);
1127        }
1128        public ListIterator<Member[]> listIterator(int index) {
1129            return new ListItr(index);
1130        }
1131        public Iterator<Member[]> iterator() {
1132            return new Itr();
1133        }
1134    }
1135
1136    // LIST Member LIST Member
1137
class ImmutableListMemberListMemberListCalc
1138            extends BaseListCalc {
1139        ImmutableListMemberListMemberListCalc(ResolvedFunCall call, Calc[] calcs) {
1140            super(call, calcs, false);
1141        }
1142        protected List<Member[]> makeList(final List l1, final List l2) {
1143            final int size = l1.size() * l2.size();
1144            // This is the mythical "local class" declaration.
1145
// Observer that in the subList method, there is another
1146
// such class declaration. The outer one can not be an
1147
// anonymous class because
1148
// the inner one must reference, have a name for, the
1149
// outer one. The inner one is needed because it includes
1150
// the offset into the outer one as instance variables.
1151
// The outer class has no explicit instance variables
1152
// though it does have the implicit List finals, l1 and l2.
1153
// One can call the inner class's subList method repeatedly
1154
// and each new Inner object return adds an additional
1155
// "fromIndex" to the "get" method calls.
1156
//
1157
// All of this works because the underlying lists are
1158
// immutable.
1159
//
1160
class Outer extends BaseImmutableList {
1161                Outer() {}
1162                public int size() {
1163                    return size;
1164                }
1165                public Member[] get(int index) {
1166                    int i = (index / l2.size());
1167                    int j = (index % l2.size());
1168                    Member m1 = (Member) l1.get(i);
1169                    Member m2 = (Member) l2.get(j);
1170                    return new Member[] { m1, m2 };
1171                }
1172                public List<Member[]> subList(int fromIndex, int toIndex) {
1173                    class Inner extends Outer {
1174                        int fromIndex;
1175                        int toIndex;
1176                        Inner(int fromIndex, int toIndex) {
1177                            this.fromIndex = fromIndex;
1178                            this.toIndex = toIndex;
1179                        }
1180                        public int size() {
1181                            return (this.toIndex - this.fromIndex);
1182                        }
1183                        public Member[] get(int index) {
1184                            return Outer.this.get(index + this.fromIndex);
1185                        }
1186                        public List<Member[]> subList(int fromIndex, int toIndex) {
1187                            return new Inner(this.fromIndex+fromIndex, this.fromIndex+toIndex);
1188                        }
1189                    }
1190                    return new Inner(fromIndex, toIndex);
1191                }
1192            };
1193            return new Outer();
1194        }
1195    }
1196
1197    // LIST Member LIST Member[]
1198
class ImmutableListMemberListMemberArrayListCalc
1199            extends BaseListCalc {
1200        ImmutableListMemberListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) {
1201            super(call, calcs, false);
1202        }
1203        protected List<Member[]> makeList(final List l1, final List l2) {
1204            final int len2 = ((Member[])l2.get(0)).length;
1205            final int size = (l1.size() * l2.size());
1206            class Outer extends BaseImmutableList {
1207                Outer() {}
1208                public int size() {
1209                    return size;
1210                }
1211                public Member[] get(int index) {
1212                    int i = (index / l2.size());
1213                    int j = (index % l2.size());
1214                    Member[] ma = new Member[1 + len2];
1215                    Member m1 = (Member) l1.get(i);
1216                    Member[] ma2 = (Member[]) l2.get(j);
1217                    ma[0] = m1;
1218                    System.arraycopy(ma2, 0, ma, 1, len2);
1219                    return ma;
1220                }
1221                public List<Member[]> subList(int fromIndex, int toIndex) {
1222                    class Inner extends Outer {
1223                        int fromIndex;
1224                        int toIndex;
1225                        Inner(int fromIndex, int toIndex) {
1226                            this.fromIndex = fromIndex;
1227                            this.toIndex = toIndex;
1228                        }
1229                        public int size() {
1230                            return (this.toIndex - this.fromIndex);
1231                        }
1232                        public Member[] get(int index) {
1233                            return Outer.this.get(index + this.fromIndex);
1234                        }
1235                        public List<Member[]> subList(int fromIndex, int toIndex) {
1236                            return new Inner(this.fromIndex+fromIndex, this.fromIndex+toIndex);
1237                        }
1238                    }
1239                    return new Inner(fromIndex, toIndex);
1240                }
1241            };
1242            return new Outer();
1243        }
1244    }
1245    // LIST Member[] LIST Member
1246
class ImmutableListMemberArrayListMemberListCalc
1247            extends BaseListCalc {
1248        ImmutableListMemberArrayListMemberListCalc(ResolvedFunCall call, Calc[] calcs) {
1249            super(call, calcs, false);
1250        }
1251        protected List<Member[]> makeList(final List l1, final List l2) {
1252            final int len1 = ((Member[])l1.get(0)).length;
1253            final int size = (l1.size() * l2.size());
1254            class Outer extends BaseImmutableList {
1255                Outer() {}
1256                public int size() {
1257                    return size;
1258                }
1259                public Member[] get(int index) {
1260                    int i = (index / l2.size());
1261                    int j = (index % l2.size());
1262                    Member[] ma = new Member[len1 + 1];
1263                    Member[] ma1 = (Member[]) l1.get(i);
1264                    Member m2 = (Member) l2.get(j);
1265                    System.arraycopy(ma1, 0, ma, 0, len1);
1266                    ma[len1] = m2;
1267                    return ma;
1268                }
1269                public List<Member[]> subList(int fromIndex, int toIndex) {
1270                    class Inner extends Outer {
1271                        int fromIndex;
1272                        int toIndex;
1273                        Inner(int fromIndex, int toIndex) {
1274                            this.fromIndex = fromIndex;
1275                            this.toIndex = toIndex;
1276                        }
1277                        public int size() {
1278                            return (this.toIndex - this.fromIndex);
1279                        }
1280                        public Member[] get(int index) {
1281                            return Outer.this.get(index + this.fromIndex);
1282                        }
1283                        public List<Member[]> subList(int fromIndex, int toIndex) {
1284                            return new Inner(this.fromIndex+fromIndex, this.fromIndex+toIndex);
1285                        }
1286                    }
1287                    return new Inner(fromIndex, toIndex);
1288                }
1289            }
1290            return new Outer();
1291        }
1292    }
1293    // LIST Member[] LIST Member[]
1294
class ImmutableListMemberArrayListMemberArrayListCalc
1295            extends BaseListCalc {
1296        ImmutableListMemberArrayListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) {
1297            super(call, calcs, false);
1298        }
1299        protected List<Member[]> makeList(final List l1, final List l2) {
1300            final int len1 = ((Member[])l1.get(0)).length;
1301            final int len2 = ((Member[])l2.get(0)).length;
1302            final int size = (l1.size() * l2.size());
1303
1304            class Outer extends BaseImmutableList {
1305                Outer() {}
1306                public int size() {
1307                    return size;
1308                }
1309                public Member[] get(int index) {
1310                    int i = (index / l2.size());
1311                    int j = (index % l2.size());
1312                    Member[] ma = new Member[len1 + len2];
1313                    Member[] ma1 = (Member[]) l1.get(i);
1314                    Member[] ma2 = (Member[]) l2.get(j);
1315                    System.arraycopy(ma1, 0, ma, 0, len1);
1316                    System.arraycopy(ma2, 0, ma, len1, len2);
1317                    return ma;
1318                }
1319                public List<Member[]> subList(int fromIndex, int toIndex) {
1320                    class Inner extends Outer {
1321                        int fromIndex;
1322                        int toIndex;
1323                        Inner(int fromIndex, int toIndex) {
1324                            this.fromIndex = fromIndex;
1325                            this.toIndex = toIndex;
1326                        }
1327                        public int size() {
1328                            return (this.toIndex - this.fromIndex);
1329                        }
1330                        public Member[] get(int index) {
1331                            return Outer.this.get(index + this.fromIndex);
1332                        }
1333                        public List<Member[]> subList(int fromIndex, int toIndex) {
1334                            return new Inner(this.fromIndex+fromIndex, this.fromIndex+toIndex);
1335                        }
1336                    }
1337                    return new Inner(fromIndex, toIndex);
1338                }
1339            }
1340            return new Outer();
1341        }
1342    }
1343
1344    ///////////////////////////////////////////////////////////////////////////
1345
///////////////////////////////////////////////////////////////////////////
1346
// Mutable List
1347
///////////////////////////////////////////////////////////////////////////
1348
///////////////////////////////////////////////////////////////////////////
1349

1350    protected ListCalc compileCallMutableList(final ResolvedFunCall call,
1351            ExpCompiler compiler) {
1352        final ListCalc listCalc1 = toList(compiler, call.getArg(0));
1353        final ListCalc listCalc2 = toList(compiler, call.getArg(1));
1354
1355        Calc[] calcs = new Calc[] {listCalc1, listCalc2};
1356        // The Calcs, 1 and 2, can be of type: Member or Member[] and
1357
// of ResultStyle: LIST or MUTABLE_LIST.
1358
// Since we want an mutable list as the result, it does not
1359
// matter whether the Calc list are of type
1360
// LIST and MUTABLE_LIST - they are treated the same,
1361
// regardless of type, one must materialize the result list; so
1362
// there are 4 possible combinations - even sweeter.
1363

1364        // Check returned calc ResultStyles
1365
checkListResultStyles(listCalc1);
1366        checkListResultStyles(listCalc2);
1367
1368        if (isMemberType(listCalc1)) {
1369            // Member
1370
if (isMemberType(listCalc2)) {
1371                // Member
1372
return new MutableListMemberListMemberListCalc(call, calcs);
1373            } else {
1374                // Member[]
1375
return new MutableListMemberListMemberArrayListCalc(call, calcs);
1376            }
1377        } else {
1378            // Member[]
1379
if (isMemberType(listCalc2)) {
1380                // Member
1381
return new MutableListMemberArrayListMemberListCalc(call, calcs);
1382            } else {
1383                // Member[]
1384
return new MutableListMemberArrayListMemberArrayListCalc(call, calcs);
1385            }
1386        }
1387    }
1388
1389    /**
1390     * A BaseMutableList can be sorted, its elements rearranged, but
1391     * its size can not be changed (the add or remove methods are not
1392     * supported).
1393     */

1394    public abstract class BaseMutableList
1395                            extends UnsupportedList<Member[]> {
1396        protected final Member[] members;
1397        protected BaseMutableList(Member[] members) {
1398            this.members = members;
1399        }
1400        public abstract int size();
1401        public abstract Member[] get(int index);
1402        public abstract Member[] set(int index, Member[] element);
1403        public abstract Member[] remove(int index);
1404        public abstract List<Member[]> subList(int fromIndex, int toIndex);
1405
1406        public Object JavaDoc[] toArray() {
1407            int size = size();
1408            Object JavaDoc[] result = new Object JavaDoc[size];
1409            for (int i = 0; i < size; i++) {
1410                result[i] = get(i);
1411            }
1412            return result;
1413        }
1414        public List<Member[]> toArrayList() {
1415            List<Member[]> l = new ArrayList<Member[]>(size());
1416            Iterator i = iterator();
1417            while (i.hasNext()) {
1418                l.add((Member[]) i.next());
1419            }
1420            return l;
1421        }
1422        public ListIterator<Member[]> listIterator() {
1423            return new LocalListItr(0);
1424        }
1425        public ListIterator<Member[]> listIterator(int index) {
1426            return new LocalListItr(index);
1427        }
1428        public Iterator<Member[]> iterator() {
1429            return new LocalItr();
1430        }
1431        private class LocalItr extends Itr {
1432            public LocalItr() {
1433                super();
1434            }
1435            public void remove() {
1436                if (lastRet == -1) {
1437                    throw new IllegalStateException JavaDoc();
1438                }
1439                //checkForComodification();
1440

1441                try {
1442                    CrossJoinFunDef.BaseMutableList.this.remove(lastRet);
1443                    if (lastRet < cursor) {
1444                        cursor--;
1445                    }
1446                    lastRet = -1;
1447                    //expectedModCount = modCount;
1448
} catch(IndexOutOfBoundsException JavaDoc e) {
1449                    throw new ConcurrentModificationException();
1450                }
1451            }
1452        }
1453        private class LocalListItr extends ListItr {
1454            public LocalListItr(int index) {
1455                super(index);
1456            }
1457            public void set(Member[] o) {
1458                if (lastRet == -1)
1459                    throw new IllegalStateException JavaDoc();
1460                try {
1461                    CrossJoinFunDef.BaseMutableList.this.set(lastRet, o);
1462                } catch(IndexOutOfBoundsException JavaDoc e) {
1463                    throw new ConcurrentModificationException();
1464                }
1465            }
1466        }
1467
1468    }
1469
1470    // LIST Member LIST Member
1471
class MutableListMemberListMemberListCalc
1472            extends BaseListCalc {
1473        MutableListMemberListMemberListCalc(ResolvedFunCall call, Calc[] calcs) {
1474            super(call, calcs, true);
1475        }
1476        protected List<Member[]> makeList(final List l1, final List l2) {
1477            int size1 = l1.size();
1478            // len1 == 1
1479
int size2 = l2.size();
1480            // len2 == 1
1481
int arraySize = (2 * (size1 * size2));
1482
1483            Member[] members = new Member[arraySize];
1484            for (int i = 0; i < size1; i++) {
1485                Member m1 = (Member) l1.get(i);
1486                int ii = i*size2;
1487                for (int j = 0; j < size2; j++) {
1488                    Member m2 = (Member) l2.get(j);
1489                    members[2*(ii + j)] = m1;
1490                    members[2*(ii + j)+1] = m2;
1491                }
1492            }
1493            return makeList(members);
1494        }
1495        protected List<Member[]> makeList(Member[] members) {
1496            // externally looks like:
1497
// [] <- [a][A]
1498
// [] <- [a][B]
1499
// ...
1500
// [] <- [m][N]
1501
//
1502
// but internally is:
1503
// [a][A][a][B] ... [m][M][m][N]
1504
List<Member[]> list = new BaseMutableList(members) {
1505                int size = members.length/2;
1506                public int size() {
1507                    return size;
1508                }
1509                public Member[] get(int index) {
1510                    int i = index+index;
1511                    return new Member[] { members[i], members[i+1] };
1512                }
1513                public Member[] set(int index, Member[] element) {
1514                    int i = index+index;
1515                    Member[] oldValue =
1516                        new Member[] { members[i], members[i+1] };
1517
1518                    members[i] = element[0];
1519                    members[i+1] = element[1];
1520
1521                    return oldValue;
1522                }
1523                public Member[] remove(int index) {
1524                    int i = index+index;
1525                    Member[] oldValue =
1526                        new Member[] { members[i], members[i+1] };
1527
1528                    System.arraycopy(members, i+2, members, i,
1529                            members.length - (i+2));
1530
1531                    size--;
1532                    return oldValue;
1533                }
1534                public List<Member[]> subList(int fromIndex, int toIndex) {
1535                    int from = fromIndex + fromIndex;
1536                    int to = toIndex + toIndex;
1537                    Member[] sublist = new Member[to - from];
1538                    System.arraycopy(members, from, sublist, 0, to - from);
1539                    return makeList(sublist);
1540                }
1541            };
1542            return list;
1543        }
1544    }
1545
1546    // LIST Member LIST Member[]
1547
class MutableListMemberListMemberArrayListCalc
1548            extends BaseListCalc {
1549        MutableListMemberListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) {
1550            super(call, calcs, true);
1551        }
1552        protected List<Member[]> makeList(final List l1, final List l2) {
1553            int size1 = l1.size();
1554            // len1 == 1
1555
int size2 = l2.size();
1556            int len2 = ((Member[])l2.get(0)).length;
1557            int totalLen = 1+len2;
1558            int arraySize = (totalLen * (size1 * size2));
1559
1560            Member[] members = new Member[arraySize];
1561            for (int i = 0; i < size1; i++) {
1562                Member m1 = (Member) l1.get(i);
1563                int ii = i*size2;
1564                for (int j = 0; j < size2; j++) {
1565                    Member[] ma2 = (Member[]) l2.get(j);
1566                    members[totalLen*(ii + j)] = m1;
1567                    for (int k = 0; k < len2; k++) {
1568                        Member m2 = (Member) ma2[k];
1569                        members[totalLen*(ii + j)+k+1] = m2;
1570                    }
1571                }
1572            }
1573
1574            return makeList(members, totalLen);
1575        }
1576        protected List<Member[]> makeList(Member[] members, final int totalLen) {
1577            // l1: a,b
1578
// l2: {A,B,C},{D,E,F}
1579
//
1580
// externally looks like:
1581
// [] <- {a,A,B,C}
1582
// [] <- {a,D,E,F}
1583
// [] <- {b,A,B,C}
1584
// [] <- {b,D,E,F}
1585
//
1586
// but internally is:
1587
// a,A,B,C,a,D,E,F,b,A,B,C,b,D,E,F
1588
List<Member[]> list = new BaseMutableList(members) {
1589                int size = members.length/totalLen;
1590                public int size() {
1591                    return size;
1592                }
1593                public Member[] get(int index) {
1594                    int i = totalLen*index;
1595                    Member[] ma = new Member[totalLen];
1596                    System.arraycopy(members, i, ma, 0, totalLen);
1597                    return ma;
1598                }
1599                public Member[] set(int index, Member[] element) {
1600                    int i = totalLen*index;
1601                    Member[] oldValue = new Member[totalLen];
1602                    System.arraycopy(members, i, oldValue, 0, totalLen);
1603
1604                    System.arraycopy(element, 0, members, i, totalLen);
1605
1606                    return oldValue;
1607                }
1608                public Member[] remove(int index) {
1609                    int i = totalLen*index;
1610                    Member[] oldValue = new Member[totalLen];
1611                    System.arraycopy(members, i, oldValue, 0, totalLen);
1612
1613                    System.arraycopy(members, i+totalLen,
1614                            members, i,
1615                            members.length-(i+totalLen));
1616
1617                    size--;
1618                    return oldValue;
1619                }
1620                public List<Member[]> subList(int fromIndex, int toIndex) {
1621                    int from = totalLen*fromIndex;
1622                    int to = totalLen*toIndex;
1623                    Member[] sublist = new Member[to - from];
1624                    System.arraycopy(members, from, sublist, 0, to - from);
1625                    return makeList(sublist, totalLen);
1626                }
1627            };
1628            return list;
1629        }
1630    }
1631    // LIST Member[] LIST Member
1632
class MutableListMemberArrayListMemberListCalc
1633            extends BaseListCalc {
1634        MutableListMemberArrayListMemberListCalc(ResolvedFunCall call, Calc[] calcs) {
1635            super(call, calcs, true);
1636        }
1637        protected List<Member[]> makeList(final List l1, final List l2) {
1638            int size1 = l1.size();
1639            int len1 = ((Member[])l1.get(0)).length;
1640            int size2 = l2.size();
1641            // len2 == 1
1642
int totalLen = 1+len1;
1643            int arraySize = (totalLen * (size1 * size2));
1644
1645            Member[] members = new Member[arraySize];
1646            for (int i = 0; i < size1; i++) {
1647                Member[] ma1 = (Member[]) l1.get(i);
1648                int ii = i*size2;
1649                for (int j = 0; j < size2; j++) {
1650                    for (int k = 0; k < len1; k++) {
1651                        Member m1 = (Member) ma1[k];
1652                        members[totalLen*(ii + j)+k] = m1;
1653                    }
1654                    Member m2 = (Member) l2.get(j);
1655                    members[totalLen*(ii + j)+len1] = m2;
1656                }
1657            }
1658
1659            return makeList(members, totalLen);
1660        }
1661        protected List<Member[]> makeList(Member[] members, final int totalLen) {
1662            // l1: {A,B,C},{D,E,F}
1663
// l2: a,b
1664
//
1665
// externally looks like:
1666
// [] <- {A,B,C,a}
1667
// [] <- {A,B,C,b}
1668
// [] <- {D,E,F,a}
1669
// [] <- {D,E,F,b}
1670
//
1671
// but internally is:
1672
// A,B,C,a,A,B,C,b,D,E,F,a,D,E,F,b
1673
List<Member[]> list = new BaseMutableList(members) {
1674                int size = members.length/totalLen;
1675                public int size() {
1676                    return size;
1677                }
1678                public Member[] get(int index) {
1679                    int i = totalLen*index;
1680                    Member[] ma = new Member[totalLen];
1681                    System.arraycopy(members, i, ma, 0, totalLen);
1682                    return ma;
1683                }
1684                public Member[] set(int index, Member[] element) {
1685                    int i = totalLen*index;
1686                    Member[] oldValue = new Member[totalLen];
1687                    System.arraycopy(members, i, oldValue, 0, totalLen);
1688
1689                    System.arraycopy(element, 0, members, i, totalLen);
1690
1691                    return oldValue;
1692                }
1693                public Member[] remove(int index) {
1694                    int i = totalLen*index;
1695                    Member[] oldValue = new Member[totalLen];
1696                    System.arraycopy(members, i, oldValue, 0, totalLen);
1697
1698                    System.arraycopy(members, i+totalLen,
1699                            members, i,
1700                            members.length-(i+totalLen));
1701
1702                    size--;
1703                    return oldValue;
1704                }
1705                public List<Member[]> subList(int fromIndex, int toIndex) {
1706                    int from = totalLen*fromIndex;
1707                    int to = totalLen*toIndex;
1708                    Member[] sublist = new Member[to - from];
1709                    System.arraycopy(members, from, sublist, 0, to - from);
1710                    return makeList(sublist, totalLen);
1711                }
1712            };
1713            return list;
1714        }
1715    }
1716    // LIST Member[] LIST Member[]
1717
class MutableListMemberArrayListMemberArrayListCalc
1718            extends BaseListCalc {
1719        MutableListMemberArrayListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) {
1720            super(call, calcs, true);
1721        }
1722        protected List<Member[]> makeList(final List l1, final List l2) {
1723            int size1 = l1.size();
1724            int len1 = ((Member[])l1.get(0)).length;
1725            int size2 = l2.size();
1726            int len2 = ((Member[])l2.get(0)).length;
1727            int totalLen = len1+len2;
1728            int arraySize = (totalLen * (size1 * size2));
1729
1730            Member[] members = new Member[arraySize];
1731            for (int i = 0; i < size1; i++) {
1732                Member[] ma1 = (Member[]) l1.get(i);
1733                int ii = i*size2;
1734                for (int j = 0; j < size2; j++) {
1735                    for (int k = 0; k < len1; k++) {
1736                        Member m1 = (Member) ma1[k];
1737                        members[totalLen*(ii + j)+k] = m1;
1738                    }
1739                    Member[] ma2 = (Member[]) l2.get(j);
1740                    for (int k = 0; k < len2; k++) {
1741                        Member m2 = (Member) ma2[k];
1742                        members[totalLen*(ii + j)+len1+k] = m2;
1743                    }
1744                }
1745            }
1746            return makeList(members, totalLen);
1747        }
1748        protected List<Member[]> makeList(Member[] members, final int totalLen) {
1749
1750            // l1: {A,B,C},{D,E,F}
1751
// l2: {a,b},{c,d},{e,f}
1752
//
1753
// externally looks like:
1754
// [] <- {A,B,C,a,b}
1755
// [] <- {A,B,C,c,d}
1756
// [] <- {A,B,C,e,f}
1757
// [] <- {D,E,F,a,b}
1758
// [] <- {D,E,F,c,d}
1759
// [] <- {D,E,F,e,d}
1760
//
1761
// but internally is:
1762
// 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
1763
//
1764
List<Member[]> list = new BaseMutableList(members) {
1765                int size = members.length/totalLen;
1766                public int size() {
1767                    return size;
1768                }
1769                public Member[] get(int index) {
1770                    int i = totalLen*index;
1771                    Member[] ma = new Member[totalLen];
1772                    System.arraycopy(members, i, ma, 0, totalLen);
1773                    return ma;
1774                }
1775                public Member[] set(int index, Member[] element) {
1776                    int i = totalLen*index;
1777                    Member[] oldValue = new Member[totalLen];
1778                    System.arraycopy(members, i, oldValue, 0, totalLen);
1779
1780                    System.arraycopy(element, 0, members, i, totalLen);
1781
1782                    return oldValue;
1783                }
1784
1785                public Member[] remove(int index) {
1786                    int i = totalLen*index;
1787                    Member[] oldValue = new Member[totalLen];
1788                    System.arraycopy(members, i, oldValue, 0, totalLen);
1789
1790                    System.arraycopy(members, i+totalLen,
1791                            members, i,
1792                            members.length-(i+totalLen));
1793
1794                    size--;
1795                    return oldValue;
1796                }
1797                public List<Member[]> subList(int fromIndex, int toIndex) {
1798                    int from = totalLen*fromIndex;
1799                    int to = totalLen*toIndex;
1800                    Member[] sublist = new Member[to - from];
1801                    System.arraycopy(members, from, sublist, 0, to - from);
1802                    return makeList(sublist, totalLen);
1803                }
1804            };
1805            return list;
1806        }
1807    }
1808
1809
1810    protected List nonEmptyOptimizeList(
1811            Evaluator evaluator,
1812            List list,
1813            ResolvedFunCall call) {
1814
1815        int opSize = MondrianProperties.instance().CrossJoinOptimizerSize.get();
1816        int size = list.size();
1817
1818        if (size > opSize && evaluator.isNonEmpty()) {
1819            // instead of overflow exception try to further
1820
// optimize nonempty(crossjoin(a,b)) ==
1821
// nonempty(crossjoin(nonempty(a),nonempty(b))
1822
final int missCount = evaluator.getMissCount();
1823
1824            list = nonEmptyList(evaluator, list, call);
1825            size = list.size();
1826            // list may be empty after nonEmpty optimization
1827
if (size == 0) {
1828                return Collections.EMPTY_LIST;
1829            }
1830            final int missCount2 = evaluator.getMissCount();
1831            final int puntMissCountListSize = 1000;
1832            if (missCount2 > missCount && size > puntMissCountListSize) {
1833                // We've hit some cells which are not in the cache. They
1834
// registered as non-empty, but we won't really know until
1835
// we've populated the cache. The cartesian product is still
1836
// huge, so let's quit now, and try again after the cache
1837
// has been loaded.
1838
// Return an empty list short circuits higher level
1839
// evaluation poping one all the way to the top.
1840
return Collections.EMPTY_LIST;
1841            }
1842        }
1843        return list;
1844    }
1845    List crossJoin(
1846        List list1,
1847        List list2,
1848        Evaluator evaluator,
1849        ResolvedFunCall call)
1850    {
1851        if (list1.isEmpty() || list2.isEmpty()) {
1852            return Collections.EMPTY_LIST;
1853        }
1854        // Optimize nonempty(crossjoin(a,b)) ==
1855
// nonempty(crossjoin(nonempty(a),nonempty(b))
1856
long size = (long)list1.size() * (long)list2.size();
1857        int resultLimit = MondrianProperties.instance().ResultLimit.get();
1858
1859        // Throw an exeption, if the size of the crossjoin exceeds the result
1860
// limit.
1861
//
1862
// FIXME: If we're going to apply a NON EMPTY constraint later, it's
1863
// possible that the ultimate result will be much smaller.
1864
if (resultLimit > 0 && resultLimit < size) {
1865            throw MondrianResource.instance().LimitExceededDuringCrossjoin.ex(
1866                size, resultLimit);
1867        }
1868
1869        // Throw an exception if the crossjoin exceeds a reasonable limit.
1870
// (Yes, 4 billion is a reasonable limit.)
1871
if (size > Integer.MAX_VALUE) {
1872            throw MondrianResource.instance().LimitExceededDuringCrossjoin.ex(
1873                size, Integer.MAX_VALUE);
1874        }
1875
1876        // Now we can safely cast size to an integer. It still might be very
1877
// large - which means we're allocating a huge array which we might
1878
// pare down later by applying NON EMPTY constraints - which is a
1879
// concern.
1880
List<Member[]> result = new ArrayList<Member[]>((int) size);
1881
1882        boolean neitherSideIsTuple = true;
1883        int arity0 = 1;
1884        int arity1 = 1;
1885        if (list1.get(0) instanceof Member[]) {
1886            arity0 = ((Member[]) list1.get(0)).length;
1887            neitherSideIsTuple = false;
1888        }
1889        if (list2.get(0) instanceof Member[]) {
1890            arity1 = ((Member[]) list2.get(0)).length;
1891            neitherSideIsTuple = false;
1892        }
1893
1894        if (neitherSideIsTuple) {
1895            // Simpler routine if we know neither side contains tuples.
1896
for (Member o0 : (List<Member>) list1) {
1897                for (Member o1 : (List<Member>) list2) {
1898                    result.add(new Member[]{o0, o1});
1899                }
1900            }
1901        } else {
1902            // More complex routine if one or both sides are arrays
1903
// (probably the product of nested CrossJoins).
1904
Member[] row = new Member[arity0 + arity1];
1905            for (int i = 0, m = list1.size(); i < m; i++) {
1906                int x = 0;
1907                Object JavaDoc o0 = list1.get(i);
1908                if (o0 instanceof Member) {
1909                    row[x++] = (Member) o0;
1910                } else {
1911                    assertTrue(o0 instanceof Member[]);
1912                    final Member[] members = (Member[]) o0;
1913                    for (Member member : members) {
1914                        row[x++] = member;
1915                    }
1916                }
1917                for (int j = 0, n = list2.size(); j < n; j++) {
1918                    Object JavaDoc o1 = list2.get(j);
1919                    if (o1 instanceof Member) {
1920                        row[x++] = (Member) o1;
1921                    } else {
1922                        assertTrue(o1 instanceof Member[]);
1923                        final Member[] members = (Member[]) o1;
1924                        for (Member member : members) {
1925                            row[x++] = member;
1926                        }
1927                    }
1928                    result.add(row.clone());
1929                    x = arity0;
1930                }
1931            }
1932        }
1933        return result;
1934    }
1935
1936    /**
1937     * Visitor which builds a list of all measures referenced in a query,
1938     * provided the measures don't reference the function call we're trying
1939     * to evaluate for non-emptiness.
1940     */

1941    private static class MeasureVisitor extends MdxVisitorImpl {
1942
1943        // This set is null unless a measure is found.
1944
Set<Member> measureSet;
1945        Set<Member> queryMeasureSet;
1946        // measures referencing this call should be excluded from the list
1947
// of measures found
1948
ResolvedFunCall crossJoinCall;
1949
1950        MeasureVisitor(
1951            Set<Member> queryMeasureSet,
1952            ResolvedFunCall crossJoinCall)
1953        {
1954            this.queryMeasureSet = queryMeasureSet;
1955            this.crossJoinCall = crossJoinCall;
1956        }
1957
1958        public Object JavaDoc visit(mondrian.mdx.ParameterExpr parameterExpr) {
1959            final Parameter parameter = parameterExpr.getParameter();
1960            final Type type = parameter.getType();
1961            if (type instanceof mondrian.olap.type.MemberType) {
1962                final Object JavaDoc value = parameter.getValue();
1963                if (value instanceof Member) {
1964                    final Member member = (Member) value;
1965                    process(member);
1966                }
1967            }
1968
1969            return null;
1970        }
1971        public Object JavaDoc visit(mondrian.mdx.MemberExpr memberExpr) {
1972            Member member = memberExpr.getMember();
1973            process(member);
1974            return null;
1975        }
1976        private void process(final Member member) {
1977            for (Member measure : queryMeasureSet) {
1978                if (measure.equals(member)) {
1979                    if (validMeasure(measure)) {
1980                        if (measureSet == null) {
1981                            measureSet = new HashSet<Member>();
1982                        }
1983                        measureSet.add(measure);
1984                        break;
1985                    }
1986                }
1987            }
1988        }
1989
1990        /**
1991         * Determines if a measure should be added to the set of measures
1992         * that make up the evaluation context for the nonempty cross join.
1993         * It should not be if it is a calculated measure that references
1994         * the cross join, unless the cross join itself also references
1995         * that calculated measure, in which case, we have a recursive call,
1996         * and an exception is thrown.
1997         *
1998         * @param measure measure being examined
1999         *
2000         * @return true if the measure should be added
2001         */

2002        private boolean validMeasure(Member measure)
2003        {
2004            if (measure.isCalculated()) {
2005                // check if the measure references the crossjoin
2006
Exp measureExp = measure.getExpression();
2007                ResolvedFunCallFinder finder =
2008                    new ResolvedFunCallFinder(crossJoinCall);
2009                measureExp.accept(finder);
2010                if (finder.found) {
2011                    // check if the arguments to the cross join reference
2012
// the measure
2013
Exp [] args = crossJoinCall.getArgs();
2014                    for (int i = 0; i < args.length; i++) {
2015                        Set<Member> measureSet = new HashSet<Member>();
2016                        measureSet.add(measure);
2017                        MeasureVisitor measureFinder =
2018                            new MeasureVisitor(measureSet, null);
2019                        args[i].accept(measureFinder);
2020                        measureSet = measureFinder.measureSet;
2021                        if (measureSet != null && measureSet.size() > 0) {
2022                            // recursive condition
2023
throw FunUtil.newEvalException(null,
2024                                "Infinite loop detected in " +
2025                                crossJoinCall.toString());
2026                        }
2027                    }
2028                    return false;
2029                }
2030            }
2031            return true;
2032        }
2033    }
2034
2035    /**
2036     * Visitor class used to locate a resolved function call within an
2037     * expression
2038     */

2039    private static class ResolvedFunCallFinder
2040        extends MdxVisitorImpl
2041    {
2042        private ResolvedFunCall call;
2043        public boolean found;
2044
2045        public ResolvedFunCallFinder(ResolvedFunCall call)
2046        {
2047            this.call = call;
2048            found = false;
2049        }
2050
2051        public Object JavaDoc visit(ResolvedFunCall funCall)
2052        {
2053            if (funCall == call) {
2054                found = true;
2055            }
2056            return null;
2057        }
2058
2059        public Object JavaDoc visit(mondrian.mdx.MemberExpr memberExpr) {
2060            Member member = memberExpr.getMember();
2061            if (member.isCalculated()) {
2062                Exp memberExp = member.getExpression();
2063                memberExp.accept(this);
2064            }
2065            return null;
2066        }
2067    }
2068
2069    /**
2070     * This is the entry point to the crossjoin non-empty optimizer code.
2071     * <p>
2072     * What one wants to determine is for each individual Member of the input
2073     * parameter list, a 'List-Member', whether across a slice there is any
2074     * data.
2075     * <p>
2076     * But what data?
2077     * <p>
2078     * For Members other than those in the list, the 'non-List-Members',
2079     * one wants to consider
2080     * all data across the scope of these other Members. For instance, if
2081     * Time is not a List-Member, then one wants to consider data
2082     * across All Time. Or, if Customer is not a List-Member, then
2083     * look at data across All Customers. The theory here, is if there
2084     * is no data for a particular Member of the list where all other
2085     * Members not part of the list are span their complete hierarchy, then
2086     * there is certainly no data for Members of that Hierarchy at a
2087     * more specific Level (more on this below).
2088     * <p>
2089     * When a Member that is a non-List-Member is part of a Hierarchy
2090     * that has an
2091     * All Member (hasAll="true"), then its very easy to make sure that
2092     * the All Member is used during the optimization.
2093     * If a non-List-Member is part of a Hierarchy that does not have
2094     * an All Member, then one must, in fact, iterate over all top-level
2095     * Members of the Hierarchy!!! - otherwise a List-Member might
2096     * be excluded because the optimization code was not looking everywhere.
2097     * <p>
2098     * Concerning default Members for those Hierarchies for the
2099     * non-List-Members, ignore them. What is wanted is either the
2100     * All Member or one must iterate across all top-level Members, what
2101     * happens to be the default Member of the Hierarchy is of no relevant.
2102     * <p>
2103     * The Measures Hierarchy has special considerations. First, there is
2104     * no All Measure. But, certainly one need only involve Measures
2105     * that are actually in the query... yes and no. For Calculated Measures
2106     * one must also get all of the non-Calculated Measures that make up
2107     * each Calculated Measure. Thus, one ends up iterating across all
2108     * Calculated and non-Calculated Measures that are explicitly
2109     * mentioned in the query as well as all Calculated and non-Calculated
2110     * Measures that are used to define the Calculated Measures in
2111     * the query. Why all of these? because this represents the total
2112     * scope of possible Measures that might yield a non-null value
2113     * for the List-Members and that is what we what to find. It might
2114     * be a super set, but thats ok; we just do not want to miss anything.
2115     *
2116     *
2117     * For other Members, the default Member is used, but for Measures one
2118     * should look for that data for all Measures associated with the query, not
2119     * just one Measure. For a dense dataset this may not be a problem or even
2120     * apparent, but for a sparse dataset, the first Measure may, in fact, have
2121     * not data but other Measures associated with the query might.
2122     * Hence, the solution here is to identify all Measures associated with the
2123     * query and then for each Member of the list, determine if there is any
2124     * data iterating across all Measures until non-null data is found or the
2125     * end of the Measures is reached.
2126     *
2127     * @param evaluator evaluator
2128     * @param list list of members being checked for non-emptiness
2129     * @param call the cross join function call
2130     */

2131    protected List nonEmptyList(
2132        Evaluator evaluator,
2133        List list,
2134        ResolvedFunCall call)
2135    {
2136        return nonEmptyListNEW(evaluator, list, call);
2137        //return nonEmptyListOLD(evaluator, list, call);
2138
}
2139
2140    /////////////////////////////////////////////////////////////////////////
2141
//
2142
// OLD optimizer
2143
//
2144
/////////////////////////////////////////////////////////////////////////
2145
protected static List nonEmptyListOLD(
2146        Evaluator evaluator,
2147        List list,
2148        ResolvedFunCall call)
2149    {
2150        if (list.isEmpty()) {
2151            return list;
2152        }
2153
2154        // A compromise between allocating too much and having lots of allocations.
2155
// If everything is null, then this is too big, but if nothing is null
2156
// then this results in TWO calls to ArrayList's ensureCapacity method
2157
// and its associated System.arraycopy method.
2158
// What is best?
2159
// Note that an ArrayList does not have an adjustable "growth factor"
2160
// but rather grows by 1.5.
2161
List result = new ArrayList((list.size() + 2) >> 1);
2162
2163        // Get all Measures
2164
// RME: The only mechanism I could find for getting all Measures
2165
// associated with the query was to use a the MdxVisitor to get all
2166
// MemberExprs and test if its Member was one of the Measures. First,
2167
// it might be expected that at query parse-time one could determine
2168
// what Measures were associated with which axes saving the use of the
2169
// visitor and, many times, this might be true but 2) if the Measures
2170
// are dynamically generated, for instance using a function such as
2171
// StrToSet, then one can not count on visiting the axes' Exp and determining
2172
// all Measures - they can only be known at execution-time.
2173
// So, here it is assumed that all Measures are known statically by
2174
// this stage of the processing.
2175
Query query = evaluator.getQuery();
2176        Set<Member> measureSet = null;
2177        Set<Member> queryMeasureSet = query.getMeasuresMembers();
2178        // if the slicer contains a Measure, then the other axes can not
2179
// contain a Measure, so look at slicer axis first
2180
if (queryMeasureSet.size() > 0) {
2181            MeasureVisitor visitor =
2182                new MeasureVisitor(queryMeasureSet, call);
2183            QueryAxis[] axes = query.getAxes();
2184            QueryAxis slicerAxis = query.getSlicerAxis();
2185            if (slicerAxis != null) {
2186                slicerAxis.accept(visitor);
2187            }
2188            if (visitor.measureSet != null) {
2189                // Slicer had a Measure, 1) use it and 2) do not need to look at
2190
// the other axes.
2191
measureSet = visitor.measureSet;
2192
2193            } else if (axes.length > 0) {
2194                for (int i = 0; i < axes.length; i++) {
2195                    if (axes[i] != null) {
2196                        axes[i].accept(visitor);
2197                    }
2198                }
2199                // It maybe null, but thats ok here
2200
measureSet = visitor.measureSet;
2201            }
2202        }
2203
2204        // Determine if there is any data.
2205
evaluator = evaluator.push();
2206        if (list.get(0) instanceof Member[]) {
2207            for (Member[] ms : ((List<Member[]>) list)) {
2208                evaluator.setContext(ms);
2209                // no measures found, use standard algorithm
2210
if (measureSet == null) {
2211                    Object JavaDoc value = evaluator.evaluateCurrent();
2212                    if (value != null && !(value instanceof Throwable JavaDoc)) {
2213                        result.add(ms);
2214                    }
2215                } else {
2216                    Iterator<Member> measureIter = measureSet.iterator();
2217                    MEASURES_LOOP:
2218                    while (measureIter.hasNext()) {
2219                        Member measure = measureIter.next();
2220                        evaluator.setContext(measure);
2221                        Object JavaDoc value = evaluator.evaluateCurrent();
2222                        if (value != null && !(value instanceof Throwable JavaDoc)) {
2223                            result.add(ms);
2224                            break MEASURES_LOOP;
2225                        }
2226                    }
2227                }
2228            }
2229        } else {
2230            for (Iterator listItr = list.iterator(); listItr.hasNext();) {
2231                Member m = (Member) listItr.next();
2232                evaluator.setContext(m);
2233                // no measures found, use standard algorithm
2234
if (measureSet == null) {
2235                    Object JavaDoc value = evaluator.evaluateCurrent();
2236                    if (value != null && !(value instanceof Throwable JavaDoc)) {
2237                        result.add(m);
2238                    }
2239                } else {
2240                    Iterator<Member> measureIter = measureSet.iterator();
2241                    measuresLoop:
2242                    while (measureIter.hasNext()) {
2243                        Member measure = measureIter.next();
2244                        evaluator.setContext(measure);
2245                        Object JavaDoc value = evaluator.evaluateCurrent();
2246                        if (value != null && !(value instanceof Throwable JavaDoc)) {
2247                            result.add(m);
2248                            break measuresLoop;
2249                        }
2250                    }
2251                }
2252            }
2253        }
2254        return result;
2255    }
2256
2257    /////////////////////////////////////////////////////////////////////////
2258
//
2259
// NEW optimizer
2260
//
2261
/////////////////////////////////////////////////////////////////////////
2262

2263    private static class MeasureVisitorNEW extends MdxVisitorImpl {
2264
2265        Set<Member> queryMeasureSet;
2266        //
2267
// measures referencing this call should be excluded from the list
2268
// of measures found
2269
ResolvedFunCall crossJoinCall;
2270
2271        MeasureVisitorNEW(Set<Member> queryMeasureSet,
2272                ResolvedFunCall crossJoinCall) {
2273            this.queryMeasureSet = queryMeasureSet;
2274            this.crossJoinCall = crossJoinCall;
2275        }
2276
2277        public Object JavaDoc visit(mondrian.mdx.ResolvedFunCall funcall) {
2278            Exp[] exps = funcall.getArgs();
2279            if (exps != null) {
2280                for (Exp exp: exps) {
2281                    exp.accept(this);
2282                }
2283            }
2284            return null;
2285        }
2286        public Object JavaDoc visit(mondrian.mdx.ParameterExpr parameterExpr) {
2287            final Parameter parameter = parameterExpr.getParameter();
2288            final Type type = parameter.getType();
2289            if (type instanceof mondrian.olap.type.MemberType) {
2290                final Object JavaDoc value = parameter.getValue();
2291                if (value instanceof Member) {
2292                    final Member member = (Member) value;
2293                    process(member);
2294                }
2295            }
2296
2297            return null;
2298        }
2299        public Object JavaDoc visit(mondrian.mdx.MemberExpr memberExpr) {
2300            Member member = memberExpr.getMember();
2301            process(member);
2302            return null;
2303        }
2304        private void process(final Member member) {
2305            if (member.isMeasure()) {
2306                if (member.isCalculated()) {
2307                    Exp exp = member.getExpression();
2308                    ResolvedFunCallFinder finder =
2309                        new ResolvedFunCallFinder(crossJoinCall);
2310                    exp.accept(finder);
2311                    if (! finder.found) {
2312                        exp.accept(this);
2313                        queryMeasureSet.add(member);
2314                    }
2315                } else {
2316                    queryMeasureSet.add(member);
2317                }
2318            }
2319        }
2320    }
2321    
2322    /**
2323     * This is a non-optimistic optimizer. What this means is that an
2324     * element of the input parameter List is only not included in the
2325     * returned result List if for no combination of Measures, non-All
2326     * Members (for Hierarchies that have no All Members) and evaluator
2327     * default Members did the element evaluate to non-null.
2328     *
2329     * @param evaluator The Evaluator
2330     * @param list The List of elements that are to be determined if there are
2331     * any non-null.
2332     * @param call The calling ResolvedFunCall used to determine what Measures
2333     * to use.
2334     * @return List of elements from the input parameter list that have
2335     * evaluated to non-null.
2336     */

2337    protected List nonEmptyListNEW(
2338        Evaluator evaluator,
2339        List list,
2340        ResolvedFunCall call)
2341    {
2342        if (list.isEmpty()) {
2343            return list;
2344        }
2345
2346        List result = new ArrayList((list.size() + 2) >> 1);
2347
2348        //
2349
// Get all of the Measures
2350
//
2351
final Query query = evaluator.getQuery();
2352
2353        final String JavaDoc measureSetKey = "MEASURE_SET-"+ctag;
2354        Set<Member> measureSet =
2355                (Set<Member>) query.getEvalCache(measureSetKey);
2356        // If not in query cache, then create and place into cache.
2357
// This information is used for each iteration so it makes
2358
// sense to create and cache it.
2359
if (measureSet == null) {
2360            measureSet = new HashSet<Member>();
2361            Set<Member> queryMeasureSet = query.getMeasuresMembers();
2362            MeasureVisitorNEW visitor = new MeasureVisitorNEW(measureSet, call);
2363            for (Member m : queryMeasureSet) {
2364                if (m.isCalculated()) {
2365                    Exp exp = m.getExpression();
2366                    exp.accept(visitor);
2367                } else {
2368                    measureSet.add(m);
2369                }
2370            }
2371
2372            Formula[] formula = query.getFormulas();
2373            if (formula != null) {
2374                for (Formula f: formula) {
2375                    f.accept(visitor);
2376                }
2377            }
2378
2379            query.putEvalCache(measureSetKey, measureSet);
2380        }
2381
2382        final String JavaDoc allMemberListKey = "ALL_MEMBER_LIST-"+ctag;
2383        List<Member> allMemberList =
2384                (List<Member>) query.getEvalCache(allMemberListKey);
2385
2386        final String JavaDoc nonAllMembersKey = "NON_ALL_MEMBERS-"+ctag;
2387        Member[][] nonAllMembers =
2388            (Member[][]) query.getEvalCache(nonAllMembersKey);
2389        if (nonAllMembers == null) {
2390            //
2391
// Get all of the All Members and those Hierarchies that
2392
// do not have All Members.
2393
//
2394
Member[] evalMembers = (Member[]) evaluator.getMembers().clone();
2395
2396            Member[] listMembers = (list.get(0) instanceof Member[])
2397                ? (Member[]) list.get(0)
2398                : new Member[] { (Member) list.get(0) };
2399
2400
2401            // Remove listMembers from evalMembers
2402
for (Member lm : listMembers) {
2403                Hierarchy h = lm.getHierarchy();
2404                for (int i = 0; i < evalMembers.length; i++) {
2405                    Member em = evalMembers[i];
2406                    if ((em != null) && h.equals(em.getHierarchy())) {
2407                        evalMembers[i] = null;
2408                    }
2409                }
2410            }
2411
2412            // Now we have the non-List-Members, but some of them may not be
2413
// All Members (default Member need not be the All Member) and
2414
// for some Hierarchies there may not be an All Member.
2415
// So we create an array of Objects some elements of which are
2416
// All Members and others elements will be an array of all top-level
2417
// Members when there is not an All Member.
2418
SchemaReader schemaReader = evaluator.getSchemaReader();
2419            allMemberList = new ArrayList<Member>();
2420            List<Member[]> nonAllMemberList = new ArrayList<Member[]>();
2421            for (int i = 0, j = 0; i < evalMembers.length; i++) {
2422                Member em = evalMembers[i];
2423                if (em == null) {
2424                    // Above we might have removed some by setting them
2425
// to null.
2426
continue;
2427                }
2428                if (em.isMeasure()) {
2429                    continue;
2430                }
2431                if (em.isCalculated()) {
2432                    continue;
2433                }
2434                // The member is not the All member
2435
if (! em.isAll()) {
2436                    Hierarchy h = em.getHierarchy();
2437                    Member[] rootMembers = schemaReader.getHierarchyRootMembers(h);
2438                    if (h.hasAll()) {
2439                        // The Hierarchy has an All member
2440
boolean found = false;
2441                        for (Member m : rootMembers) {
2442                            if (m.isAll()) {
2443                                allMemberList.add(m);
2444                                found = true;
2445                                break;
2446                            }
2447                        }
2448                        if (! found) {
2449System.out.println("CrossJoinFunDef.nonEmptyListNEW: ERROR");
2450                        }
2451                    } else {
2452                        // The Hierarchy does NOT have an All member
2453
nonAllMemberList.add(rootMembers);
2454                    }
2455                }
2456            }
2457            nonAllMembers =
2458                (Member[][]) nonAllMemberList.toArray(new Member[0][]);
2459
2460            query.putEvalCache(allMemberListKey, allMemberList);
2461            query.putEvalCache(nonAllMembersKey, nonAllMembers);
2462        }
2463
2464        //
2465
// Determine if there is any data.
2466
//
2467
evaluator = evaluator.push();
2468
2469        // Put all of the All Members into Evaluator
2470
evaluator.setContext(allMemberList);
2471
2472        // Iterate over elements of the input list (whether it contains
2473
// Member[] or Member elements). If for any combination of
2474
// Measure and non-All Members evaluation is non-null, then
2475
// add it to the result List.
2476
if (list.get(0) instanceof Member[]) {
2477            for (Member[] ms : ((List<Member[]>) list)) {
2478                evaluator.setContext(ms);
2479                if (checkData(nonAllMembers, nonAllMembers.length-1,
2480                            measureSet, evaluator)) {
2481                    result.add(ms);
2482                }
2483            }
2484        } else {
2485            for (Member m : ((List<Member>) list)) {
2486                evaluator.setContext(m);
2487                if (checkData(nonAllMembers, nonAllMembers.length-1,
2488                            measureSet, evaluator)) {
2489                    result.add(m);
2490                }
2491            }
2492        }
2493
2494        return result;
2495    }
2496
2497    /**
2498     * Return <code>true</code> if for some combination of Members
2499     * from the nonAllMembers array of Member arrays and Measures from
2500     * the Set of Measures evaluate to a non-null value. Even if a
2501     * particular combination is non-null, all combinations are tested
2502     * just to make sure that the data is loaded.
2503     *
2504     * @param nonAllMembers array of Member arrays of top-level Members
2505     * for Hierarchies that have no All Member.
2506     * @param cnt which Member array is to be processed.
2507     * @param measureSet Set of all that should be tested against.
2508     * @param evaluator the Evaluator.
2509     * @return True if at least one combination evaluated to non-null.
2510     */

2511    private static boolean checkData(
2512            Member[][] nonAllMembers,
2513            int cnt,
2514            Set<Member> measureSet,
2515            Evaluator evaluator) {
2516
2517        if (cnt < 0) {
2518            // no measures found, use standard algorithm
2519
if (measureSet.isEmpty()) {
2520                Object JavaDoc value = evaluator.evaluateCurrent();
2521                if (value != null && !(value instanceof Throwable JavaDoc)) {
2522                    return true;
2523                }
2524            } else {
2525                // Here we evaluate across all measures just to
2526
// make sure that the data is all loaded
2527
boolean found = false;
2528                for (Member measure : measureSet) {
2529                    evaluator.setContext(measure);
2530                    Object JavaDoc value = evaluator.evaluateCurrent();
2531                    if (value != null && !(value instanceof Throwable JavaDoc)) {
2532                        found = true;
2533                    }
2534                }
2535                return found;
2536            }
2537        } else {
2538            boolean found = false;
2539            for (Member m : nonAllMembers[cnt]) {
2540                evaluator.setContext(m);
2541                if (checkData(nonAllMembers, cnt-1, measureSet, evaluator)) {
2542                    found = true;
2543                }
2544            }
2545            return found;
2546        }
2547        return false;
2548    }
2549
2550    private static class StarCrossJoinResolver extends MultiResolver {
2551        public StarCrossJoinResolver() {
2552            super(
2553                    "*",
2554                    "<Set1> * <Set2>",
2555                    "Returns the cross product of two sets.",
2556                    new String JavaDoc[]{"ixxx", "ixmx", "ixxm", "ixmm"});
2557        }
2558
2559        public FunDef resolve(
2560                Exp[] args, Validator validator, int[] conversionCount) {
2561            // This function only applies in contexts which require a set.
2562
// Elsewhere, "*" is the multiplication operator.
2563
// This means that [Measures].[Unit Sales] * [Gender].[M] is
2564
// well-defined.
2565
if (validator.requiresExpression()) {
2566                return null;
2567            }
2568            return super.resolve(args, validator, conversionCount);
2569        }
2570
2571        protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) {
2572            return new CrossJoinFunDef(dummyFunDef);
2573        }
2574    }
2575
2576
2577}
2578
2579// End CrossJoinFunDef.java
2580
Popular Tags