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