Skip to content

Commit

Permalink
MONDRIAN: Fix MONDRIAN-734, "Exception thrown when creating a 'New An…
Browse files Browse the repository at this point in the history
…alysis View'

    with JPivot".  Also fix bugs with aggregate tables: change 13479 fixed some
    things but broke others.

[git-p4: depot-paths = "//open/mondrian-release/3.2/": change = 13600]
  • Loading branch information
julianhyde committed May 3, 2010
1 parent b667f21 commit 4d7d237
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 23 deletions.
10 changes: 10 additions & 0 deletions src/main/mondrian/rolap/RolapEvaluator.java
Expand Up @@ -78,6 +78,16 @@ public class RolapEvaluator implements Evaluator {
private Boolean nativeEnabled;
private Member[] nonAllMembers;

/**
* Set of expressions actively being expanded. Prevents infinite cycle of
* expansions.
*
* @return Mutable set of expressions being expanded
*/
public Set<Exp> getActiveNativeExpansions() {
return root.activeNativeExpansions;
}

/**
* States of the finite state machine for determining the max solve order
* for the "scoped" behavior.
Expand Down
2 changes: 2 additions & 0 deletions src/main/mondrian/rolap/RolapEvaluatorRoot.java
Expand Up @@ -53,6 +53,8 @@ class RolapEvaluatorRoot {
MondrianProperties.instance().SolveOrderMode.get().toUpperCase(),
MondrianProperties.SolveOrderModeEnum.ABSOLUTE);

final Set<Exp> activeNativeExpansions = new HashSet<Exp>();

/**
* Creates a RolapEvaluatorRoot.
*
Expand Down
5 changes: 5 additions & 0 deletions src/main/mondrian/rolap/SqlConstraintUtils.java
Expand Up @@ -1133,6 +1133,11 @@ private static String generateSingleValueInExpr(
int bitPos = column.getBitPosition();
AggStar.Table.Column aggColumn =
aggStar.lookupColumn(bitPos);
if (aggColumn == null) {
throw Util.newInternal(
"AggStar " + aggStar + " has no column for "
+ column + " (bitPos " + bitPos + ")");
}
AggStar.Table table = aggColumn.getTable();
table.addToFrom(sqlQuery, false, true);
q = aggColumn.generateExprString(sqlQuery);
Expand Down
44 changes: 26 additions & 18 deletions src/main/mondrian/rolap/SqlTupleReader.java
Expand Up @@ -780,7 +780,7 @@ String generateSelectForLevels(


Evaluator evaluator = getEvaluator(constraint);
AggStar aggStar = chooseAggStar(evaluator);
AggStar aggStar = chooseAggStar(constraint, evaluator);

// add the selects for all levels to fetch
for (TargetBase target : targets) {
Expand Down Expand Up @@ -1083,20 +1083,6 @@ protected void addLevelMemberSql(
*/
protected Evaluator getEvaluator(TupleConstraint constraint) {
if (constraint instanceof SqlContextConstraint) {
if (constraint
instanceof RolapNativeCrossJoin.NonEmptyCrossJoinConstraint)
{
// Cannot evaluate NonEmptyCrossJoinConstraint using an agg
// table if one of its args is a DescendantsConstraint.
RolapNativeCrossJoin.NonEmptyCrossJoinConstraint necj =
(RolapNativeCrossJoin.NonEmptyCrossJoinConstraint)
constraint;
for (CrossJoinArg arg : necj.args) {
if (!(arg instanceof MemberListCrossJoinArg)) {
return null;
}
}
}
return constraint.getEvaluator();
}
if (constraint instanceof DescendantsConstraint) {
Expand All @@ -1116,11 +1102,11 @@ protected Evaluator getEvaluator(TupleConstraint constraint) {
* Obtains the AggStar instance which corresponds to an aggregate table
* which can be used to support the member constraint.
*
* @param constraint
* @param evaluator the current evaluator to obtain the cube and members to
* be queried
* @return AggStar for aggregate table
* be queried @return AggStar for aggregate table
*/
AggStar chooseAggStar(Evaluator evaluator) {
AggStar chooseAggStar(TupleConstraint constraint, Evaluator evaluator) {
if (!MondrianProperties.instance().UseAggregates.get()) {
return null;
}
Expand Down Expand Up @@ -1182,6 +1168,28 @@ AggStar chooseAggStar(Evaluator evaluator) {

measureBitKey.set(bitPosition);

if (constraint
instanceof RolapNativeCrossJoin.NonEmptyCrossJoinConstraint)
{
// Cannot evaluate NonEmptyCrossJoinConstraint using an agg
// table if one of its args is a DescendantsConstraint.
RolapNativeCrossJoin.NonEmptyCrossJoinConstraint necj =
(RolapNativeCrossJoin.NonEmptyCrossJoinConstraint)
constraint;
for (CrossJoinArg arg : necj.args) {
if (arg instanceof DescendantsCrossJoinArg
|| arg instanceof MemberListCrossJoinArg)
{
final RolapLevel level = arg.getLevel();
if (level != null && !level.isAll()) {
RolapStar.Column column =
((RolapCubeLevel)level).getStarKeyColumn();
levelBitKey.set(column.getBitPosition());
}
}
}
}

// find the aggstar using the masks
AggStar aggStar = AggregationManager.instance().findAgg(
star, levelBitKey, measureBitKey, new boolean[]{ false });
Expand Down
6 changes: 5 additions & 1 deletion src/main/mondrian/rolap/sql/CrossJoinArgFactory.java
Expand Up @@ -895,7 +895,9 @@ private CrossJoinArg[] expandNonNative(
{
ExpCompiler compiler = evaluator.getQuery().createCompiler();
CrossJoinArg[] arg0 = null;
if (shouldExpandNonEmpty(exp)) {
if (shouldExpandNonEmpty(exp)
&& evaluator.getActiveNativeExpansions().add(exp))
{
ListCalc listCalc0 = compiler.compileList(exp);
List<RolapMember> list0 =
Util.cast(listCalc0.evaluateList(evaluator));
Expand All @@ -909,12 +911,14 @@ private CrossJoinArg[] expandNonNative(
if (arg != null) {
arg0 = new CrossJoinArg[]{arg};
}
evaluator.getActiveNativeExpansions().remove(exp);
}
return arg0;
}

private boolean shouldExpandNonEmpty(Exp exp) {
return MondrianProperties.instance().ExpandNonNative.get()
// && !MondrianProperties.instance().EnableNativeCrossJoin.get()
|| isCheapSet(exp);
}

Expand Down
40 changes: 36 additions & 4 deletions testsrc/main/mondrian/rolap/NonEmptyTest.java
Expand Up @@ -103,7 +103,7 @@ public void testBugCantRestrictSlicerToCalcMember() throws Exception {
* mondrian is doing crossjoins in memory; and the test case throws because
* the result limit is exceeded.
*/
public void testAnalyzerPerformanceIssue() throws Exception {
public void testAnalyzerPerformanceIssue() {
final MondrianProperties mondrianProperties =
MondrianProperties.instance();
propSaver.set(mondrianProperties.EnableNativeCrossJoin, true);
Expand Down Expand Up @@ -714,7 +714,7 @@ public void testBug1515302() {
* RolapStar in SqlContextConstraint/SqlConstraintUtils. Test ensures that
* no exception is thrown.
*/
public void testVirtualCube() throws Exception {
public void testVirtualCube() {
if (MondrianProperties.instance().TestExpDependencies.get() > 0) {
return;
}
Expand Down Expand Up @@ -3729,7 +3729,7 @@ public void testNonEmptyResults() {
* MONDRIAN-412, "NON EMPTY and Filter() breaking aggregate
* calculations"</a>.
*/
public void testBugMondrian412() throws Exception {
public void testBugMondrian412() {
TestContext ctx = getTestContext();
ctx.assertQueryReturns(
"with member [Measures].[AvgRevenue] as 'Avg([Store].[Store Name].Members, [Measures].[Store Sales])' "
Expand Down Expand Up @@ -4344,7 +4344,7 @@ public void testNonUniformConstraintsAreNotUsedForOptimization() {
getTestContext(), mdx, new SqlPattern[]{pattern},true, false, true);
}

public void _testMeasureConstraintsInACrossjoinHaveCorrectResults() {
public void testMeasureConstraintsInACrossjoinHaveCorrectResults() {
//http://jira.pentaho.com/browse/MONDRIAN-715
propSaver.set(MondrianProperties.instance().EnableNativeNonEmpty, true);
String mdx =
Expand Down Expand Up @@ -4472,6 +4472,38 @@ public void testCalculatedDefaultMeasureOnVirtualCubeNoThrowException() {
+ "Row #2: 124,366\n");
}

/**
* Test case for <a href="http://jira.pentaho.com/browse/MONDRIAN-734">
* MONDRIAN-734, "Exception thrown when creating a "New Analysis View" with
* JPivot"</a>.
*/
public void testExpandNonNativeWithEnableNativeCrossJoin() {
final MondrianProperties mondrianProperties =
MondrianProperties.instance();
propSaver.set(mondrianProperties.EnableNativeCrossJoin, true);
propSaver.set(mondrianProperties.ExpandNonNative, true);

String mdx =
"select NON EMPTY {[Measures].[Unit Sales]} ON COLUMNS,"
+ " NON EMPTY Crossjoin(Hierarchize(Crossjoin({[Store].[All Stores]}, Crossjoin({[Store Size in SQFT].[All Store Size in SQFTs]}, Crossjoin({[Store Type].[All Store Types]}, Union(Crossjoin({[Time].[1997]}, {[Product].[All Products]}), Crossjoin({[Time].[1997]}, [Product].[All Products].Children)))))), {([Promotion Media].[All Media], [Promotions].[All Promotions], [Customers].[All Customers], [Education Level].[All Education Levels], [Gender].[All Gender], [Marital Status].[All Marital Status], [Yearly Income].[All Yearly Incomes])}) ON ROWS"
+ " from [Sales]";
assertQueryReturns(
mdx,
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[All Stores], [Store Size in SQFT].[All Store Size in SQFTs], [Store Type].[All Store Types], [Time].[1997], [Product].[All Products], [Promotion Media].[All Media], [Promotions].[All Promotions], [Customers].[All Customers], [Education Level].[All Education Levels], [Gender].[All Gender], [Marital Status].[All Marital Status], [Yearly Income].[All Yearly Incomes]}\n"
+ "{[Store].[All Stores], [Store Size in SQFT].[All Store Size in SQFTs], [Store Type].[All Store Types], [Time].[1997], [Product].[Drink], [Promotion Media].[All Media], [Promotions].[All Promotions], [Customers].[All Customers], [Education Level].[All Education Levels], [Gender].[All Gender], [Marital Status].[All Marital Status], [Yearly Income].[All Yearly Incomes]}\n"
+ "{[Store].[All Stores], [Store Size in SQFT].[All Store Size in SQFTs], [Store Type].[All Store Types], [Time].[1997], [Product].[Food], [Promotion Media].[All Media], [Promotions].[All Promotions], [Customers].[All Customers], [Education Level].[All Education Levels], [Gender].[All Gender], [Marital Status].[All Marital Status], [Yearly Income].[All Yearly Incomes]}\n"
+ "{[Store].[All Stores], [Store Size in SQFT].[All Store Size in SQFTs], [Store Type].[All Store Types], [Time].[1997], [Product].[Non-Consumable], [Promotion Media].[All Media], [Promotions].[All Promotions], [Customers].[All Customers], [Education Level].[All Education Levels], [Gender].[All Gender], [Marital Status].[All Marital Status], [Yearly Income].[All Yearly Incomes]}\n"
+ "Row #0: 266,773\n"
+ "Row #1: 24,597\n"
+ "Row #2: 191,940\n"
+ "Row #3: 50,236\n");
}

void clearAndHardenCache(MemberCacheHelper helper) {
helper.mapLevelToMembers.setCache(
new HardSmartCache<Pair<RolapLevel, Object>, List<RolapMember>>());
Expand Down

0 comments on commit 4d7d237

Please sign in to comment.