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