Skip to content

Commit

Permalink
MONDRIAN: [MONDRIAN-960] Adds more tests for this case.
Browse files Browse the repository at this point in the history
[git-p4: depot-paths = "//open/mondrian/": change = 14980]
  • Loading branch information
lucboudreau committed Feb 23, 2012
1 parent 656fb35 commit 3c6170c
Show file tree
Hide file tree
Showing 3 changed files with 274 additions and 52 deletions.
12 changes: 12 additions & 0 deletions src/main/mondrian/resource/MondrianResource.xml
Expand Up @@ -332,6 +332,18 @@
<text>Unknown dimension ''{0}'' for calculated member ''{1}'' in cube ''{2}''</text>
</exception>

<exception id="40121" name="CalcMemberHasBothDimensionAndHierarchy">
<text>Cannot specify both a dimension and hierarchy for calculated member ''{0}'' in cube ''{1}''</text>
</exception>

<exception id="40122" name="CalcMemberHasUnknownParent">
<text>Cannot find a parent with name ''{0}'' for calculated member ''{1}'' in cube ''{2}''</text>
</exception>

<exception id="40123" name="CalcMemberHasDifferentParentAndHierarchy">
<text>The calculated member ''{0}'' in cube ''{1}'' is defined for hierarchy ''{2}'' but its parent member is not part of that hierarchy</text>
</exception>

<exception id="40130" name="CalcMemberNotUnique">
<text>Calculated member ''{0}'' already exists in cube ''{1}''</text>
</exception>
Expand Down
45 changes: 37 additions & 8 deletions src/main/mondrian/rolap/RolapCube.java
Expand Up @@ -920,18 +920,15 @@ private Query resolveCalcMembers(
final RolapConnection conn = schema.getInternalConnection();
return Locus.execute(
conn,
"Validate calculated members in cube",
"RolapCube.resolveCalcMembers",
new Locus.Action<Query>() {
public Query execute() {
final Query queryExp = (Query)
conn.parseStatement(
Locus.peek().execution.getMondrianStatement(),
queryString, null, false);
final Query queryExp =
conn.parseQuery(queryString);
queryExp.resolve();
return queryExp;
}
}
);
});
} catch (Exception e) {
throw MondrianResource.instance().UnknownNamedSetHasBadFormula.ex(
getName(), e);
Expand Down Expand Up @@ -993,6 +990,7 @@ private void postCalcMember(
List<RolapMember> memberList)
{
MondrianDef.CalculatedMember xmlCalcMember = xmlCalcMembers.get(i);

final Formula formula = queryExp.getFormulas()[i];

calculatedMemberList.add(formula);
Expand Down Expand Up @@ -1036,6 +1034,14 @@ private void preCalcMember(
{
MondrianDef.CalculatedMember xmlCalcMember = xmlCalcMembers.get(j);

if (xmlCalcMember.hierarchy != null
&& xmlCalcMember.dimension != null)
{
throw MondrianResource.instance()
.CalcMemberHasBothDimensionAndHierarchy.ex(
xmlCalcMember.name, getName());
}

// Lookup dimension
Hierarchy hierarchy = null;
String dimName = null;
Expand All @@ -1052,7 +1058,7 @@ private void preCalcMember(
} else if (xmlCalcMember.hierarchy != null) {
dimName = xmlCalcMember.hierarchy;
hierarchy = (Hierarchy)
getSchemaReader().lookupCompound(
getSchemaReader().withLocus().lookupCompound(
this,
Util.parseIdentifier(dimName),
false,
Expand All @@ -1071,6 +1077,29 @@ private void preCalcMember(
parentFqName = hierarchy.getUniqueNameSsas();
}

if (!hierarchy.getDimension().isMeasures()) {
// Check if the parent exists.
final OlapElement parent =
Util.lookupCompound(
getSchemaReader().withLocus(),
this,
Util.parseIdentifier(parentFqName),
false,
Category.Unknown);

if (parent == null) {
throw MondrianResource.instance()
.CalcMemberHasUnknownParent.ex(
parentFqName, xmlCalcMember.name, getName());
}

if (parent.getHierarchy() != hierarchy) {
throw MondrianResource.instance()
.CalcMemberHasDifferentParentAndHierarchy.ex(
xmlCalcMember.name, getName(), hierarchy.getUniqueName());
}
}

// If we're processing a virtual cube, it's possible that we've
// already processed this calculated member because it's
// referenced in another measure; in that case, remove it from the
Expand Down
269 changes: 225 additions & 44 deletions testsrc/main/mondrian/test/SchemaTest.java
Expand Up @@ -2060,15 +2060,196 @@ public void testCalcMemberInCube() {
+ "Row #0: 27,780\n");
}

// TODO: test where hierarchy & dimension both specified. should fail
// TODO: test where hierarchy is not uname of valid hierarchy. should
// fail
// TODO: test where formula is invalid. should fail
// TODO: test where parent is invalid. should fail
// TODO: test where parent is not in same hierarchy as hierarchy. should
// fail
// TODO: test where calc member has no formula (formula attribute or
// Test where hierarchy & dimension both specified. should fail
try {
final TestContext testContextFail1 =
TestContext.instance().createSubstitutingCube(
"Sales",
null,
null,
"<CalculatedMember\n"
+ " name='SF and LA'\n"
+ " hierarchy='[Store]'\n"
+ " dimension='[Store]'\n"
+ " parent='[Store].[USA].[CA]'>\n"
+ " <Formula>\n"
+ " [Store].[USA].[CA].[San Francisco]\n"
+ " + [Store].[USA].[CA].[Los Angeles]\n"
+ " </Formula>\n"
+ "</CalculatedMember>",
null);
testContextFail1.assertQueryReturns(
"select {[Store].[All Stores].[USA].[CA].[SF and LA]} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA].[SF and LA]}\n"
+ "Row #0: 27,780\n");
fail();
} catch (MondrianException e) {
assertTrue(
e.getMessage().contains(
"Cannot specify both a dimension and hierarchy"
+ " for calculated member 'SF and LA' in cube 'Sales'"));
}

// test where hierarchy is not uname of valid hierarchy. should fail
try {
final TestContext testContextFail1 =
TestContext.instance().createSubstitutingCube(
"Sales",
null,
null,
"<CalculatedMember\n"
+ " name='SF and LA'\n"
+ " hierarchy='[Bacon]'\n"
+ " parent='[Store].[USA].[CA]'>\n"
+ " <Formula>\n"
+ " [Store].[USA].[CA].[San Francisco]\n"
+ " + [Store].[USA].[CA].[Los Angeles]\n"
+ " </Formula>\n"
+ "</CalculatedMember>",
null);
testContextFail1.assertQueryReturns(
"select {[Store].[All Stores].[USA].[CA].[SF and LA]} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA].[SF and LA]}\n"
+ "Row #0: 27,780\n");
fail();
} catch (MondrianException e) {
assertTrue(
e.getMessage().contains(
"Unknown dimension '[Bacon]' for calculated member"
+ " 'SF and LA' in cube 'Sales'"));
}

// test where formula is invalid. should fail
try {
final TestContext testContextFail1 =
TestContext.instance().createSubstitutingCube(
"Sales",
null,
null,
"<CalculatedMember\n"
+ " name='SF and LA'\n"
+ " hierarchy='[Store]'\n"
+ " parent='[Store].[USA].[CA]'>\n"
+ " <Formula>\n"
+ " Baconating!\n"
+ " </Formula>\n"
+ "</CalculatedMember>",
null);
testContextFail1.assertQueryReturns(
"select {[Store].[All Stores].[USA].[CA].[SF and LA]} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA].[SF and LA]}\n"
+ "Row #0: 27,780\n");
fail();
} catch (MondrianException e) {
assertTrue(
e.getMessage().contains(
"Named set in cube 'Sales' has bad formula"));
}

// Test where parent is invalid. should fail
try {
final TestContext testContextFail1 =
TestContext.instance().createSubstitutingCube(
"Sales",
null,
null,
"<CalculatedMember\n"
+ " name='SF and LA'\n"
+ " hierarchy='[Store]'\n"
+ " parent='[Store].[USA].[CA].[Baconville]'>\n"
+ " <Formula>\n"
+ " [Store].[USA].[CA].[San Francisco]\n"
+ " + [Store].[USA].[CA].[Los Angeles]\n"
+ " </Formula>\n"
+ "</CalculatedMember>",
null);
testContextFail1.assertQueryReturns(
"select {[Store].[All Stores].[USA].[CA].[SF and LA]} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA].[SF and LA]}\n"
+ "Row #0: 27,780\n");
fail();
} catch (MondrianException e) {
assertTrue(
e.getMessage().contains(
"Cannot find a parent with name '[Store].[USA].[CA]"
+ ".[Baconville]' for calculated member 'SF and LA'"
+ " in cube 'Sales'"));
}

// test where parent is not in same hierarchy as hierarchy. should fail
try {
final TestContext testContextFail1 =
TestContext.instance().createSubstitutingCube(
"Sales",
null,
null,
"<CalculatedMember\n"
+ " name='SF and LA'\n"
+ " hierarchy='[Store Type]'\n"
+ " parent='[Store].[USA].[CA]'>\n"
+ " <Formula>\n"
+ " [Store].[USA].[CA].[San Francisco]\n"
+ " + [Store].[USA].[CA].[Los Angeles]\n"
+ " </Formula>\n"
+ "</CalculatedMember>",
null);
testContextFail1.assertQueryReturns(
"select {[Store].[All Stores].[USA].[CA].[SF and LA]} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA].[SF and LA]}\n"
+ "Row #0: 27,780\n");
fail();
} catch (MondrianException e) {
assertTrue(
e.getMessage().contains(
"The calculated member 'SF and LA' in cube 'Sales'"
+ " is defined for hierarchy '[Store Type]' but its"
+ " parent member is not part of that hierarchy"));
}

// test where calc member has no formula (formula attribute or
// embedded element); should fail
try {
final TestContext testContextFail1 =
TestContext.instance().createSubstitutingCube(
"Sales",
null,
null,
"<CalculatedMember\n"
+ " name='SF and LA'\n"
+ " hierarchy='[Store]'\n"
+ " parent='[Store].[USA].[CA]'>\n"
+ " <Formula>\n"
+ " </Formula>\n"
+ "</CalculatedMember>",
null);
testContextFail1.assertQueryReturns(
"select {[Store].[All Stores].[USA].[CA].[SF and LA]} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA].[SF and LA]}\n"
+ "Row #0: 27,780\n");
fail();
} catch (MondrianException e) {
assertTrue(
e.getMessage().contains(
"Named set in cube 'Sales' has bad formula"));
}
}

/**
Expand Down Expand Up @@ -4334,42 +4515,42 @@ public void testBugMondrian1065() {
return;
}
TestContext testContext = TestContext.instance().createSubstitutingCube(
"Sales",
" <Dimension name=\"PandaSteak\" foreignKey=\"promotion_id\">\n"
+ " <Hierarchy hasAll=\"false\" primaryKey=\"lvl_3_id\">\n"
+ " <InlineTable alias=\"meatShack\">\n"
+ " <ColumnDefs>\n"
+ " <ColumnDef name=\"lvl_1_id\" type=\"Integer\"/>\n"
+ " <ColumnDef name=\"lvl_1_name\" type=\"String\"/>\n"
+ " <ColumnDef name=\"lvl_2_id\" type=\"Integer\"/>\n"
+ " <ColumnDef name=\"lvl_2_name\" type=\"String\"/>\n"
+ " <ColumnDef name=\"lvl_3_id\" type=\"Integer\"/>\n"
+ " <ColumnDef name=\"lvl_3_name\" type=\"String\"/>\n"
+ " </ColumnDefs>\n"
+ " <Rows>\n"
+ " <Row>\n"
+ " <Value column=\"lvl_1_id\">1</Value>\n"
+ " <Value column=\"lvl_1_name\">level 1</Value>\n"
+ " <Value column=\"lvl_2_id\">1</Value>\n"
+ " <Value column=\"lvl_2_name\">level 2 - 1</Value>\n"
+ " <Value column=\"lvl_3_id\">112</Value>\n"
+ " <Value column=\"lvl_3_name\">level 3 - 1</Value>\n"
+ " </Row>\n"
+ " <Row>\n"
+ " <Value column=\"lvl_1_id\">1</Value>\n"
+ " <Value column=\"lvl_1_name\">level 1</Value>\n"
+ " <Value column=\"lvl_2_id\">1</Value>\n"
+ " <Value column=\"lvl_2_name\">level 2 - 1</Value>\n"
+ " <Value column=\"lvl_3_id\">114</Value>\n"
+ " <Value column=\"lvl_3_name\">level 3 - 2</Value>\n"
+ " </Row>\n"
+ " </Rows>\n"
+ " </InlineTable>\n"
+ " <Level name=\"Level1\" column=\"lvl_1_id\" nameColumn=\"lvl_1_name\" />\n"
+ " <Level name=\"Level2\" column=\"lvl_2_id\" nameColumn=\"lvl_2_name\" />\n"
+ " <Level name=\"Level3\" column=\"lvl_3_id\" nameColumn=\"lvl_3_name\" />\n"
+ " </Hierarchy>\n"
+ " </Dimension>\n");
"Sales",
" <Dimension name=\"PandaSteak\" foreignKey=\"promotion_id\">\n"
+ " <Hierarchy hasAll=\"false\" primaryKey=\"lvl_3_id\">\n"
+ " <InlineTable alias=\"meatShack\">\n"
+ " <ColumnDefs>\n"
+ " <ColumnDef name=\"lvl_1_id\" type=\"Integer\"/>\n"
+ " <ColumnDef name=\"lvl_1_name\" type=\"String\"/>\n"
+ " <ColumnDef name=\"lvl_2_id\" type=\"Integer\"/>\n"
+ " <ColumnDef name=\"lvl_2_name\" type=\"String\"/>\n"
+ " <ColumnDef name=\"lvl_3_id\" type=\"Integer\"/>\n"
+ " <ColumnDef name=\"lvl_3_name\" type=\"String\"/>\n"
+ " </ColumnDefs>\n"
+ " <Rows>\n"
+ " <Row>\n"
+ " <Value column=\"lvl_1_id\">1</Value>\n"
+ " <Value column=\"lvl_1_name\">level 1</Value>\n"
+ " <Value column=\"lvl_2_id\">1</Value>\n"
+ " <Value column=\"lvl_2_name\">level 2 - 1</Value>\n"
+ " <Value column=\"lvl_3_id\">112</Value>\n"
+ " <Value column=\"lvl_3_name\">level 3 - 1</Value>\n"
+ " </Row>\n"
+ " <Row>\n"
+ " <Value column=\"lvl_1_id\">1</Value>\n"
+ " <Value column=\"lvl_1_name\">level 1</Value>\n"
+ " <Value column=\"lvl_2_id\">1</Value>\n"
+ " <Value column=\"lvl_2_name\">level 2 - 1</Value>\n"
+ " <Value column=\"lvl_3_id\">114</Value>\n"
+ " <Value column=\"lvl_3_name\">level 3 - 2</Value>\n"
+ " </Row>\n"
+ " </Rows>\n"
+ " </InlineTable>\n"
+ " <Level name=\"Level1\" column=\"lvl_1_id\" nameColumn=\"lvl_1_name\" />\n"
+ " <Level name=\"Level2\" column=\"lvl_2_id\" nameColumn=\"lvl_2_name\" />\n"
+ " <Level name=\"Level3\" column=\"lvl_3_id\" nameColumn=\"lvl_3_name\" />\n"
+ " </Hierarchy>\n"
+ " </Dimension>\n");
testContext.assertQueryReturns(
"select non empty crossjoin({[PandaSteak].[Level3].[level 3 - 1], [PandaSteak].[Level3].[level 3 - 2]}, {[Measures].[Unit Sales], [Measures].[Store Cost]}) on columns, {[Product].[Product Family].Members} on rows from [Sales]",
"Axis #0:\n"
Expand Down

0 comments on commit 3c6170c

Please sign in to comment.