001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/CaseTestFunDef.java#5 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2006-2007 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package mondrian.olap.fun;
011    
012    import mondrian.olap.*;
013    import mondrian.calc.Calc;
014    import mondrian.calc.ExpCompiler;
015    import mondrian.calc.BooleanCalc;
016    import mondrian.calc.impl.ConstantCalc;
017    import mondrian.calc.impl.GenericCalc;
018    import mondrian.mdx.ResolvedFunCall;
019    
020    import java.util.List;
021    import java.util.ArrayList;
022    
023    /**
024     * Definition of the tested <code>CASE</code> MDX operator.
025     *
026     * Syntax is:
027     * <blockquote><pre><code>Case
028     * When &lt;Logical Expression&gt; Then &lt;Expression&gt;
029     * [...]
030     * [Else &lt;Expression&gt;]
031     * End</code></blockquote>.
032     *
033     * @see CaseMatchFunDef
034     *
035     * @author jhyde
036     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/CaseTestFunDef.java#5 $
037     * @since Mar 23, 2006
038     */
039    class CaseTestFunDef extends FunDefBase {
040        static final ResolverImpl Resolver = new ResolverImpl();
041    
042        public CaseTestFunDef(FunDef dummyFunDef) {
043            super(dummyFunDef);
044        }
045    
046        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
047            final Exp[] args = call.getArgs();
048            final BooleanCalc[] conditionCalcs =
049                    new BooleanCalc[args.length / 2];
050            final Calc[] exprCalcs =
051                    new Calc[args.length / 2];
052            final List<Calc> calcList = new ArrayList<Calc>();
053            for (int i = 0, j = 0; i < exprCalcs.length; i++) {
054                conditionCalcs[i] =
055                        compiler.compileBoolean(args[j++]);
056                calcList.add(conditionCalcs[i]);
057                exprCalcs[i] = compiler.compile(args[j++]);
058                calcList.add(exprCalcs[i]);
059            }
060            final Calc defaultCalc =
061                    args.length % 2 == 1 ?
062                    compiler.compileScalar(args[args.length - 1], true) :
063                    ConstantCalc.constantNull(call.getType());
064            calcList.add(defaultCalc);
065            final Calc[] calcs = calcList.toArray(new Calc[calcList.size()]);
066    
067            return new GenericCalc(call) {
068                public Object evaluate(Evaluator evaluator) {
069                    for (int i = 0; i < conditionCalcs.length; i++) {
070                        if (conditionCalcs[i].evaluateBoolean(evaluator)) {
071                            return exprCalcs[i].evaluate(evaluator);
072                        }
073                    }
074                    return defaultCalc.evaluate(evaluator);
075                }
076    
077                public Calc[] getCalcs() {
078                    return calcs;
079                }
080            };
081        }
082    
083        private static class ResolverImpl extends ResolverBase {
084            public ResolverImpl() {
085                super(
086                        "_CaseTest",
087                        "Case When <Logical Expression> Then <Expression> [...] [Else <Expression>] End",
088                        "Evaluates various conditions, and returns the corresponding expression for the first which evaluates to true.",
089                        Syntax.Case);
090            }
091    
092            public FunDef resolve(
093                    Exp[] args, Validator validator, int[] conversionCount) {
094                if (args.length < 1) {
095                    return null;
096                }
097                int j = 0;
098                int clauseCount = args.length / 2;
099                int mismatchingArgs = 0;
100                int returnType = args[1].getCategory();
101                for (int i = 0; i < clauseCount; i++) {
102                    if (!validator.canConvert(args[j++], Category.Logical, conversionCount)) {
103                        mismatchingArgs++;
104                    }
105                    if (!validator.canConvert(args[j++], returnType, conversionCount)) {
106                        mismatchingArgs++;
107                    }
108                }
109                if (j < args.length) {
110                    if (!validator.canConvert(args[j++], returnType, conversionCount)) {
111                        mismatchingArgs++;
112                    }
113                }
114                Util.assertTrue(j == args.length);
115                if (mismatchingArgs != 0) {
116                    return null;
117                }
118                FunDef dummy = createDummyFunDef(this, returnType, args);
119                return new CaseTestFunDef(dummy);
120            }
121    
122            public boolean requiresExpression(int k) {
123                return true;
124            }
125        }
126    }
127    
128    // End CaseTestFunDef.java