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.calc.impl; 011 012import mondrian.calc.*; 013import mondrian.olap.*; 014import mondrian.olap.fun.TupleFunDef; 015import mondrian.olap.type.TupleType; 016import mondrian.olap.type.Type; 017 018/** 019 * Expression which evaluates a tuple expression, 020 * sets the dimensional context to the result of that expression, 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 * @see mondrian.calc.impl.ValueCalc 027 * @see mondrian.calc.impl.MemberValueCalc 028 * 029 * @author jhyde 030 * @since Sep 27, 2005 031 */ 032public class TupleValueCalc extends GenericCalc { 033 private final TupleCalc tupleCalc; 034 private final boolean nullCheck; 035 036 /** 037 * Creates a TupleValueCalc. 038 * 039 * @param exp Expression 040 * @param tupleCalc Compiled expression to evaluate the tuple 041 * @param nullCheck Whether to check for null values due to non-joining 042 * dimensions in a virtual cube 043 */ 044 public TupleValueCalc(Exp exp, TupleCalc tupleCalc, boolean nullCheck) { 045 super(exp); 046 this.tupleCalc = tupleCalc; 047 this.nullCheck = nullCheck; 048 } 049 050 public Object evaluate(Evaluator evaluator) { 051 final Member[] members = tupleCalc.evaluateTuple(evaluator); 052 if (members == null) { 053 return null; 054 } 055 056 if (nullCheck 057 && evaluator.needToReturnNullForUnrelatedDimension(members)) 058 { 059 return null; 060 } 061 062 final int savepoint = evaluator.savepoint(); 063 try { 064 evaluator.setContext(members); 065 Object result = evaluator.evaluateCurrent(); 066 return result; 067 } finally { 068 evaluator.restore(savepoint); 069 } 070 } 071 072 public Calc[] getCalcs() { 073 return new Calc[] {tupleCalc}; 074 } 075 076 public boolean dependsOn(Hierarchy hierarchy) { 077 if (super.dependsOn(hierarchy)) { 078 return true; 079 } 080 for (Type type : ((TupleType) tupleCalc.getType()).elementTypes) { 081 // If the expression definitely includes the dimension (in this 082 // case, that means it is a member of that dimension) then we 083 // do not depend on the dimension. For example, the scalar value of 084 // ([Store].[USA], [Gender].[F]) 085 // does not depend on [Store]. 086 // 087 // If the dimensionality of the expression is unknown, then the 088 // expression MIGHT include the dimension, so to be safe we have to 089 // say that it depends on the given dimension. For example, 090 // (Dimensions(3).CurrentMember.Parent, [Gender].[F]) 091 // may depend on [Store]. 092 if (type.usesHierarchy(hierarchy, true)) { 093 return false; 094 } 095 } 096 return true; 097 } 098 099 /** 100 * Optimizes the scalar evaluation of a tuple. It evaluates the members 101 * of the tuple, sets the context to these members, and evaluates the 102 * scalar result in one step, without generating a tuple.<p/> 103 * 104 * This is useful when evaluating calculated members:<blockquote><code> 105 * 106 * <pre>WITH MEMBER [Measures].[Sales last quarter] 107 * AS ' ([Measures].[Unit Sales], [Time].PreviousMember) '</pre> 108 * 109 * </code></blockquote> 110 * 111 * @return optimized expression 112 */ 113 public Calc optimize() { 114 if (tupleCalc instanceof TupleFunDef.CalcImpl) { 115 TupleFunDef.CalcImpl calc = (TupleFunDef.CalcImpl) tupleCalc; 116 return MemberValueCalc.create( 117 new DummyExp(type), 118 calc.getMemberCalcs(), 119 nullCheck); 120 } 121 return this; 122 } 123} 124 125// End TupleValueCalc.java