001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/FilterFunDef.java#12 $ 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) 2006-2007 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.olap.fun; 011 012 import mondrian.calc.*; 013 import mondrian.calc.impl.AbstractListCalc; 014 import mondrian.calc.impl.AbstractIterCalc; 015 import mondrian.mdx.ResolvedFunCall; 016 import mondrian.olap.type.SetType; 017 import mondrian.olap.type.MemberType; 018 import mondrian.olap.*; 019 020 import java.util.List; 021 import java.util.ArrayList; 022 import java.util.Iterator; 023 024 /** 025 * Definition of the <code>Filter</code> MDX function. 026 * 027 * <p>Syntax: 028 * <blockquote><code>Filter(<Set>, <Search Condition>)</code></blockquote> 029 * 030 * 031 * @author jhyde 032 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/FilterFunDef.java#12 $ 033 * @since Mar 23, 2006 034 */ 035 class FilterFunDef extends FunDefBase { 036 static final FilterFunDef instance = new FilterFunDef(); 037 038 private FilterFunDef() { 039 super( 040 "Filter", 041 "Returns the set resulting from filtering a set based on a search condition.", 042 "fxxb"); 043 } 044 045 public Calc compileCall(final ResolvedFunCall call, ExpCompiler compiler) { 046 // What is the desired return type? 047 for (ResultStyle r : compiler.getAcceptableResultStyles()) { 048 switch (r) { 049 case ITERABLE: 050 case ANY: 051 // Consumer wants ITERABLE or ANY 052 return compileCallIterable(call, compiler); 053 case MUTABLE_LIST: 054 case LIST: 055 // Consumer wants MUTABLE_LIST or LIST 056 return compileCallList(call, compiler); 057 } 058 } 059 throw ResultStyleException.generate( 060 ResultStyle.ITERABLE_LIST_MUTABLELIST_ANY, 061 compiler.getAcceptableResultStyles()); 062 } 063 064 065 /** 066 * Returns an IterCalc. 067 * 068 * <p>Here we would like to get either a IterCalc or ListCalc (mutable) 069 * from the inner expression. For the IterCalc, its Iterator 070 * can be wrapped with another Iterator that filters each element. 071 * For the mutable list, remove all members that are filtered. 072 * 073 * @param call Call 074 * @param compiler Compiler 075 * @return Implementation of this function call in the Iterable result style 076 */ 077 protected IterCalc compileCallIterable( 078 final ResolvedFunCall call, 079 ExpCompiler compiler) 080 { 081 // want iterable, mutable list or immutable list in that order 082 Calc imlcalc = compiler.compileAs(call.getArg(0), 083 null, ResultStyle.ITERABLE_LIST_MUTABLELIST); 084 BooleanCalc bcalc = compiler.compileBoolean(call.getArg(1)); 085 Calc[] calcs = new Calc[] {imlcalc, bcalc}; 086 087 // check returned calc ResultStyles 088 checkIterListResultStyles(imlcalc); 089 090 if (((SetType) imlcalc.getType()).getElementType() instanceof MemberType) { 091 if (imlcalc.getResultStyle() == ResultStyle.ITERABLE) { 092 return new IterMemberIterCalc(call, calcs); 093 } else if (imlcalc.getResultStyle() == ResultStyle.LIST) { 094 return new ImMutableMemberIterCalc(call, calcs); 095 } else { 096 return new MutableMemberIterCalc(call, calcs); 097 } 098 099 } else { 100 101 if (imlcalc.getResultStyle() == ResultStyle.ITERABLE) { 102 return new IterMemberArrayIterCalc(call, calcs); 103 } else if (imlcalc.getResultStyle() == ResultStyle.LIST) { 104 return new ImMutableMemberArrayIterCalc(call, calcs); 105 } else { 106 return new MutableMemberArrayIterCalc(call, calcs); 107 } 108 } 109 } 110 111 private static abstract class BaseIterCalc extends AbstractIterCalc { 112 protected BaseIterCalc(ResolvedFunCall call, Calc[] calcs) { 113 super(call, calcs); 114 } 115 public Iterable evaluateIterable(Evaluator evaluator) { 116 ResolvedFunCall call = (ResolvedFunCall) exp; 117 // Use a native evaluator, if more efficient. 118 // TODO: Figure this out at compile time. 119 SchemaReader schemaReader = evaluator.getSchemaReader(); 120 NativeEvaluator nativeEvaluator = 121 schemaReader.getNativeSetEvaluator( 122 call.getFunDef(), call.getArgs(), evaluator, this); 123 if (nativeEvaluator != null) { 124 return (Iterable) nativeEvaluator.execute( 125 ResultStyle.ITERABLE); 126 } else { 127 return makeIterable(evaluator); 128 } 129 } 130 protected abstract Iterable makeIterable(Evaluator evaluator); 131 132 public boolean dependsOn(Dimension dimension) { 133 return anyDependsButFirst(getCalcs(), dimension); 134 } 135 } 136 // 137 // Member Iter Calcs 138 // 139 private static class MutableMemberIterCalc extends BaseIterCalc { 140 MutableMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 141 super(call, calcs); 142 } 143 protected Iterable makeIterable(Evaluator evaluator) { 144 Calc[] calcs = getCalcs(); 145 ListCalc lcalc = (ListCalc) calcs[0]; 146 BooleanCalc bcalc = (BooleanCalc) calcs[1]; 147 148 final Evaluator evaluator2 = evaluator.push(); 149 List members = lcalc.evaluateList(evaluator); 150 151 Iterator it = members.iterator(); 152 while (it.hasNext()) { 153 Member member = (Member) it.next(); 154 evaluator2.setContext(member); 155 if (! bcalc.evaluateBoolean(evaluator2)) { 156 it.remove(); 157 } 158 } 159 return members; 160 } 161 } 162 private static class ImMutableMemberIterCalc extends BaseIterCalc { 163 ImMutableMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 164 super(call, calcs); 165 } 166 protected Iterable makeIterable(Evaluator evaluator) { 167 Calc[] calcs = getCalcs(); 168 ListCalc lcalc = (ListCalc) calcs[0]; 169 BooleanCalc bcalc = (BooleanCalc) calcs[1]; 170 171 final Evaluator evaluator2 = evaluator.push(); 172 List<Member> members = lcalc.evaluateList(evaluator); 173 174 // Not mutable, must create new list 175 List<Member> result = new ArrayList<Member>(); 176 for (int i = 0, count = members.size(); i < count; i++) { 177 Member member = members.get(i); 178 evaluator2.setContext(member); 179 if (bcalc.evaluateBoolean(evaluator2)) { 180 result.add(member); 181 } 182 } 183 return result; 184 } 185 } 186 private static class IterMemberIterCalc extends BaseIterCalc { 187 IterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) { 188 super(call, calcs); 189 } 190 protected Iterable makeIterable(Evaluator evaluator) { 191 Calc[] calcs = getCalcs(); 192 IterCalc icalc = (IterCalc) calcs[0]; 193 final BooleanCalc bcalc = (BooleanCalc) calcs[1]; 194 195 final Evaluator evaluator2 = evaluator.push(); 196 // This does dynamics, just in time, 197 // as needed filtering 198 final Iterable<Member> iter = icalc.evaluateIterable(evaluator); 199 200 return new Iterable<Member>() { 201 public Iterator<Member> iterator() { 202 return new Iterator<Member>() { 203 Iterator<Member> it = iter.iterator(); 204 Member m = null; 205 public boolean hasNext() { 206 if (m != null) { 207 return true; 208 } 209 if (! it.hasNext()) { 210 return false; 211 } 212 this.m = it.next(); 213 evaluator2.setContext(this.m); 214 while (! bcalc.evaluateBoolean(evaluator2)) { 215 if (! it.hasNext()) { 216 return false; 217 } 218 this.m = it.next(); 219 evaluator2.setContext(this.m); 220 } 221 return true; 222 } 223 public Member next() { 224 try { 225 return this.m; 226 } finally { 227 this.m = null; 228 } 229 } 230 public void remove() { 231 throw new UnsupportedOperationException("remove"); 232 } 233 }; 234 } 235 }; 236 } 237 } 238 239 // 240 // Member[] Iter Calcs 241 // 242 private static class MutableMemberArrayIterCalc extends BaseIterCalc { 243 MutableMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 244 super(call, calcs); 245 } 246 protected Iterable makeIterable(Evaluator evaluator) { 247 Calc[] calcs = getCalcs(); 248 ListCalc lcalc = (ListCalc) calcs[0]; 249 BooleanCalc bcalc = (BooleanCalc) calcs[1]; 250 251 final Evaluator evaluator2 = evaluator.push(); 252 List members = lcalc.evaluateList(evaluator); 253 254 Iterator it = members.iterator(); 255 while (it.hasNext()) { 256 Member[] member = (Member[]) it.next(); 257 evaluator2.setContext(member); 258 if (! bcalc.evaluateBoolean(evaluator2)) { 259 it.remove(); 260 } 261 } 262 return members; 263 } 264 } 265 private static class ImMutableMemberArrayIterCalc extends BaseIterCalc { 266 ImMutableMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 267 super(call, calcs); 268 } 269 protected Iterable makeIterable(Evaluator evaluator) { 270 Calc[] calcs = getCalcs(); 271 ListCalc lcalc = (ListCalc) calcs[0]; 272 BooleanCalc bcalc = (BooleanCalc) calcs[1]; 273 274 final Evaluator evaluator2 = evaluator.push(); 275 List<Member[]> members = lcalc.evaluateList(evaluator); 276 277 // Not mutable, must create new list 278 List<Member[]> result = new ArrayList<Member[]>(); 279 for (int i = 0, count = members.size(); i < count; i++) { 280 Member[] member = members.get(i); 281 evaluator2.setContext(member); 282 if (bcalc.evaluateBoolean(evaluator2)) { 283 result.add(member); 284 } 285 } 286 return result; 287 } 288 } 289 private static class IterMemberArrayIterCalc extends BaseIterCalc { 290 IterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) { 291 super(call, calcs); 292 } 293 protected Iterable makeIterable(Evaluator evaluator) { 294 Calc[] calcs = getCalcs(); 295 IterCalc icalc = (IterCalc) calcs[0]; 296 final BooleanCalc bcalc = (BooleanCalc) calcs[1]; 297 298 final Evaluator evaluator2 = evaluator.push(); 299 300 // This does dynamics, just in time, 301 // as needed filtering 302 final Iterable<Member[]> iter = icalc.evaluateIterable(evaluator); 303 return new Iterable<Member[]>() { 304 public Iterator<Member[]> iterator() { 305 return new Iterator<Member[]>() { 306 Iterator<Member[]> it = iter.iterator(); 307 Member[] m = null; 308 public boolean hasNext() { 309 if (m != null) { 310 return true; 311 } 312 if (! it.hasNext()) { 313 return false; 314 } 315 this.m = it.next(); 316 evaluator2.setContext(this.m); 317 while (! bcalc.evaluateBoolean(evaluator2)) { 318 if (! it.hasNext()) { 319 return false; 320 } 321 this.m = it.next(); 322 evaluator2.setContext(this.m); 323 } 324 return true; 325 } 326 public Member[] next() { 327 try { 328 return this.m; 329 } finally { 330 this.m = null; 331 } 332 } 333 public void remove() { 334 throw new UnsupportedOperationException("remove"); 335 } 336 }; 337 } 338 }; 339 } 340 } 341 342 343 /** 344 * Returns a ListCalc. 345 * 346 * @param call Call 347 * @param compiler Compiler 348 * @return Implementation of this function call in the List result style 349 */ 350 protected ListCalc compileCallList( 351 final ResolvedFunCall call, 352 ExpCompiler compiler) 353 { 354 Calc ilcalc = compiler.compileAs( 355 call.getArg(0), 356 null, ResultStyle.MUTABLELIST_LIST); 357 BooleanCalc bcalc = compiler.compileBoolean(call.getArg(1)); 358 Calc[] calcs = new Calc[] {ilcalc, bcalc}; 359 360 // Note that all of the ListCalc's return will be mutable 361 if (((SetType) ilcalc.getType()).getElementType() instanceof MemberType) { 362 switch (ilcalc.getResultStyle()) { 363 case LIST: 364 return new ImMutableMemberListCalc(call, calcs); 365 case MUTABLE_LIST: 366 return new MutableMemberListCalc(call, calcs); 367 } 368 throw ResultStyleException.generateBadType( 369 ResultStyle.MUTABLELIST_LIST, 370 ilcalc.getResultStyle()); 371 372 } else { 373 374 switch (ilcalc.getResultStyle()) { 375 case LIST: 376 return new ImMutableMemberArrayListCalc(call, calcs); 377 case MUTABLE_LIST: 378 return new MutableMemberArrayListCalc(call, calcs); 379 } 380 throw ResultStyleException.generateBadType( 381 ResultStyle.MUTABLELIST_LIST, 382 ilcalc.getResultStyle()); 383 } 384 } 385 386 private static abstract class BaseListCalc extends AbstractListCalc { 387 protected BaseListCalc(ResolvedFunCall call, Calc[] calcs) { 388 super(call, calcs); 389 } 390 public List evaluateList(Evaluator evaluator) { 391 ResolvedFunCall call = (ResolvedFunCall) exp; 392 // Use a native evaluator, if more efficient. 393 // TODO: Figure this out at compile time. 394 SchemaReader schemaReader = evaluator.getSchemaReader(); 395 NativeEvaluator nativeEvaluator = 396 schemaReader.getNativeSetEvaluator( 397 call.getFunDef(), call.getArgs(), evaluator, this); 398 if (nativeEvaluator != null) { 399 return (List) nativeEvaluator.execute( 400 ResultStyle.ITERABLE); 401 // return (List) nativeEvaluator.execute( 402 // ResultStyle.MUTABLE_LIST); 403 } else { 404 return makeList(evaluator); 405 } 406 } 407 protected abstract List makeList(Evaluator evaluator); 408 409 public boolean dependsOn(Dimension dimension) { 410 return anyDependsButFirst(getCalcs(), dimension); 411 } 412 } 413 // 414 // Member List Calcs 415 // 416 private static class MutableMemberListCalc extends BaseListCalc { 417 MutableMemberListCalc(ResolvedFunCall call, Calc[] calcs) { 418 super(call, calcs); 419 } 420 protected List makeList(Evaluator evaluator) { 421 Calc[] calcs = getCalcs(); 422 ListCalc lcalc = (ListCalc) calcs[0]; 423 BooleanCalc bcalc = (BooleanCalc) calcs[1]; 424 425 final Evaluator evaluator2 = evaluator.push(); 426 List members = lcalc.evaluateList(evaluator); 427 428 Iterator it = members.iterator(); 429 while (it.hasNext()) { 430 Member member = (Member) it.next(); 431 evaluator2.setContext(member); 432 if (! bcalc.evaluateBoolean(evaluator2)) { 433 it.remove(); 434 } 435 } 436 return members; 437 } 438 } 439 private static class ImMutableMemberListCalc extends BaseListCalc { 440 ImMutableMemberListCalc(ResolvedFunCall call, Calc[] calcs) { 441 super(call, calcs); 442 } 443 protected List makeList(Evaluator evaluator) { 444 Calc[] calcs = getCalcs(); 445 ListCalc lcalc = (ListCalc) calcs[0]; 446 BooleanCalc bcalc = (BooleanCalc) calcs[1]; 447 448 final Evaluator evaluator2 = evaluator.push(); 449 List<Member> members = lcalc.evaluateList(evaluator); 450 451 // Not mutable, must create new list 452 List<Member> result = new ArrayList<Member>(); 453 for (int i = 0, count = members.size(); i < count; i++) { 454 Member member = members.get(i); 455 evaluator2.setContext(member); 456 if (bcalc.evaluateBoolean(evaluator2)) { 457 result.add(member); 458 } 459 } 460 return result; 461 } 462 } 463 // 464 // Member[] List Calcs 465 // 466 private static class MutableMemberArrayListCalc extends BaseListCalc { 467 MutableMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) { 468 super(call, calcs); 469 } 470 protected List makeList(Evaluator evaluator) { 471 Calc[] calcs = getCalcs(); 472 ListCalc lcalc = (ListCalc) calcs[0]; 473 BooleanCalc bcalc = (BooleanCalc) calcs[1]; 474 475 final Evaluator evaluator2 = evaluator.push(); 476 List members = lcalc.evaluateList(evaluator); 477 478 Iterator it = members.iterator(); 479 while (it.hasNext()) { 480 Member[] member = (Member[]) it.next(); 481 evaluator2.setContext(member); 482 if (! bcalc.evaluateBoolean(evaluator2)) { 483 it.remove(); 484 } 485 } 486 return members; 487 } 488 } 489 private static class ImMutableMemberArrayListCalc extends BaseListCalc { 490 ImMutableMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) { 491 super(call, calcs); 492 } 493 protected List makeList(Evaluator evaluator) { 494 Calc[] calcs = getCalcs(); 495 ListCalc lcalc = (ListCalc) calcs[0]; 496 BooleanCalc bcalc = (BooleanCalc) calcs[1]; 497 498 final Evaluator evaluator2 = evaluator.push(); 499 List<Member[]> members = lcalc.evaluateList(evaluator); 500 501 // Not mutable, must create new list 502 List<Member[]> result = new ArrayList<Member[]>(); 503 for (int i = 0, count = members.size(); i < count; i++) { 504 Member[] member = members.get(i); 505 evaluator2.setContext(member); 506 if (bcalc.evaluateBoolean(evaluator2)) { 507 result.add(member); 508 } 509 } 510 return result; 511 } 512 } 513 } 514 515 // End FilterFunDef.java