001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/SetFunDef.java#27 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2002-2002 Kana Software, Inc. 007 // Copyright (C) 2002-2008 Julian Hyde and others 008 // All Rights Reserved. 009 // You must accept the terms of that agreement to use this software. 010 // 011 // jhyde, 3 March, 2002 012 */ 013 package mondrian.olap.fun; 014 015 import mondrian.calc.*; 016 import mondrian.calc.impl.*; 017 import mondrian.mdx.ResolvedFunCall; 018 import mondrian.olap.*; 019 import mondrian.olap.type.*; 020 import mondrian.resource.MondrianResource; 021 import mondrian.util.ConcatenableList; 022 import mondrian.util.FilteredIterableList; 023 024 import java.io.PrintWriter; 025 import java.util.*; 026 027 /** 028 * <code>SetFunDef</code> implements the 'set' function (whose syntax is the 029 * brace operator, <code>{ ... }</code>). 030 * 031 * @author jhyde 032 * @since 3 March, 2002 033 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/SetFunDef.java#27 $ 034 */ 035 public class SetFunDef extends FunDefBase { 036 static final ResolverImpl Resolver = new ResolverImpl(); 037 038 SetFunDef(Resolver resolver, int[] argTypes) { 039 super(resolver, Category.Set, argTypes); 040 } 041 042 public void unparse(Exp[] args, PrintWriter pw) { 043 ExpBase.unparseList(pw, args, "{", ", ", "}"); 044 } 045 046 public Type getResultType(Validator validator, Exp[] args) { 047 // All of the members in {<Member1>[,<MemberI>]...} must have the same 048 // Hierarchy. But if there are no members, we can't derive a 049 // hierarchy. 050 Type type0 = null; 051 if (args.length == 0) { 052 // No members to go on, so we can't guess the hierarchy. 053 type0 = MemberType.Unknown; 054 } else { 055 for (int i = 0; i < args.length; i++) { 056 Exp arg = args[i]; 057 Type type = arg.getType(); 058 type = TypeUtil.toMemberOrTupleType(type); 059 if (i == 0) { 060 type0 = type; 061 } else { 062 if (!TypeUtil.isUnionCompatible(type0, type)) { 063 throw MondrianResource.instance().ArgsMustHaveSameHierarchy.ex(getName()); 064 } 065 } 066 } 067 } 068 return new SetType(type0); 069 } 070 071 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 072 final Exp[] args = call.getArgs(); 073 return new ListSetCalc( 074 call, args, compiler, 075 ResultStyle.LIST_MUTABLELIST); 076 } 077 078 /** 079 * Compiled expression to implement the MDX set function, <code>{ ... 080 * }</code>. 081 * 082 * <p>The set function can contain expressions which yield sets together 083 * with expressions which yield individual members/tuples, provided that 084 * they all have the same type. It automatically removes null members 085 * or partially-null tuples from the list. 086 * 087 * <p>The implementation uses {@link VoidCalc} objects with side-effects 088 * to avoid generating lots of intermediate lists. 089 */ 090 public static class ListSetCalc extends AbstractListCalc { 091 private List result = new ConcatenableList(); 092 private final VoidCalc[] voidCalcs; 093 094 public ListSetCalc( 095 Exp exp, Exp[] args, ExpCompiler compiler, 096 List<ResultStyle> resultStyles) 097 { 098 super(exp, null); 099 voidCalcs = compileSelf(args, compiler, resultStyles); 100 } 101 102 public Calc[] getCalcs() { 103 return voidCalcs; 104 } 105 106 private VoidCalc[] compileSelf(Exp[] args, 107 ExpCompiler compiler, 108 List<ResultStyle> resultStyles) { 109 VoidCalc[] voidCalcs = new VoidCalc[args.length]; 110 for (int i = 0; i < args.length; i++) { 111 voidCalcs[i] = createCalc(args[i], compiler, resultStyles); 112 } 113 return voidCalcs; 114 } 115 116 private VoidCalc createCalc( 117 Exp arg, 118 ExpCompiler compiler, 119 List<ResultStyle> resultStyles) 120 { 121 final Type type = arg.getType(); 122 if (type instanceof SetType) { 123 // TODO use resultStyles 124 final ListCalc listCalc = compiler.compileList(arg); 125 final Type elementType = ((SetType) type).getElementType(); 126 if (elementType instanceof MemberType) { 127 final MemberListCalc memberListCalc = 128 (MemberListCalc) listCalc; 129 return new AbstractVoidCalc(arg, new Calc[] {listCalc}) { 130 public void evaluateVoid(Evaluator evaluator) { 131 final List<Member> memberList = 132 memberListCalc.evaluateMemberList(evaluator); 133 final List<Member> list = 134 new FilteredIterableList<Member>( 135 memberList, 136 new FilteredIterableList.Filter<Member>() { 137 public boolean accept(Member m) { 138 return m != null && !m.isNull(); 139 } 140 } 141 ); 142 result.addAll(list); 143 } 144 145 protected String getName() { 146 return "Sublist"; 147 } 148 }; 149 } else { 150 final TupleListCalc tupleListCalc = 151 (TupleListCalc) listCalc; 152 return new AbstractVoidCalc(arg, new Calc[] {listCalc}) { 153 public void evaluateVoid(Evaluator evaluator) { 154 List<Member[]> list = 155 tupleListCalc.evaluateTupleList(evaluator); 156 // Add only tuples which are not null. Tuples with 157 // any null members are considered null. 158 outer: 159 for (Member[] members : list) { 160 for (Member member : members) { 161 if (member == null || member.isNull()) { 162 continue outer; 163 } 164 } 165 result.add(members); 166 } 167 } 168 169 protected String getName() { 170 return "Sublist"; 171 } 172 }; 173 } 174 } else if (TypeUtil.couldBeMember(type)) { 175 final MemberCalc listCalc = compiler.compileMember(arg); 176 return new AbstractVoidCalc(arg, new Calc[] {listCalc}) { 177 public void evaluateVoid(Evaluator evaluator) { 178 Member member = listCalc.evaluateMember(evaluator); 179 if (member == null || member.isNull()) { 180 return; 181 } 182 result.add(member); 183 } 184 185 protected String getName() { 186 return "Sublist"; 187 } 188 }; 189 } else { 190 final TupleCalc tupleCalc = compiler.compileTuple(arg); 191 return new AbstractVoidCalc(arg, new Calc[] {tupleCalc}) { 192 public void evaluateVoid(Evaluator evaluator) { 193 // Don't add null or partially null tuple to result. 194 Member[] members = tupleCalc.evaluateTuple(evaluator); 195 if (members == null) { 196 return; 197 } 198 assert !tupleContainsNullMember(members); 199 200 result.add(members); 201 } 202 }; 203 } 204 } 205 206 public List evaluateList(final Evaluator evaluator) { 207 this.result = new ConcatenableList(); 208 for (VoidCalc voidCalc : voidCalcs) { 209 voidCalc.evaluateVoid(evaluator); 210 } 211 // REVIEW: What the heck is this code doing? Why is it OK to 212 // ignore IndexOutOfBoundsException and NullPointerException? 213 try { 214 if (result.get(0) instanceof Member) { 215 if (!((Member)result.get(0)).getDimension() 216 .isHighCardinality()) { 217 result.toArray(); 218 } 219 } 220 } catch (IndexOutOfBoundsException iooe) { 221 } catch (NullPointerException npe) { 222 } 223 return result; 224 } 225 } 226 227 public static class IterSetCalc extends AbstractIterCalc { 228 private final IterCalc[] iterCalcs; 229 230 public IterSetCalc( 231 Exp exp, 232 Exp[] args, 233 ExpCompiler compiler, 234 List<ResultStyle> resultStyles) 235 { 236 super(exp, null); 237 iterCalcs = compileSelf(args, compiler, resultStyles); 238 } 239 240 public Calc[] getCalcs() { 241 return iterCalcs; 242 } 243 244 private IterCalc[] compileSelf( 245 Exp[] args, 246 ExpCompiler compiler, 247 List<ResultStyle> resultStyles) 248 { 249 IterCalc[] iterCalcs = new IterCalc[args.length]; 250 for (int i = 0; i < args.length; i++) { 251 iterCalcs[i] = createCalc(args[i], compiler, resultStyles); 252 } 253 return iterCalcs; 254 } 255 256 private IterCalc createCalc( 257 Exp arg, 258 ExpCompiler compiler, 259 List<ResultStyle> resultStyles) 260 { 261 final Type type = arg.getType(); 262 if (type instanceof SetType) { 263 final Calc calc = compiler.compileAs(arg, null, resultStyles); 264 final Type elementType = ((SetType) type).getElementType(); 265 if (elementType instanceof MemberType) { 266 switch (calc.getResultStyle()) { 267 case ITERABLE: 268 return new AbstractIterCalc(arg, new Calc[] {calc}) { 269 private final IterCalc iterCalc = (IterCalc) calc; 270 public Iterable evaluateIterable(Evaluator evaluator) { 271 return iterCalc.evaluateIterable(evaluator); 272 } 273 protected String getName() { 274 return "Sublist"; 275 } 276 }; 277 case LIST: 278 case MUTABLE_LIST: 279 return new AbstractIterCalc(arg, new Calc[] {calc}) { 280 private final MemberListCalc memberListCalc = 281 (MemberListCalc) calc; 282 public Iterable evaluateIterable(Evaluator evaluator) { 283 List<Member> result = new ArrayList<Member>(); 284 List<Member> list = 285 memberListCalc.evaluateMemberList(evaluator); 286 // Add only members which are not null. 287 for (Member member : list) { 288 if (member == null || member.isNull()) { 289 continue; 290 } 291 result.add(member); 292 } 293 return result; 294 } 295 protected String getName() { 296 return "Sublist"; 297 } 298 }; 299 } 300 throw ResultStyleException.generateBadType( 301 ResultStyle.ITERABLE_LIST_MUTABLELIST, 302 calc.getResultStyle()); 303 } else { 304 switch (calc.getResultStyle()) { 305 case ITERABLE: 306 return new AbstractIterCalc(arg, new Calc[] {calc}) { 307 private final IterCalc iterCalc = (IterCalc) calc; 308 public Iterable evaluateIterable(Evaluator evaluator) { 309 return iterCalc.evaluateIterable(evaluator); 310 } 311 protected String getName() { 312 return "Sublist"; 313 } 314 }; 315 case LIST: 316 case MUTABLE_LIST: 317 return new AbstractIterCalc(arg, new Calc[] {calc}) { 318 private final TupleListCalc tupleListCalc = 319 (TupleListCalc) calc; 320 321 public Iterable evaluateIterable(Evaluator evaluator) { 322 return evaluateTupleIterable(evaluator); 323 } 324 325 public Iterable<Member[]> evaluateTupleIterable( 326 Evaluator evaluator) 327 { 328 List<Member[]> result = 329 new ArrayList<Member[]>(); 330 List<Member[]> list = 331 tupleListCalc.evaluateTupleList(evaluator); 332 // Add only tuples which are not null. Tuples with 333 // any null members are considered null. 334 list: 335 for (Member[] members : list) { 336 for (Member member : members) { 337 if (member == null || member.isNull()) { 338 continue list; 339 } 340 } 341 result.add(members); 342 } 343 return result; 344 } 345 346 protected String getName() { 347 return "Sublist"; 348 } 349 }; 350 } 351 throw ResultStyleException.generateBadType( 352 ResultStyle.ITERABLE_LIST_MUTABLELIST, 353 calc.getResultStyle()); 354 } 355 } else if (TypeUtil.couldBeMember(type)) { 356 final MemberCalc memberCalc = compiler.compileMember(arg); 357 final ResolvedFunCall call = wrapAsSet(arg); 358 return new AbstractIterCalc(call, new Calc[] {memberCalc}) { 359 public Iterable evaluateIterable(Evaluator evaluator) { 360 final Member member = 361 memberCalc.evaluateMember(evaluator); 362 return new Iterable<Member>() { 363 public Iterator<Member> iterator() { 364 return new Iterator<Member>() { 365 private Member m = member; 366 public boolean hasNext() { 367 return (m != null); 368 } 369 public Member next() { 370 try { 371 return m; 372 } finally { 373 m = null; 374 } 375 } 376 public void remove() { 377 throw new UnsupportedOperationException("remove"); 378 } 379 }; 380 } 381 }; 382 } 383 protected String getName() { 384 return "Sublist"; 385 } 386 }; 387 } else { 388 final TupleCalc tupleCalc = compiler.compileTuple(arg); 389 final ResolvedFunCall call = wrapAsSet(arg); 390 return new AbstractIterCalc(call, new Calc[] {tupleCalc}) { 391 public Iterable evaluateIterable(Evaluator evaluator) { 392 final Member[] members = tupleCalc.evaluateTuple(evaluator); 393 return new Iterable<Member[]>() { 394 public Iterator<Member[]> iterator() { 395 return new Iterator<Member[]>() { 396 private Member[] m = members; 397 public boolean hasNext() { 398 return (m != null); 399 } 400 public Member[] next() { 401 try { 402 return m; 403 } finally { 404 m = null; 405 } 406 } 407 public void remove() { 408 throw new UnsupportedOperationException("remove"); 409 } 410 }; 411 } 412 }; 413 } 414 protected String getName() { 415 return "Sublist"; 416 } 417 }; 418 } 419 } 420 421 private ResolvedFunCall wrapAsSet(Exp arg) { 422 return new ResolvedFunCall( 423 new SetFunDef(Resolver, new int[] {arg.getCategory()}), 424 new Exp[] {arg}, 425 new SetType(arg.getType())); 426 } 427 428 public Iterable evaluateIterable(final Evaluator evaluator) { 429 return new Iterable<Member>() { 430 public Iterator<Member> iterator() { 431 return new Iterator<Member>() { 432 int index = 0; 433 Iterator<Member> currentIterator = null; 434 Member member = null; 435 public boolean hasNext() { 436 if (member != null) { 437 return true; 438 } 439 if (currentIterator == null) { 440 if (index >= iterCalcs.length) { 441 return false; 442 } 443 IterCalc iterCalc = iterCalcs[index++]; 444 Iterable<Member> iter = 445 iterCalc.evaluateMemberIterable(evaluator); 446 currentIterator = iter.iterator(); 447 } 448 while (true) { 449 boolean b = currentIterator.hasNext(); 450 while (! b) { 451 if (index >= iterCalcs.length) { 452 return false; 453 } 454 IterCalc iterCalc = iterCalcs[index++]; 455 Iterable<Member> iter = 456 iterCalc.evaluateMemberIterable(evaluator); 457 currentIterator = iter.iterator(); 458 b = currentIterator.hasNext(); 459 } 460 member = currentIterator.next(); 461 if (member != null) { 462 break; 463 } 464 } 465 return true; 466 } 467 public Member next() { 468 try { 469 return member; 470 } finally { 471 member = null; 472 } 473 } 474 public void remove() { 475 throw new UnsupportedOperationException("remove"); 476 } 477 }; 478 } 479 }; 480 } 481 } 482 483 private static class ResolverImpl extends ResolverBase { 484 public ResolverImpl() { 485 super( 486 "{}", 487 "{<Member> [, <Member>...]}", 488 "Brace operator constructs a set.", 489 Syntax.Braces); 490 } 491 492 public FunDef resolve( 493 Exp[] args, Validator validator, int[] conversionCount) { 494 int[] parameterTypes = new int[args.length]; 495 for (int i = 0; i < args.length; i++) { 496 if (validator.canConvert( 497 args[i], Category.Member, conversionCount)) { 498 parameterTypes[i] = Category.Member; 499 continue; 500 } 501 if (validator.canConvert( 502 args[i], Category.Set, conversionCount)) { 503 parameterTypes[i] = Category.Set; 504 continue; 505 } 506 if (validator.canConvert( 507 args[i], Category.Tuple, conversionCount)) { 508 parameterTypes[i] = Category.Tuple; 509 continue; 510 } 511 return null; 512 } 513 return new SetFunDef(this, parameterTypes); 514 } 515 } 516 } 517 518 // End SetFunDef.java