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.AbstractTupleCalc;
015import mondrian.mdx.ResolvedFunCall;
016import mondrian.olap.*;
017import mondrian.olap.type.*;
018
019import java.io.PrintWriter;
020import java.util.List;
021
022/**
023 * <code>TupleFunDef</code> implements the '(...)' operator which builds
024 * tuples, as in <code>([Time].CurrentMember,
025 * [Stores].[USA].[California])</code>.
026 *
027 * @author jhyde
028 * @since 3 March, 2002
029 */
030public class TupleFunDef extends FunDefBase {
031    private final int[] argTypes;
032    static final ResolverImpl Resolver = new ResolverImpl();
033
034    private TupleFunDef(int[] argTypes) {
035        super(
036            "()",
037            "(<Member> [, <Member>]...)",
038            "Parenthesis operator constructs a tuple.  If there is only one member, the expression is equivalent to the member expression.",
039            Syntax.Parentheses,
040            Category.Tuple,
041            argTypes);
042        this.argTypes = argTypes;
043    }
044
045    public int getReturnCategory() {
046        return Category.Tuple;
047    }
048
049    public int[] getParameterCategories() {
050        return argTypes;
051    }
052
053    public void unparse(Exp[] args, PrintWriter pw) {
054        ExpBase.unparseList(pw, args, "(", ", ", ")");
055    }
056
057    public Type getResultType(Validator validator, Exp[] args) {
058        // _Tuple(<Member1>[,<MemberI>]...), which is written
059        // (<Member1>[,<MemberI>]...), has type [Hie1] x ... x [HieN].
060        //
061        // If there is only one member, it merely represents a parenthesized
062        // expression, whose Hierarchy is that of the member.
063        if (args.length == 1) {
064            return TypeUtil.toMemberType(args[0].getType());
065        } else {
066            MemberType[] types = new MemberType[args.length];
067            for (int i = 0; i < args.length; i++) {
068                Exp arg = args[i];
069                types[i] = TypeUtil.toMemberType(arg.getType());
070            }
071            TupleType.checkHierarchies(types);
072            return new TupleType(types);
073        }
074    }
075
076    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
077        final Exp[] args = call.getArgs();
078        final MemberCalc[] memberCalcs = new MemberCalc[args.length];
079        for (int i = 0; i < args.length; i++) {
080            memberCalcs[i] = compiler.compileMember(args[i]);
081        }
082        return new CalcImpl(call, memberCalcs);
083    }
084
085    public static class CalcImpl extends AbstractTupleCalc {
086        private final MemberCalc[] memberCalcs;
087
088        public CalcImpl(ResolvedFunCall call, MemberCalc[] memberCalcs) {
089            super(call, memberCalcs);
090            this.memberCalcs = memberCalcs;
091        }
092
093        public Member[] evaluateTuple(Evaluator evaluator) {
094            final Member[] members = new Member[memberCalcs.length];
095            for (int i = 0; i < members.length; i++) {
096                final Member member =
097                    members[i] =
098                    memberCalcs[i].evaluateMember(evaluator);
099                if (member == null || member.isNull()) {
100                    return null;
101                }
102            }
103            return members;
104        }
105
106        public MemberCalc[] getMemberCalcs() {
107            return memberCalcs;
108        }
109    }
110
111    private static class ResolverImpl extends ResolverBase {
112        public ResolverImpl() {
113            super("()", null, null, Syntax.Parentheses);
114        }
115
116        public FunDef resolve(
117            Exp[] args,
118            Validator validator,
119            List<Conversion> conversions)
120        {
121            // Compare with TupleFunDef.getReturnCategory().  For example,
122            //   ([Gender].members) is a set,
123            //   ([Gender].[M]) is a member,
124            //   (1 + 2) is a numeric,
125            // but
126            //   ([Gender].[M], [Marital Status].[S]) is a tuple.
127            if (args.length == 1) {
128                return new ParenthesesFunDef(args[0].getCategory());
129            } else {
130                final int[] argTypes = new int[args.length];
131                for (int i = 0; i < args.length; i++) {
132                    // Arg must be a member:
133                    //  OK: ([Gender].[S], [Time].[1997])   (member, member)
134                    //  OK: ([Gender], [Time])           (dimension, dimension)
135                    // Not OK:
136                    //  ([Gender].[S], [Store].[Store City]) (member, level)
137                    if (!validator.canConvert(
138                            i, args[i], Category.Member, conversions))
139                    {
140                        return null;
141                    }
142                    argTypes[i] = Category.Member;
143                }
144                return new TupleFunDef(argTypes);
145            }
146        }
147    }
148}
149
150// End TupleFunDef.java