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

NullPointerException when passing in null param value

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Blocker Blocker
    • Resolution: Fixed
    • Affects Version/s: 3.2.0 GA (3.6.0 GA Suite Release)
    • Component/s: None
    • Labels:
      None

      Description

      In 3.2.0.13583, The following unit test passes. In 3.2.0.13643, the test fails with a NullPointerException

          public void testNullStrToMember() {
           Connection connection = getConnection();
           Query query = connection.parseQuery(
           "select NON EMPTY {[Time].[1997]} ON COLUMNS, " +
           "NON EMPTY {StrToMember(Parameter(\"sProduct\", STRING, \"[Gender].[Gender].[F]\"))} ON ROWS " +
           "from [Sales]"
           );
            Parameter[] parameters = query.getParameters();
            parameters[0].setValue(null);
            Result result = connection.execute(query);
            String resultString = TestContext.toString(result);
            TestContext.assertEqualsVerbose(
             "Axis #0:\n"
                  + "{}\n"
                  + "Axis #1:\n"
                  + "{[Time].[1997]}\n"
                  + "Axis #2:\n"
                  + "{[Gender].[F]}\n"
                  + "Row #0: 131,558\n",
                resultString);
          }



      mondrian.olap.MondrianException: Mondrian Error:Internal error: Error while executing query [select NON EMPTY {[Time].[1997]} ON COLUMNS,
        NON EMPTY {StrToMember(Parameter("sProduct", STRING, "[Gender].[Gender].[F]"))} ON ROWS
      from [Sales]
      ]
      at mondrian.resource.MondrianResource$_Def0.ex(MondrianResource.java:821)
      at mondrian.olap.Util.newInternal(Util.java:1490)
      at mondrian.olap.Util.newError(Util.java:1506)
      at mondrian.rolap.RolapConnection.execute(RolapConnection.java:622)
      at mondrian.test.ParameterTest.testNullStrToMember(ParameterTest.java:170)
      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:154)
      at junit.framework.TestCase.runBare(TestCase.java:127)
      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:118)
      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.NullPointerException
      at mondrian.util.IdentifierParser.parseMember(IdentifierParser.java:148)
      at mondrian.olap.fun.FunUtil.parseMember(FunUtil.java:2319)
      at mondrian.olap.fun.FunUtil.parseMember(FunUtil.java:2326)
      at mondrian.olap.fun.StrToMemberFunDef$1.evaluateMember(StrToMemberFunDef.java:43)
      at mondrian.olap.fun.SetFunDef$MemberSetListCalc$2.evaluateVoid(SetFunDef.java:173)
      at mondrian.olap.fun.SetFunDef$MemberSetListCalc.evaluateMemberList(SetFunDef.java:190)
      at mondrian.calc.impl.AbstractExpCompiler$MemberListIterCalc.evaluateMemberIterable(AbstractExpCompiler.java:592)
      at mondrian.calc.impl.AbstractMemberIterCalc.evaluate(AbstractMemberIterCalc.java:52)
      at mondrian.rolap.RolapResult.executeAxis(RolapResult.java:732)
      at mondrian.rolap.RolapResult.evalLoad(RolapResult.java:575)
      at mondrian.rolap.RolapResult.loadMembers(RolapResult.java:541)
      at mondrian.rolap.RolapResult.<init>(RolapResult.java:273)
      at mondrian.rolap.RolapConnection.execute(RolapConnection.java:593)
      ... 17 more


        Activity

        Hide
        Pedro Alves added a comment -
        This is also blocking our upgrade. One of the subreport on a critical report hits this error.
        Show
        Pedro Alves added a comment - This is also blocking our upgrade. One of the subreport on a critical report hits this error.
        Hide
        Julian Hyde added a comment -
        It depends what StrToMember should do if passed a null string value. I need to check what SSAS does; but it does seem reasonable that StrToMember should throw.

        This bug isn't really about parameters; they're just the way that the null string value happens to get into the system.
        Show
        Julian Hyde added a comment - It depends what StrToMember should do if passed a null string value. I need to check what SSAS does; but it does seem reasonable that StrToMember should throw. This bug isn't really about parameters; they're just the way that the null string value happens to get into the system.
        Hide
        Julian Hyde added a comment -
        By the way, this test case assumes the undocumented behavior that setting a parameter to null would cause it to revert to its default value. That behavior was stopping us from allowing genuine null values for parameters, so I removed it.

        I can add a method to result a parameter to its default value, if that would help. Say 'void Parameter.unsetValue()'.
        Show
        Julian Hyde added a comment - By the way, this test case assumes the undocumented behavior that setting a parameter to null would cause it to revert to its default value. That behavior was stopping us from allowing genuine null values for parameters, so I removed it. I can add a method to result a parameter to its default value, if that would help. Say 'void Parameter.unsetValue()'.
        Hide
        Will Gorman added a comment -
        The test case demonstrates null to default value in parameters, which was the behavior before Change #13592. What is the purpose of the default value if it's not to be used when nulls are passed in? Change #13592 didn't include a JIRA case, can you give more details on why you made the change?
        Show
        Will Gorman added a comment - The test case demonstrates null to default value in parameters, which was the behavior before Change #13592. What is the purpose of the default value if it's not to be used when nulls are passed in? Change #13592 didn't include a JIRA case, can you give more details on why you made the change?
        Hide
        Pedro Alves added a comment -
        One thing I can't understand;

        What's the possible advantage of setting a member to null and then having a method (mondrian.rolap.RolapSchemaReader.getMemberParent(RolapSchemaReader.java:120)) that will throw a NPE?


        Here's my stack:

        mondrian.rolap.RolapSchemaReader.getMemberParent(RolapSchemaReader.java:120)
        mondrian.olap.DelegatingSchemaReader.getMemberParent(DelegatingSchemaReader.java:64)
        mondrian.olap.fun.BuiltinFunTable$15.memberParent(BuiltinFunTable.java:535)
        mondrian.olap.fun.BuiltinFunTable$15$1.evaluateMember(BuiltinFunTable.java:529)
        mondrian.olap.fun.LastPeriodsFunDef$1.evaluateList(LastPeriodsFunDef.java:89)
        mondrian.calc.impl.AbstractListCalc.evaluate(AbstractListCalc.java:71)
        mondrian.rolap.RolapResult.evaluateExp(RolapResult.java:852)
        mondrian.rolap.RolapNamedSetEvaluator.ensureList(RolapNamedSetEvaluator.java:98)
        mondrian.rolap.RolapNamedSetEvaluator.evaluateMemberIterable(RolapNamedSetEvaluator.java:64)
        mondrian.mdx.NamedSetExpr$2.evaluateMemberIterable(NamedSetExpr.java:122)
        mondrian.olap.fun.OrderFunDef$MemberCalcImpl.evaluateDual(OrderFunDef.java:184)
        mondrian.olap.fun.OrderFunDef$ContextCalc.evaluate(OrderFunDef.java:452)
        mondrian.rolap.RolapResult.executeAxis(RolapResult.java:732)
        mondrian.rolap.RolapResult.evalLoad(RolapResult.java:575)
        mondrian.rolap.RolapResult.loadMembers(RolapResult.java:541)
        mondrian.rolap.RolapResult.<init>(RolapResult.java:273)
        mondrian.rolap.RolapConnection.execute(RolapConnection.java:593)
        org.pentaho.reporting.engine.classic.extensions.datasources.mondrian.AbstractMDXDataFactory.performQuery(AbstractMDXDataFactory.java:498)
        org.pentaho.reporting.engine.classic.extensions.datasources.mondrian.AbstractNamedMDXDataFactory.performQuery(AbstractNamedMDXDataFactory.java:81)
        org.pentaho.reporting.engine.classic.extensions.datasources.mondrian.BandedMDXDataFactory.queryData(BandedMDXDataFactory.java:54)
        org.pentaho.reporting.engine.classic.core.CompoundDataFactory.queryData(CompoundDataFactory.java:88)
        org.pentaho.reporting.engine.classic.core.states.CachingDataFactory.queryInternal(CachingDataFactory.java:168)
        org.pentaho.reporting.engine.classic.core.states.CachingDataFactory.queryData(CachingDataFactory.java:143)
        org.pentaho.reporting.engine.classic.core.states.CascadingDataFactory.queryData(CascadingDataFactory.java:81)
        org.pentaho.reporting.engine.classic.core.states.datarow.ReportDataRow.createDataRow(ReportDataRow.java:97)
        org.pentaho.reporting.engine.classic.core.states.datarow.DefaultFlowController.performSubReportQuery(DefaultFlowController.java:258)
        org.pentaho.reporting.engine.classic.core.states.process.ProcessState.<init>(ProcessState.java:433)
        org.pentaho.reporting.engine.classic.core.states.process.EndSubReportHandler.commit(EndSubReportHandler.java:58)
        org.pentaho.reporting.engine.classic.core.states.process.ProcessState.commit(ProcessState.java:819)
        org.pentaho.reporting.engine.classic.core.states.process.InlineSubreportProcessor.processInline(InlineSubreportProcessor.java:95)
        org.pentaho.reporting.engine.classic.core.states.process.EndGroupHandler.advance(EndGroupHandler.java:43)
        org.pentaho.reporting.engine.classic.core.states.process.ProcessState.advance(ProcessState.java:814)
        org.pentaho.reporting.engine.classic.core.layout.output.AbstractReportProcessor.processPrepareLevels(AbstractReportProcessor.java:417)
        org.pentaho.reporting.engine.classic.core.layout.output.AbstractReportProcessor.performStructuralPreprocessing(AbstractReportProcessor.java:569)
        org.pentaho.reporting.engine.classic.core.layout.output.AbstractReportProcessor.prepareReportProcessing(AbstractReportProcessor.java:483)
        org.pentaho.reporting.engine.classic.core.modules.output.pageable.graphics.PrintReportProcessor.getNumberOfPages(PrintReportProcessor.java:78)
        org.pentaho.reporting.engine.classic.core.modules.gui.base.PreviewPane$RepaginationRunnable.run(PreviewPane.java:266)
        org.pentaho.reporting.engine.classic.core.util.Worker.run(Worker.java:174)
        Show
        Pedro Alves added a comment - One thing I can't understand; What's the possible advantage of setting a member to null and then having a method (mondrian.rolap.RolapSchemaReader.getMemberParent(RolapSchemaReader.java:120)) that will throw a NPE? Here's my stack: mondrian.rolap.RolapSchemaReader.getMemberParent(RolapSchemaReader.java:120) mondrian.olap.DelegatingSchemaReader.getMemberParent(DelegatingSchemaReader.java:64) mondrian.olap.fun.BuiltinFunTable$15.memberParent(BuiltinFunTable.java:535) mondrian.olap.fun.BuiltinFunTable$15$1.evaluateMember(BuiltinFunTable.java:529) mondrian.olap.fun.LastPeriodsFunDef$1.evaluateList(LastPeriodsFunDef.java:89) mondrian.calc.impl.AbstractListCalc.evaluate(AbstractListCalc.java:71) mondrian.rolap.RolapResult.evaluateExp(RolapResult.java:852) mondrian.rolap.RolapNamedSetEvaluator.ensureList(RolapNamedSetEvaluator.java:98) mondrian.rolap.RolapNamedSetEvaluator.evaluateMemberIterable(RolapNamedSetEvaluator.java:64) mondrian.mdx.NamedSetExpr$2.evaluateMemberIterable(NamedSetExpr.java:122) mondrian.olap.fun.OrderFunDef$MemberCalcImpl.evaluateDual(OrderFunDef.java:184) mondrian.olap.fun.OrderFunDef$ContextCalc.evaluate(OrderFunDef.java:452) mondrian.rolap.RolapResult.executeAxis(RolapResult.java:732) mondrian.rolap.RolapResult.evalLoad(RolapResult.java:575) mondrian.rolap.RolapResult.loadMembers(RolapResult.java:541) mondrian.rolap.RolapResult.<init>(RolapResult.java:273) mondrian.rolap.RolapConnection.execute(RolapConnection.java:593) org.pentaho.reporting.engine.classic.extensions.datasources.mondrian.AbstractMDXDataFactory.performQuery(AbstractMDXDataFactory.java:498) org.pentaho.reporting.engine.classic.extensions.datasources.mondrian.AbstractNamedMDXDataFactory.performQuery(AbstractNamedMDXDataFactory.java:81) org.pentaho.reporting.engine.classic.extensions.datasources.mondrian.BandedMDXDataFactory.queryData(BandedMDXDataFactory.java:54) org.pentaho.reporting.engine.classic.core.CompoundDataFactory.queryData(CompoundDataFactory.java:88) org.pentaho.reporting.engine.classic.core.states.CachingDataFactory.queryInternal(CachingDataFactory.java:168) org.pentaho.reporting.engine.classic.core.states.CachingDataFactory.queryData(CachingDataFactory.java:143) org.pentaho.reporting.engine.classic.core.states.CascadingDataFactory.queryData(CascadingDataFactory.java:81) org.pentaho.reporting.engine.classic.core.states.datarow.ReportDataRow.createDataRow(ReportDataRow.java:97) org.pentaho.reporting.engine.classic.core.states.datarow.DefaultFlowController.performSubReportQuery(DefaultFlowController.java:258) org.pentaho.reporting.engine.classic.core.states.process.ProcessState.<init>(ProcessState.java:433) org.pentaho.reporting.engine.classic.core.states.process.EndSubReportHandler.commit(EndSubReportHandler.java:58) org.pentaho.reporting.engine.classic.core.states.process.ProcessState.commit(ProcessState.java:819) org.pentaho.reporting.engine.classic.core.states.process.InlineSubreportProcessor.processInline(InlineSubreportProcessor.java:95) org.pentaho.reporting.engine.classic.core.states.process.EndGroupHandler.advance(EndGroupHandler.java:43) org.pentaho.reporting.engine.classic.core.states.process.ProcessState.advance(ProcessState.java:814) org.pentaho.reporting.engine.classic.core.layout.output.AbstractReportProcessor.processPrepareLevels(AbstractReportProcessor.java:417) org.pentaho.reporting.engine.classic.core.layout.output.AbstractReportProcessor.performStructuralPreprocessing(AbstractReportProcessor.java:569) org.pentaho.reporting.engine.classic.core.layout.output.AbstractReportProcessor.prepareReportProcessing(AbstractReportProcessor.java:483) org.pentaho.reporting.engine.classic.core.modules.output.pageable.graphics.PrintReportProcessor.getNumberOfPages(PrintReportProcessor.java:78) org.pentaho.reporting.engine.classic.core.modules.gui.base.PreviewPane$RepaginationRunnable.run(PreviewPane.java:266) org.pentaho.reporting.engine.classic.core.util.Worker.run(Worker.java:174)
        Hide
        Pedro Alves added a comment -
        I applied the patch in http://jira.pentaho.com/browse/PRD-2731 to prevent null members/sets to be passed in org/pentaho/reporting/engine/classic/extensions/datasources/mondrian/AbstractMDXDataFactory.java
        Show
        Pedro Alves added a comment - I applied the patch in http://jira.pentaho.com/browse/PRD-2731 to prevent null members/sets to be passed in org/pentaho/reporting/engine/classic/extensions/datasources/mondrian/AbstractMDXDataFactory.java
        Hide
        Julian Hyde added a comment -
        Fixed in change 13650.

        Previously, setting a parameter to null would reset it to its default value, so it would never have the value null (unless the default was null). Now setting it to null makes it null.

        If you want to reset a parameter, call the new method Parameter.unset(). To test whether it has been set, call Parameter.isSet(). I have also added methods to olap4j: PreparedOlapStatement.isSet(int) and .unset(int). Will be in olap4j revision 314.

        This is a breaking change (albeit a minor one), but hey, mondrian-3.2.0 is a minor release so a little pain is allowed.

        StrToMember, StrToSet, StrToTuple should not throw NPE if given a null string. In change 13650 I also made these throw a reasonable error.
        Show
        Julian Hyde added a comment - Fixed in change 13650. Previously, setting a parameter to null would reset it to its default value, so it would never have the value null (unless the default was null). Now setting it to null makes it null. If you want to reset a parameter, call the new method Parameter.unset(). To test whether it has been set, call Parameter.isSet(). I have also added methods to olap4j: PreparedOlapStatement.isSet(int) and .unset(int). Will be in olap4j revision 314. This is a breaking change (albeit a minor one), but hey, mondrian-3.2.0 is a minor release so a little pain is allowed. StrToMember, StrToSet, StrToTuple should not throw NPE if given a null string. In change 13650 I also made these throw a reasonable error.
        Hide
        Sean Flatley added a comment -
        PRD related cases have been validated.
        Show
        Sean Flatley added a comment - PRD related cases have been validated.

          People

          • Assignee:
            Sean Flatley
            Reporter:
            Will Gorman
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: