Skip to content

Commit

Permalink
MONDRIAN: NativizeSet, turning off all native evaluation when below t…
Browse files Browse the repository at this point in the history
…he high cardinality threshold. Fixing ClassCastException when using the .levels() function.

[git-p4: depot-paths = "//open/mondrian/": change = 13112]
  • Loading branch information
Matt Campbell authored and Matt Campbell committed Oct 20, 2009
1 parent b4eec54 commit b5c3aae
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 10 deletions.
11 changes: 11 additions & 0 deletions src/main/mondrian/olap/Evaluator.java
Expand Up @@ -290,6 +290,17 @@ public interface Evaluator {
*/
boolean needToReturnNullForUnrelatedDimension(Member[] members);

/**
* @param enabled indicates if native evaluation should be used
*/
void setNativeEnabled(Boolean enabled);

/**
* indicates whether native evaluation is enabled in this context
* @return boolean
*/
boolean nativeEnabled();

/**
* Interface for evaluating a particular named set.
*/
Expand Down
11 changes: 7 additions & 4 deletions src/main/mondrian/olap/fun/NativizeSetFunDef.java
Expand Up @@ -177,6 +177,7 @@ public List<Member[]> computeTuples(Evaluator evaluator) {
new TransformFromFormulasVisitor(query, compiler));
query.resolve();
ListCalc calc = compiler.compileList(resolved);
evaluator.setNativeEnabled(false);
return calc.evaluateList(evaluator);
}

Expand Down Expand Up @@ -331,9 +332,11 @@ public FindLevelsVisitor(
@Override
public Object visitResolvedFunCall(ResolvedFunCall call) {
if (call.getFunDef() instanceof LevelMembersFunDef) {
Level level = ((LevelExpr) call.getArg(0)).getLevel();
substitutionMap.put(createMemberId(level), level);
dimensions.add(level.getDimension());
if (call.getArg(0) instanceof LevelExpr) {
Level level = ((LevelExpr) call.getArg(0)).getLevel();
substitutionMap.put(createMemberId(level), level);
dimensions.add(level.getDimension());
}
} else if (
functionWhitelist.contains(call.getFunDef().getClass()))
{
Expand Down Expand Up @@ -1400,4 +1403,4 @@ private static String getLevelNameFromMemberName(String memberName) {

}

// End NativizeSetFunDef.java
// End NativizeSetFunDef.java
17 changes: 17 additions & 0 deletions src/main/mondrian/rolap/RolapEvaluator.java
Expand Up @@ -75,6 +75,7 @@ public class RolapEvaluator implements Evaluator {
protected List<List<Member[]>> aggregationLists;

private final List<Member> slicerMembers;
private Boolean nativeEnabled;

/**
* States of the finite state machine for determining the max solve order
Expand Down Expand Up @@ -130,6 +131,8 @@ protected RolapEvaluator(
}
expandingMember = parent.expandingMember;
}
nativeEnabled =
MondrianProperties.instance().EnableNativeNonEmpty.get();
}

/**
Expand Down Expand Up @@ -226,6 +229,14 @@ public boolean needToReturnNullForUnrelatedDimension(Member[] members) {
return false;
}

public boolean nativeEnabled() {
return nativeEnabled;
}

public void setNativeEnabled(final Boolean nativeEnabled) {
this.nativeEnabled = nativeEnabled;
}

protected final Logger getLogger() {
return LOGGER;
}
Expand Down Expand Up @@ -609,6 +620,12 @@ public final Object getProperty(String name, Object defaultValue) {
continue;
}

// Don’t call member.getPropertyValue unless this member’s
// solve order is greater than one we’ve already seen.
// The getSolveOrder call is cheap call compared to the
// getPropertyValue call, and when we’re evaluating millions
// of members, this has proven to make a significant performance
// difference.
final int solve = member.getSolveOrder();
if (solve > maxSolve) {
final Object p = member.getPropertyValue(name);
Expand Down
19 changes: 14 additions & 5 deletions src/main/mondrian/rolap/SqlConstraintFactory.java
Expand Up @@ -8,15 +8,15 @@
*/
package mondrian.rolap;

import java.util.List;

import mondrian.olap.Id;
import mondrian.olap.Evaluator;
import mondrian.olap.Id;
import mondrian.olap.Level;
import mondrian.olap.MondrianProperties;
import mondrian.rolap.sql.MemberChildrenConstraint;
import mondrian.rolap.sql.TupleConstraint;

import java.util.List;

/**
* Creates the right constraint for common tasks.
*
Expand All @@ -36,6 +36,13 @@ public class SqlConstraintFactory {
private SqlConstraintFactory() {
}

private boolean enabled(final Evaluator context) {
if (context != null) {
return enabled && context.nativeEnabled();
}
return enabled;
}

public static SqlConstraintFactory instance() {
setNativeNonEmptyValue();
return instance;
Expand All @@ -48,7 +55,9 @@ public static void setNativeNonEmptyValue() {
public MemberChildrenConstraint getMemberChildrenConstraint(
Evaluator context)
{
if (!enabled || !SqlContextConstraint.isValidContext(context, false)) {
if (!enabled(context)
|| !SqlContextConstraint.isValidContext(context, false))
{
return DefaultMemberChildrenConstraint.instance();
}
return new SqlContextConstraint((RolapEvaluator) context, false);
Expand All @@ -74,7 +83,7 @@ public TupleConstraint getLevelMembersConstraint(
if (context == null) {
return DefaultTupleConstraint.instance();
}
if (!enabled) {
if (!enabled(context)) {
return DefaultTupleConstraint.instance();
}
if (!SqlContextConstraint.isValidContext(
Expand Down
38 changes: 37 additions & 1 deletion testsrc/main/mondrian/olap/fun/NativizeSetFunDefTest.java
Expand Up @@ -5,10 +5,13 @@
import mondrian.olap.Result;
import mondrian.olap.Util;
import mondrian.rolap.NonEmptyTest;
import mondrian.rolap.BatchTestCase;
import mondrian.test.FoodMartTestCase;
import mondrian.test.PropertySaver;
import mondrian.test.SqlPattern;
import mondrian.spi.Dialect;

public class NativizeSetFunDefTest extends FoodMartTestCase {
public class NativizeSetFunDefTest extends BatchTestCase {
private final PropertySaver propSaver = new PropertySaver();
private long highCardThreshold;
private long nativeResultLimit;
Expand Down Expand Up @@ -1208,6 +1211,39 @@ public void testCrossjoinWithFilter() {
+ "Row #0: 131,558\n");
}

public void testEvaluationIsNonNativeWhenBelowHighcardThreshoold() {
NativizeSetFunDef.setHighCardinalityThreshold(10000L);
SqlPattern[] patterns = {
new SqlPattern(
Dialect.DatabaseProduct.ACCESS,
"select `customer`.`gender` as `c0` "
+ "from `customer` as `customer`, `sales_fact_1997` as `sales_fact_1997` "
+ "where `sales_fact_1997`.`customer_id` = `customer`.`customer_id` "
+ "and `customer`.`marital_status` = 'S' "
+ "group by `customer`.`gender` order by 1 ASC", 251)
};
String mdxQuery =
"select non empty NativizeSet("
+ "Crossjoin([Gender].[Gender].members,{[Time].[1997]})) on 0 "
+ "from [Warehouse and Sales] "
+ "where [Marital Status].[Marital Status].[S]";
assertQuerySqlOrNot(
getTestContext(), mdxQuery, patterns, true, false, true);
}

public void testCalculatedLevelsDoNotCauseException() {
String mdx =
"SELECT \n"
+ " Nativizeset\n"
+ " (\n"
+ " {\n"
+ " [Store].Levels(0).MEMBERS\n"
+ " }\n"
+ " ) ON COLUMNS\n"
+ "FROM [Sales]";
checkNotNative(mdx);
}

private void checkNotNative(String mdx) {
NonEmptyTest.checkNotNative(mdx, getResult(removeNativize(mdx)));
}
Expand Down

0 comments on commit b5c3aae

Please sign in to comment.