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

UDF returning List works under 2.4, fails under 3.1.1

    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

      I'm having some trouble with a UDF returning a List that worked under 2.4, but fails with a parse error under 3.1.1. I'm not sure whether the problem is a flaw in the UDF or in how the newer version of Mondrian is attempting to use it.

      Here's the function, which simply reverses the order of a set:

        public class ReverseFunction implements UserDefinedFunction {
      public Object execute(Evaluator eval, Argument[] args) {
      List memberList = (List) args[0].evaluate(eval);
      Collections.reverse(memberList);
      return memberList;
      }
      public String getDescription() {
      return "Reverses the order of a set";
      }
      public String getName() {
      return "Reverse";
      }
      public Type[] getParameterTypes() {
      return new Type[] {new SetType(MemberType.Unknown)};
      }
      public String[] getReservedWords() {
      return null;
      }
      public Type getReturnType(Type[] arg0) {
      return arg0[0];
      }
      public Syntax getSyntax() {
      return Syntax.Function;
      }
        }

      The stack trace for the underlying cause of the error is here:

      Caused by: mondrian.olap.MondrianException: Mondrian Error:Internal error: Cannot convert calc to list: mondrian.olap.fun.UdfResolver$CalcImpl@315d04
      at mondrian.resource.MondrianResource$_Def0.ex(MondrianResource.java:803)
      at mondrian.olap.Util.newInternal(Util.java:1465)
      at mondrian.calc.impl.AbstractExpCompiler.compileList(AbstractExpCompiler.java:286)
      at mondrian.calc.impl.BetterExpCompiler.compileList(BetterExpCompiler.java:77)
      at mondrian.calc.impl.AbstractExpCompiler.compileList(AbstractExpCompiler.java:260)
      at mondrian.olap.fun.SetFunDef$MemberSetListCalc.createCalc(SetFunDef.java:147)
      at mondrian.olap.fun.SetFunDef$MemberSetListCalc.compileSelf(SetFunDef.java:134)
      at mondrian.olap.fun.SetFunDef$MemberSetListCalc.<init>(SetFunDef.java:120)
      at mondrian.olap.fun.SetFunDef.compileCall(SetFunDef.java:89)
      at mondrian.mdx.ResolvedFunCall.accept(ResolvedFunCall.java:152)
      at mondrian.calc.impl.AbstractExpCompiler.compile(AbstractExpCompiler.java:79)
      at mondrian.calc.impl.AbstractExpCompiler.compileAs(AbstractExpCompiler.java:124)
      at mondrian.calc.impl.AbstractExpCompiler.compileIter(AbstractExpCompiler.java:311)
      at mondrian.olap.QueryAxis.compile(QueryAxis.java:122)
      at mondrian.olap.Query.compile(Query.java:519)
      at mondrian.olap.Query.resolve(Query.java:456)
      at mondrian.olap.Query.<init>(Query.java:231)
      at mondrian.olap.Query.<init>(Query.java:187)
      at mondrian.olap.Parser.makeQuery(Parser.java:870)
      at mondrian.olap.CUP$Parser$actions.CUP$Parser$do_action(Parser.java:1764)
      at mondrian.olap.Parser.do_action(Parser.java:699)
      at java_cup.runtime.lr_parser.parse(lr_parser.java:569)
      at mondrian.olap.Parser.parseInternal(Parser.java:772)

      The immediate problem is in AbstractExpCompiler.compileList(). It compiles the expression "Reverse([Requested Dates])", gets a mondrian.olap.fun.UdfResolver$CalcImpl instance as a result, then complains because said calc is neither null, a ListCalc, or an IterCalc.

      UDF documentation seems a little thin, and I've been unable to find an example of a UDF returning a list in either mondrian/udf or in UdfTest to use as a reference point. Searching the archive, I do see that Pappyn Bart asked a somewhat similar question back in 2007, but I didn't see a clear resolution.

      Additional note: I've experimented with changing UdfResolver to return an object that implements AbstractMemberListCalc rather than just GenericCalc if the compiler's preferred result type is a list. I'm not sure it's right, but it gets me past the error.

      Unfortunately, I discover downstream that when the UDF is actually executed, args[0].evaluate(eval) returns an anonymous Iterable generated from RolapNamedSetEvaluator.evaluateMemberIterable(), rather than a List, causing a class cast exception.

      That's not too bad, since it's easy to build an ArrayList from an Iterable in reverse order. It does, however, mean that choosing the optimal initial size of the return ArrayList can't be done without a full scan, which is a bit self-defeating.

        Activity

        Hide
        Julian Hyde added a comment -
        Fixed in change 12979.
        Show
        Julian Hyde added a comment - Fixed in change 12979.

          People

          • Assignee:
            Julian Hyde
            Reporter:
            Eric McDermid
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: