Skip to content

Commit

Permalink
Mondrian: bug fixes for cached expression, ParallelPeriod
Browse files Browse the repository at this point in the history
boundary case, and NECJ when ExpandNonNative is set.

[git-p4: depot-paths = "//open/mondrian/": change = 10858]
  • Loading branch information
Rushan Chen committed Apr 11, 2008
1 parent a271d13 commit 0914fea
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 70 deletions.
7 changes: 7 additions & 0 deletions src/main/mondrian/olap/fun/LeadLagFunDef.java
Expand Up @@ -56,6 +56,13 @@ public Member evaluateMember(Evaluator evaluator) {
Member member = memberCalc.evaluateMember(evaluator);
int n = integerCalc.evaluateInteger(evaluator);
if (lag) {
if (n == Integer.MIN_VALUE) {
// bump up lagValue by one
// otherwise -n(used in the getLeadMember call below)is out of range
// because Integer.MAX_VALUE == -(Integer.MIN_VALUE + 1)
n += 1;
}

n = -n;
}
return evaluator.getSchemaReader().getLeadMember(member, n);
Expand Down
7 changes: 7 additions & 0 deletions src/main/mondrian/olap/fun/ParallelPeriodFunDef.java
Expand Up @@ -134,6 +134,13 @@ Member parallelPeriod(
);
}

if (lagValue == Integer.MIN_VALUE) {
// bump up lagValue by one
// otherwise -lagValue(used in the getleadMember call below)is out of range
// because Integer.MAX_VALUE == -(Integer.MIN_VALUE + 1)
lagValue += 1;
}

int distance = member.getLevel().getDepth() -
ancestorLevel.getDepth();
Member ancestor = FunUtil.ancestor(
Expand Down
1 change: 0 additions & 1 deletion src/main/mondrian/rolap/FastBatchingCellReader.java
Expand Up @@ -168,7 +168,6 @@ boolean loadAggregations() {
*/
boolean loadAggregations(Query query) {
final long t1 = System.currentTimeMillis();
requestCount = 0;
if (!isDirty()) {
return false;
}
Expand Down
25 changes: 15 additions & 10 deletions src/main/mondrian/rolap/RolapNativeCrossJoin.java
Expand Up @@ -83,28 +83,33 @@ NativeEvaluator createEvaluator(RolapEvaluator evaluator, FunDef fun, Exp[] args
return null;
}

// check if all CrossJoinArgs are "All" members
// "All" members do not have relational representation.
boolean inputListsContainNonAllMember = false;
// check if all CrossJoinArgs are either "All" members or Calc members
// "All" members and calc members do not have relational expression.
// If NECJ only has these two types if inputs, then sql evaluation is
// not possible.
int countNonNativeInputArg = 0;

for (CrossJoinArg arg : cargs) {
if (!(arg instanceof MemberListCrossJoinArg) ||
!((MemberListCrossJoinArg)arg).hasAllMember()) {
inputListsContainNonAllMember = true;
break;
if (arg instanceof MemberListCrossJoinArg) {
MemberListCrossJoinArg cjArg =
(MemberListCrossJoinArg)arg;
if (cjArg.hasAllMember() ||
cjArg.hasCalcMembers()) {
countNonNativeInputArg ++;
}
}
}

if (!inputListsContainNonAllMember) {
if (countNonNativeInputArg == 2) {
// All inputs contain "All" members.
// Native evaluation is not feasible.
alertCrossJoinNonNative(
evaluator,
fun,
"all arguments contain either the ALL member or a calculated member");
"all arguments contain either the ALL member or a calculated member");
return null;
}

if (isPreferInterpreter(cargs, true)) {
// Native evaluation wouldn't buy us anything, so no
// need to alert
Expand Down
32 changes: 32 additions & 0 deletions testsrc/main/mondrian/olap/fun/FunctionTest.java
Expand Up @@ -80,6 +80,38 @@ public class FunctionTest extends FoodMartTestCase {
" [Customers].[All Customers].[USA].[CA].[Bellflower], " +
" [Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer])");

/**
* Tests that Integeer.MIN_VALUE(-2147483648) does not cause NPE.
*/
public void testParallelPeriodMinValue() {
String query =
"with " +
"member [measures].[foo] as " +
"'([Measures].[unit sales],ParallelPeriod([Time].[Quarter], -2147483648))' " +
"select " +
"[measures].[foo] on columns, " +
"[time].[1997].children on rows " +
"from [sales]";

executeQuery(query);
}

/**
* Tests that Integeer.MIN_VALUE(-2147483648) in Lag is handled correctly.
*/
public void testLagMinValue() {
String query =
"with " +
"member [measures].[foo] as " +
"'([Measures].[unit sales], [Time].[1997].[Q1].Lag(-2147483648))' " +
"select " +
"[measures].[foo] on columns, " +
"[time].[1997].children on rows " +
"from [sales]";

executeQuery(query);
}

public void testNumericLiteral() {
assertExprReturns("2", "2");
if (false) {
Expand Down
31 changes: 31 additions & 0 deletions testsrc/main/mondrian/rolap/FastBatchingCellReaderTest.java
Expand Up @@ -34,6 +34,37 @@ protected void setUp() throws Exception {
getTestContext().clearConnection();
}

public void testMissingSubtotalBug() {
String query =
"With " +
"Set [*NATIVE_CJ_SET] as " +
"'NonEmptyCrossJoin({[Time].[Year].[1997]}," +
" NonEmptyCrossJoin({[Product].[All Products].[Drink]},{[Education Level].[All Education Levels].[Bachelors Degree]}))' " +
"Set [*METRIC_CJ_SET] as 'Filter([*NATIVE_CJ_SET],[Measures].[*Unit Sales_SEL~SUM] > 1000.0)' "+
"Set [*METRIC_MEMBERS_Education Level] as 'Generate([*METRIC_CJ_SET], {[Education Level].CurrentMember})' " +
"Member [Measures].[*Unit Sales_SEL~SUM] as '([Measures].[Unit Sales],[Time].CurrentMember,[Product].CurrentMember,[Education Level].CurrentMember)', SOLVE_ORDER=200 " +
"Member [Education Level].[*CTX_MEMBER_SEL~SUM] as 'Sum(Filter([*METRIC_MEMBERS_Education Level],[Measures].[*Unit Sales_SEL~SUM] > 1000.0))', SOLVE_ORDER=-102 " +
"Select " +
"{[Measures].[Unit Sales]} on columns, " +
"Non Empty Union(CrossJoin(Generate([*METRIC_CJ_SET], {([Time].CurrentMember,[Product].CurrentMember)}),{[Education Level].[*CTX_MEMBER_SEL~SUM]})," +
" Generate([*METRIC_CJ_SET], {([Time].CurrentMember,[Product].CurrentMember,[Education Level].CurrentMember)})) on rows " +
"From [Sales]";

String result =
"Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[Unit Sales]}\n"+
"Axis #2:\n" +
"{[Time].[1997], [Product].[All Products].[Drink], [Education Level].[*CTX_MEMBER_SEL~SUM]}\n" +
"{[Time].[1997], [Product].[All Products].[Drink], [Education Level].[All Education Levels].[Bachelors Degree]}\n" +
"Row #0: 6,423\n" +
"Row #1: 6,423\n";

assertQueryReturns(query, result);
}


public void testShouldUseGroupingFunctionOnPropertyTrueAndOnSupportedDB() {
boolean oldValue = MondrianProperties.instance().EnableGroupingSets.get();
MondrianProperties.instance().EnableGroupingSets.set(true);
Expand Down
155 changes: 96 additions & 59 deletions testsrc/main/mondrian/rolap/NonEmptyTest.java
Expand Up @@ -603,6 +603,101 @@ public void testExpandCalcMembersInAllInputs() {
MondrianProperties.instance().EnableNativeCrossJoin.set(origNativeCrossJoin);
}

/**
* Check that if both inputs to NECJ are either
* AllMember(currentMember, defaultMember are also AllMember)
* or Calcculated member
* native CJ is not used.
*/
public void testExpandCalcMemberInputNECJ() {
String query =
"With \n" +
"Member [Product].[All Products].[Food].[CalcSum] as \n" +
"'Sum({[Product].[All Products].[Food]})', SOLVE_ORDER=-100\n" +
"Select\n" +
"{[Measures].[Store Cost]} on columns,\n" +
"NonEmptyCrossJoin({[Product].[All Products].[Food].[CalcSum]},\n" +
" {[Education Level].DefaultMember}) on rows\n" +
"From [Sales]";

String result =
"Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[Store Cost]}\n" +
"Axis #2:\n" +
"{[Product].[All Products].[Food].[CalcSum], [Education Level].[All Education Levels]}\n" +
"Row #0: 163,270.72\n";

boolean origExpandNonNative =
MondrianProperties.instance().ExpandNonNative.get();
MondrianProperties.instance().ExpandNonNative.set(true);
try {
checkNotNative(1, query, fold(result));
} finally {
MondrianProperties.instance().ExpandNonNative.set(origExpandNonNative);
}
}

/**
* Verify that naitve evaluation is possible when calculated members are present
* expanded member list inputs to NECJ, as long as the other input to NECJ can be
* expressed in SQL.
*
*/
public void testExpandCalcMembers() {
// Note there is a bug currently wrt Calc members in the inputs to native cross join.
// See testCjEnumCalcMembersBug() test.
// However, that bug doe snot affect this test as the empty cell is filtered out by
// the Filter, whose result is not affected by the calc members in its input.
String query =
"with " +
"member [Store Type].[All Store Types].[S] as sum({[Store Type].[All Store Types]}) " +
"set [Enum Store Types] as {" +
" [Store Type].[All Store Types].[Small Grocery], " +
" [Store Type].[All Store Types].[Supermarket], " +
" [Store Type].[All Store Types].[HeadQuarters], " +
" [Store Type].[All Store Types].[S]} " +
"set [Filtered Enum Store Types] as Filter([Enum Store Types], [Measures].[Unit Sales] > 0)" +
"select NonEmptyCrossJoin([Product].[All Products].Children, [Filtered Enum Store Types]) on rows from [Sales]";

String result =
"Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Product].[All Products].[Drink], [Store Type].[All Store Types].[Small Grocery]}\n" +
"{[Product].[All Products].[Drink], [Store Type].[All Store Types].[Supermarket]}\n" +
"{[Product].[All Products].[Drink], [Store Type].[All Store Types].[S]}\n" +
"{[Product].[All Products].[Food], [Store Type].[All Store Types].[Small Grocery]}\n" +
"{[Product].[All Products].[Food], [Store Type].[All Store Types].[Supermarket]}\n" +
"{[Product].[All Products].[Food], [Store Type].[All Store Types].[S]}\n" +
"{[Product].[All Products].[Non-Consumable], [Store Type].[All Store Types].[Small Grocery]}\n" +
"{[Product].[All Products].[Non-Consumable], [Store Type].[All Store Types].[Supermarket]}\n" +
"{[Product].[All Products].[Non-Consumable], [Store Type].[All Store Types].[S]}\n" +
"Row #0: 574\n" +
"Row #0: 14,092\n" +
"Row #0: 24,597\n" +
"Row #0: 4,764\n" +
"Row #0: 108,188\n" +
"Row #0: 191,940\n" +
"Row #0: 1,219\n" +
"Row #0: 28,275\n" +
"Row #0: 50,236\n";

boolean origExpandNonNative =
MondrianProperties.instance().ExpandNonNative.get();
MondrianProperties.instance().ExpandNonNative.set(true);

// Get a fresh connection; Otherwise the mondrian property setting
// is not refreshed for this parameter.
boolean requestFreshConnection = true;
try {
checkNative(0, 9, query, fold(result), requestFreshConnection);
} finally {
MondrianProperties.instance().ExpandNonNative.set(origExpandNonNative);
}
}

/**
* Verify that evaluation is native for expressions with nested non native
* inputs that preduce MemberList results.
Expand Down Expand Up @@ -727,64 +822,6 @@ public void testExpandDifferentLevels() {
}
}

/**
* Verify that naitve evaluation is possible when calculated members are present
* expanded member list inputs to NECJ.
*
*/
public void testExpandCalcMembers() {
// Note there is a bug currently wrt Calc members in the inputs to native cross join.
// See testCjEnumCalcMembersBug() test.
// However, that bug doe snot affect this test as the empty cell is filtered out by
// the Filter, whose result is not affected by the calc members in its input.
String query =
"with " +
"member [Store Type].[All Store Types].[S] as sum({[Store Type].[All Store Types]}) " +
"set [Enum Store Types] as {" +
" [Store Type].[All Store Types].[Small Grocery], " +
" [Store Type].[All Store Types].[Supermarket], " +
" [Store Type].[All Store Types].[HeadQuarters], " +
" [Store Type].[All Store Types].[S]} " +
"set [Filtered Enum Store Types] as Filter([Enum Store Types], [Measures].[Unit Sales] > 0)" +
"select NonEmptyCrossJoin([Product].[All Products].Children, [Filtered Enum Store Types]) on rows from [Sales]";

String result =
"Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Product].[All Products].[Drink], [Store Type].[All Store Types].[Small Grocery]}\n" +
"{[Product].[All Products].[Drink], [Store Type].[All Store Types].[Supermarket]}\n" +
"{[Product].[All Products].[Drink], [Store Type].[All Store Types].[S]}\n" +
"{[Product].[All Products].[Food], [Store Type].[All Store Types].[Small Grocery]}\n" +
"{[Product].[All Products].[Food], [Store Type].[All Store Types].[Supermarket]}\n" +
"{[Product].[All Products].[Food], [Store Type].[All Store Types].[S]}\n" +
"{[Product].[All Products].[Non-Consumable], [Store Type].[All Store Types].[Small Grocery]}\n" +
"{[Product].[All Products].[Non-Consumable], [Store Type].[All Store Types].[Supermarket]}\n" +
"{[Product].[All Products].[Non-Consumable], [Store Type].[All Store Types].[S]}\n" +
"Row #0: 574\n" +
"Row #0: 14,092\n" +
"Row #0: 24,597\n" +
"Row #0: 4,764\n" +
"Row #0: 108,188\n" +
"Row #0: 191,940\n" +
"Row #0: 1,219\n" +
"Row #0: 28,275\n" +
"Row #0: 50,236\n";

boolean origExpandNonNative =
MondrianProperties.instance().ExpandNonNative.get();
MondrianProperties.instance().ExpandNonNative.set(true);

// Get a fresh connection; Otherwise the mondrian property setting
// is not refreshed for this parameter.
boolean requestFreshConnection = true;
try {
checkNative(0, 9, query, fold(result), requestFreshConnection);
} finally {
MondrianProperties.instance().ExpandNonNative.set(origExpandNonNative);
}
}

/**
* Verify that native evaluation is turned off for tuple inputs, even if
* ExpandNonNative is set.
Expand Down Expand Up @@ -814,7 +851,7 @@ public void testExpandTupleInputs() {
MondrianProperties.instance().ExpandNonNative.set(origExpandNonNative);
}
}

/**
* Verify that native MemberLists inputs are subject to SQL constriant
* limitation. If mondrian.rolap.maxConstraints is set too low, native
Expand Down

0 comments on commit 0914fea

Please sign in to comment.