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.StringCalc; 17 import mondrian.calc.impl.AbstractListCalc; 18 import mondrian.mdx.ResolvedFunCall; 19 import mondrian.mdx.DimensionExpr; 20 import mondrian.mdx.HierarchyExpr; 21 import mondrian.resource.MondrianResource; 22 23 import java.util.ArrayList ; 24 import java.util.List ; 25 26 33 class StrToSetFunDef extends FunDefBase { 34 static final ResolverImpl Resolver = new ResolverImpl(); 35 36 private StrToSetFunDef(int[] parameterTypes) { 37 super("StrToSet", "<Set> StrToSet(<String>[, <Dimension>...])", 38 "Constructs a set from a string expression.", 39 Syntax.Function, Category.Set, parameterTypes); 40 } 41 42 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 43 final StringCalc stringCalc = compiler.compileString(call.getArg(0)); 44 SetType type = (SetType) call.getType(); 45 Type elementType = type.getElementType(); 46 if (elementType instanceof MemberType) { 47 final Hierarchy hierarchy = elementType.getHierarchy(); 48 return new AbstractListCalc(call, new Calc[] {stringCalc}) { 49 public List evaluateList(Evaluator evaluator) { 50 String string = stringCalc.evaluateString(evaluator); 51 return parseMemberList(evaluator, string, hierarchy); 52 } 53 }; 54 } else { 55 TupleType tupleType = (TupleType) elementType; 56 final Hierarchy[] hierarchies = 57 new Hierarchy[tupleType.elementTypes.length]; 58 for (int i = 0; i < tupleType.elementTypes.length; i++) { 59 hierarchies[i] = tupleType.elementTypes[i].getHierarchy(); 60 } 61 return new AbstractListCalc(call, new Calc[] {stringCalc}) { 62 public List evaluateList(Evaluator evaluator) { 63 String string = stringCalc.evaluateString(evaluator); 64 return parseTupleList(evaluator, string, hierarchies); 65 } 66 }; 67 } 68 } 69 70 private static List <Member[]> parseTupleList( 71 Evaluator evaluator, 72 String string, 73 Hierarchy[] hierarchies) 74 { 75 List <Member[]> tupleList = new ArrayList <Member[]>(); 76 Member[] members = new Member[hierarchies.length]; 77 int i = 0; 78 char c; 79 while ((c = string.charAt(i++)) == ' ') { 80 } 81 if (c != '{') { 82 throw fail(string, i, "{"); 83 } 84 while (true) { 85 i = parseTuple(evaluator, string, i, members, hierarchies); 86 tupleList.add(members.clone()); 87 while ((c = string.charAt(i++)) == ' ') { 88 } 89 if (c == ',') { 90 } else if (c == '}') { 92 return tupleList; 94 } else { 95 throw fail(string, i, ", or }"); 96 } 97 } 98 } 99 100 112 static int parseTuple( 113 Evaluator evaluator, 114 String string, 115 int i, 116 Member[] members, 117 Hierarchy[] hierarchies) 118 { 119 char c; 120 while ((c = string.charAt(i++)) == ' ') { 121 } 122 if (c != '(') { 123 throw fail(string, i, "("); 124 } 125 int j = 0; 126 while (true) { 127 i = parseMember(evaluator, string, i, members, hierarchies, j); 128 while ((c = string.charAt(i++)) == ' ') { 129 } 130 ++j; 131 if (j < hierarchies.length) { 132 if (c == ',') { 133 } else if (c == ')') { 135 throw Util.newInternal("too few members"); 137 } else { 138 } 139 } else { 140 if (c == ')') { 141 break; 142 } else { 143 throw Util.newInternal("expected ')"); 144 } 145 } 146 } 147 return i; 148 } 149 150 private static List <Member> parseMemberList( 151 Evaluator evaluator, 152 String string, 153 Hierarchy hierarchy) 154 { 155 Hierarchy[] hierarchies = new Hierarchy[] {hierarchy}; 156 List <Member> memberList = new ArrayList <Member>(); 157 Member[] members = {null}; 158 int i = 0; 159 char c; 160 while ((c = string.charAt(i++)) == ' ') { 161 } 162 if (c != '{') { 163 throw fail(string, i, "{"); 164 } 165 while (true) { 166 i = parseMember(evaluator, string, i, members, hierarchies, 0); 167 memberList.add(members[0]); 168 while ((c = string.charAt(i++)) == ' ') { 169 } 170 if (c == ',') { 171 } else if (c == '}') { 173 return memberList; 175 } else { 176 throw fail(string, i, ", or }"); 177 } 178 } 179 } 180 181 private static final int BEFORE_SEG = 0; 183 private static final int IN_BRACKET_SEG = 1; 184 private static final int AFTER_SEG = 2; 185 private static final int IN_SEG = 3; 186 187 static int parseMember( 188 Evaluator evaluator, 189 String string, 190 int i, 191 Member[] members, 192 Hierarchy[] hierarchies, 193 int j) 194 { 195 int k = string.length(); 196 List <String > nameList = new ArrayList <String >(); 197 int state = BEFORE_SEG; 198 int start = 0; 199 char c; 200 201 loop: 202 while (i < k) { 203 switch (state) { 204 case BEFORE_SEG: 205 c = string.charAt(i); 206 switch (c) { 207 case '[': 208 ++i; 209 start = i; 210 state = IN_BRACKET_SEG; 211 break; 212 213 case ' ': 214 ++i; 216 break; 217 218 case ',': 219 case '}': 220 break loop; 221 222 case '.': 223 throw Util.newInternal("unexpected: '.'"); 225 226 default: 227 state = IN_SEG; 229 start = i; 230 break; 231 } 232 break; 233 234 case IN_SEG: 235 c = string.charAt(i); 236 switch (c) { 237 case '.': 238 nameList.add(string.substring(start, i)); 239 state = BEFORE_SEG; 240 ++i; 241 default: 242 ++i; 243 } 244 break; 245 246 case IN_BRACKET_SEG: 247 c = string.charAt(i); 248 switch (c) { 249 case ']': 250 nameList.add(string.substring(start, i)); 251 ++i; 252 state = AFTER_SEG; 253 break; 254 255 default: 256 ++i; 258 } 259 break; 260 261 case AFTER_SEG: 262 c = string.charAt(i); 263 switch (c) { 264 case ' ': 265 ++i; 268 break; 269 case '.': 270 state = BEFORE_SEG; 271 ++i; 272 break; 273 274 default: 275 break loop; 278 } 279 break; 280 281 default: 282 throw Util.newInternal("unexpected state: " + state); 283 } 284 } 285 286 final String [] names = nameList.toArray(new String [nameList.size()]); 288 Member member = 289 (Member) 290 Util.lookupCompound( 291 evaluator.getSchemaReader(), 292 evaluator.getCube(), 293 names, true, Category.Member); 294 members[j] = member; 295 if (member.getHierarchy() != hierarchies[j]) { 296 throw Util.newInternal("member is of wrong hierarchy"); 298 } 299 return i; 300 } 301 302 private static RuntimeException fail(String string, int i, String expecting) { 303 throw Util.newInternal("expected '" + expecting + "' at position " + i + " in '" + string + "'"); 304 } 305 306 public Exp createCall(Validator validator, Exp[] args) { 307 final int argCount = args.length; 308 if (argCount <= 1) { 309 throw MondrianResource.instance().MdxFuncArgumentsNum.ex(getName()); 310 } 311 for (int i = 1; i < argCount; i++) { 312 final Exp arg = args[i]; 313 if (arg instanceof DimensionExpr) { 314 DimensionExpr dimensionExpr = (DimensionExpr) arg; 317 Dimension dimension = dimensionExpr.getDimension(); 318 args[i] = new HierarchyExpr(dimension.getHierarchy()); 319 } else if (arg instanceof HierarchyExpr) { 320 } else { 322 throw MondrianResource.instance().MdxFuncNotHier.ex( 323 i + 1, getName()); 324 } 325 } 326 return super.createCall(validator, args); 327 } 328 329 public Type getResultType(Validator validator, Exp[] args) { 330 switch (args.length) { 331 case 1: 332 return new SetType(null); 335 336 case 2: { 337 final Type argType = args[1].getType(); 338 return new SetType( 339 new MemberType( 340 argType.getDimension(), 341 argType.getHierarchy(), 342 argType.getLevel(), 343 null)); 344 } 345 346 default: { 347 final List <Type> list = new ArrayList <Type>(); 354 for (int i = 1; i < args.length; i++) { 355 Exp arg = args[i]; 356 final Type argType = arg.getType(); 357 list.add( 358 new MemberType( 359 argType.getDimension(), 360 argType.getHierarchy(), 361 argType.getLevel(), 362 null) 363 ); 364 } 365 final Type[] types = list.toArray(new Type[list.size()]); 366 return new SetType(new TupleType(types)); 367 } 368 } 369 } 370 371 private static class ResolverImpl extends ResolverBase { 372 ResolverImpl() { 373 super( 374 "StrToSet", 375 "StrToSet(<String Expression>)", 376 "Constructs a set from a string expression.", 377 Syntax.Function); 378 } 379 380 public FunDef resolve( 381 Exp[] args, Validator validator, int[] conversionCount) { 382 if (args.length < 1) { 383 return null; 384 } 385 Type type = args[0].getType(); 386 if (!(type instanceof StringType)) { 387 return null; 388 } 389 for (int i = 1; i < args.length; i++) { 390 Exp exp = args[i]; 391 if (!(exp instanceof DimensionExpr)) { 392 return null; 393 } 394 } 395 int[] argTypes = new int[args.length]; 396 argTypes[0] = Category.String; 397 for (int i = 1; i < argTypes.length; i++) { 398 argTypes[i] = Category.Hierarchy; 399 } 400 return new StrToSetFunDef(argTypes); 401 } 402 403 public FunDef getFunDef() { 404 return new StrToSetFunDef(new int[] {Category.String}); 405 } 406 } 407 } 408 409 | Popular Tags |