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.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 mondrian.calc.impl.ValueCalc}; see also {@link mondrian.calc.impl.TupleValueCalc}. 028 * 029 * @author jhyde 030 * @since Sep 27, 2005 031 */ 032public class MemberValueCalc extends GenericCalc { 033 private final MemberCalc memberCalc; 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 memberCalc Compiled expression 046 * @param nullCheck Whether to check for null values due to non-joining 047 * dimensions in a virtual cube 048 */ 049 public MemberValueCalc(Exp exp, MemberCalc memberCalc, boolean nullCheck) { 050 super(exp); 051 this.nullCheck = nullCheck; 052 final Type type = exp.getType(); 053 assert type instanceof ScalarType : exp; 054 this.memberCalc = memberCalc; 055 } 056 057 /** 058 * Creates a {@link ValueCalc}, {@link MemberValueCalc} or 059 * {@link MemberArrayValueCalc}. 060 * 061 * @param exp Expression 062 * @param memberCalcs Array of members to evaluate 063 * @param nullCheck Whether to check for null values due to non-joining 064 * dimensions in a virtual cube 065 * @return Compiled expression to evaluate each member expression, set 066 * evaluator context to each resulting member, then evaluate the current 067 * context 068 */ 069 public static GenericCalc create( 070 Exp exp, 071 MemberCalc[] memberCalcs, 072 boolean nullCheck) 073 { 074 switch (memberCalcs.length) { 075 case 0: 076 return new ValueCalc(exp); 077 case 1: 078 return new MemberValueCalc(exp, memberCalcs[0], nullCheck); 079 default: 080 return new MemberArrayValueCalc(exp, memberCalcs, nullCheck); 081 } 082 } 083 084 public Object evaluate(Evaluator evaluator) { 085 final int savepoint = evaluator.savepoint(); 086 try { 087 final Member member = memberCalc.evaluateMember(evaluator); 088 if (member == null 089 || member.isNull()) 090 { 091 return null; 092 } 093 evaluator.setContext(member); 094 if (nullCheck 095 && evaluator.needToReturnNullForUnrelatedDimension( 096 new Member[] {member})) 097 { 098 return null; 099 } 100 final Object result = evaluator.evaluateCurrent(); 101 return result; 102 } finally { 103 evaluator.restore(savepoint); 104 } 105 } 106 107 public Calc[] getCalcs() { 108 return new MemberCalc[] {memberCalc}; 109 } 110 111 public boolean dependsOn(Hierarchy hierarchy) { 112 if (super.dependsOn(hierarchy)) { 113 return true; 114 } 115 // If the expression definitely includes the dimension (in this 116 // case, that means it is a member of that dimension) then we 117 // do not depend on the dimension. For example, the scalar value of 118 // [Store].[USA] 119 // does not depend on [Store]. 120 // 121 // If the dimensionality of the expression is unknown, then the 122 // expression MIGHT include the dimension, so to be safe we have to 123 // say that it depends on the given dimension. For example, 124 // Dimensions(3).CurrentMember.Parent 125 // may depend on [Store]. 126 return !memberCalc.getType().usesHierarchy(hierarchy, true); 127 } 128} 129 130// End MemberValueCalc.java