001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java#17 $ 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) 2005-2008 Julian Hyde and others 007 // Copyright (C) 2004-2005 SAS Institute, Inc. 008 // All Rights Reserved. 009 // You must accept the terms of that agreement to use this software. 010 // 011 // sasebb, 16 December, 2004 012 */ 013 package mondrian.olap.fun; 014 015 import java.util.List; 016 import java.util.Collections; 017 018 import mondrian.olap.*; 019 import mondrian.calc.*; 020 import mondrian.calc.impl.AbstractListCalc; 021 import mondrian.mdx.ResolvedFunCall; 022 023 024 /** 025 * Definition of the <code>NonEmptyCrossJoin</code> MDX function. 026 * 027 * @author jhyde 028 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java#17 $ 029 * @since Mar 23, 2006 030 */ 031 public class NonEmptyCrossJoinFunDef extends CrossJoinFunDef { 032 static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver( 033 "NonEmptyCrossJoin", 034 "NonEmptyCrossJoin(<Set1>, <Set2>)", 035 "Returns the cross product of two sets, excluding empty tuples and tuples without associated fact table data.", 036 new String[]{"fxxx"}, 037 NonEmptyCrossJoinFunDef.class); 038 039 public NonEmptyCrossJoinFunDef(FunDef dummyFunDef) { 040 super(dummyFunDef); 041 } 042 043 public Calc compileCall(final ResolvedFunCall call, ExpCompiler compiler) { 044 final ListCalc listCalc1 = compiler.compileList(call.getArg(0)); 045 final ListCalc listCalc2 = compiler.compileList(call.getArg(1)); 046 return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}, false) { 047 public List evaluateList(Evaluator evaluator) { 048 SchemaReader schemaReader = evaluator.getSchemaReader(); 049 evaluator.setNonEmpty(true); 050 NativeEvaluator nativeEvaluator = 051 schemaReader.getNativeSetEvaluator( 052 call.getFunDef(), call.getArgs(), evaluator, this); 053 if (nativeEvaluator != null) { 054 return (List) nativeEvaluator.execute(ResultStyle.LIST); 055 } 056 057 final List list1 = listCalc1.evaluateList(evaluator); 058 if (list1.isEmpty()) { 059 return Collections.EMPTY_LIST; 060 } 061 final List list2 = listCalc2.evaluateList(evaluator); 062 // evaluate the arguments in non empty mode 063 evaluator = evaluator.push(); 064 evaluator.setNonEmpty(true); 065 List<Member[]> result = crossJoin(list1, list2); 066 067 // remove any remaining empty crossings from the result 068 result = nonEmptyList(evaluator, result, call); 069 return result; 070 } 071 072 public boolean dependsOn(Dimension dimension) { 073 if (super.dependsOn(dimension)) { 074 return true; 075 } 076 // Member calculations generate members, which mask the actual 077 // expression from the inherited context. 078 if (listCalc1.getType().usesDimension(dimension, true)) { 079 return false; 080 } 081 if (listCalc2.getType().usesDimension(dimension, true)) { 082 return false; 083 } 084 // The implicit value expression, executed to figure out 085 // whether a given tuple is empty, depends upon all dimensions. 086 return true; 087 } 088 }; 089 } 090 091 } 092 093 // End NonEmptyCrossJoinFunDef.java