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-2009 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.olap.fun;
011
012import mondrian.calc.*;
013import mondrian.calc.impl.AbstractMemberCalc;
014import mondrian.mdx.ResolvedFunCall;
015import mondrian.olap.*;
016
017/**
018 * Definition of the <code>Lead</code> and <code>Lag</code> MDX functions.
019 *
020 * @author jhyde
021 * @since Mar 23, 2006
022 */
023class LeadLagFunDef extends FunDefBase {
024    static final ReflectiveMultiResolver LagResolver =
025        new ReflectiveMultiResolver(
026            "Lag",
027            "<Member>.Lag(<Numeric Expression>)",
028            "Returns a member further along the specified member's dimension.",
029            new String[]{"mmmn"},
030            LeadLagFunDef.class);
031
032    static final ReflectiveMultiResolver LeadResolver =
033        new ReflectiveMultiResolver(
034            "Lead",
035            "<Member>.Lead(<Numeric Expression>)",
036            "Returns a member further along the specified member's dimension.",
037            new String[]{"mmmn"},
038            LeadLagFunDef.class);
039
040    public LeadLagFunDef(FunDef dummyFunDef) {
041        super(dummyFunDef);
042    }
043
044    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
045        final MemberCalc memberCalc =
046                compiler.compileMember(call.getArg(0));
047        final IntegerCalc integerCalc =
048                compiler.compileInteger(call.getArg(1));
049        final boolean lag = call.getFunName().equals("Lag");
050        return new AbstractMemberCalc(
051            call,
052            new Calc[] {memberCalc, integerCalc})
053        {
054            public Member evaluateMember(Evaluator evaluator) {
055                Member member = memberCalc.evaluateMember(evaluator);
056                int n = integerCalc.evaluateInteger(evaluator);
057                if (lag) {
058                    if (n == Integer.MIN_VALUE) {
059                        // Bump up lagValue by one, otherwise -n (used
060                        // in the getLeadMember call below) is out of
061                        // range because Integer.MAX_VALUE ==
062                        // -(Integer.MIN_VALUE + 1).
063                        n += 1;
064                    }
065
066                    n = -n;
067                }
068                return evaluator.getSchemaReader().getLeadMember(member, n);
069            }
070        };
071    }
072}
073
074// End LeadLagFunDef.java