rankfundef.java

来自「数据仓库展示程序」· Java 代码 · 共 468 行 · 第 1/2 页

JAVA
468
字号
/*
// $Id: //open/mondrian/src/main/mondrian/olap/fun/RankFunDef.java#6 $
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// (C) Copyright 2005-2005 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/

package mondrian.olap.fun;

import mondrian.olap.*;
import mondrian.olap.type.Type;
import mondrian.olap.type.NumericType;

import java.util.*;
import java.io.PrintWriter;

/**
 * Definition of the <code>RANK</code> MDX function.
 *
 * @author Richard Emberson
 * @since 17 January, 2005
 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/RankFunDef.java#6 $
 */
public abstract class RankFunDef extends FunDefBase {
    public RankFunDef(FunDef dummyFunDef) {
        super(dummyFunDef);
    }

    protected Exp validateArg(
            Validator validator, FunCall call, int i, int type) {
        // If this is the two-argument form of the function,
        // and if expression cache is enabled,
        // wrap second argument (the set)
        // in a function which will use the expression cache.
        if (call.getArgCount() == 2 && i == 1) {
            Exp arg = call.getArgs()[1];
            RankedListExp rankedListExp = new RankedListExp(arg);
            if (MondrianProperties.instance().EnableExpCache.get()) {
                final Exp cacheCall = new FunCall(
                        "$Cache",
                        Syntax.Internal,
                        new Exp[] {
                            rankedListExp
                        });
                return validator.validate(cacheCall, false);
            } else {
                return validator.validate(rankedListExp, false);
            }
        }
        return super.validateArg(validator, call, i, type);
    }

    /**
     * Returns whether two tuples are equal.
     */
    static boolean equalTuple(Member[] tuple, Member[] m) {
        if (tuple.length != m.length) {
            return false;
        }
        for (int i = 0; i < tuple.length; i++) {
            if (! tuple[i].equals(m[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * Returns whether one of the members in a tuple is null.
     */
    static boolean tupleContainsNullMember(Member[] tuple) {
        for (int i = 0; i < tuple.length; i++) {
            // Rank of a null member or partially null tuple returns null.
            Member member = tuple[i];
            if (member.isNull()) {
                return true;
            }
        }
        return false;
    }

    public static MultiResolver createResolver() {
        return new MultiResolver(
                "Rank",
                "Rank(<Tuple>, <Set> [, <Calc Expression>])",
                "Returns the one-based rank of a tuple in a set.",
                new String[]{"fitx","fitxn", "fimx", "fimxn"}) {
            protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) {
                switch (args.length) {
                case 2:
                    return new Rank2FunDef(dummyFunDef);
                case 3:
                    return new Rank3FunDef(dummyFunDef);
                default:
                    throw Util.newInternal("invalid arg count " + args.length);
                }
            }
        };
    }

    /**
     * Rank function with 2 arguments:
     *
     * {@code Rank(<<Tuple>>, <<Set>>)}
     */
    private static class Rank2FunDef extends RankFunDef {
        public Rank2FunDef(FunDef dummyFunDef) {
            super(dummyFunDef);
        }

        public Object evaluate(Evaluator evaluator, Exp[] args) {
            // Get member or tuple.
            // If the member is null (or the tuple contains a null member)
            // the result is null (even if the list is null).
            Exp arg = args[0];
            Object o = arg.evaluate(evaluator);
            if (o == null ||
                    o instanceof Member &&
                    ((Member) o).isNull() ||
                    o instanceof Member[] &&
                    tupleContainsNullMember((Member[]) o)) {
                return null;
            }
            // Get the set of members/tuples.
            // If the list is empty, MSAS cannot figure out the type of the
            // list, so returns an error "Formula error - dimension count is
            // not valid - in the Rank function". We will naturally return 0,
            // which I think is better.
            RankedList rankedList = (RankedList) getArg(evaluator, args, 1);
            if (rankedList == null) {
                return new Double(0);
            }

            if (o instanceof Member[]) {
                Member[] tuple = (Member[]) o;
                if (tupleContainsNullMember(tuple)) {
                    return null;
                }
                // Find position of member in list. -1 signifies not found.
                final int i = rankedList.indexOf(tuple);
                // Return 1-based rank. 0 signifies not found.
                return new Double(i + 1);
            } else if (o instanceof Member) {
                Member member = (Member) o;
                if (member.isNull()) {
                    return null;
                }

                // Find position of member in list. -1 signifies not found.
                final int i = rankedList.indexOf(member);
                // Return 1-based rank. 0 signifies not found.
                return new Double(i + 1);
            } else {
                throw Util.newInternal("Expected tuple or member, got " + o);
            }
        }
    }

    /**
     * Rank function with 3 arguments:
     *
     * {@code Rank(<<Tuple>>, <<Set>>, <<Calc Expression>>)}
     */
    private static class Rank3FunDef extends RankFunDef {
        private ExpCacheDescriptor cacheDescriptor;
        private static final boolean debug = false;

        public Rank3FunDef(FunDef dummyFunDef) {
            super(dummyFunDef);
        }

        public Object evaluate(Evaluator evaluator, Exp[] args) {
            // get tuple
            Member[] tuple = getTupleOrMemberArg(evaluator, args, 0);
            if (tuple == null ||
                    tupleContainsNullMember(tuple)) {
                return null;
            }

            // Compute the value of the tuple.
            final Evaluator evaluator2 = evaluator.push(tuple);
            final Exp sortExp = args[2];
            Object value = sortExp.evaluateScalar(evaluator2);
            if (value instanceof RuntimeException) {
                // The value wasn't ready, so quit now... we'll be back.
                return value;
            }

            // Evaluate the list (or retrieve from cache).
            if (cacheDescriptor == null) {
                final Exp listExp = args[1];
                final BuiltinFunTable funTable = BuiltinFunTable.instance();
                Exp sortedListExp = new SortExp(
                        listExp,
                        funTable.createValueFunCall(
                                sortExp,
                                Util.createSimpleValidator(funTable)));
                cacheDescriptor = new ExpCacheDescriptor(sortedListExp, evaluator);
            }
            final Object cachedResult =
                    evaluator.getCachedResult(cacheDescriptor);
            // If there was an exception while calculating the list, propagate
            // it up.
            if (cachedResult instanceof RuntimeException) {
                return (RuntimeException) cachedResult;
            }
            final SortResult sortResult = (SortResult) cachedResult;
            if (debug) {
                sortResult.print(new PrintWriter(System.out));
            }
            if (sortResult.empty) {
                // If list is empty, the rank is null.
                return Util.nullValue;
            }

            // If value is null, it won't be in the values array.
            if (value == Util.nullValue) {
                return new Double(sortResult.values.length + 1);
            }
            // Look for the ranked value in the array.
            int j = FunUtil.searchValuesDesc(sortResult.values, value);
            if (j < 0) {
                // Value not found. Flip the result to find the insertion point.
                j = -(j + 1);
                return new Double(j + 1); // 1-based
            }
            if (j <= sortResult.values.length) {
                // If the values preceding are equal, increase the rank.
                while (j > 0 && sortResult.values[j - 1].equals(value)) {
                    --j;
                }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?