1 10 package mondrian.olap.fun; 11 12 import mondrian.olap.*; 13 import mondrian.olap.type.*; 14 import mondrian.calc.Calc; 15 import mondrian.calc.ExpCompiler; 16 import mondrian.calc.ListCalc; 17 import mondrian.calc.StringCalc; 18 import mondrian.calc.impl.AbstractListCalc; 19 import mondrian.calc.impl.ConstantCalc; 20 import mondrian.calc.impl.AbstractStringCalc; 21 import mondrian.mdx.ResolvedFunCall; 22 23 import java.util.List ; 24 import java.util.Arrays ; 25 import java.util.ArrayList ; 26 import java.util.HashSet ; 27 import java.util.Set ; 28 29 36 class GenerateFunDef extends FunDefBase { 37 static final ReflectiveMultiResolver ListResolver = 38 new ReflectiveMultiResolver( 39 "Generate", 40 "Generate(<Set1>, <Set2>[, ALL])", 41 "Applies a set to each member of another set and joins the resulting sets by union.", 42 new String [] {"fxxx", "fxxxy"}, 43 GenerateFunDef.class); 44 45 static final ReflectiveMultiResolver StringResolver = 46 new ReflectiveMultiResolver( 47 "Generate", 48 "Generate(<Set>, <String>[, <String>])", 49 "Applies a set to a string expression and joins resulting sets by string concatenation.", 50 new String [] {"fSxS", "fSxSS"}, 51 GenerateFunDef.class); 52 53 private static final String [] ReservedWords = new String [] {"ALL"}; 54 55 public GenerateFunDef(FunDef dummyFunDef) { 56 super(dummyFunDef); 57 } 58 59 public Type getResultType(Validator validator, Exp[] args) { 60 final Type type = args[1].getType(); 61 if (type instanceof StringType) { 62 return type; 64 } else { 65 final Type memberType = TypeUtil.toMemberOrTupleType(type); 66 return new SetType(memberType); 67 } 68 } 69 70 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 71 final ListCalc listCalc = compiler.compileList(call.getArg(0)); 72 final boolean tuple = ((SetType) listCalc.getType()).getElementType() 73 instanceof TupleType; 74 if (call.getArg(1).getType() instanceof StringType) { 75 final StringCalc stringCalc = compiler.compileString(call.getArg(1)); 76 final StringCalc delimCalc; 77 if (call.getArgCount() == 3) { 78 delimCalc = compiler.compileString(call.getArg(2)); 79 } else { 80 delimCalc = ConstantCalc.constantString(""); 81 } 82 83 return new GenerateStringCalcImpl( 84 call, listCalc, stringCalc, tuple, delimCalc); 85 } else { 86 final ListCalc listCalc2 = compiler.compileList(call.getArg(1)); 87 final String literalArg = getLiteralArg(call, 2, "", ReservedWords); 88 final boolean all = literalArg.equalsIgnoreCase("ALL"); 89 90 return new GenerateListCalcImpl( 91 call, listCalc, listCalc2, tuple, all); 92 } 93 } 94 95 private static class GenerateListCalcImpl extends AbstractListCalc { 96 private final ListCalc listCalc1; 97 private final ListCalc listCalc2; 98 private final boolean tuple; 99 private final boolean all; 100 101 public GenerateListCalcImpl( 102 ResolvedFunCall call, 103 ListCalc listCalc1, 104 ListCalc listCalc2, 105 boolean tuple, boolean all) { 106 super(call, new Calc[]{listCalc1, listCalc2}); 107 this.listCalc1 = listCalc1; 108 this.listCalc2 = listCalc2; 109 this.tuple = tuple; 110 this.all = all; 111 } 112 113 public List evaluateList(Evaluator evaluator) { 114 List <Object > result = new ArrayList <Object >(); 115 if (tuple) { 116 final List <Member[]> list1 = listCalc1.evaluateList(evaluator); 117 final Evaluator evaluator2 = evaluator.push(); 118 if (all) { 119 for (Member[] members : list1) { 120 evaluator2.setContext(members); 121 final List <Object > result2 = 122 listCalc2.evaluateList(evaluator2); 123 result.addAll(result2); 124 } 125 } else { 126 final Set <Object > emitted = new HashSet <Object >(); 127 for (Member[] members : list1) { 128 evaluator2.setContext(members); 129 final List <Object > result2 = 130 listCalc2.evaluateList(evaluator2); 131 addDistinct(result, result2, emitted); 132 } 133 } 134 } else { 135 final List <Member> list1 = listCalc1.evaluateList(evaluator); 136 final Evaluator evaluator2 = evaluator.push(); 137 if (all) { 138 for (Member member : list1) { 139 evaluator2.setContext(member); 140 final List <Object > result2 = 141 listCalc2.evaluateList(evaluator2); 142 result.addAll(result2); 143 } 144 } else { 145 Set <Object > emitted = new HashSet <Object >(); 146 for (Member member : list1) { 147 evaluator2.setContext(member); 148 final List <Object > result2 = 149 listCalc2.evaluateList(evaluator2); 150 addDistinct(result, result2, emitted); 151 } 152 } 153 } 154 return result; 155 } 156 157 private void addDistinct( 158 List <Object > result, 159 List <Object > result2, 160 Set <Object > emitted) { 161 162 for (Object row : result2) { 163 Object entry = row; 164 if (entry instanceof Member []) { 165 entry = new ArrayHolder<Member>((Member []) entry); 167 } 168 if (emitted.add(entry)) { 169 result.add(row); 170 } 171 } 172 } 173 174 public boolean dependsOn(Dimension dimension) { 175 return anyDependsButFirst(getCalcs(), dimension); 176 } 177 } 178 179 private static class GenerateStringCalcImpl extends AbstractStringCalc { 180 private final ListCalc listCalc; 181 private final StringCalc stringCalc; 182 private final boolean tuple; 183 private final StringCalc sepCalc; 184 185 public GenerateStringCalcImpl( 186 ResolvedFunCall call, 187 ListCalc listCalc, 188 StringCalc stringCalc, 189 boolean tuple, StringCalc sepCalc) { 190 super(call, new Calc[]{listCalc, stringCalc}); 191 this.listCalc = listCalc; 192 this.stringCalc = stringCalc; 193 this.tuple = tuple; 194 this.sepCalc = sepCalc; 195 } 196 197 public String evaluateString(Evaluator evaluator) { 198 StringBuilder buf = new StringBuilder (); 199 int k = 0; 200 if (tuple) { 201 final List <Member[]> list1 = listCalc.evaluateList(evaluator); 202 final Evaluator evaluator2 = evaluator.push(); 203 for (Member[] members : list1) { 204 evaluator2.setContext(members); 205 if (k++ > 0) { 206 String sep = sepCalc.evaluateString(evaluator2); 207 buf.append(sep); 208 } 209 final String result2 = 210 stringCalc.evaluateString(evaluator2); 211 buf.append(result2); 212 } 213 } else { 214 final List <Member> list1 = listCalc.evaluateList(evaluator); 215 final Evaluator evaluator2 = evaluator.push(); 216 for (Member member : list1) { 217 evaluator2.setContext(member); 218 if (k++ > 0) { 219 String sep = sepCalc.evaluateString(evaluator2); 220 buf.append(sep); 221 } 222 final String result2 = 223 stringCalc.evaluateString(evaluator2); 224 buf.append(result2); 225 } 226 } 227 return buf.toString(); 228 } 229 230 public boolean dependsOn(Dimension dimension) { 231 return anyDependsButFirst(getCalcs(), dimension); 232 } 233 } 234 } 235 236 | Popular Tags |