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