001    /*
002    // $Id: //open/mondrian/src/main/mondrian/calc/impl/TupleValueCalc.java#7 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2006-2007 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package mondrian.calc.impl;
011    
012    import mondrian.olap.*;
013    import mondrian.olap.fun.TupleFunDef;
014    import mondrian.olap.type.TupleType;
015    import mondrian.olap.type.Type;
016    import mondrian.calc.TupleCalc;
017    import mondrian.calc.Calc;
018    import mondrian.calc.DummyExp;
019    
020    /**
021     * Expression which evaluates a tuple expression,
022     * sets the dimensional context to the result of that expression,
023     * then yields the value of the current measure in the current
024     * dimensional context.
025     *
026     * <p>The evaluator's context is preserved.
027     *
028     * @see mondrian.calc.impl.ValueCalc
029     * @see mondrian.calc.impl.MemberValueCalc
030     *
031     * @author jhyde
032     * @version $Id: //open/mondrian/src/main/mondrian/calc/impl/TupleValueCalc.java#7 $
033     * @since Sep 27, 2005
034     */
035    public class TupleValueCalc extends GenericCalc {
036        private final TupleCalc tupleCalc;
037    
038        public TupleValueCalc(Exp exp, TupleCalc tupleCalc) {
039            super(exp);
040            this.tupleCalc = tupleCalc;
041        }
042    
043        public Object evaluate(Evaluator evaluator) {
044            final Member[] members = tupleCalc.evaluateTuple(evaluator);
045            if (members == null) {
046                return null;
047            }
048    
049            final boolean needToReturnNull =
050                evaluator.needToReturnNullForUnrelatedDimension(members);
051            if (needToReturnNull) {
052                return null;
053            }
054    
055            Member [] savedMembers = new Member[members.length];
056            for (int i = 0; i < members.length; i++) {
057                savedMembers[i] = evaluator.setContext(members[i]);
058            }
059            Object result = evaluator.evaluateCurrent();
060            evaluator.setContext(savedMembers);
061            return result;
062        }
063    
064        public Calc[] getCalcs() {
065            return new Calc[] {tupleCalc};
066        }
067    
068        public boolean dependsOn(Dimension dimension) {
069            if (super.dependsOn(dimension)) {
070                return true;
071            }
072            for (Type type : ((TupleType) tupleCalc.getType()).elementTypes) {
073                // If the expression definitely includes the dimension (in this
074                // case, that means it is a member of that dimension) then we
075                // do not depend on the dimension. For example, the scalar value of
076                //   ([Store].[USA], [Gender].[F])
077                // does not depend on [Store].
078                //
079                // If the dimensionality of the expression is unknown, then the
080                // expression MIGHT include the dimension, so to be safe we have to
081                // say that it depends on the given dimension. For example,
082                //   (Dimensions(3).CurrentMember.Parent, [Gender].[F])
083                // may depend on [Store].
084                if (type.usesDimension(dimension, true)) {
085                    return false;
086                }
087            }
088            return true;
089        }
090    
091        /**
092         * Optimizes the scalar evaluation of a tuple. It evaluates the members
093         * of the tuple, sets the context to these members, and evaluates the
094         * scalar result in one step, without generating a tuple.<p/>
095         *
096         * This is useful when evaluating calculated members:<blockquote><code>
097         *
098         * <pre>WITH MEMBER [Measures].[Sales last quarter]
099         *   AS ' ([Measures].[Unit Sales], [Time].PreviousMember '</pre>
100         *
101         * </code></blockquote>
102         *
103         * @return optimized expression
104         */
105        public Calc optimize() {
106            if (tupleCalc instanceof TupleFunDef.CalcImpl) {
107                TupleFunDef.CalcImpl calc = (TupleFunDef.CalcImpl) tupleCalc;
108                return new MemberValueCalc(
109                        new DummyExp(type), calc.getMemberCalcs());
110            }
111            return this;
112        }
113    }
114    
115    // End TupleValueCalc.java