[Mondrian] RE: When iif has tupletypes with unequal lengthsasarguments, we get an exception

Julian Hyde jhyde at pentaho.org
Fri Feb 8 11:10:08 EST 2008


Harun,
 
You're approaching this exactly right. As you suspect, the common type
between a member and tuple should be a tuple. That tuple can then be
converted to a scalar, but at a conversion cost, so the system would prefer
to keep it as a tuple.
 
See further comments inline.
 
Julian


  _____  

From: mondrian-bounces at pentaho.org [mailto:mondrian-bounces at pentaho.org] On
Behalf Of Harun Pathan
Sent: Friday, February 08, 2008 5:15 AM
To: mondrian at pentaho.org
Subject: [Mondrian] RE: When iif has tupletypes with unequal
lengthsasarguments, we get an exception


Sorry for late reply. We have been working on this issue, and added a new
IIF Tuple instance as 

    static final FunDefBase TUPLE_INSTANCE =
        new IifFunDef(
            "IIf",
            "Returns one of two tuples determined by a logical test.",
            "ftbtt")
        {
            public Calc compileCall(ResolvedFunCall call, ExpCompiler
compiler) {
                final BooleanCalc booleanCalc =
                    compiler.compileBoolean(call.getArg(0));
                final Calc calc1 = compiler.compileTuple(call.getArg(1));
                final Calc calc2 = compiler.compileTuple(call.getArg(2));
                return new GenericCalc(call) {
                    public Object evaluate(Evaluator evaluator) {
                        final boolean b =
                            booleanCalc.evaluateBoolean(evaluator);
                        Calc calc = b ? calc1 : calc2;
                        return calc.evaluate(evaluator);
                    }

                    public Calc[] getCalcs() {
                        return new Calc[] {booleanCalc, calc1, calc2};
                    }
                };
            }
        };


By incrementing conversion count for Numeric and value instance the
IIF(<expression>,<Tuple>,<Tuple>) version gets resolved as the best match.

We have added a rule to create a commontype between two tuples of unequal
sizes as a larger tuple with scalar types for the extra element types.

As the common tuple might be larger than the smaller original one the
savedMembers array in TupleValueCalc needs to be equal to the size of the 
tuple evaluated by it.

    public Object evaluate(Evaluator evaluator) {
        final Member[] members = tupleCalc.evaluateTuple(evaluator);
        if (members == null) {
            return null;
        }
        for (int i = 0; i < members.length; i++) {
            savedMembers[i] = evaluator.setContext(members[i]);
        }
        final Object o = evaluator.evaluateCurrent();

    //Currently it is just evaluator.setContext(savedMembers[i]);
        for (int i = 0; i < members.length; i++) {
            evaluator.setContext(savedMembers[i]);
        }
        return o;
    }

Is there a better alternative to doing this ? 
 

Making savedMembers a member of the class was a slight optimization that
doesn't apply anymore. Make it a local variable, and it should just work:
 
        final Member[] members = tupleCalc.evaluateTuple(evaluator);
        if (members == null) {
            return null;
        }
      Member[] savedMembers = new Member[members.length];
        for (int i = 0; i < members.length; i++) {
            savedMembers[i] = evaluator.setContext(members[i]);
        }


But this fix failed to work for IIF(<expression>,<Member>,<Tuple>) and
IIF(<expression>,<Tuple>,<Member>),
because in ealier fix we returned a scalar type as a common type between
member and a tuple. 
But when these IIF gets resolved they gets resolved to TUPLE_INSTANCE, where
in we compile tuples and not scalars.

To fix this, we are thinking to change the common type between a tuple of
one Member and Tuple to a larger Tuple as above. 
 

I agree. 




MemberType:


        if (type instanceof TupleType) {
            TupleType tupleType = (TupleType) type;
            if (tupleType.elementTypes.length == 1) {
                return new TupleType(new Type[]
{type}).computeCommonType(tupleType,
                    conversionCount);
            } else {
                return tupleType.computeCommonType(this,conversionCount); //
Currently it is:computeCommonType(tupleType.getValueType, conversionCount);
            }
        }


TupleType:

In TupleType, we create a new tupleType as the commontype for the MemberType
and follow the same logic which is used in case of two tuples.

Is it valid? 
 

It should be valid. It might be possible to ONLY have a Iif(<Boolean>,
<Tuple>, <Tuple>) and if one of the args was a member it would implicitly
convert to tuple.

 Or do you think creating different IIF instances for 
IIF(Expression, Member, Tuple) and IIF(Expression, Tuple, Member) is a good
idea.


We tried MDXs with following IIFs and all are working with the fixes
mentioned above:

IIF(Expression, Member, Tuple)
IIF(Expression, Tuple, Member)
IIF(Expression, Tuple, Tuple) // Tuples of same length
IIF(Expression, Tuple, Tuple) //Tuples of different length
IIF(Expression, Tuple, Tuple) //Tuples with different order of element Types


Julian 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.pentaho.org/pipermail/mondrian/attachments/20080208/d39b0f79/attachment.html 


More information about the Mondrian mailing list