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 + -
显示快捷键?