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