Skip to content

Commit

Permalink
MONDRIAN - Fixed LER-4059. The check to determine whether a function
Browse files Browse the repository at this point in the history
       applied on a measures dimension/member should disable a cross join was
       incorrect.

[git-p4: depot-paths = "//open/mondrian/": change = 8643]
  • Loading branch information
Zelaine Fong committed Feb 2, 2007
1 parent 2e260c4 commit 498b5c8
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 17 deletions.
45 changes: 28 additions & 17 deletions src/main/mondrian/olap/fun/FunUtil.java
Expand Up @@ -1743,27 +1743,38 @@ public static FunDef resolveFunArgs(
final FunTable funTable = validator.getFunTable();
FunDef funDef = funTable.getDef(newArgs, validator, name, syntax);

// if a measure or the measures dimension is referenced in a function,
// then native cross joins cannot be used because the functions need
// to be executed to determine the resultant measures; the set
// function is ok since it just enumerates its arguments
// If the first argument to a function is either:
// 1) the measures dimension or
// 2) a measures member where the function returns another member or
// a set,
// then these are functions that dynamically return one or more
// members ofthe measures dimension. In that case, we cannot use
// native cross joins because the functions need to be executed to
// determine the resultant measures.
//
// As a result, we disallow functions like AllMembers applied on the
// Measures dimension as well as functions like the range operator,
// siblings, and lag, when the argument is a measure member.
// However, we do allow functions like isEmpty, rank, and topPercent.
// Also, the set function is ok since it just enumerates its
// arguments.
if (!(funDef instanceof SetFunDef) && query != null &&
query.nativeCrossJoinVirtualCube())
{
int[] paramCategories = funDef.getParameterCategories();
for (int i = 0; i < paramCategories.length; i++) {
if ((paramCategories[i] == Category.Dimension &&
newArgs[i] instanceof DimensionExpr &&
((DimensionExpr) newArgs[i]).getDimension().
getOrdinal(cube) == 0) ||
(paramCategories[i] == Category.Member &&
newArgs[i] instanceof MemberExpr &&
((MemberExpr) newArgs[i]).getMember().getDimension().
getOrdinal(cube) == 0))
{
query.setVirtualCubeNonNativeCrossJoin();
break;
}
if (paramCategories.length > 0 &&
((paramCategories[0] == Category.Dimension &&
newArgs[0] instanceof DimensionExpr &&
((DimensionExpr) newArgs[0]).getDimension().
getOrdinal(cube) == 0) ||
(paramCategories[0] == Category.Member &&
newArgs[0] instanceof MemberExpr &&
((MemberExpr) newArgs[0]).getMember().getDimension().
getOrdinal(cube) == 0 &&
(funDef.getReturnCategory() == Category.Member ||
funDef.getReturnCategory() == Category.Set))))
{
query.setVirtualCubeNonNativeCrossJoin();
}
}

Expand Down
47 changes: 47 additions & 0 deletions testsrc/main/mondrian/rolap/NonEmptyTest.java
Expand Up @@ -1411,6 +1411,53 @@ public void testCrossJoinEvaluatorContext2()
"Row #2: 50.28%\n" +
"Row #2: 100.00%\n"));
}

public void testVCNativeCJWithIsEmptyOnMeasure()
{
// Don't use checkNative method here because in the case where
// native cross join isn't used, the query causes a stack overflow.
//
// A measures member is referenced in the IsEmpty() function. This
// shouldn't prevent native cross join from being used.
assertQueryReturns(
"with " +
"set BM_PRODUCT as {[Product].[All Products].[Drink]} " +
"set BM_EDU as [Education Level].[Education Level].Members " +
"set BM_GENDER as {[Gender].[Gender].[M]} " +
"set CJ as NonEmptyCrossJoin(BM_GENDER,NonEmptyCrossJoin(BM_EDU,BM_PRODUCT)) " +
"set GM_PRODUCT as Generate(CJ, {[Product].CurrentMember}) " +
"set GM_EDU as Generate(CJ, {[Education Level].CurrentMember}) " +
"set GM_GENDER as Generate(CJ, {[Gender].CurrentMember}) " +
"set GM_MEASURE as {[Measures].[Unit Sales]} " +
"member [Education Level].FILTER1 as Aggregate(GM_EDU) " +
"member [Gender].FILTER2 as Aggregate(GM_GENDER) " +
"select " +
"Filter(GM_PRODUCT, Not IsEmpty([Measures].[Unit Sales])) on rows, " +
"GM_MEASURE on columns " +
"from [Warehouse and Sales] " +
"where ([Education Level].FILTER1, [Gender].FILTER2)",
fold(
"Axis #0:\n" +
"{[Education Level].[FILTER1], [Gender].[FILTER2]}\n" +
"Axis #1:\n" +
"{[Measures].[Unit Sales]}\n" +
"Axis #2:\n" +
"{[Product].[All Products].[Drink]}\n" +
"Row #0: 12,395\n"));
}

public void testVCNativeCJWithTopPercent()
{
// The reference to [Store Sales] inside the topPercent function
// should not prevent native cross joins from being used
checkNative(
92,
1,
"select {topPercent(nonemptycrossjoin([Product].[Product Department].members, " +
"[Time].[1997].children),10,[Measures].[Store Sales])} on columns, " +
"{[Measures].[Store Sales]} on rows from " +
"[Warehouse and Sales]");
}

/**
* make sure the following is not run natively
Expand Down

0 comments on commit 498b5c8

Please sign in to comment.