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