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