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) 2002-2005 Julian Hyde 008// Copyright (C) 2005-2011 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.olap.fun; 012 013import mondrian.calc.*; 014import mondrian.calc.impl.*; 015import mondrian.mdx.ResolvedFunCall; 016import mondrian.olap.*; 017import mondrian.olap.type.NullType; 018import mondrian.resource.MondrianResource; 019import mondrian.rolap.RolapMember; 020 021/** 022 * Definition of the MDX <code><Member> : <Member></code> operator, 023 * which returns the set of members between a given pair of members. 024 * 025 * @author jhyde 026 * @since 3 March, 2002 027 */ 028class RangeFunDef extends FunDefBase { 029 static final RangeFunDef instance = new RangeFunDef(); 030 031 private RangeFunDef() { 032 super( 033 ":", 034 "<Member> : <Member>", 035 "Infix colon operator returns the set of members between a given pair of members.", 036 "ixmm"); 037 } 038 039 040 /** 041 * Returns two membercalc objects, substituting nulls with the hierarchy 042 * null member of the other expression. 043 * 044 * @param exp0 first expression 045 * @param exp1 second expression 046 * 047 * @return two member calcs 048 */ 049 private MemberCalc[] compileMembers( 050 Exp exp0, Exp exp1, ExpCompiler compiler) 051 { 052 MemberCalc[] members = new MemberCalc[2]; 053 054 if (exp0.getType() instanceof NullType) { 055 members[0] = null; 056 } else { 057 members[0] = compiler.compileMember(exp0); 058 } 059 060 if (exp1.getType() instanceof NullType) { 061 members[1] = null; 062 } else { 063 members[1] = compiler.compileMember(exp1); 064 } 065 066 // replace any null types with hierachy null member 067 // if both objects are null, throw exception 068 069 if (members[0] == null && members[1] == null) { 070 throw MondrianResource.instance().TwoNullsNotSupported.ex(); 071 } else if (members[0] == null) { 072 Member nullMember = 073 ((RolapMember) members[1].evaluate(null)).getHierarchy() 074 .getNullMember(); 075 members[0] = (MemberCalc)ConstantCalc.constantMember(nullMember); 076 } else if (members[1] == null) { 077 Member nullMember = 078 ((RolapMember) members[0].evaluate(null)).getHierarchy() 079 .getNullMember(); 080 members[1] = (MemberCalc)ConstantCalc.constantMember(nullMember); 081 } 082 083 return members; 084 } 085 086 public Calc compileCall(final ResolvedFunCall call, ExpCompiler compiler) { 087 final MemberCalc[] memberCalcs = 088 compileMembers(call.getArg(0), call.getArg(1), compiler); 089 return new AbstractListCalc( 090 call, new Calc[] {memberCalcs[0], memberCalcs[1]}) 091 { 092 public TupleList evaluateList(Evaluator evaluator) { 093 final Member member0 = memberCalcs[0].evaluateMember(evaluator); 094 final Member member1 = memberCalcs[1].evaluateMember(evaluator); 095 if (member0.isNull() || member1.isNull()) { 096 return TupleCollections.emptyList(1); 097 } 098 if (member0.getLevel() != member1.getLevel()) { 099 throw evaluator.newEvalException( 100 call.getFunDef(), 101 "Members must belong to the same level"); 102 } 103 return new UnaryTupleList( 104 FunUtil.memberRange(evaluator, member0, member1)); 105 } 106 }; 107 } 108} 109 110// End RangeFunDef.java