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