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