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) 2008-2009 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.olap.fun;
011
012import mondrian.calc.*;
013import mondrian.calc.impl.*;
014import mondrian.mdx.ResolvedFunCall;
015import mondrian.olap.*;
016import mondrian.olap.type.*;
017
018/**
019 * Definition of the <code>Iif</code> MDX function.
020 *
021 * @author jhyde
022 * @since Jan 17, 2008
023 */
024public class IifFunDef extends FunDefBase {
025    /**
026     * Creates an IifFunDef.
027     *
028     * @param name        Name of the function, for example "Members".
029     * @param description Description of the function
030     * @param flags       Encoding of the syntactic, return, and parameter types
031     */
032    protected IifFunDef(
033        String name,
034        String description,
035        String flags)
036    {
037        super(name, description, flags);
038    }
039
040    public Type getResultType(Validator validator, Exp[] args) {
041        // This is messy. We have already decided which variant of Iif to use,
042        // and that involves some upcasts. For example, Iif(b, n, NULL) resolves
043        // to the type of n. We don't want to throw it away and take the most
044        // general type. So, for scalar types we create a type based on
045        // returnCategory.
046        //
047        // But for dimensional types (member, level, hierarchy, dimension,
048        // tuple) we want to preserve as much type information as possible, so
049        // we recompute the type based on the common types of all args.
050        //
051        // FIXME: We should pass more info into this method, such as the list
052        // of conversions computed while resolving overloadings.
053        switch (returnCategory) {
054        case Category.Numeric:
055            return new NumericType();
056        case Category.String:
057            return new StringType();
058        case Category.Logical:
059            return new BooleanType();
060        default:
061            return TypeUtil.computeCommonType(
062                true, args[1].getType(), args[2].getType());
063        }
064    }
065
066    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
067        final BooleanCalc booleanCalc =
068            compiler.compileBoolean(call.getArg(0));
069        final Calc calc1 =
070            compiler.compileAs(
071                call.getArg(1), call.getType(), ResultStyle.ANY_LIST);
072        final Calc calc2 =
073            compiler.compileAs(
074                call.getArg(2), call.getType(), ResultStyle.ANY_LIST);
075        if (call.getType() instanceof SetType) {
076            return new GenericIterCalc(call) {
077                public Object evaluate(Evaluator evaluator) {
078                    final boolean b =
079                        booleanCalc.evaluateBoolean(evaluator);
080                    Calc calc = b ? calc1 : calc2;
081                    return calc.evaluate(evaluator);
082                }
083
084                public Calc[] getCalcs() {
085                    return new Calc[] {booleanCalc, calc1, calc2};
086                }
087            };
088        } else {
089            return new GenericCalc(call) {
090                public Object evaluate(Evaluator evaluator) {
091                    final boolean b =
092                        booleanCalc.evaluateBoolean(evaluator);
093                    Calc calc = b ? calc1 : calc2;
094                    return calc.evaluate(evaluator);
095                }
096
097                public Calc[] getCalcs() {
098                    return new Calc[] {booleanCalc, calc1, calc2};
099                }
100            };
101        }
102    }
103
104    // IIf(<Logical Expression>, <String Expression>, <String Expression>)
105    static final FunDefBase STRING_INSTANCE = new FunDefBase(
106        "IIf",
107        "Returns one of two string values determined by a logical test.",
108        "fSbSS")
109    {
110        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
111            final BooleanCalc booleanCalc =
112                compiler.compileBoolean(call.getArg(0));
113            final StringCalc calc1 = compiler.compileString(call.getArg(1));
114            final StringCalc calc2 = compiler.compileString(call.getArg(2));
115            return new AbstractStringCalc(
116                call, new Calc[] {booleanCalc, calc1, calc2}) {
117                public String evaluateString(Evaluator evaluator) {
118                    final boolean b =
119                        booleanCalc.evaluateBoolean(evaluator);
120                    StringCalc calc = b ? calc1 : calc2;
121                    return calc.evaluateString(evaluator);
122                }
123            };
124        }
125    };
126
127    // IIf(<Logical Expression>, <Numeric Expression>, <Numeric Expression>)
128    static final FunDefBase NUMERIC_INSTANCE =
129        new IifFunDef(
130            "IIf",
131            "Returns one of two numeric values determined by a logical test.",
132            "fnbnn")
133        {
134            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler)
135            {
136                final BooleanCalc booleanCalc =
137                    compiler.compileBoolean(call.getArg(0));
138                final Calc calc1 = compiler.compileScalar(call.getArg(1), true);
139                final Calc calc2 = compiler.compileScalar(call.getArg(2), true);
140                return new GenericCalc(call) {
141                    public Object evaluate(Evaluator evaluator) {
142                        final boolean b =
143                            booleanCalc.evaluateBoolean(evaluator);
144                        Calc calc = b ? calc1 : calc2;
145                        return calc.evaluate(evaluator);
146                    }
147
148                    public Calc[] getCalcs() {
149                        return new Calc[] {booleanCalc, calc1, calc2};
150                    }
151                };
152            }
153        };
154
155    // IIf(<Logical Expression>, <Tuple Expression>, <Tuple Expression>)
156    static final FunDefBase TUPLE_INSTANCE =
157        new IifFunDef(
158            "IIf",
159            "Returns one of two tuples determined by a logical test.",
160            "ftbtt")
161        {
162            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler)
163            {
164                final BooleanCalc booleanCalc =
165                    compiler.compileBoolean(call.getArg(0));
166                final Calc calc1 = compiler.compileTuple(call.getArg(1));
167                final Calc calc2 = compiler.compileTuple(call.getArg(2));
168                return new GenericCalc(call) {
169                    public Object evaluate(Evaluator evaluator) {
170                        final boolean b =
171                            booleanCalc.evaluateBoolean(evaluator);
172                        Calc calc = b ? calc1 : calc2;
173                        return calc.evaluate(evaluator);
174                    }
175
176                    public Calc[] getCalcs() {
177                        return new Calc[] {booleanCalc, calc1, calc2};
178                    }
179                };
180            }
181        };
182
183    // IIf(<Logical Expression>, <Boolean Expression>, <Boolean Expression>)
184    static final FunDefBase BOOLEAN_INSTANCE = new FunDefBase(
185        "IIf",
186        "Returns boolean determined by a logical test.",
187        "fbbbb")
188    {
189        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
190            final BooleanCalc booleanCalc =
191                compiler.compileBoolean(call.getArg(0));
192            final BooleanCalc booleanCalc1 =
193                compiler.compileBoolean(call.getArg(1));
194            final BooleanCalc booleanCalc2 =
195                compiler.compileBoolean(call.getArg(2));
196            Calc[] calcs = {booleanCalc, booleanCalc1, booleanCalc2};
197            return new AbstractBooleanCalc(call, calcs) {
198                public boolean evaluateBoolean(Evaluator evaluator) {
199                    final boolean condition =
200                        booleanCalc.evaluateBoolean(evaluator);
201                    if (condition) {
202                        return booleanCalc1.evaluateBoolean(evaluator);
203                    } else {
204                        return booleanCalc2.evaluateBoolean(evaluator);
205                    }
206                }
207            };
208        }
209    };
210
211    // IIf(<Logical Expression>, <Member Expression>, <Member Expression>)
212    static final IifFunDef MEMBER_INSTANCE =
213        new IifFunDef(
214            "IIf",
215            "Returns one of two member values determined by a logical test.",
216            "fmbmm");
217
218    // IIf(<Logical Expression>, <Level Expression>, <Level Expression>)
219    static final IifFunDef LEVEL_INSTANCE =
220        new IifFunDef(
221            "IIf",
222            "Returns one of two level values determined by a logical test.",
223            "flbll");
224
225    // IIf(<Logical Expression>, <Hierarchy Expression>, <Hierarchy Expression>)
226    static final IifFunDef HIERARCHY_INSTANCE =
227        new IifFunDef(
228            "IIf",
229            "Returns one of two hierarchy values determined by a logical test.",
230            "fhbhh");
231
232    // IIf(<Logical Expression>, <Dimension Expression>, <Dimension Expression>)
233    static final IifFunDef DIMENSION_INSTANCE =
234        new IifFunDef(
235            "IIf",
236            "Returns one of two dimension values determined by a logical test.",
237            "fdbdd");
238
239    // IIf(<Logical Expression>, <Set Expression>, <Set Expression>)
240    static final IifFunDef SET_INSTANCE =
241        new IifFunDef(
242            "IIf",
243            "Returns one of two set values determined by a logical test.",
244            "fxbxx");
245}
246
247// End IifFunDef.java