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-2009 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.olap.fun.extra;
011
012import mondrian.calc.*;
013import mondrian.calc.impl.AbstractMemberCalc;
014import mondrian.mdx.ResolvedFunCall;
015import mondrian.olap.*;
016import mondrian.olap.fun.FunDefBase;
017
018import java.util.List;
019
020/**
021 * Definition of the <code>CalculatedChild</code> MDX function.
022 *
023 * <p>Syntax:
024 * <blockquote><code>&lt;Member&gt;
025 * CalculatedChild(&lt;String&gt;)</code></blockquote>
026 *
027 * @author bchow
028 * @since 2006/4/12
029 */
030public class CalculatedChildFunDef extends FunDefBase {
031    public static final CalculatedChildFunDef instance =
032        new CalculatedChildFunDef();
033
034    CalculatedChildFunDef() {
035        super(
036            "CalculatedChild",
037            "Returns an existing calculated child member with name <String> from the specified <Member>.",
038            "mmmS");
039    }
040
041    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
042        final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
043        final StringCalc stringCalc = compiler.compileString(call.getArg(1));
044
045        return new AbstractMemberCalc(
046            call,
047            new Calc[] {memberCalc, stringCalc})
048        {
049            public Member evaluateMember(Evaluator evaluator) {
050                Member member = memberCalc.evaluateMember(evaluator);
051                String name = stringCalc.evaluateString(evaluator);
052                return getCalculatedChild(member, name, evaluator);
053            }
054        };
055    }
056
057    private Member getCalculatedChild(
058        Member parent,
059        String childName,
060        Evaluator evaluator)
061    {
062        final SchemaReader schemaReader =
063                evaluator.getQuery().getSchemaReader(true);
064        Level childLevel = parent.getLevel().getChildLevel();
065        if (childLevel == null) {
066            return parent.getHierarchy().getNullMember();
067        }
068        List<Member> calcMemberList =
069            schemaReader.getCalculatedMembers(childLevel);
070
071        for (Member child : calcMemberList) {
072            // the parent check is required in case there are parallel children
073            // with the same names
074            if (child.getParentMember().equals(parent)
075                && child.getName().equals(childName))
076            {
077                return child;
078            }
079        }
080
081        return parent.getHierarchy().getNullMember();
082    }
083}
084
085
086// End CalculatedChildFunDef.java