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) 2006-2011 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.olap.fun;
011
012import mondrian.calc.*;
013import mondrian.calc.impl.AbstractDoubleCalc;
014import mondrian.calc.impl.ValueCalc;
015import mondrian.mdx.ResolvedFunCall;
016import mondrian.olap.*;
017
018/**
019 * Definition of the <code>Sum</code> MDX function.
020 *
021 * @author jhyde
022 * @since Mar 23, 2006
023 */
024class SumFunDef extends AbstractAggregateFunDef {
025    static final ReflectiveMultiResolver Resolver =
026        new ReflectiveMultiResolver(
027            "Sum",
028            "Sum(<Set>[, <Numeric Expression>])",
029            "Returns the sum of a numeric expression evaluated over a set.",
030            new String[]{"fnx", "fnxn"},
031            SumFunDef.class);
032
033    public SumFunDef(FunDef dummyFunDef) {
034        super(dummyFunDef);
035    }
036
037    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
038        // What is the desired type to use to get the underlying values
039        for (ResultStyle r : compiler.getAcceptableResultStyles()) {
040            Calc calc;
041            switch (r) {
042            case ITERABLE:
043            case ANY:
044                // Consumer wants ITERABLE or ANY to be used
045                //return compileCallIterable(call, compiler);
046                calc = compileCall(call, compiler, ResultStyle.ITERABLE);
047                if (calc != null) {
048                    return calc;
049                }
050                break;
051            case MUTABLE_LIST:
052                // Consumer wants MUTABLE_LIST
053                calc = compileCall(call, compiler, ResultStyle.MUTABLE_LIST);
054                if (calc != null) {
055                    return calc;
056                }
057                break;
058            case LIST:
059                // Consumer wants LIST to be used
060                //return compileCallList(call, compiler);
061                calc = compileCall(call, compiler, ResultStyle.LIST);
062                if (calc != null) {
063                    return calc;
064                }
065                break;
066            }
067        }
068        throw ResultStyleException.generate(
069            ResultStyle.ITERABLE_LIST_MUTABLELIST_ANY,
070            compiler.getAcceptableResultStyles());
071    }
072
073    protected Calc compileCall(
074        final ResolvedFunCall call,
075        ExpCompiler compiler,
076        ResultStyle resultStyle)
077    {
078        final Calc ncalc = compiler.compileIter(call.getArg(0));
079        if (ncalc == null) {
080            return null;
081        }
082        final Calc calc = call.getArgCount() > 1
083            ? compiler.compileScalar(call.getArg(1), true)
084            : new ValueCalc(call);
085        // we may have asked for one sort of Calc, but here's what we got.
086        if (ncalc instanceof ListCalc) {
087            return genListCalc(call, (ListCalc) ncalc, calc);
088        } else {
089            return genIterCalc(call, (IterCalc) ncalc, calc);
090        }
091    }
092
093    protected Calc genIterCalc(
094        final ResolvedFunCall call,
095        final IterCalc iterCalc,
096        final Calc calc)
097    {
098        return new AbstractDoubleCalc(call, new Calc[] {iterCalc, calc}) {
099            public double evaluateDouble(Evaluator evaluator) {
100                TupleIterable iterable =
101                    evaluateCurrentIterable(iterCalc, evaluator);
102                final int savepoint = evaluator.savepoint();
103                try {
104                    return sumDouble(evaluator, iterable, calc);
105                } finally {
106                    evaluator.restore(savepoint);
107                }
108            }
109
110            public boolean dependsOn(Hierarchy hierarchy) {
111                return anyDependsButFirst(getCalcs(), hierarchy);
112            }
113        };
114    }
115
116    protected Calc genListCalc(
117        final ResolvedFunCall call,
118        final ListCalc listCalc,
119        final Calc calc)
120    {
121        return new AbstractDoubleCalc(call, new Calc[] {listCalc, calc}) {
122            public double evaluateDouble(Evaluator evaluator) {
123                TupleList memberList = evaluateCurrentList(listCalc, evaluator);
124                final int savepoint = evaluator.savepoint();
125                try {
126                    evaluator.setNonEmpty(false);
127                    return
128                        sumDouble(
129                            evaluator, memberList, calc);
130                } finally {
131                    evaluator.restore(savepoint);
132                }
133            }
134
135            public boolean dependsOn(Hierarchy hierarchy) {
136                return anyDependsButFirst(getCalcs(), hierarchy);
137            }
138        };
139    }
140}
141
142// End SumFunDef.java