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