1 11 package mondrian.olap.fun; 12 13 import mondrian.calc.*; 14 import mondrian.calc.impl.*; 15 import mondrian.olap.*; 16 import mondrian.mdx.ResolvedFunCall; 17 18 import java.util.*; 19 20 27 class OrderFunDef extends FunDefBase { 28 29 static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver( 30 "Order", 31 "Order(<Set>, <Value Expression>[, ASC | DESC | BASC | BDESC])", 32 "Arranges members of a set, optionally preserving or breaking the hierarchy.", 33 new String []{"fxxvy", "fxxv"}, 34 OrderFunDef.class, 35 Flag.getNames()); 36 37 public OrderFunDef(FunDef dummyFunDef) { 38 super(dummyFunDef); 39 } 40 41 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 42 final ListCalc listCalc = compiler.compileList(call.getArg(0), true); 43 final Calc expCalc = compiler.compileScalar(call.getArg(1), true); 44 final Flag order = getLiteralArg(call, 2, Flag.ASC, Flag.class); 45 46 if (expCalc instanceof MemberValueCalc) { 47 MemberValueCalc memberValueCalc = (MemberValueCalc) expCalc; 48 List<Calc> constantList = new ArrayList<Calc>(); 49 List<Calc> variableList = new ArrayList<Calc>(); 50 final MemberCalc[] calcs = (MemberCalc[]) memberValueCalc.getCalcs(); 51 for (MemberCalc memberCalc : calcs) { 52 if (memberCalc instanceof ConstantCalc && 53 !listCalc.dependsOn( 54 memberCalc.getType().getHierarchy().getDimension())) { 55 constantList.add(memberCalc); 56 } else { 57 variableList.add(memberCalc); 58 } 59 } 60 if (constantList.isEmpty()) { 61 } else if (variableList.isEmpty()) { 63 return new ContextCalc( 66 calcs, 67 new CalcImpl( 68 call, 69 listCalc, 70 new ValueCalc( 71 new DummyExp(expCalc.getType())), 72 order.descending, 73 order.brk)); 74 } else { 75 return new ContextCalc( 78 constantList.toArray( 79 new MemberCalc[constantList.size()]), 80 new CalcImpl( 81 call, 82 listCalc, 83 new MemberValueCalc( 84 new DummyExp(expCalc.getType()), 85 variableList.toArray( 86 new MemberCalc[variableList.size()])), 87 order.descending, 88 order.brk)); 89 } 90 } 91 return new CalcImpl(call, listCalc, expCalc, order.descending, order.brk); 92 } 93 94 97 enum Flag { 98 ASC(false, false), 99 DESC(true, false), 100 BASC(false, true), 101 BDESC(true, true); 102 103 private final boolean descending; 104 private final boolean brk; 105 106 Flag(boolean descending, boolean brk) { 107 this.descending = descending; 108 this.brk = brk; 109 } 110 111 public static String [] getNames() { 112 List<String > names = new ArrayList<String >(); 113 for (Flag flags : Flag.class.getEnumConstants()) { 114 names.add(flags.name()); 115 } 116 return names.toArray(new String [names.size()]); 117 } 118 } 119 120 private class CalcImpl extends AbstractListCalc { 121 private final ListCalc listCalc; 122 private final Calc expCalc; 123 private final boolean desc; 124 private final boolean brk; 125 126 public CalcImpl( 127 ResolvedFunCall call, 128 ListCalc listCalc, 129 Calc expCalc, 130 boolean desc, 131 boolean brk) 132 { 133 super(call, new Calc[]{listCalc, expCalc}); 134 assert listCalc.getResultStyle() == ExpCompiler.ResultStyle.MUTABLE_LIST; 135 this.listCalc = listCalc; 136 this.expCalc = expCalc; 137 this.desc = desc; 138 this.brk = brk; 139 } 140 141 public List evaluateList(Evaluator evaluator) { 142 List list = listCalc.evaluateList(evaluator); 143 sortMembers(evaluator.push(), list, expCalc, desc, brk); 144 return list; 145 } 146 147 public Calc[] getCalcs() { 148 return new Calc[] {listCalc, expCalc}; 149 } 150 151 public List<Object > getArguments() { 152 return Collections.singletonList( 153 (Object ) (desc ? 154 (brk ? Flag.BDESC : Flag.DESC) : 155 (brk ? Flag.BASC : Flag.ASC))); 156 } 157 158 public boolean dependsOn(Dimension dimension) { 159 return anyDependsButFirst(getCalcs(), dimension); 160 } 161 } 162 163 private static class ContextCalc extends GenericCalc { 164 private final MemberCalc[] memberCalcs; 165 private final Calc calc; 166 private final Calc[] calcs; 167 private final Member[] members; 169 protected ContextCalc(MemberCalc[] memberCalcs, Calc calc) { 170 super(new DummyExp(calc.getType())); 171 this.memberCalcs = memberCalcs; 172 this.calc = calc; 173 this.calcs = new Calc[memberCalcs.length + 1]; 174 System.arraycopy(memberCalcs, 0, this.calcs, 0, memberCalcs.length); 175 this.calcs[this.calcs.length - 1] = calc; 176 this.members = new Member[memberCalcs.length]; 177 } 178 179 public Calc[] getCalcs() { 180 return calcs; 181 } 182 183 public Object evaluate(Evaluator evaluator) { 184 for (int i = 0; i < memberCalcs.length; i++) { 187 members[i] = memberCalcs[i].evaluateMember(evaluator); 188 } 189 final Evaluator subEval = evaluator.push(members); 190 return calc.evaluate(subEval); 192 } 193 194 public boolean dependsOn(Dimension dimension) { 195 if (anyDepends(memberCalcs, dimension)) { 196 return true; 197 } 198 for (MemberCalc memberCalc : memberCalcs) { 201 if (memberCalc.getType().usesDimension(dimension, true)) { 202 return false; 203 } 204 } 205 return calc.dependsOn(dimension); 206 } 207 public ExpCompiler.ResultStyle getResultStyle() { 208 return calc.getResultStyle(); 209 } 210 } 211 } 212 213 | Popular Tags |