001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/CoalesceEmptyFunDef.java#10 $
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) 2004-2006 Julian Hyde and others
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.*;
014    import mondrian.calc.impl.GenericCalc;
015    import mondrian.mdx.ResolvedFunCall;
016    
017    /**
018     * Definition of the <code>CoalesceEmpty</code> MDX function.
019     *
020     * <p>It evaluates each of the arguments to the function, returning the
021     * first such argument that does not return a null value.
022     *
023     * @author gjohnson
024     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/CoalesceEmptyFunDef.java#10 $
025     */
026    public class CoalesceEmptyFunDef extends FunDefBase {
027        static final ResolverBase Resolver = new ResolverImpl();
028    
029        public CoalesceEmptyFunDef(ResolverBase resolverBase, int type, int[] types) {
030            super(resolverBase,  type, types);
031        }
032    
033        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
034            final Exp[] args = call.getArgs();
035            final Calc[] calcs = new Calc[args.length];
036            for (int i = 0; i < args.length; i++) {
037                calcs[i] = compiler.compileScalar(args[i], true);
038            }
039            return new GenericCalc(call) {
040                public Object evaluate(Evaluator evaluator) {
041                    for (Calc calc : calcs) {
042                        final Object o = calc.evaluate(evaluator);
043                        if (o != null) {
044                            return o;
045                        }
046                    }
047                    return null;
048                }
049    
050                public Calc[] getCalcs() {
051                    return calcs;
052                }
053            };
054        }
055    
056        private static class ResolverImpl extends ResolverBase {
057            public ResolverImpl() {
058                super(
059                        "CoalesceEmpty",
060                        "CoalesceEmpty(<Value Expression>[, <Value Expression>...])",
061                        "Coalesces an empty cell value to a different value. All of the expressions must be of the same type (number or string).",
062                        Syntax.Function);
063            }
064    
065            public FunDef resolve(
066                    Exp[] args, Validator validator, int[] conversionCount) {
067                if (args.length < 1) {
068                    return null;
069                }
070                final int[] types = {Category.Numeric, Category.String};
071                final int[] argTypes = new int[args.length];
072                for (int type : types) {
073                    int matchingArgs = 0;
074                    conversionCount[0] = 0;
075                    for (int i = 0; i < args.length; i++) {
076                        if (validator.canConvert(args[i], type, conversionCount)) {
077                            matchingArgs++;
078                        }
079                        argTypes[i] = type;
080                    }
081                    if (matchingArgs == args.length) {
082                        return new CoalesceEmptyFunDef(this, type, argTypes);
083                    }
084                }
085                return null;
086            }
087    
088            public boolean requiresExpression(int k) {
089                return true;
090            }
091        }
092    }
093    
094    // End CoalesceEmptyFunDef.java