001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/ExistsFunDef.java#3 $
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-2008 Julian Hyde and others
008    // All Rights Reserved.
009    // You must accept the terms of that agreement to use this software.
010    */
011    package mondrian.olap.fun;
012    
013    import mondrian.olap.*;
014    import mondrian.calc.*;
015    import mondrian.calc.impl.AbstractListCalc;
016    import mondrian.mdx.ResolvedFunCall;
017    import mondrian.olap.type.*;
018    
019    import java.util.*;
020    
021    /**
022     * Definition of the <code>EXISTS</code> MDX function.
023     *
024     * @author kvu
025     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/ExistsFunDef.java#3 $
026     * @since Mar 23, 2008
027     */
028    class ExistsFunDef extends FunDefBase
029    {
030        static final Resolver resolver = new ReflectiveMultiResolver(
031                "Exists",
032                "Exists(<Set1>, <Set2>])",
033                "Returns the the set of tuples of the first set that exist with one or more tuples of the second set.",
034                new String[] {"fxxx"},
035                ExistsFunDef.class);
036    
037        public ExistsFunDef(FunDef dummyFunDef)
038        {
039            super(dummyFunDef);
040        }
041    
042        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
043            final ListCalc listCalc1 = compiler.compileList(call.getArg(0));
044            final ListCalc listCalc2 = compiler.compileList(call.getArg(1));
045    
046            return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}) {
047                public List evaluateList(Evaluator evaluator) {
048                    List left = listCalc1.evaluateList(evaluator);
049                    if (left == null || left.isEmpty()) {
050                        return Collections.EMPTY_LIST;
051                    }
052                    List right = listCalc2.evaluateList(evaluator);
053                    if (right == null || right.isEmpty()) {
054                        return Collections.EMPTY_LIST;
055                    }
056                    List result = new ArrayList();
057    
058                    Object leftHead = left.get(0);
059                    Object rightHead = right.get(0);
060                    List<Dimension> leftDims = getDimensions(leftHead);
061                    List<Dimension> rightDims = getDimensions(rightHead);
062    
063                    // map dimensions of right object to those in left object
064                    // return empty list if not all of right dims can be mapped
065                    int rightSize = rightDims.size();
066                    int [] idxmap = new int[rightSize];
067                    for (int i = 0; i < rightSize; i++) {
068                        Dimension d = rightDims.get(i);
069                        if (leftDims.contains(d)) {
070                            idxmap[i] = leftDims.indexOf(d);
071                        } else {
072                            return Collections.EMPTY_LIST;
073                        }
074                    }
075    
076                    for (Object  leftObject : left) {
077                        if (leftObject instanceof Object[]) { // leftObject is a tuple
078                            boolean exist = true;
079                            for (Object rightObject : right) {
080                                for (int i = 0; i < rightSize; i++) {
081                                    Object [] leftObjs = (Object []) leftObject;
082                                    Member leftMem = (Member) leftObjs[idxmap[i]];
083                                    Member rightMem;
084                                    if (! (rightObject instanceof Object [])) {
085                                        rightMem = (Member) rightObject;
086                                    } else {
087                                        Object [] rightObjs =
088                                            (Object []) rightObject;
089                                        rightMem = (Member) (rightObjs[i]);
090                                    }
091                                    if (! isOnSameHierarchyChain(
092                                            leftMem, rightMem)) {
093                                        exist = false;
094                                        break;
095                                    }
096                                }
097                                if (exist) {
098                                    result.add(leftObject);
099                                    break;
100                                }
101                            }
102                        } else { // leftObject is a member
103                            for (Object rightObject : right) {
104                                if (isOnSameHierarchyChain(
105                                        (Member) leftObject,
106                                        (Member) rightObject)) {
107                                    result.add(leftObject);
108                                    break;
109                                }
110                            }
111                        }
112                    }
113                    return result;
114                }
115            };
116        }
117    
118        private static boolean isOnSameHierarchyChain(Member mA, Member mB)
119        {
120            return (FunUtil.isAncestorOf(mA, mB, false))||
121                (FunUtil.isAncestorOf(mB, mA, false));
122        }
123    
124        private static List<Dimension> getDimensions(Object obj)
125        {
126            List<Dimension> dimensions = new ArrayList<Dimension>();
127    
128            if (obj instanceof Object []) {
129                for (Object dim : (Object []) obj) {
130                    dimensions.add(((Member) dim).getDimension());
131                }
132            } else {
133                dimensions.add(((Member) obj).getDimension());
134            }
135            return dimensions;
136        }
137    }
138    
139    // End ExistsFunDef.java