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