001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/LastPeriodsFunDef.java#5 $ 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.olap.*; 013 import mondrian.olap.type.Type; 014 import mondrian.olap.type.SetType; 015 import mondrian.olap.type.MemberType; 016 import mondrian.olap.type.TypeUtil; 017 import mondrian.resource.MondrianResource; 018 import mondrian.calc.Calc; 019 import mondrian.calc.ExpCompiler; 020 import mondrian.calc.MemberCalc; 021 import mondrian.calc.IntegerCalc; 022 import mondrian.calc.impl.DimensionCurrentMemberCalc; 023 import mondrian.calc.impl.AbstractListCalc; 024 import mondrian.mdx.ResolvedFunCall; 025 026 import java.util.List; 027 import java.util.Collections; 028 import java.util.ArrayList; 029 030 /** 031 * Definition of the <code>LastPeriods</code> MDX function. 032 * 033 * @author jhyde 034 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/LastPeriodsFunDef.java#5 $ 035 * @since Mar 23, 2006 036 */ 037 class LastPeriodsFunDef extends FunDefBase { 038 static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver( 039 "LastPeriods", 040 "LastPeriods(<Index> [, <Member>])", 041 "Returns a set of members prior to and including a specified member.", 042 new String[] {"fxn", "fxnm"}, 043 LastPeriodsFunDef.class); 044 045 public LastPeriodsFunDef(FunDef dummyFunDef) { 046 super(dummyFunDef); 047 } 048 049 public Type getResultType(Validator validator, Exp[] args) { 050 if (args.length == 1) { 051 // If Member is not specified, 052 // it is Time.CurrentMember. 053 Dimension defaultTimeDimension = 054 validator.getQuery().getCube().getTimeDimension(); 055 if (defaultTimeDimension == null) { 056 throw MondrianResource.instance(). 057 NoTimeDimensionInCube.ex(getName()); 058 } 059 Hierarchy hierarchy = defaultTimeDimension.getHierarchy(); 060 return new SetType(MemberType.forHierarchy(hierarchy)); 061 } else { 062 Type type = args[1].getType(); 063 Type memberType = 064 TypeUtil.toMemberOrTupleType(type); 065 return new SetType(memberType); 066 } 067 } 068 069 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 070 // Member defaults to [Time].currentmember 071 Exp[] args = call.getArgs(); 072 final MemberCalc memberCalc; 073 if (args.length == 1) { 074 Dimension timeDimension = 075 compiler.getEvaluator().getCube() 076 .getTimeDimension(); 077 if (timeDimension == null) { 078 throw MondrianResource.instance(). 079 NoTimeDimensionInCube.ex(getName()); 080 } 081 memberCalc = new DimensionCurrentMemberCalc( 082 timeDimension); 083 } else { 084 memberCalc = compiler.compileMember(args[1]); 085 } 086 087 // Numeric Expression. 088 final IntegerCalc indexValueCalc = 089 compiler.compileInteger(args[0]); 090 091 return new AbstractListCalc(call, new Calc[] {memberCalc, indexValueCalc}) { 092 public List evaluateList(Evaluator evaluator) { 093 Member member = memberCalc.evaluateMember(evaluator); 094 int indexValue = indexValueCalc.evaluateInteger(evaluator); 095 096 return lastPeriods(member, evaluator, indexValue); 097 } 098 }; 099 } 100 101 /* 102 If Index is positive, returns the set of Index 103 members ending with Member and starting with the 104 member lagging Index - 1 from Member. 105 106 If Index is negative, returns the set of (- Index) 107 members starting with Member and ending with the 108 member leading (- Index - 1) from Member. 109 110 If Index is zero, the empty set is returned. 111 */ 112 List<Member> lastPeriods( 113 Member member, 114 Evaluator evaluator, 115 int indexValue) { 116 // empty set 117 if ((indexValue == 0) || member.isNull()) { 118 return Collections.emptyList(); 119 } 120 List<Member> list = new ArrayList<Member>(); 121 122 // set with just member 123 if ((indexValue == 1) || (indexValue == -1)) { 124 list.add(member); 125 return list; 126 } 127 128 // When null is found, getting the first/last 129 // member at a given level is not particularly 130 // fast. 131 Member startMember; 132 Member endMember; 133 if (indexValue > 0) { 134 startMember = evaluator.getSchemaReader() 135 .getLeadMember(member, - (indexValue - 1)); 136 endMember = member; 137 if (startMember.isNull()) { 138 List<Member> members = evaluator.getSchemaReader() 139 .getLevelMembers(member.getLevel(), false); 140 startMember = members.get(0); 141 } 142 } else { 143 startMember = member; 144 endMember = evaluator.getSchemaReader() 145 .getLeadMember(member, -(indexValue + 1)); 146 if (endMember.isNull()) { 147 List<Member> members = evaluator.getSchemaReader() 148 .getLevelMembers(member.getLevel(), false); 149 endMember = members.get(members.size() - 1); 150 } 151 } 152 153 evaluator.getSchemaReader(). 154 getMemberRange(member.getLevel(), 155 startMember, 156 endMember, 157 list); 158 return list; 159 } 160 } 161 162 // End LastPeriodsFunDef.java