001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/UnionFunDef.java#5 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2006-2008 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package mondrian.olap.fun;
011    
012    import mondrian.olap.FunDef;
013    import mondrian.olap.Evaluator;
014    import mondrian.calc.Calc;
015    import mondrian.calc.ExpCompiler;
016    import mondrian.calc.ListCalc;
017    import mondrian.calc.impl.AbstractListCalc;
018    import mondrian.mdx.ResolvedFunCall;
019    
020    import java.util.List;
021    import java.util.Set;
022    import java.util.HashSet;
023    import java.util.ArrayList;
024    
025    /**
026     * Definition of the <code>Union</code> MDX function.
027     *
028     * @author jhyde
029     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/UnionFunDef.java#5 $
030     * @since Mar 23, 2006
031     */
032    class UnionFunDef extends FunDefBase {
033        static final String[] ReservedWords = new String[] {"ALL", "DISTINCT"};
034    
035        static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver(
036                "Union",
037                "Union(<Set1>, <Set2>[, ALL])",
038                "Returns the union of two sets, optionally retaining duplicates.",
039                new String[] {"fxxx", "fxxxy"},
040                UnionFunDef.class,
041                ReservedWords);
042    
043        public UnionFunDef(FunDef dummyFunDef) {
044            super(dummyFunDef);
045        }
046    
047        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
048            String allString = getLiteralArg(call, 2, "DISTINCT", ReservedWords);
049            final boolean all = allString.equalsIgnoreCase("ALL");
050            checkCompatible(call.getArg(0), call.getArg(1), null); // todo: do at validate time
051            final ListCalc listCalc0 =
052                    compiler.compileList(call.getArg(0));
053            final ListCalc listCalc1 =
054                    compiler.compileList(call.getArg(1));
055            return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) {
056                public List evaluateList(Evaluator evaluator) {
057                    List list0 = listCalc0.evaluateList(evaluator);
058                    List list1 = listCalc1.evaluateList(evaluator);
059                    return union(list0, list1, all);
060                }
061            };
062        }
063    
064        <T> List<T> union(List<T> list0, List<T> list1, final boolean all) {
065            assert list0 != null;
066            assert list1 != null;
067            if (all) {
068                if (list0.isEmpty()) {
069                    return list1;
070                }
071                if (list1.isEmpty()) {
072                    return list0;
073                }
074                List<T> result = new ArrayList<T>();
075                result.addAll(list0);
076                result.addAll(list1);
077                return result;
078            } else {
079                Set<Object> added = new HashSet<Object>();
080                List<T> result = new ArrayList<T>();
081                FunUtil.addUnique(result, list0, added);
082                FunUtil.addUnique(result, list1, added);
083                return result;
084            }
085        }
086    }
087    
088    // End UnionFunDef.java