001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/IntersectFunDef.java#12 $
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) 2004-2002 Kana Software, Inc.
007    // Copyright (C) 2004-2007 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.olap.*;
014    import mondrian.calc.*;
015    import mondrian.calc.impl.AbstractListCalc;
016    import mondrian.mdx.ResolvedFunCall;
017    
018    import java.util.*;
019    
020    /**
021     * Definition of the <code>INTERSECT</code> MDX function.
022     *
023     * @author jhyde
024     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/IntersectFunDef.java#12 $
025     * @since Mar 23, 2006
026     */
027    class IntersectFunDef extends FunDefBase
028    {
029        private static final String[] ReservedWords = new String[] {"ALL"};
030    
031        static final Resolver resolver = new ReflectiveMultiResolver(
032                "Intersect",
033                "Intersect(<Set1>, <Set2>[, ALL])",
034                "Returns the intersection of two input sets, optionally retaining duplicates.",
035                new String[] {"fxxxy", "fxxx"},
036                IntersectFunDef.class,
037                ReservedWords);
038    
039        public IntersectFunDef(FunDef dummyFunDef)
040        {
041            super(dummyFunDef);
042        }
043    
044        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
045            final ListCalc listCalc1 = compiler.compileList(call.getArg(0));
046            final ListCalc listCalc2 = compiler.compileList(call.getArg(1));
047            final String literalArg = getLiteralArg(call, 2, "", ReservedWords);
048            final boolean all = literalArg.equalsIgnoreCase("ALL");
049    
050            // todo: optimize for member lists vs. tuple lists
051            return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}) {
052                public List evaluateList(Evaluator evaluator) {
053                    List left = listCalc1.evaluateList(evaluator);
054                    if (left == null || left.isEmpty()) {
055                        return Collections.EMPTY_LIST;
056                    }
057                    Collection right = listCalc2.evaluateList(evaluator);
058                    if (right == null || right.isEmpty()) {
059                        return Collections.EMPTY_LIST;
060                    }
061                    right = buildSearchableCollection(right);
062                    List result = new ArrayList();
063    
064                    for (Object leftObject : left) {
065                        Object resultObject = leftObject;
066    
067                        if (leftObject instanceof Object[]) {
068                            leftObject = new ArrayHolder((Object[]) leftObject);
069                        }
070    
071                        if (right.contains(leftObject)) {
072                            if (all || !result.contains(leftObject)) {
073                                result.add(resultObject);
074                            }
075                        }
076                    }
077                    return result;
078                }
079            };
080        }
081    
082        private static Collection buildSearchableCollection(Collection right) {
083            Iterator iter = right.iterator();
084            Set result = new HashSet(right.size(), 1);
085            while (iter.hasNext()) {
086                Object element = iter.next();
087    
088                if (element instanceof Object[]) {
089                    element = new ArrayHolder((Object[])element);
090                }
091    
092                result.add(element);
093            }
094    
095            return result;
096        }
097    }
098    
099    // End IntersectFunDef.java