001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/ExceptFunDef.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) 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.calc.*; 013 import mondrian.calc.impl.AbstractListCalc; 014 import mondrian.mdx.ResolvedFunCall; 015 import mondrian.olap.*; 016 import mondrian.olap.type.*; 017 import mondrian.util.FilteredIterableList; 018 019 import java.util.*; 020 021 /** 022 * Definition of the <code>Except</code> MDX function. 023 * 024 * @author jhyde 025 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/ExceptFunDef.java#3 $ 026 * @since Mar 23, 2006 027 */ 028 class ExceptFunDef extends FunDefBase { 029 static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver( 030 "Except", 031 "Except(<Set1>, <Set2>[, ALL])", 032 "Finds the difference between two sets, optionally retaining duplicates.", 033 new String[]{"fxxx", "fxxxy"}, 034 ExceptFunDef.class); 035 036 public ExceptFunDef(FunDef dummyFunDef) { 037 super(dummyFunDef); 038 } 039 040 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 041 // todo: implement ALL 042 final ListCalc listCalc0 = compiler.compileList(call.getArg(0)); 043 final ListCalc listCalc1 = compiler.compileList(call.getArg(1)); 044 final Type elementType = ((SetType) listCalc0.getType()).getElementType(); 045 if (elementType instanceof TupleType) { 046 final TupleListCalc tupleListCalc0 = (TupleListCalc) listCalc0; 047 final TupleListCalc tupleListCalc1 = (TupleListCalc) listCalc1; 048 return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) { 049 public List evaluateList(Evaluator evaluator) { 050 List<Member[]> list0 = 051 tupleListCalc0.evaluateTupleList(evaluator); 052 if (list0.isEmpty()) { 053 return list0; 054 } 055 List<Member[]> list1 = tupleListCalc1.evaluateTupleList(evaluator); 056 return exceptTuples(list0, list1); 057 } 058 }; 059 } else { 060 final MemberListCalc memberListCalc0 = (MemberListCalc) listCalc0; 061 final MemberListCalc memberListCalc1 = (MemberListCalc) listCalc1; 062 return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) { 063 public List evaluateList(Evaluator evaluator) { 064 List<Member> list0 = memberListCalc0.evaluateMemberList(evaluator); 065 if (list0.isEmpty()) { 066 return list0; 067 } 068 List<Member> list1 = memberListCalc1.evaluateMemberList(evaluator); 069 return except(list0, list1); 070 } 071 }; 072 } 073 } 074 075 <T> List<T> except(final List<T> list0, final List<T> list1) { 076 if (list0.size() == 0) { 077 return list0; 078 } 079 final Set<T> set = new HashSet<T>(list1); 080 return new FilteredIterableList<T>( 081 list0, 082 new FilteredIterableList.Filter<T>() { 083 public boolean accept(final T o) { 084 return !set.contains(o); 085 } 086 }); 087 } 088 089 List exceptTuples(final List<Member[]> list0, final List<Member[]> list1) { 090 if (list0.size() == 0) { 091 return list0; 092 } 093 // Because the .equals and .hashCode methods of 094 // Member[] use identity, wrap each tuple in a list. 095 final Set<List<Member>> set = new HashSet<List<Member>>(); 096 for (Member[] members : list1) { 097 set.add(Arrays.asList(members)); 098 } 099 return new FilteredIterableList<Member[]>( 100 list0, 101 new FilteredIterableList.Filter<Member[]>() { 102 public boolean accept(final Member[] o) { 103 return !set.contains(Arrays.asList(o)); 104 } 105 }); 106 } 107 } 108 109 // End ExceptFunDef.java