1 11 package mondrian.olap.fun; 12 13 import mondrian.calc.*; 14 import mondrian.calc.impl.AbstractListCalc; 15 import mondrian.mdx.ResolvedFunCall; 16 import mondrian.olap.*; 17 18 import java.util.List ; 19 import java.util.Map ; 20 21 29 class TopBottomPercentSumFunDef extends FunDefBase { 30 33 final boolean top; 34 37 final boolean percent; 38 39 static final ResolverImpl TopPercentResolver = new ResolverImpl( 40 "TopPercent", 41 "TopPercent(<Set>, <Percentage>, <Numeric Expression>)", 42 "Sorts a set and returns the top N elements whose cumulative total is at least a specified percentage.", 43 new String []{"fxxnn"}, true, true); 44 45 static final ResolverImpl BottomPercentResolver = new ResolverImpl( 46 "BottomPercent", 47 "BottomPercent(<Set>, <Percentage>, <Numeric Expression>)", 48 "Sorts a set and returns the bottom N elements whose cumulative total is at least a specified percentage.", 49 new String []{"fxxnn"}, false, true); 50 51 static final ResolverImpl TopSumResolver = new ResolverImpl( 52 "TopSum", 53 "TopSum(<Set>, <Value>, <Numeric Expression>)", 54 "Sorts a set and returns the top N elements whose cumulative total is at least a specified value.", 55 new String []{"fxxnn"}, true, false); 56 57 static final ResolverImpl BottomSumResolver = new ResolverImpl( 58 "BottomSum", 59 "BottomSum(<Set>, <Value>, <Numeric Expression>)", 60 "Sorts a set and returns the bottom N elements whose cumulative total is at least a specified value.", 61 new String []{"fxxnn"}, false, false); 62 63 public TopBottomPercentSumFunDef( 64 FunDef dummyFunDef, boolean top, boolean percent) { 65 super(dummyFunDef); 66 this.top = top; 67 this.percent = percent; 68 } 69 70 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 71 final ListCalc listCalc = (ListCalc) compiler.compile(call.getArg(0), 72 ExpCompiler.MUTABLE_LIST_RESULT_STYLE_ARRAY); 73 final DoubleCalc doubleCalc = compiler.compileDouble(call.getArg(1)); 74 final Calc calc = compiler.compileScalar(call.getArg(2), true); 75 return new CalcImpl(call, listCalc, doubleCalc, calc); 76 } 77 78 private static class ResolverImpl extends MultiResolver { 79 private final boolean top; 80 private final boolean percent; 81 82 public ResolverImpl( 83 final String name, final String signature, 84 final String description, final String [] signatures, 85 boolean top, boolean percent) { 86 super(name, signature, description, signatures); 87 this.top = top; 88 this.percent = percent; 89 } 90 91 protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) { 92 return new TopBottomPercentSumFunDef(dummyFunDef, top, percent); 93 } 94 } 95 96 private class CalcImpl extends AbstractListCalc { 97 private final ListCalc listCalc; 98 private final DoubleCalc doubleCalc; 99 private final Calc calc; 100 101 public CalcImpl(ResolvedFunCall call, ListCalc listCalc, DoubleCalc doubleCalc, Calc calc) { 102 super(call, new Calc[]{listCalc, doubleCalc, calc}); 103 this.listCalc = listCalc; 104 this.doubleCalc = doubleCalc; 105 this.calc = calc; 106 } 107 108 public List evaluateList(Evaluator evaluator) { 109 List list = listCalc.evaluateList(evaluator); 110 double target = doubleCalc.evaluateDouble(evaluator); 111 if (list.isEmpty()) { 112 return list; 113 } 114 Map mapMemberToValue; 115 Object first = list.get(0); 116 boolean isMember = true; 117 if (first instanceof Member) { 118 List <Member> memberList = (List <Member>) list; 119 mapMemberToValue = 120 evaluateMembers(evaluator, calc, memberList, false); 121 sortMembers(evaluator, memberList, calc, top, true); 122 } else { 123 isMember = false; 124 List <Member[]> tupleList = (List <Member[]>) list; 125 mapMemberToValue = 126 evaluateTuples(evaluator, calc, tupleList); 127 int arity = ((Member[]) first).length; 128 sortTuples(evaluator, tupleList, calc, top, true, arity); 129 } 130 if (percent) { 131 toPercent(list, mapMemberToValue, isMember); 132 } 133 double runningTotal = 0; 134 int memberCount = list.size(); 135 int nullCount = 0; 136 for (int i = 0; i < memberCount; i++) { 137 if (runningTotal >= target) { 138 list = list.subList(0, i); 139 break; 140 } 141 Object o = (isMember) 142 ? mapMemberToValue.get(list.get(i)) 143 : mapMemberToValue.get( 144 new ArrayHolder<Member>((Member []) list.get(i))); 145 if (o == Util.nullValue) { 146 nullCount++; 147 } else if (o instanceof Number ) { 148 runningTotal += ((Number ) o).doubleValue(); 149 } else if (o instanceof Exception ) { 150 } else { 152 throw Util.newInternal("got " + o + " when expecting Number"); 153 } 154 } 155 156 if (memberCount > 0 && percent && nullCount == memberCount) { 160 return top ? 161 list.subList(0, 1) : 162 list.subList(memberCount - 1, memberCount); 163 } 164 return list; 165 } 166 167 public boolean dependsOn(Dimension dimension) { 168 return anyDependsButFirst(getCalcs(), dimension); 169 } 170 } 171 } 172 173 | Popular Tags |