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