[Mondrian] Problem moving UDF returning a list from 2.4 to 3.1.1

Eric McDermid mcdermid at stonecreek.com
Tue Aug 4 02:42:55 EDT 2009


Thanks for the quick fix, Julian.  Im applying it now.

Blindly casting the argument did seem unsafe (for obvious reasons  
given the ClassCastException), but this was legacy code I inherited.   
Existing examples seem to use exactly that technique, which is  
probably how the pattern got established.  The new javadoc you've  
included should definitely help on that front.

It seems to me that the reverse function is generically useful, by the  
way.  Is it worth adding to the built-in UDF suite alongside  
MatchesUdf, NullValueUdf, etcetera?

  -- Eric


On Aug 3, 2009, at 11:49 PM, Julian Hyde wrote:

> By coincidence, I had remembered that you had received a  
> ClassCastException, and there was something to do with a calculated  
> set, and I was investigating as you filed the bug.
>
> Mondrian implements MDX sets as both java.util.List and  
> java.util.Iterable internally. It is not safe for the author of a  
> UDF to assume that if the argument is an MDX set then  
> Argument.evaluate will return a List, as you did in your Reverse  
> UDF. I added new methods Argument.evaluateList and  
> Argument.evaluateIter. The author of the UDF must call one of these.
>
> See further comments in the bug: http://jira.pentaho.com/browse/MONDRIAN-589
>
> Note that this is fixed on the 3.1 branch.
>
> Julian
>
> From: Eric McDermid [mailto:mcdermid at stonecreek.com]
> Sent: Monday, August 03, 2009 8:31 PM
> To: jhyde at pentaho.com
> Cc: Mondrian developer mailing list
> Subject: Re: [Mondrian] Problem moving UDF returning a list from 2.4  
> to 3.1.1
>
> Thanks for the fix, Julian.
>
> Running the new code, I do find that i still run into the second  
> issue I mentioned below (args[0] evaluating anonymous Iterable  
> rather than a List).  Near as I can tell, the problem only occurs  
> when passing a named set to the UDF.
>
> I've created a simple reproduction case that demonstrates the  
> problem, and created MONDRIAN-589 to track it.
>
>  -- Eric
>
> On Jul 31, 2009, at 9:10 PM, Eric McDermid wrote:
>
>> Done.  Mondrian-588.
>>
>> I've also added some further notes in that description.  I  
>> experimented this afternoon 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 the right answer, and I've yet to run the full  
>> test suite on it, but it does get me past the error.
>>
>> Unfortunately, when the Reverse UDF is actually executed,  
>> "args[0].evaluate(eval)" returns an anonymous Iterable generated  
>> from RolapNamedSetEvaluator.evaluateMemberIterable(), rather than a  
>> List as used to be the case under 2.4, triggering a class cast  
>> exception.  This has nothing to do with my workaround; I've seen it  
>> prior to the change as well.
>>
>>  -- Eric
>>
>> On Jul 31, 2009, at 7:33 PM, Julian Hyde wrote:
>>
>>> I'll look into it over the weekend. Can you please log a bug.
>>>
>>> Julian
>>>
>>> From: mondrian-bounces at pentaho.org [mailto:mondrian-bounces at pentaho.org 
>>> ] On Behalf Of Eric McDermid
>>> Sent: Friday, July 31, 2009 10:36 AM
>>> To: Mondrian developer mailing list
>>> Subject: [Mondrian] Problem moving UDF returning a list from 2.4  
>>> to 3.1.1
>>>
>>> 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 at 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.
>>>
>>> Can anyone help me sort this problem out, or failing that at least  
>>> point me to an example of a UDF that does successfully return a  
>>> list that I can compare against?
>>>
>>>  -- Eric
>>>
>>>
>>> _______________________________________________
>>> Mondrian mailing list
>>> Mondrian at pentaho.org
>>> http://lists.pentaho.org/mailman/listinfo/mondrian
>>
>> _______________________________________________
>> Mondrian mailing list
>> Mondrian at pentaho.org
>> http://lists.pentaho.org/mailman/listinfo/mondrian
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.pentaho.org/pipermail/mondrian/attachments/20090804/3fd48258/attachment.html 


More information about the Mondrian mailing list