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.olap.fun;
011
012import mondrian.calc.*;
013import mondrian.calc.impl.AbstractMemberCalc;
014import mondrian.calc.impl.AbstractTupleCalc;
015import mondrian.mdx.*;
016import mondrian.olap.*;
017import mondrian.olap.type.*;
018import mondrian.resource.MondrianResource;
019
020import java.util.ArrayList;
021import java.util.List;
022
023/**
024 * Definition of the <code>StrToTuple</code> MDX function.
025 *
026 * @author jhyde
027 * @since Mar 23, 2006
028 */
029class StrToTupleFunDef extends FunDefBase {
030    static final ResolverImpl Resolver = new ResolverImpl();
031
032    private StrToTupleFunDef(int[] parameterTypes) {
033        super(
034            "StrToTuple",
035            null,
036            "Constructs a tuple from a string.",
037            Syntax.Function, Category.Tuple, parameterTypes);
038    }
039
040    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
041        final StringCalc stringCalc = compiler.compileString(call.getArg(0));
042        Type elementType = call.getType();
043        if (elementType instanceof MemberType) {
044            final Hierarchy hierarchy = elementType.getHierarchy();
045            return new AbstractMemberCalc(call, new Calc[] {stringCalc}) {
046                public Member evaluateMember(Evaluator evaluator) {
047                    String string = stringCalc.evaluateString(evaluator);
048                    if (string == null) {
049                        throw newEvalException(
050                            MondrianResource.instance().NullValue.ex());
051                    }
052                    return parseMember(evaluator, string, hierarchy);
053                }
054            };
055        } else {
056            TupleType tupleType = (TupleType) elementType;
057            final List<Hierarchy> hierarchies = tupleType.getHierarchies();
058            return new AbstractTupleCalc(call, new Calc[] {stringCalc}) {
059                public Member[] evaluateTuple(Evaluator evaluator) {
060                    String string = stringCalc.evaluateString(evaluator);
061                    if (string == null) {
062                        throw newEvalException(
063                            MondrianResource.instance().NullValue.ex());
064                    }
065                    return parseTuple(evaluator, string, hierarchies);
066                }
067            };
068        }
069    }
070
071    public Exp createCall(Validator validator, Exp[] args) {
072        final int argCount = args.length;
073        if (argCount <= 1) {
074            throw MondrianResource.instance().MdxFuncArgumentsNum.ex(getName());
075        }
076        for (int i = 1; i < argCount; i++) {
077            final Exp arg = args[i];
078            if (arg instanceof DimensionExpr) {
079                // if arg is a dimension, switch to dimension's default
080                // hierarchy
081                DimensionExpr dimensionExpr = (DimensionExpr) arg;
082                Dimension dimension = dimensionExpr.getDimension();
083                args[i] = new HierarchyExpr(dimension.getHierarchy());
084            } else if (arg instanceof HierarchyExpr) {
085                // nothing
086            } else {
087                throw MondrianResource.instance().MdxFuncNotHier.ex(
088                    i + 1, getName());
089            }
090        }
091        return super.createCall(validator, args);
092    }
093
094    public Type getResultType(Validator validator, Exp[] args) {
095        switch (args.length) {
096        case 1:
097            // This is a call to the standard version of StrToTuple,
098            // which doesn't give us any hints about type.
099            return new TupleType(null);
100
101        case 2:
102            final Type argType = args[1].getType();
103            return new MemberType(
104                argType.getDimension(),
105                argType.getHierarchy(),
106                argType.getLevel(),
107                null);
108
109        default: {
110            // This is a call to Mondrian's extended version of
111            // StrToTuple, of the form
112            //   StrToTuple(s, <Hier1>, ... , <HierN>)
113            //
114            // The result is a tuple
115            //  (<Hier1>, ... ,  <HierN>)
116            final List<MemberType> list = new ArrayList<MemberType>();
117            for (int i = 1; i < args.length; i++) {
118                Exp arg = args[i];
119                final Type type = arg.getType();
120                list.add(TypeUtil.toMemberType(type));
121            }
122            final MemberType[] types =
123                list.toArray(new MemberType[list.size()]);
124            TupleType.checkHierarchies(types);
125            return new TupleType(types);
126        }
127        }
128    }
129
130    private static class ResolverImpl extends ResolverBase {
131        ResolverImpl() {
132            super(
133                "StrToTuple",
134                "StrToTuple(<String Expression>)",
135                "Constructs a tuple from a string.",
136                Syntax.Function);
137        }
138
139        public FunDef resolve(
140            Exp[] args,
141            Validator validator,
142            List<Conversion> conversions)
143        {
144            if (args.length < 1) {
145                return null;
146            }
147            Type type = args[0].getType();
148            if (!(type instanceof StringType)
149                && !(type instanceof NullType))
150            {
151                return null;
152            }
153            for (int i = 1; i < args.length; i++) {
154                Exp exp = args[i];
155                if (!(exp instanceof DimensionExpr
156                    || exp instanceof HierarchyExpr))
157                {
158                    return null;
159                }
160            }
161            int[] argTypes = new int[args.length];
162            argTypes[0] = Category.String;
163            for (int i = 1; i < argTypes.length; i++) {
164                argTypes[i] = Category.Hierarchy;
165            }
166            return new StrToTupleFunDef(argTypes);
167        }
168
169        public FunDef getFunDef() {
170            return new StrToTupleFunDef(new int[] {Category.String});
171        }
172    }
173}
174
175// End StrToTupleFunDef.java