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) 2011-2011 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.calc.impl;
011
012import mondrian.calc.Calc;
013import mondrian.calc.MemberCalc;
014import mondrian.olap.*;
015import mondrian.olap.type.ScalarType;
016import mondrian.olap.type.Type;
017
018/**
019 * Expression which evaluates a few member expressions,
020 * sets the dimensional context to the result of those expressions,
021 * then yields the value of the current measure in the current
022 * dimensional context.
023 *
024 * <p>The evaluator's context is preserved.
025 *
026 * <p>Note that a MemberValueCalc with 0 member expressions is equivalent to a
027 * {@link ValueCalc}; see also {@link TupleValueCalc}.
028 *
029 * @author jhyde
030 */
031public class MemberArrayValueCalc extends GenericCalc {
032    private final MemberCalc[] memberCalcs;
033    private final Member[] members;
034    private final boolean nullCheck;
035
036    /**
037     * Creates a MemberArrayValueCalc.
038     *
039     * <p>Clients outside this package should use the
040     * {@link MemberValueCalc#create(mondrian.olap.Exp,
041     * mondrian.calc.MemberCalc[], boolean)}
042     * factory method.
043     *
044     * @param exp Expression
045     * @param memberCalcs Array of compiled expressions
046     * @param nullCheck Whether to check for null values due to non-joining
047     *     dimensions in a virtual cube
048     */
049    MemberArrayValueCalc(Exp exp, MemberCalc[] memberCalcs, boolean nullCheck) {
050        super(exp);
051        this.nullCheck = nullCheck;
052        final Type type = exp.getType();
053        assert type instanceof ScalarType : exp;
054        this.memberCalcs = memberCalcs;
055        this.members = new Member[memberCalcs.length];
056    }
057
058    public Object evaluate(Evaluator evaluator) {
059        final int savepoint = evaluator.savepoint();
060        try {
061            for (int i = 0; i < memberCalcs.length; i++) {
062                MemberCalc memberCalc = memberCalcs[i];
063                final Member member = memberCalc.evaluateMember(evaluator);
064                if (member == null
065                        || member.isNull())
066                {
067                    return null;
068                }
069                evaluator.setContext(member);
070                members[i] = member;
071            }
072            if (nullCheck
073                && evaluator.needToReturnNullForUnrelatedDimension(members))
074            {
075                return null;
076            }
077            final Object result = evaluator.evaluateCurrent();
078            return result;
079        } finally {
080            evaluator.restore(savepoint);
081        }
082    }
083
084    public Calc[] getCalcs() {
085        return memberCalcs;
086    }
087
088    public boolean dependsOn(Hierarchy hierarchy) {
089        if (super.dependsOn(hierarchy)) {
090            return true;
091        }
092        for (MemberCalc memberCalc : memberCalcs) {
093            // If the expression definitely includes the dimension (in this
094            // case, that means it is a member of that dimension) then we
095            // do not depend on the dimension. For example, the scalar value of
096            //   [Store].[USA]
097            // does not depend on [Store].
098            //
099            // If the dimensionality of the expression is unknown, then the
100            // expression MIGHT include the dimension, so to be safe we have to
101            // say that it depends on the given dimension. For example,
102            //   Dimensions(3).CurrentMember.Parent
103            // may depend on [Store].
104            if (memberCalc.getType().usesHierarchy(hierarchy, true)) {
105                return false;
106            }
107        }
108        return true;
109    }
110}
111
112// End MemberArrayValueCalc.java