001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2006-2011 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap.fun; 011 012import mondrian.calc.*; 013import mondrian.calc.impl.AbstractListCalc; 014import mondrian.calc.impl.UnaryTupleList; 015import mondrian.mdx.ResolvedFunCall; 016import mondrian.olap.*; 017import mondrian.olap.type.*; 018 019import java.util.*; 020 021/** 022 * Definition of the <code>AddCalculatedMembers</code> MDX function. 023 * 024 * <p>AddCalculatedMembers adds calculated members that are siblings 025 * of the members in the set. The set is limited to one dimension. 026 * 027 * <p>Syntax: 028 * 029 * <blockquote><pre>AddCalculatedMembers(<Set>)</pre></blockquote> 030 031 * @author jhyde 032 * @since Mar 23, 2006 033 */ 034class AddCalculatedMembersFunDef extends FunDefBase { 035 private static final AddCalculatedMembersFunDef instance = 036 new AddCalculatedMembersFunDef(); 037 038 public static final Resolver resolver = new ResolverImpl(); 039 private static final String FLAG = "fxx"; 040 041 private AddCalculatedMembersFunDef() { 042 super( 043 "AddCalculatedMembers", 044 "Adds calculated members to a set.", 045 FLAG); 046 } 047 048 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 049 final ListCalc listCalc = compiler.compileList(call.getArg(0)); 050 return new AbstractListCalc(call, new Calc[] {listCalc}) { 051 public TupleList evaluateList(Evaluator evaluator) { 052 final TupleList list = 053 listCalc.evaluateList(evaluator); 054 return new UnaryTupleList( 055 addCalculatedMembers(list.slice(0), evaluator)); 056 } 057 }; 058 } 059 060 private List<Member> addCalculatedMembers( 061 List<Member> memberList, 062 Evaluator evaluator) 063 { 064 // Determine unique levels in the set 065 final Set<Level> levels = new LinkedHashSet<Level>(); 066 Hierarchy hierarchy = null; 067 068 for (Member member : memberList) { 069 if (hierarchy == null) { 070 hierarchy = member.getHierarchy(); 071 } else if (hierarchy != member.getHierarchy()) { 072 throw newEvalException( 073 this, 074 "Only members from the same hierarchy are allowed in the " 075 + "AddCalculatedMembers set: " + hierarchy 076 + " vs " + member.getHierarchy()); 077 } 078 levels.add(member.getLevel()); 079 } 080 081 // For each level, add the calculated members from both 082 // the schema and the query 083 List<Member> workingList = new ArrayList<Member>(memberList); 084 final SchemaReader schemaReader = 085 evaluator.getQuery().getSchemaReader(true); 086 for (Level level : levels) { 087 List<Member> calcMemberList = 088 schemaReader.getCalculatedMembers(level); 089 workingList.addAll(calcMemberList); 090 } 091 return workingList; 092 } 093 094 private static class ResolverImpl extends MultiResolver { 095 public ResolverImpl() { 096 super( 097 instance.getName(), 098 instance.getSignature(), 099 instance.getDescription(), 100 new String[] {FLAG}); 101 } 102 103 protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) { 104 if (args.length == 1) { 105 Exp arg = args[0]; 106 final Type type1 = arg.getType(); 107 if (type1 instanceof SetType) { 108 SetType type = (SetType) type1; 109 if (type.getElementType() instanceof MemberType) { 110 return instance; 111 } else { 112 throw newEvalException( 113 instance, 114 "Only single dimension members allowed in set for AddCalculatedMembers"); 115 } 116 } 117 } 118 return null; 119 } 120 } 121} 122 123// End AddCalculatedMembersFunDef.java