Pentaho Analysis - Mondrian
  1. Pentaho Analysis - Mondrian
  2. MONDRIAN-412

NON EMPTY and Filter() breaking aggregate calculations

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Severe Severe
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None
    • Notice:
      When an issue is open, the "Fix Version/s" field conveys a target, not necessarily a commitment. When an issue is closed, the "Fix Version/s" field conveys the version that the issue was fixed in.

      Description

      Here is a query against FoodMart that asks for stores with above average sales:

      with
      member [Measures].[AvgRevenue] as
      'Avg([Store].[Store Name].Members, [Measures].[Store Sales].Value)'

      select
      {[Measures].[Store Sales], [Measures].[AvgRevenue]} ON COLUMNS,
      Filter([Store].[Store Name].Members, ([Measures].[AvgRevenue] < [Measures].[Store Sales].Value)) ON ROWS

      from [Sales]

      The query works great. However if NON EMPTY is applied to ON ROWS clause, [Measures].[AvgRevenue] starts to return a different value. The value is 45,750.24, which happens to be sales for Store 6. The same value 45,750.24 is returned if I change Avg to Sum, Min or Max.

      If a new member that computes the Avg is defined and not used within a filter clause, its value is NOT changing when NON EMPTY is applied. The query to demonstrate this is:

      with member [Measures].[AvgRevenue] as 'Avg([Store].[Store Name].Members, [Measures].[Store Sales].Value)'
      member [Measures].[AvgRevenueNotUsed] as 'Avg([Store].[Store Name].Members, [Measures].[Store Sales].Value)'
      select {[Measures].[Store Sales], [Measures].[AvgRevenue], [Measures].[AvgRevenueNotUsed]} ON COLUMNS,
      NON EMPTY Filter([Store].[Store Name].Members, ([Measures].[AvgRevenue] < [Measures].[Store Sales].Value)) ON ROWS
      from [Sales]

      The problem is that I need to generate a query that works within JPivot, one of whose buttons introduces NON EMPTY. Any ideas?

      Thanks,

      Milan

        Activity

        Hide
        Mondrian Importer User added a comment -
        {nobody}, 05/09/2008: IP, Artifact Created: 204.50.1.114 |
        {avix}, 10/15/2008: IP, Comment Added: 213.157.10.126 |
        {avix}, 10/15/2008: IP, Comment Added: 213.157.10.126 |
        {jhyde}, 10/15/2008: IP, Comment Added: 64.132.248.34 |
        {jhyde}, 10/15/2008: artifact_group_id, 100 |
        {jhyde}, 10/15/2008: assigned_to, 100 |
        {jhyde}, 01/07/2009: IP, Comment Added: 64.81.57.79 |
        {jhyde}, 01/07/2009: status_id, 1 |
        {jhyde}, 01/07/2009: resolution_id, 100 |
        {jhyde}, 01/07/2009: assigned_to, 312935 |
        {jhyde}, 01/07/2009: close_date, 0
        Show
        Mondrian Importer User added a comment - {nobody}, 05/09/2008: IP, Artifact Created: 204.50.1.114 | {avix}, 10/15/2008: IP, Comment Added: 213.157.10.126 | {avix}, 10/15/2008: IP, Comment Added: 213.157.10.126 | {jhyde}, 10/15/2008: IP, Comment Added: 64.132.248.34 | {jhyde}, 10/15/2008: artifact_group_id, 100 | {jhyde}, 10/15/2008: assigned_to, 100 | {jhyde}, 01/07/2009: IP, Comment Added: 64.81.57.79 | {jhyde}, 01/07/2009: status_id, 1 | {jhyde}, 01/07/2009: resolution_id, 100 | {jhyde}, 01/07/2009: assigned_to, 312935 | {jhyde}, 01/07/2009: close_date, 0
        Hide
        Mondrian Importer User added a comment -
        {avix}, 10/15/2008: I raised the priority to "critical" because I think Mondrian may throw
        exceptions or loop forever, but it should not return wrong results.

        --

        This bug consists of three bugs (I think). I have attached a patch that fixes these bugs (hopefully). The patch is against a mondrian 2.x version (probably the latest JDK-1.4 version). Together with the description below it should be easy to apply the fix against the head version of Mondrian.

        Description of the fixes:


        1. SqlContextConstraint#isValidContext()

        We can only restrict the result if we are in NON EMPTY mode. So I added

                // we can restrict the result in NON EMPTY mode only
                if (!context.isNonEmpty()) {
                    return false;
                }


        2. RolapEvaluator#getExpResultCacheKey()

        The RolapEvaluator caches results that have been computed for an expression. The cache key consideres the members of those dimensions that the expression depends on. In NON EMPTY mode however, the result may depend on any dimension. So I added:

            /**
             * Creates a key which uniquely identifes an expression and its
             * context. The context includes members of dimensions which the
             * expression is dependent upon.
             */
            private Object getExpResultCacheKey(ExpCacheDescriptor descriptor) {
                List key = new ArrayList();
                key.add(descriptor.getExp());
                
                // in NON EMPTY mode the result depends on everything, e.g.
                // "NON EMPTY [Customer].[Name].members" may return different results
                // for 1997-01 and 1997-02
                if (nonEmpty) {
                    for (int i = 0; i < currentMembers.length; i++)
                        key.add(currentMembers[i]);
                    return key;
                }

                ...
                

        3. check all invocations of ListCalc#evaluateList()

        This is the tricky one. The problem is that for a NON EMPTY axis expression the expression and all of its sub expressions are evaluated in NON EMPTY mode. Thats wrong. Lets look at the query excerpt

        NON EMPTY Filter([Store].[Store Name].Members, ([Measures].[AvgRevenue] < [Measures].[Store Sales]))

        Here the Filter() is evaluated in NON EMPTY context. Its OK to evaluate the set expression [Store].[Store Name].Members in NON EMPTY mode too, because the empty stores are removed from the result later anyway. But its not ok to evaluate the condition in NON EMPTY mode.

        During evaluation the Filter() function places one Store after the other into the context and evaluates the condition. Here the condition contains the expression

        Avg([Store].[Store Name].Members, [Measures].[Store Sales])

        If here the [Store].[Store Name].Members argument is evaluated in NON EMPTY mode and there is a particular store in the context, then the sql optimizer will return only that store - no need to return them all. Thats wrong in the context of AVG, we want to compute the average over all stores, so the Filter() has to cancel the NON EMPTY mode when evaluating the condition.

        In general, the NON EMPTY mode has to be cancelled when certain sub expressions are evaluated. I found it difficult to decide for which sub expressions the NON EMPTY mode has to be cancelled. A rule of thumb may be:

        a) when a function returns a set, then its input set argument may be evaluated in NON EMPTY MODE (e.g. Filter, TopCount, CrossJoin)
          
        b) all expressions, that do not return a set may not evaluate their set arguments in NON EMPTY mode (e.g. Aggregate, Avg)

        c) non-set evaluation does not care (e.g. boolean, number, member, tuple)

        But there are exceptions, e.g. Tail(<Set>). Here the set argument has to be evaluated with NON EMPTY cancelled - (I think).

        I added to RolapEvaluator


            public Evaluator push(boolean nonEmpty) {
                final RolapEvaluator evaluator = _push();
                evaluator.setNonEmpty(nonEmpty);
                return evaluator;
            }


        Then I checked all invocations of ListCalc#evaluateList(). For example in AvgFunDef I changed

                    public Object evaluate(Evaluator evaluator) {
                        List memberList = listCalc.evaluateList(evaluator);
                        return avg(evaluator.push(), memberList, calc);
                    }

        to

                    public Object evaluate(Evaluator evaluator) {
                        List memberList = listCalc.evaluateList(evaluator.push(false));
                        return avg(evaluator.push(false), memberList, calc);
                    }


        so the AVG function always evaluates its arguments with NON EMPTY cancelled.

        --

        I leave this bug open until someone (Julian?) reviews this fix and applies it to Mondrian head version - I currently do not have a working Perforce workspace here.

        Andreas
        Show
        Mondrian Importer User added a comment - {avix}, 10/15/2008: I raised the priority to "critical" because I think Mondrian may throw exceptions or loop forever, but it should not return wrong results. -- This bug consists of three bugs (I think). I have attached a patch that fixes these bugs (hopefully). The patch is against a mondrian 2.x version (probably the latest JDK-1.4 version). Together with the description below it should be easy to apply the fix against the head version of Mondrian. Description of the fixes: 1. SqlContextConstraint#isValidContext() We can only restrict the result if we are in NON EMPTY mode. So I added         // we can restrict the result in NON EMPTY mode only         if (!context.isNonEmpty()) {             return false;         } 2. RolapEvaluator#getExpResultCacheKey() The RolapEvaluator caches results that have been computed for an expression. The cache key consideres the members of those dimensions that the expression depends on. In NON EMPTY mode however, the result may depend on any dimension. So I added:     /**      * Creates a key which uniquely identifes an expression and its      * context. The context includes members of dimensions which the      * expression is dependent upon.      */     private Object getExpResultCacheKey(ExpCacheDescriptor descriptor) {         List key = new ArrayList();         key.add(descriptor.getExp());                  // in NON EMPTY mode the result depends on everything, e.g.         // "NON EMPTY [Customer].[Name].members" may return different results         // for 1997-01 and 1997-02         if (nonEmpty) {             for (int i = 0; i < currentMembers.length; i++)                 key.add(currentMembers[i]);             return key;         }         ...          3. check all invocations of ListCalc#evaluateList() This is the tricky one. The problem is that for a NON EMPTY axis expression the expression and all of its sub expressions are evaluated in NON EMPTY mode. Thats wrong. Lets look at the query excerpt NON EMPTY Filter([Store].[Store Name].Members, ([Measures].[AvgRevenue] < [Measures].[Store Sales])) Here the Filter() is evaluated in NON EMPTY context. Its OK to evaluate the set expression [Store].[Store Name].Members in NON EMPTY mode too, because the empty stores are removed from the result later anyway. But its not ok to evaluate the condition in NON EMPTY mode. During evaluation the Filter() function places one Store after the other into the context and evaluates the condition. Here the condition contains the expression Avg([Store].[Store Name].Members, [Measures].[Store Sales]) If here the [Store].[Store Name].Members argument is evaluated in NON EMPTY mode and there is a particular store in the context, then the sql optimizer will return only that store - no need to return them all. Thats wrong in the context of AVG, we want to compute the average over all stores, so the Filter() has to cancel the NON EMPTY mode when evaluating the condition. In general, the NON EMPTY mode has to be cancelled when certain sub expressions are evaluated. I found it difficult to decide for which sub expressions the NON EMPTY mode has to be cancelled. A rule of thumb may be: a) when a function returns a set, then its input set argument may be evaluated in NON EMPTY MODE (e.g. Filter, TopCount, CrossJoin)    b) all expressions, that do not return a set may not evaluate their set arguments in NON EMPTY mode (e.g. Aggregate, Avg) c) non-set evaluation does not care (e.g. boolean, number, member, tuple) But there are exceptions, e.g. Tail(<Set>). Here the set argument has to be evaluated with NON EMPTY cancelled - (I think). I added to RolapEvaluator     public Evaluator push(boolean nonEmpty) {         final RolapEvaluator evaluator = _push();         evaluator.setNonEmpty(nonEmpty);         return evaluator;     } Then I checked all invocations of ListCalc#evaluateList(). For example in AvgFunDef I changed             public Object evaluate(Evaluator evaluator) {                 List memberList = listCalc.evaluateList(evaluator);                 return avg(evaluator.push(), memberList, calc);             } to             public Object evaluate(Evaluator evaluator) {                 List memberList = listCalc.evaluateList(evaluator.push(false));                 return avg(evaluator.push(false), memberList, calc);             } so the AVG function always evaluates its arguments with NON EMPTY cancelled. -- I leave this bug open until someone (Julian?) reviews this fix and applies it to Mondrian head version - I currently do not have a working Perforce workspace here. Andreas
        Hide
        Mondrian Importer User added a comment -
        {avix}, 10/15/2008: Dont know how to attach a file :-( So I paste the patches here


        patch for the source folder:

        Index: src/main/mondrian/olap/fun/LinReg.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/LinReg.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 LinReg.java
        --- src/main/mondrian/olap/fun/LinReg.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/LinReg.java 15 Oct 2008 12:56:56 -0000
        @@ -363,7 +363,7 @@
                     DoubleCalc yCalc,
                     DoubleCalc xCalc,
                     boolean isTuples) {
        - List members = listCalc.evaluateList(evaluator);
        + List members = listCalc.evaluateList(evaluator.push(false));
         
                 evaluator = evaluator.push();
         
        Index: src/main/mondrian/olap/fun/SumFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/SumFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 SumFunDef.java
        --- src/main/mondrian/olap/fun/SumFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/SumFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -48,8 +48,8 @@
                         new ValueCalc(call);
                 return new AbstractDoubleCalc(call, new Calc[] {listCalc, calc}) {
                     public double evaluateDouble(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        - return sumDouble(evaluator.push(), memberList, calc);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
        + return sumDouble(evaluator.push(false), memberList, calc);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/olap/fun/SetItemFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/SetItemFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 SetItemFunDef.java
        --- src/main/mondrian/olap/fun/SetItemFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/SetItemFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -110,7 +110,7 @@
                     if (isString) {
                         return new AbstractTupleCalc(call, calcs) {
                             public Member[] evaluateTuple(Evaluator evaluator) {
        - final List list = listCalc.evaluateList(evaluator);
        + final List list = listCalc.evaluateList(evaluator.push(false));
                                 assert list != null;
                                 String[] results = new String[stringCalcs.length];
                                 for (int i = 0; i < stringCalcs.length; i++) {
        @@ -138,7 +138,7 @@
                     } else {
                         return new AbstractTupleCalc(call, calcs) {
                             public Member[] evaluateTuple(Evaluator evaluator) {
        - final List list = listCalc.evaluateList(evaluator);
        + final List list = listCalc.evaluateList(evaluator.push(false));
                                 assert list != null;
                                 final int index = indexCalc.evaluateInteger(evaluator);
                                 int listSize = list.size();
        @@ -156,7 +156,7 @@
                     if (isString) {
                         return new AbstractMemberCalc(call, calcs) {
                             public Member evaluateMember(Evaluator evaluator) {
        - final List list = listCalc.evaluateList(evaluator);
        + final List list = listCalc.evaluateList(evaluator.push(false));
                                 assert list != null;
                                 final String result =
                                         stringCalcs[0].evaluateString(evaluator);
        @@ -172,7 +172,7 @@
                     } else {
                         return new AbstractMemberCalc(call, calcs) {
                             public Member evaluateMember(Evaluator evaluator) {
        - final List list = listCalc.evaluateList(evaluator);
        + final List list = listCalc.evaluateList(evaluator.push(false));
                                 assert list != null;
                                 final int index = indexCalc.evaluateInteger(evaluator);
                                 int listSize = list.size();
        Index: src/main/mondrian/olap/fun/MedianFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/MedianFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 MedianFunDef.java
        --- src/main/mondrian/olap/fun/MedianFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/MedianFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -48,8 +48,8 @@
                         new ValueCalc(call);
                 return new AbstractCalc(call) {
                     public Object evaluate(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        - return median(evaluator.push(), memberList, calc);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
        + return median(evaluator.push(false), memberList, calc);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/olap/fun/AvgFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/AvgFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 AvgFunDef.java
        --- src/main/mondrian/olap/fun/AvgFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/AvgFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -48,8 +48,8 @@
                         new ValueCalc(call);
                 return new AbstractCalc(call) {
                     public Object evaluate(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        - return avg(evaluator.push(), memberList, calc);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
        + return avg(evaluator.push(false), memberList, calc);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/olap/fun/BuiltinFunTable.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/BuiltinFunTable.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 BuiltinFunTable.java
        --- src/main/mondrian/olap/fun/BuiltinFunTable.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/BuiltinFunTable.java 15 Oct 2008 12:56:56 -0000
        @@ -674,8 +674,8 @@
                         return new AbstractIntegerCalc(call, new Calc[] {memberListCalc}) {
                             public int evaluateInteger(Evaluator evaluator) {
                                 List memberList =
        - memberListCalc.evaluateList(evaluator);
        - return count(evaluator, memberList, true);
        + memberListCalc.evaluateList(evaluator.push(false));
        + return count(evaluator.push(false), memberList, true);
                             }
                         };
                     }
        Index: src/main/mondrian/olap/fun/CorrelationFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/CorrelationFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 CorrelationFunDef.java
        --- src/main/mondrian/olap/fun/CorrelationFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/CorrelationFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -50,8 +50,8 @@
                         new ValueCalc(call);
                 return new AbstractDoubleCalc(call, new Calc[] {listCalc, calc1, calc2}) {
                     public double evaluateDouble(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        - return correlation(evaluator.push(),
        + List memberList = listCalc.evaluateList(evaluator.push(false));
        + return correlation(evaluator.push(false),
                                 memberList, calc1, calc2);
                     }
         
        Index: src/main/mondrian/olap/fun/StdevPFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/StdevPFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 StdevPFunDef.java
        --- src/main/mondrian/olap/fun/StdevPFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/StdevPFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -58,8 +58,8 @@
                         new ValueCalc(call);
                 return new AbstractCalc(call) {
                     public Object evaluate(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        - return stdev(evaluator.push(), memberList, calc, true);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
        + return stdev(evaluator.push(false), memberList, calc, true);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/olap/fun/GenerateFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/GenerateFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 GenerateFunDef.java
        --- src/main/mondrian/olap/fun/GenerateFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/GenerateFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -61,7 +61,7 @@
         
                 return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}) {
                     public List evaluateList(Evaluator evaluator) {
        - final List list1 = listCalc1.evaluateList(evaluator);
        + final List list1 = listCalc1.evaluateList(evaluator.push(false));
                         final Evaluator evaluator2 = evaluator.push();
                         List result = new ArrayList();
                         if (tuple) {
        Index: src/main/mondrian/olap/fun/VarFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/VarFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 VarFunDef.java
        --- src/main/mondrian/olap/fun/VarFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/VarFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -55,8 +55,8 @@
                         new ValueCalc(call);
                 return new AbstractCalc(call) {
                     public Object evaluate(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        - return var(evaluator.push(), memberList, calc, false);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
        + return var(evaluator.push(false), memberList, calc, false);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/olap/fun/CountFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/CountFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 CountFunDef.java
        --- src/main/mondrian/olap/fun/CountFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/CountFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -53,6 +53,7 @@
                 return new AbstractIntegerCalc(
                         call, new Calc[] {memberListCalc}) {
                     public int evaluateInteger(Evaluator evaluator) {
        + evaluator = evaluator.push(false);
                         List memberList =
                                 memberListCalc.evaluateList(evaluator);
                         return count(evaluator, memberList, includeEmpty);
        Index: src/main/mondrian/olap/fun/AggregateFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/AggregateFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 AggregateFunDef.java
        --- src/main/mondrian/olap/fun/AggregateFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/AggregateFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -53,8 +53,8 @@
                         if (rollup == null) {
                             throw newEvalException(null, "Don't know how to rollup aggregator '" + aggregator + "'");
                         }
        - final List list = listCalc.evaluateList(evaluator);
        - return rollup.aggregate(evaluator.push(), list, calc);
        + final List list = listCalc.evaluateList(evaluator.push(false));
        + return rollup.aggregate(evaluator.push(false), list, calc);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/olap/fun/HeadTailFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/HeadTailFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 HeadTailFunDef.java
        --- src/main/mondrian/olap/fun/HeadTailFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/HeadTailFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -62,6 +62,7 @@
                 if (head) {
                     return new AbstractListCalc(call, new Calc[] {listCalc, integerCalc}) {
                         public List evaluateList(Evaluator evaluator) {
        + evaluator = evaluator.push(false);
                             List list = listCalc.evaluateList(evaluator);
                             int count = integerCalc.evaluateInteger(evaluator);
                             return head(count, list);
        @@ -71,6 +72,7 @@
                     return new AbstractListCalc(call, new Calc[] {listCalc, integerCalc}) {
         
                         public List evaluateList(Evaluator evaluator) {
        + evaluator = evaluator.push(false);
                             List list = listCalc.evaluateList(evaluator);
                             int count = integerCalc.evaluateInteger(evaluator);
                             return tail(count, list);
        Index: src/main/mondrian/olap/fun/TopBottomCountFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/TopBottomCountFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 TopBottomCountFunDef.java
        --- src/main/mondrian/olap/fun/TopBottomCountFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/TopBottomCountFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -82,7 +82,7 @@
                         List list = listCalc.evaluateList(evaluator);
                         int n = integerCalc.evaluateInteger(evaluator);
                         if (orderCalc != null) {
        - sort(evaluator.push(), list, orderCalc, top, true);
        + sort(evaluator.push(false), list, orderCalc, top, true);
                         }
                         if (n < list.size()) {
                             list = list.subList(0, n);
        Index: src/main/mondrian/olap/fun/MinMaxFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/MinMaxFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 MinMaxFunDef.java
        --- src/main/mondrian/olap/fun/MinMaxFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/MinMaxFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -58,10 +58,10 @@
                         new ValueCalc(call);
                 return new AbstractCalc(call) {
                     public Object evaluate(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
                         return max ?
        - max(evaluator.push(), memberList, calc) :
        - min(evaluator.push(), memberList, calc);
        + max(evaluator.push(false), memberList, calc) :
        + min(evaluator.push(false), memberList, calc);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/olap/fun/CovarianceFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/CovarianceFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 CovarianceFunDef.java
        --- src/main/mondrian/olap/fun/CovarianceFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/CovarianceFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -60,9 +60,9 @@
                         new ValueCalc(call);
                 return new AbstractCalc(call) {
                     public Object evaluate(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
                         return covariance(
        - evaluator.push(), memberList,
        + evaluator.push(false), memberList,
                                 calc1, calc2, biased);
                     }
         
        Index: src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 NonEmptyCrossJoinFunDef.java
        --- src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -44,14 +44,13 @@
                 final ListCalc listCalc2 = compiler.compileList(call.getArg(1));
                 return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}) {
                     public List evaluateList(Evaluator evaluator) {
        + // evaluate the arguments in non empty mode
        + evaluator = evaluator.push(true);
                         final List list1 = listCalc1.evaluateList(evaluator);
                         if (list1.isEmpty()) {
                             return Collections.EMPTY_LIST;
                         }
                         final List list2 = listCalc2.evaluateList(evaluator);
        - // evaluate the arguments in non empty mode
        - evaluator = evaluator.push();
        - evaluator.setNonEmpty(true);
                         List result = crossJoin(list1, list2, evaluator);
         
                         // remove any remaining empty crossings from the result
        Index: src/main/mondrian/olap/fun/FilterFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/FilterFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 FilterFunDef.java
        --- src/main/mondrian/olap/fun/FilterFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/FilterFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -58,7 +58,7 @@
         
                             List members = listCalc.evaluateList(evaluator);
                             List result = new ArrayList();
        - Evaluator evaluator2 = evaluator.push();
        + Evaluator evaluator2 = evaluator.push(false);
                             for (int i = 0, count = members.size(); i < count; i++) {
                                 Member member = (Member) members.get(i);
                                 evaluator2.setContext(member);
        Index: src/main/mondrian/olap/fun/VarPFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/VarPFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 VarPFunDef.java
        --- src/main/mondrian/olap/fun/VarPFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/VarPFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -56,8 +56,8 @@
                         new ValueCalc(call);
                 return new AbstractCalc(call) {
                     public Object evaluate(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        - return var(evaluator.push(), memberList, calc, true);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
        + return var(evaluator.push(false), memberList, calc, true);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/olap/fun/RankFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/RankFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 RankFunDef.java
        --- src/main/mondrian/olap/fun/RankFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/RankFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -446,7 +446,7 @@
                 public Object evaluate(Evaluator evaluator) {
                     // Construct an array containing the value of the expression
                     // for each member.
        - List members = listCalc.evaluateList(evaluator);
        + List members = listCalc.evaluateList(evaluator.push(false));
                     if (members == null) {
                         return null;
                     }
        Index: src/main/mondrian/olap/fun/StdevFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/StdevFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 StdevFunDef.java
        --- src/main/mondrian/olap/fun/StdevFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/StdevFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -56,8 +56,8 @@
                         new ValueCalc(call);
                 return new AbstractCalc(call) {
                     public Object evaluate(Evaluator evaluator) {
        - List memberList = listCalc.evaluateList(evaluator);
        - return stdev(evaluator.push(), memberList, calc, false);
        + List memberList = listCalc.evaluateList(evaluator.push(false));
        + return stdev(evaluator.push(false), memberList, calc, false);
                     }
         
                     public Calc[] getCalcs() {
        Index: src/main/mondrian/rolap/RolapEvaluator.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/rolap/RolapEvaluator.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 RolapEvaluator.java
        --- src/main/mondrian/rolap/RolapEvaluator.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/rolap/RolapEvaluator.java 15 Oct 2008 12:56:56 -0000
        @@ -237,6 +237,12 @@
                 return evaluator;
             }
         
        + public Evaluator push(boolean nonEmpty) {
        + final RolapEvaluator evaluator = _push();
        + evaluator.setNonEmpty(nonEmpty);
        + return evaluator;
        + }
        +
             public Evaluator push() {
                 return _push();
             }
        @@ -587,6 +593,16 @@
             private Object getExpResultCacheKey(ExpCacheDescriptor descriptor) {
                 List key = new ArrayList();
                 key.add(descriptor.getExp());
        +
        + // in NON EMPTY mode the result depends on everything, e.g.
        + // "NON EMPTY [Customer].[Name].members" may return different results
        + // for 1997-01 and 1997-02
        + if (nonEmpty) {
        + for (int i = 0; i < currentMembers.length; i++)
        + key.add(currentMembers[i]);
        + return key;
        + }
        +
                 int[] dimensionOrdinals = descriptor.getDependentDimensionOrdinals();
                 for (int i = 0; i < dimensionOrdinals.length; i++) {
                     int dimensionOrdinal = dimensionOrdinals[i];
        Index: src/main/mondrian/rolap/SqlContextConstraint.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/rolap/SqlContextConstraint.java,v
        retrieving revision 1.3
        diff -u -r1.3 SqlContextConstraint.java
        --- src/main/mondrian/rolap/SqlContextConstraint.java 28 Nov 2007 09:13:37 -0000 1.3
        +++ src/main/mondrian/rolap/SqlContextConstraint.java 15 Oct 2008 12:56:56 -0000
        @@ -68,6 +68,12 @@
                 if (context == null) {
                     return false;
                 }
        +
        + // we can restrict the result in NON EMPTY mode only
        + if (!context.isNonEmpty()) {
        + return false;
        + }
        +
                 if (disallowVirtualCube) {
                     RolapCube cube = (RolapCube) context.getCube();
                     if (cube.isVirtual()) {
        Index: src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 NthQuartileFunDef.java
        --- src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java 15 Oct 2008 12:56:56 -0000
        @@ -65,8 +65,8 @@
                         new ValueCalc(call);
                 return new AbstractDoubleCalc(call, new Calc[] {listCalc, doubleCalc}) {
                     public double evaluateDouble(Evaluator evaluator) {
        - List members = listCalc.evaluateList(evaluator);
        - return quartile(evaluator.push(), members, doubleCalc, range);
        + List members = listCalc.evaluateList(evaluator.push(false));
        + return quartile(evaluator.push(false), members, doubleCalc, range);
                     }
         
                     public boolean dependsOn(Dimension dimension) {
        Index: src/main/mondrian/olap/Evaluator.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/Evaluator.java,v
        retrieving revision 1.1.1.1
        diff -u -r1.1.1.1 Evaluator.java
        --- src/main/mondrian/olap/Evaluator.java 3 Nov 2006 11:32:15 -0000 1.1.1.1
        +++ src/main/mondrian/olap/Evaluator.java 15 Oct 2008 12:56:56 -0000
        @@ -56,6 +56,11 @@
             Evaluator push(Member member);
         
             /**
        + * Creates a new evaluator with the same state except nonEmpty property.
        + */
        + Evaluator push(boolean nonEmpty);
        +
        + /**
              * Restores previous evaluator.
              */
             Evaluator pop();

        patch for the test folder:

        Index: testsrc/main/mondrian/rolap/NonEmptyTest.java
        ===================================================================
        RCS file: /cvsroot/mondrian-2.2/testsrc/main/mondrian/rolap/NonEmptyTest.java,v
        retrieving revision 1.4
        diff -u -r1.4 NonEmptyTest.java
        --- testsrc/main/mondrian/rolap/NonEmptyTest.java 27 Nov 2007 16:17:31 -0000 1.4
        +++ testsrc/main/mondrian/rolap/NonEmptyTest.java 15 Oct 2008 13:00:06 -0000
        @@ -80,6 +80,51 @@
                   "Row #2: 3,926" + nl
                 );
             }
        +
        + public void testBug1961163() throws Exception {
        + TestContext ctx = TestContext.instance();
        + ctx.assertQueryReturns(
        + "with member [Measures].[AvgRevenue] as 'Avg([Store].[Store Name].Members, [Measures].[Store Sales])' " +
        + "select NON EMPTY {[Measures].[Store Sales], [Measures].[AvgRevenue]} ON COLUMNS, " +
        + "NON EMPTY Filter([Store].[Store Name].Members, ([Measures].[AvgRevenue] < [Measures].[Store Sales])) ON ROWS " +
        + "from [Sales]",
        +
        + "Axis #0:" + nl +
        + "{}" + nl +
        + "Axis #1:" + nl +
        + "{[Measures].[Store Sales]}" + nl +
        + "{[Measures].[AvgRevenue]}" + nl +
        + "Axis #2:" + nl +
        + "{[Store].[All Stores].[USA].[CA].[Beverly Hills].[Store 6]}" + nl +
        + "{[Store].[All Stores].[USA].[CA].[Los Angeles].[Store 7]}" + nl +
        + "{[Store].[All Stores].[USA].[CA].[San Diego].[Store 24]}" + nl +
        + "{[Store].[All Stores].[USA].[OR].[Portland].[Store 11]}" + nl +
        + "{[Store].[All Stores].[USA].[OR].[Salem].[Store 13]}" + nl +
        + "{[Store].[All Stores].[USA].[WA].[Bremerton].[Store 3]}" + nl +
        + "{[Store].[All Stores].[USA].[WA].[Seattle].[Store 15]}" + nl +
        + "{[Store].[All Stores].[USA].[WA].[Spokane].[Store 16]}" + nl +
        + "{[Store].[All Stores].[USA].[WA].[Tacoma].[Store 17]}" + nl +
        + "Row #0: 45,750.24" + nl +
        + "Row #0: 43,479.86" + nl +
        + "Row #1: 54,545.28" + nl +
        + "Row #1: 43,479.86" + nl +
        + "Row #2: 54,431.14" + nl +
        + "Row #2: 43,479.86" + nl +
        + "Row #3: 55,058.79" + nl +
        + "Row #3: 43,479.86" + nl +
        + "Row #4: 87,218.28" + nl +
        + "Row #4: 43,479.86" + nl +
        + "Row #5: 52,896.30" + nl +
        + "Row #5: 43,479.86" + nl +
        + "Row #6: 52,644.07" + nl +
        + "Row #6: 43,479.86" + nl +
        + "Row #7: 49,634.46" + nl +
        + "Row #7: 43,479.86" + nl +
        + "Row #8: 74,843.96" + nl +
        + "Row #8: 43,479.86" + nl
        +
        + );
        + }
         
             public void testTopCountCachingBug() {
               TestContext ctx = TestContext.instance();
        @@ -244,7 +289,7 @@
                         32,
                         18,
                         "select {[Measures].[Store Sales]} ON COLUMNS, "
        - + "Order(Filter(Descendants([Customers].[All Customers].[USA].[CA], [Customers].[Name]), ([Measures].[Store Sales] > 200.0)), [Measures].[Store Sales], DESC) ON ROWS "
        + + "NON EMPTY Order(Filter(Descendants([Customers].[All Customers].[USA].[CA], [Customers].[Name]), ([Measures].[Store Sales] > 200.0)), [Measures].[Store Sales], DESC) ON ROWS "
                                 + "from [Sales] "
                                 + "where ([Time].[1997])");
             }
        @@ -763,7 +808,7 @@
                 TupleConstraint lmc = scf.getLevelMembersConstraint(null);
                 assertNull(smr.mapLevelToMembers.get(nameLevel, lmc));
                 // make sure that NON EMPTY [Customers].[Name].Members IS in cache
        - lmc = scf.getLevelMembersConstraint(context);
        + lmc = scf.getLevelMembersConstraint(context.push(true));
                 List list = smr.mapLevelToMembers.get(nameLevel, lmc);
                 assertNotNull(list);
                 assertEquals(20, list.size());
        @@ -779,7 +824,7 @@
                 assertNull(smr.mapMemberToChildren.get(parent, mcc));
         
                 // lookup NON EMPTY children of [Burlingame] -> yes these are in cache
        - mcc = scf.getMemberChildrenConstraint(context);
        + mcc = scf.getMemberChildrenConstraint(context.push(true));
                 list = smr.mapMemberToChildren.get(parent, mcc);
                 assertNotNull(list);
                 assertTrue(list.contains(member));
        @@ -806,7 +851,7 @@
                 assertNotNull(list);
                 assertEquals(10281, list.size());
                 // make sure that NON EMPTY [Customers].[Name].Members is NOT in cache
        - lmc = scf.getLevelMembersConstraint(context);
        + lmc = scf.getLevelMembersConstraint(context.push(true));
                 assertNull(smr.mapLevelToMembers.get(nameLevel, lmc));
         
                 // make sure that the parent/child for the context are cached
        @@ -822,7 +867,7 @@
                 assertTrue(list.contains(member));
         
                 // lookup NON EMPTY children of [Burlingame] -> not in cache
        - mcc = scf.getMemberChildrenConstraint(context);
        + mcc = scf.getMemberChildrenConstraint(context.push(true));
                 list = smr.mapMemberToChildren.get(parent, mcc);
                 assertNull(list);
             }
        @@ -944,7 +989,7 @@
                 assertNull(smr.mapMemberToChildren.get(burlingame, mcc));
                 // but non empty children is
                 Evaluator evaluator = getEvaluator(result, new int[] { 0, 0});
        - mcc = scf.getMemberChildrenConstraint(evaluator);
        + mcc = scf.getMemberChildrenConstraint(evaluator.push(true));
                 List list = smr.mapMemberToChildren.get(burlingame, mcc);
                 assertNotNull(list);
                 assertTrue(list.contains(peggy));
        Show
        Mondrian Importer User added a comment - {avix}, 10/15/2008: Dont know how to attach a file :-( So I paste the patches here patch for the source folder: Index: src/main/mondrian/olap/fun/LinReg.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/LinReg.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 LinReg.java --- src/main/mondrian/olap/fun/LinReg.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/LinReg.java 15 Oct 2008 12:56:56 -0000 @@ -363,7 +363,7 @@              DoubleCalc yCalc,              DoubleCalc xCalc,              boolean isTuples) { - List members = listCalc.evaluateList(evaluator); + List members = listCalc.evaluateList(evaluator.push(false));            evaluator = evaluator.push();   Index: src/main/mondrian/olap/fun/SumFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/SumFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 SumFunDef.java --- src/main/mondrian/olap/fun/SumFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/SumFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -48,8 +48,8 @@                  new ValueCalc(call);          return new AbstractDoubleCalc(call, new Calc[] {listCalc, calc}) {              public double evaluateDouble(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); - return sumDouble(evaluator.push(), memberList, calc); + List memberList = listCalc.evaluateList(evaluator.push(false)); + return sumDouble(evaluator.push(false), memberList, calc);              }                public Calc[] getCalcs() { Index: src/main/mondrian/olap/fun/SetItemFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/SetItemFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 SetItemFunDef.java --- src/main/mondrian/olap/fun/SetItemFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/SetItemFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -110,7 +110,7 @@              if (isString) {                  return new AbstractTupleCalc(call, calcs) {                      public Member[] evaluateTuple(Evaluator evaluator) { - final List list = listCalc.evaluateList(evaluator); + final List list = listCalc.evaluateList(evaluator.push(false));                          assert list != null;                          String[] results = new String[stringCalcs.length];                          for (int i = 0; i < stringCalcs.length; i++) { @@ -138,7 +138,7 @@              } else {                  return new AbstractTupleCalc(call, calcs) {                      public Member[] evaluateTuple(Evaluator evaluator) { - final List list = listCalc.evaluateList(evaluator); + final List list = listCalc.evaluateList(evaluator.push(false));                          assert list != null;                          final int index = indexCalc.evaluateInteger(evaluator);                          int listSize = list.size(); @@ -156,7 +156,7 @@              if (isString) {                  return new AbstractMemberCalc(call, calcs) {                      public Member evaluateMember(Evaluator evaluator) { - final List list = listCalc.evaluateList(evaluator); + final List list = listCalc.evaluateList(evaluator.push(false));                          assert list != null;                          final String result =                                  stringCalcs[0].evaluateString(evaluator); @@ -172,7 +172,7 @@              } else {                  return new AbstractMemberCalc(call, calcs) {                      public Member evaluateMember(Evaluator evaluator) { - final List list = listCalc.evaluateList(evaluator); + final List list = listCalc.evaluateList(evaluator.push(false));                          assert list != null;                          final int index = indexCalc.evaluateInteger(evaluator);                          int listSize = list.size(); Index: src/main/mondrian/olap/fun/MedianFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/MedianFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 MedianFunDef.java --- src/main/mondrian/olap/fun/MedianFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/MedianFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -48,8 +48,8 @@                  new ValueCalc(call);          return new AbstractCalc(call) {              public Object evaluate(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); - return median(evaluator.push(), memberList, calc); + List memberList = listCalc.evaluateList(evaluator.push(false)); + return median(evaluator.push(false), memberList, calc);              }                public Calc[] getCalcs() { Index: src/main/mondrian/olap/fun/AvgFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/AvgFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 AvgFunDef.java --- src/main/mondrian/olap/fun/AvgFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/AvgFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -48,8 +48,8 @@                  new ValueCalc(call);          return new AbstractCalc(call) {              public Object evaluate(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); - return avg(evaluator.push(), memberList, calc); + List memberList = listCalc.evaluateList(evaluator.push(false)); + return avg(evaluator.push(false), memberList, calc);              }                public Calc[] getCalcs() { Index: src/main/mondrian/olap/fun/BuiltinFunTable.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/BuiltinFunTable.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 BuiltinFunTable.java --- src/main/mondrian/olap/fun/BuiltinFunTable.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/BuiltinFunTable.java 15 Oct 2008 12:56:56 -0000 @@ -674,8 +674,8 @@                  return new AbstractIntegerCalc(call, new Calc[] {memberListCalc}) {                      public int evaluateInteger(Evaluator evaluator) {                          List memberList = - memberListCalc.evaluateList(evaluator); - return count(evaluator, memberList, true); + memberListCalc.evaluateList(evaluator.push(false)); + return count(evaluator.push(false), memberList, true);                      }                  };              } Index: src/main/mondrian/olap/fun/CorrelationFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/CorrelationFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 CorrelationFunDef.java --- src/main/mondrian/olap/fun/CorrelationFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/CorrelationFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -50,8 +50,8 @@                  new ValueCalc(call);          return new AbstractDoubleCalc(call, new Calc[] {listCalc, calc1, calc2}) {              public double evaluateDouble(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); - return correlation(evaluator.push(), + List memberList = listCalc.evaluateList(evaluator.push(false)); + return correlation(evaluator.push(false),                          memberList, calc1, calc2);              }   Index: src/main/mondrian/olap/fun/StdevPFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/StdevPFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 StdevPFunDef.java --- src/main/mondrian/olap/fun/StdevPFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/StdevPFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -58,8 +58,8 @@                  new ValueCalc(call);          return new AbstractCalc(call) {              public Object evaluate(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); - return stdev(evaluator.push(), memberList, calc, true); + List memberList = listCalc.evaluateList(evaluator.push(false)); + return stdev(evaluator.push(false), memberList, calc, true);              }                public Calc[] getCalcs() { Index: src/main/mondrian/olap/fun/GenerateFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/GenerateFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 GenerateFunDef.java --- src/main/mondrian/olap/fun/GenerateFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/GenerateFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -61,7 +61,7 @@            return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}) {              public List evaluateList(Evaluator evaluator) { - final List list1 = listCalc1.evaluateList(evaluator); + final List list1 = listCalc1.evaluateList(evaluator.push(false));                  final Evaluator evaluator2 = evaluator.push();                  List result = new ArrayList();                  if (tuple) { Index: src/main/mondrian/olap/fun/VarFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/VarFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 VarFunDef.java --- src/main/mondrian/olap/fun/VarFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/VarFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -55,8 +55,8 @@                  new ValueCalc(call);          return new AbstractCalc(call) {              public Object evaluate(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); - return var(evaluator.push(), memberList, calc, false); + List memberList = listCalc.evaluateList(evaluator.push(false)); + return var(evaluator.push(false), memberList, calc, false);              }                public Calc[] getCalcs() { Index: src/main/mondrian/olap/fun/CountFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/CountFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 CountFunDef.java --- src/main/mondrian/olap/fun/CountFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/CountFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -53,6 +53,7 @@          return new AbstractIntegerCalc(                  call, new Calc[] {memberListCalc}) {              public int evaluateInteger(Evaluator evaluator) { + evaluator = evaluator.push(false);                  List memberList =                          memberListCalc.evaluateList(evaluator);                  return count(evaluator, memberList, includeEmpty); Index: src/main/mondrian/olap/fun/AggregateFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/AggregateFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 AggregateFunDef.java --- src/main/mondrian/olap/fun/AggregateFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/AggregateFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -53,8 +53,8 @@                  if (rollup == null) {                      throw newEvalException(null, "Don't know how to rollup aggregator '" + aggregator + "'");                  } - final List list = listCalc.evaluateList(evaluator); - return rollup.aggregate(evaluator.push(), list, calc); + final List list = listCalc.evaluateList(evaluator.push(false)); + return rollup.aggregate(evaluator.push(false), list, calc);              }                public Calc[] getCalcs() { Index: src/main/mondrian/olap/fun/HeadTailFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/HeadTailFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 HeadTailFunDef.java --- src/main/mondrian/olap/fun/HeadTailFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/HeadTailFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -62,6 +62,7 @@          if (head) {              return new AbstractListCalc(call, new Calc[] {listCalc, integerCalc}) {                  public List evaluateList(Evaluator evaluator) { + evaluator = evaluator.push(false);                      List list = listCalc.evaluateList(evaluator);                      int count = integerCalc.evaluateInteger(evaluator);                      return head(count, list); @@ -71,6 +72,7 @@              return new AbstractListCalc(call, new Calc[] {listCalc, integerCalc}) {                    public List evaluateList(Evaluator evaluator) { + evaluator = evaluator.push(false);                      List list = listCalc.evaluateList(evaluator);                      int count = integerCalc.evaluateInteger(evaluator);                      return tail(count, list); Index: src/main/mondrian/olap/fun/TopBottomCountFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/TopBottomCountFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 TopBottomCountFunDef.java --- src/main/mondrian/olap/fun/TopBottomCountFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/TopBottomCountFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -82,7 +82,7 @@                  List list = listCalc.evaluateList(evaluator);                  int n = integerCalc.evaluateInteger(evaluator);                  if (orderCalc != null) { - sort(evaluator.push(), list, orderCalc, top, true); + sort(evaluator.push(false), list, orderCalc, top, true);                  }                  if (n < list.size()) {                      list = list.subList(0, n); Index: src/main/mondrian/olap/fun/MinMaxFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/MinMaxFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 MinMaxFunDef.java --- src/main/mondrian/olap/fun/MinMaxFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/MinMaxFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -58,10 +58,10 @@                  new ValueCalc(call);          return new AbstractCalc(call) {              public Object evaluate(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); + List memberList = listCalc.evaluateList(evaluator.push(false));                  return max ? - max(evaluator.push(), memberList, calc) : - min(evaluator.push(), memberList, calc); + max(evaluator.push(false), memberList, calc) : + min(evaluator.push(false), memberList, calc);              }                public Calc[] getCalcs() { Index: src/main/mondrian/olap/fun/CovarianceFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/CovarianceFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 CovarianceFunDef.java --- src/main/mondrian/olap/fun/CovarianceFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/CovarianceFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -60,9 +60,9 @@                  new ValueCalc(call);          return new AbstractCalc(call) {              public Object evaluate(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); + List memberList = listCalc.evaluateList(evaluator.push(false));                  return covariance( - evaluator.push(), memberList, + evaluator.push(false), memberList,                          calc1, calc2, biased);              }   Index: src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 NonEmptyCrossJoinFunDef.java --- src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/NonEmptyCrossJoinFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -44,14 +44,13 @@          final ListCalc listCalc2 = compiler.compileList(call.getArg(1));          return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}) {              public List evaluateList(Evaluator evaluator) { + // evaluate the arguments in non empty mode + evaluator = evaluator.push(true);                  final List list1 = listCalc1.evaluateList(evaluator);                  if (list1.isEmpty()) {                      return Collections.EMPTY_LIST;                  }                  final List list2 = listCalc2.evaluateList(evaluator); - // evaluate the arguments in non empty mode - evaluator = evaluator.push(); - evaluator.setNonEmpty(true);                  List result = crossJoin(list1, list2, evaluator);                    // remove any remaining empty crossings from the result Index: src/main/mondrian/olap/fun/FilterFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/FilterFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 FilterFunDef.java --- src/main/mondrian/olap/fun/FilterFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/FilterFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -58,7 +58,7 @@                        List members = listCalc.evaluateList(evaluator);                      List result = new ArrayList(); - Evaluator evaluator2 = evaluator.push(); + Evaluator evaluator2 = evaluator.push(false);                      for (int i = 0, count = members.size(); i < count; i++) {                          Member member = (Member) members.get(i);                          evaluator2.setContext(member); Index: src/main/mondrian/olap/fun/VarPFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/VarPFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 VarPFunDef.java --- src/main/mondrian/olap/fun/VarPFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/VarPFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -56,8 +56,8 @@                  new ValueCalc(call);          return new AbstractCalc(call) {              public Object evaluate(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); - return var(evaluator.push(), memberList, calc, true); + List memberList = listCalc.evaluateList(evaluator.push(false)); + return var(evaluator.push(false), memberList, calc, true);              }                public Calc[] getCalcs() { Index: src/main/mondrian/olap/fun/RankFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/RankFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 RankFunDef.java --- src/main/mondrian/olap/fun/RankFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/RankFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -446,7 +446,7 @@          public Object evaluate(Evaluator evaluator) {              // Construct an array containing the value of the expression              // for each member. - List members = listCalc.evaluateList(evaluator); + List members = listCalc.evaluateList(evaluator.push(false));              if (members == null) {                  return null;              } Index: src/main/mondrian/olap/fun/StdevFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/StdevFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 StdevFunDef.java --- src/main/mondrian/olap/fun/StdevFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/StdevFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -56,8 +56,8 @@                  new ValueCalc(call);          return new AbstractCalc(call) {              public Object evaluate(Evaluator evaluator) { - List memberList = listCalc.evaluateList(evaluator); - return stdev(evaluator.push(), memberList, calc, false); + List memberList = listCalc.evaluateList(evaluator.push(false)); + return stdev(evaluator.push(false), memberList, calc, false);              }                public Calc[] getCalcs() { Index: src/main/mondrian/rolap/RolapEvaluator.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/rolap/RolapEvaluator.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 RolapEvaluator.java --- src/main/mondrian/rolap/RolapEvaluator.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/rolap/RolapEvaluator.java 15 Oct 2008 12:56:56 -0000 @@ -237,6 +237,12 @@          return evaluator;      }   + public Evaluator push(boolean nonEmpty) { + final RolapEvaluator evaluator = _push(); + evaluator.setNonEmpty(nonEmpty); + return evaluator; + } +      public Evaluator push() {          return _push();      } @@ -587,6 +593,16 @@      private Object getExpResultCacheKey(ExpCacheDescriptor descriptor) {          List key = new ArrayList();          key.add(descriptor.getExp()); + + // in NON EMPTY mode the result depends on everything, e.g. + // "NON EMPTY [Customer].[Name].members" may return different results + // for 1997-01 and 1997-02 + if (nonEmpty) { + for (int i = 0; i < currentMembers.length; i++) + key.add(currentMembers[i]); + return key; + } +          int[] dimensionOrdinals = descriptor.getDependentDimensionOrdinals();          for (int i = 0; i < dimensionOrdinals.length; i++) {              int dimensionOrdinal = dimensionOrdinals[i]; Index: src/main/mondrian/rolap/SqlContextConstraint.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/rolap/SqlContextConstraint.java,v retrieving revision 1.3 diff -u -r1.3 SqlContextConstraint.java --- src/main/mondrian/rolap/SqlContextConstraint.java 28 Nov 2007 09:13:37 -0000 1.3 +++ src/main/mondrian/rolap/SqlContextConstraint.java 15 Oct 2008 12:56:56 -0000 @@ -68,6 +68,12 @@          if (context == null) {              return false;          } + + // we can restrict the result in NON EMPTY mode only + if (!context.isNonEmpty()) { + return false; + } +          if (disallowVirtualCube) {              RolapCube cube = (RolapCube) context.getCube();              if (cube.isVirtual()) { Index: src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 NthQuartileFunDef.java --- src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java 15 Oct 2008 12:56:56 -0000 @@ -65,8 +65,8 @@                  new ValueCalc(call);          return new AbstractDoubleCalc(call, new Calc[] {listCalc, doubleCalc}) {              public double evaluateDouble(Evaluator evaluator) { - List members = listCalc.evaluateList(evaluator); - return quartile(evaluator.push(), members, doubleCalc, range); + List members = listCalc.evaluateList(evaluator.push(false)); + return quartile(evaluator.push(false), members, doubleCalc, range);              }                public boolean dependsOn(Dimension dimension) { Index: src/main/mondrian/olap/Evaluator.java =================================================================== RCS file: /cvsroot/mondrian-2.2/src/main/mondrian/olap/Evaluator.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 Evaluator.java --- src/main/mondrian/olap/Evaluator.java 3 Nov 2006 11:32:15 -0000 1.1.1.1 +++ src/main/mondrian/olap/Evaluator.java 15 Oct 2008 12:56:56 -0000 @@ -56,6 +56,11 @@      Evaluator push(Member member);        /** + * Creates a new evaluator with the same state except nonEmpty property. + */ + Evaluator push(boolean nonEmpty); + + /**       * Restores previous evaluator.       */      Evaluator pop(); patch for the test folder: Index: testsrc/main/mondrian/rolap/NonEmptyTest.java =================================================================== RCS file: /cvsroot/mondrian-2.2/testsrc/main/mondrian/rolap/NonEmptyTest.java,v retrieving revision 1.4 diff -u -r1.4 NonEmptyTest.java --- testsrc/main/mondrian/rolap/NonEmptyTest.java 27 Nov 2007 16:17:31 -0000 1.4 +++ testsrc/main/mondrian/rolap/NonEmptyTest.java 15 Oct 2008 13:00:06 -0000 @@ -80,6 +80,51 @@            "Row #2: 3,926" + nl          );      } + + public void testBug1961163() throws Exception { + TestContext ctx = TestContext.instance(); + ctx.assertQueryReturns( + "with member [Measures].[AvgRevenue] as 'Avg([Store].[Store Name].Members, [Measures].[Store Sales])' " + + "select NON EMPTY {[Measures].[Store Sales], [Measures].[AvgRevenue]} ON COLUMNS, " + + "NON EMPTY Filter([Store].[Store Name].Members, ([Measures].[AvgRevenue] < [Measures].[Store Sales])) ON ROWS " + + "from [Sales]", + + "Axis #0:" + nl + + "{}" + nl + + "Axis #1:" + nl + + "{[Measures].[Store Sales]}" + nl + + "{[Measures].[AvgRevenue]}" + nl + + "Axis #2:" + nl + + "{[Store].[All Stores].[USA].[CA].[Beverly Hills].[Store 6]}" + nl + + "{[Store].[All Stores].[USA].[CA].[Los Angeles].[Store 7]}" + nl + + "{[Store].[All Stores].[USA].[CA].[San Diego].[Store 24]}" + nl + + "{[Store].[All Stores].[USA].[OR].[Portland].[Store 11]}" + nl + + "{[Store].[All Stores].[USA].[OR].[Salem].[Store 13]}" + nl + + "{[Store].[All Stores].[USA].[WA].[Bremerton].[Store 3]}" + nl + + "{[Store].[All Stores].[USA].[WA].[Seattle].[Store 15]}" + nl + + "{[Store].[All Stores].[USA].[WA].[Spokane].[Store 16]}" + nl + + "{[Store].[All Stores].[USA].[WA].[Tacoma].[Store 17]}" + nl + + "Row #0: 45,750.24" + nl + + "Row #0: 43,479.86" + nl + + "Row #1: 54,545.28" + nl + + "Row #1: 43,479.86" + nl + + "Row #2: 54,431.14" + nl + + "Row #2: 43,479.86" + nl + + "Row #3: 55,058.79" + nl + + "Row #3: 43,479.86" + nl + + "Row #4: 87,218.28" + nl + + "Row #4: 43,479.86" + nl + + "Row #5: 52,896.30" + nl + + "Row #5: 43,479.86" + nl + + "Row #6: 52,644.07" + nl + + "Row #6: 43,479.86" + nl + + "Row #7: 49,634.46" + nl + + "Row #7: 43,479.86" + nl + + "Row #8: 74,843.96" + nl + + "Row #8: 43,479.86" + nl + + ); + }        public void testTopCountCachingBug() {        TestContext ctx = TestContext.instance(); @@ -244,7 +289,7 @@                  32,                  18,                  "select {[Measures].[Store Sales]} ON COLUMNS, " - + "Order(Filter(Descendants([Customers].[All Customers].[USA].[CA], [Customers].[Name]), ([Measures].[Store Sales] > 200.0)), [Measures].[Store Sales], DESC) ON ROWS " + + "NON EMPTY Order(Filter(Descendants([Customers].[All Customers].[USA].[CA], [Customers].[Name]), ([Measures].[Store Sales] > 200.0)), [Measures].[Store Sales], DESC) ON ROWS "                          + "from [Sales] "                          + "where ([Time].[1997])");      } @@ -763,7 +808,7 @@          TupleConstraint lmc = scf.getLevelMembersConstraint(null);          assertNull(smr.mapLevelToMembers.get(nameLevel, lmc));          // make sure that NON EMPTY [Customers].[Name].Members IS in cache - lmc = scf.getLevelMembersConstraint(context); + lmc = scf.getLevelMembersConstraint(context.push(true));          List list = smr.mapLevelToMembers.get(nameLevel, lmc);          assertNotNull(list);          assertEquals(20, list.size()); @@ -779,7 +824,7 @@          assertNull(smr.mapMemberToChildren.get(parent, mcc));            // lookup NON EMPTY children of [Burlingame] -> yes these are in cache - mcc = scf.getMemberChildrenConstraint(context); + mcc = scf.getMemberChildrenConstraint(context.push(true));          list = smr.mapMemberToChildren.get(parent, mcc);          assertNotNull(list);          assertTrue(list.contains(member)); @@ -806,7 +851,7 @@          assertNotNull(list);          assertEquals(10281, list.size());          // make sure that NON EMPTY [Customers].[Name].Members is NOT in cache - lmc = scf.getLevelMembersConstraint(context); + lmc = scf.getLevelMembersConstraint(context.push(true));          assertNull(smr.mapLevelToMembers.get(nameLevel, lmc));            // make sure that the parent/child for the context are cached @@ -822,7 +867,7 @@          assertTrue(list.contains(member));            // lookup NON EMPTY children of [Burlingame] -> not in cache - mcc = scf.getMemberChildrenConstraint(context); + mcc = scf.getMemberChildrenConstraint(context.push(true));          list = smr.mapMemberToChildren.get(parent, mcc);          assertNull(list);      } @@ -944,7 +989,7 @@          assertNull(smr.mapMemberToChildren.get(burlingame, mcc));          // but non empty children is          Evaluator evaluator = getEvaluator(result, new int[] { 0, 0}); - mcc = scf.getMemberChildrenConstraint(evaluator); + mcc = scf.getMemberChildrenConstraint(evaluator.push(true));          List list = smr.mapMemberToChildren.get(burlingame, mcc);          assertNotNull(list);          assertTrue(list.contains(peggy));
        Hide
        Mondrian Importer User added a comment -
        {jhyde}, 10/15/2008: Thanks Andreas. I will incorporate the fix.
        Show
        Mondrian Importer User added a comment - {jhyde}, 10/15/2008: Thanks Andreas. I will incorporate the fix.
        Hide
        Mondrian Importer User added a comment -
        {jhyde}, 01/07/2009: Fixed by Andreas in change 12208. Will be in mondrian-3.1.
        Show
        Mondrian Importer User added a comment - {jhyde}, 01/07/2009: Fixed by Andreas in change 12208. Will be in mondrian-3.1.

          People

          • Assignee:
            avix
            Reporter:
            Unassigned User
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: