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