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 021/** 022 * Definition of the <code>PeriodsToDate</code> MDX function. 023 * 024 * @author jhyde 025 * @since Mar 23, 2006 026 */ 027class PeriodsToDateFunDef extends FunDefBase { 028 static final ReflectiveMultiResolver Resolver = 029 new ReflectiveMultiResolver( 030 "PeriodsToDate", 031 "PeriodsToDate([<Level>[, <Member>]])", 032 "Returns a set of periods (members) from a specified level starting with the first period and ending with a specified member.", 033 new String[]{"fx", "fxl", "fxlm"}, 034 PeriodsToDateFunDef.class); 035 036 public PeriodsToDateFunDef(FunDef dummyFunDef) { 037 super(dummyFunDef); 038 } 039 040 public Type getResultType(Validator validator, Exp[] args) { 041 if (args.length == 0) { 042 // With no args, the default implementation cannot 043 // guess the hierarchy. 044 RolapHierarchy defaultTimeHierarchy = 045 ((RolapCube) validator.getQuery().getCube()).getTimeHierarchy( 046 getName()); 047 return new SetType(MemberType.forHierarchy(defaultTimeHierarchy)); 048 } 049 050 if (args.length >= 2) { 051 Type hierarchyType = args[0].getType(); 052 MemberType memberType = (MemberType) args[1].getType(); 053 if (memberType.getHierarchy() != null 054 && hierarchyType.getHierarchy() != null 055 && memberType.getHierarchy() != hierarchyType.getHierarchy()) 056 { 057 throw Util.newError( 058 "Type mismatch: member must belong to hierarchy " 059 + hierarchyType.getHierarchy().getUniqueName()); 060 } 061 } 062 063 // If we have at least one arg, it's a level which will 064 // tell us the type. 065 return super.getResultType(validator, args); 066 } 067 068 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 069 final LevelCalc levelCalc = 070 call.getArgCount() > 0 071 ? compiler.compileLevel(call.getArg(0)) 072 : null; 073 final MemberCalc memberCalc = 074 call.getArgCount() > 1 075 ? compiler.compileMember(call.getArg(1)) 076 : null; 077 final RolapHierarchy timeHierarchy = 078 levelCalc == null 079 ? ((RolapCube) compiler.getEvaluator().getCube()).getTimeHierarchy( 080 getName()) 081 : null; 082 083 return new AbstractListCalc(call, new Calc[] {levelCalc, memberCalc}) { 084 public TupleList evaluateList(Evaluator evaluator) { 085 final Member member; 086 final Level level; 087 if (levelCalc == null) { 088 member = evaluator.getContext(timeHierarchy); 089 level = member.getLevel().getParentLevel(); 090 } else { 091 level = levelCalc.evaluateLevel(evaluator); 092 if (memberCalc == null) { 093 member = evaluator.getContext(level.getHierarchy()); 094 } else { 095 member = memberCalc.evaluateMember(evaluator); 096 } 097 } 098 return new UnaryTupleList( 099 periodsToDate(evaluator, level, member)); 100 } 101 102 public boolean dependsOn(Hierarchy hierarchy) { 103 if (super.dependsOn(hierarchy)) { 104 return true; 105 } 106 if (memberCalc != null) { 107 return false; 108 } else if (levelCalc != null) { 109 return levelCalc.getType().usesHierarchy(hierarchy, true); 110 } else { 111 return hierarchy == timeHierarchy; 112 } 113 } 114 }; 115 } 116} 117 118// End PeriodsToDateFunDef.java