Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Severe Severe
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 3.1 GA
    • 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

      Mondrian throws a class-cast exception when attempting to process an MDX referencing members on a Parent/child dimension where there is no closure on the hierarchy.

      I have confirmed this issue against the latest code in the 3.1 Perforce repo as of this morning. Attached is a TestCase which I believe would be most appropriate to put in mondrian.test.ParentChildHierarchyTest (which is where I have been using it). The test case is 'simple'. It runs a simple MDX query against the Parent/Child hierarchy in FoodMart(Employees) using a Closure table. Then runs the identical MDX against the identical cube except the second time there is no closure defined. It attemtps to assert that the results of both MDX's are identical.

      The trace as thrown in JUnit is as follows, and I have taken the liberty of 'annotating it' so that I can describe the relevant details of the problem. My notes are indicated with *rlear note x* and after the trace I give a break-down of the relevant system states for the various notes.

      mondrian.olap.MondrianException: Mondrian Error:Internal error: Error while executing query [select {[Measures].[Count]} ON COLUMNS,
        NON EMPTY {[Employees].AllMembers} ON ROWS
      from [HR4C]
      ]
       at mondrian.resource.MondrianResource$_Def0.ex(MondrianResource.java:811)
       at mondrian.olap.Util.newInternal(Util.java:1472)
       at mondrian.olap.Util.newError(Util.java:1488)
       at mondrian.rolap.RolapConnection.execute(RolapConnection.java:589)
       at mondrian.test.TestContext.executeQuery(TestContext.java:478)
       at mondrian.test.TestContext.assertQueryReturns(TestContext.java:820)
       at mondrian.test.ParentChildHierarchyTest.testClosureVsNoClosure(ParentChildHierarchyTest.java:238)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at junit.framework.TestCase.runTest(TestCase.java:164)
       at junit.framework.TestCase.runBare(TestCase.java:130)
       at junit.framework.TestResult$1.protect(TestResult.java:106)
       at junit.framework.TestResult.runProtected(TestResult.java:124)
       at junit.framework.TestResult.run(TestResult.java:109)
       at junit.framework.TestCase.run(TestCase.java:120)
       at junit.framework.TestSuite.runTest(TestSuite.java:230)
       at junit.framework.TestSuite.run(TestSuite.java:225)
       at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
       at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
       at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
      Caused by: java.lang.ClassCastException: mondrian.rolap.RolapMember
      *rlear note 1*
       at mondrian.rolap.RolapCubeHierarchy$CacheRolapCubeHierarchyMemberReader.readMemberChildren(RolapCubeHierarchy.java:475)
       at mondrian.rolap.RolapCubeHierarchy$CacheRolapCubeHierarchyMemberReader.getMemberChildren(RolapCubeHierarchy.java:585)
       at mondrian.rolap.SmartMemberReader.getMemberChildren(SmartMemberReader.java:175)
       at mondrian.rolap.SmartMemberReader.getMemberChildren(SmartMemberReader.java:165)
      *rlear note 2*
       at mondrian.rolap.SqlMemberSource$RolapParentChildMember.getPropertyValue(SqlMemberSource.java:1158)
       at mondrian.rolap.RolapCubeMember.getPropertyValue(RolapCubeMember.java:223)
       at mondrian.rolap.RolapMember.getPropertyValue(RolapMember.java:524)
       at mondrian.olap.fun.BuiltinFunTable$22$1.aggregateChildren(BuiltinFunTable.java:713)
       at mondrian.olap.fun.BuiltinFunTable$22$1$1.evaluate(BuiltinFunTable.java:700)
       at mondrian.rolap.RolapEvaluator.evaluateCurrent(RolapEvaluator.java:449)
       at mondrian.rolap.RolapResult.executeStripe(RolapResult.java:890)
       at mondrian.rolap.RolapResult.executeStripe(RolapResult.java:1027)
       at mondrian.rolap.RolapResult.executeStripe(RolapResult.java:1027)
       at mondrian.rolap.RolapResult.executeBody(RolapResult.java:788)
       at mondrian.rolap.RolapResult.<init>(RolapResult.java:414)
       at mondrian.rolap.RolapConnection.execute(RolapConnection.java:560)
       ... 21 more


      *rlear note 1* the list parentRolapCubeMemberList is iterated over with the expectation that it contains RolapCubeMember instances. In this particular case though, it contains just a RolapMember (not RolapCubeMember). This is what causes the exception.

      *rlear note 2* the RolapParentChildMember that is referred to here is actually a RolapParentChildMemberNoClosure, and the significance of the trace at this point is that the 'dataMember' instance variable is a plain RolapMember, not a RolapCubeMember. This is why the ClassCastException happens later in the trace.


      I tried to 'fix' this issue by modifying the SqlMemberSource.makeMember() method to create the RolapParentChildMemberNoClosure instance with a RolapCubeMember in the constructor instead of a RolapCube, and this works for single-level hierarchies, but, there is a form of recursion that happens in this code section as the hierarchy is traversed finding the Child members, and I can't find a way to ensure that the correct RolapCubeMember is used in the lower levels. Further, I am not certain that this would be the best 'fix'.

      Rolf

        Activity

        Hide
        Mondrian Importer User added a comment -
        {rlear}, 03/25/2009: IP, Artifact Created: 99.250.137.235 |
        {rlear}, 03/25/2009: File Added, 319452: bug.testcase.java.snippet
        Show
        Mondrian Importer User added a comment - {rlear}, 03/25/2009: IP, Artifact Created: 99.250.137.235 | {rlear}, 03/25/2009: File Added, 319452: bug.testcase.java.snippet
        Hide
        rlear added a comment -
        The attachment did not make the move successfully from Sourceforge, so, here is the code snippet for the test:

            public void testClosureVsNoClosure() {
                
                String cubestart =
                    "<Cube name=\"HR4C\">\n" +
                    " <Table name=\"salary\"/>\n" +
                    " <Dimension name=\"Employees\" foreignKey=\"employee_id\">\n" +
                    " <Hierarchy hasAll=\"true\" allMemberName=\"All\"\n" +
                    " primaryKey=\"employee_id\">\n" +
                    " <Table name=\"employee\"/>\n" +
                    " <Level name=\"Employee Id\" type=\"Numeric\" uniqueMembers=\"true\"\n" +
                    " column=\"employee_id\" parentColumn=\"supervisor_id\"\n" +
                    " nameColumn=\"full_name\" nullParentValue=\"0\">\n";
                
                String closure =
                    " <Closure parentColumn=\"supervisor_id\" childColumn=\"employee_id\">\n" +
                    " <Table name=\"employee_closure\"/>\n" +
                    " </Closure>\n";
                
                String cubeend =
                    " </Level>\n" +
                    " </Hierarchy>\n" +
                    " </Dimension>\n" +
                    "\n" +
                    " <Measure name=\"Count\" column=\"employee_id\" aggregator=\"count\" />\n" +
                    "</Cube>\n";
                
                String mdx =
                    "select {[Measures].[Count]} ON COLUMNS, NON EMPTY {[Employees].AllMembers} ON ROWS from [HR4C]";
                
                TestContext testClosureContext = TestContext.create(
                        null,
                        cubestart + closure + cubeend, null, null, null, null);
                
                String expect = TestContext.toString(testClosureContext.executeQuery(mdx));
                
                TestContext testNoClosureContext = TestContext.create(
                        null,
                        cubestart + cubeend, null, null, null, null);
                
                testNoClosureContext.assertQueryReturns(mdx, expect);
            }
        Show
        rlear added a comment - The attachment did not make the move successfully from Sourceforge, so, here is the code snippet for the test:     public void testClosureVsNoClosure() {                  String cubestart =             "<Cube name=\"HR4C\">\n" +             " <Table name=\"salary\"/>\n" +             " <Dimension name=\"Employees\" foreignKey=\"employee_id\">\n" +             " <Hierarchy hasAll=\"true\" allMemberName=\"All\"\n" +             " primaryKey=\"employee_id\">\n" +             " <Table name=\"employee\"/>\n" +             " <Level name=\"Employee Id\" type=\"Numeric\" uniqueMembers=\"true\"\n" +             " column=\"employee_id\" parentColumn=\"supervisor_id\"\n" +             " nameColumn=\"full_name\" nullParentValue=\"0\">\n";                  String closure =             " <Closure parentColumn=\"supervisor_id\" childColumn=\"employee_id\">\n" +             " <Table name=\"employee_closure\"/>\n" +             " </Closure>\n";                  String cubeend =             " </Level>\n" +             " </Hierarchy>\n" +             " </Dimension>\n" +             "\n" +             " <Measure name=\"Count\" column=\"employee_id\" aggregator=\"count\" />\n" +             "</Cube>\n";                  String mdx =             "select {[Measures].[Count]} ON COLUMNS, NON EMPTY {[Employees].AllMembers} ON ROWS from [HR4C]";                  TestContext testClosureContext = TestContext.create(                 null,                 cubestart + closure + cubeend, null, null, null, null);                  String expect = TestContext.toString(testClosureContext.executeQuery(mdx));                  TestContext testNoClosureContext = TestContext.create(                 null,                 cubestart + cubeend, null, null, null, null);                  testNoClosureContext.assertQueryReturns(mdx, expect);     }
        Hide
        Will Gorman added a comment -
        fix 12574, will appear in 3.1.0 GA
        Show
        Will Gorman added a comment - fix 12574, will appear in 3.1.0 GA

          People

          • Assignee:
            Will Gorman
            Reporter:
            rlear
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: