Skip to content

Commit

Permalink
MONDRIAN: Fix for #1914570, Error with Snowflake Dimension with multi…
Browse files Browse the repository at this point in the history
…ple Hierarchies. Removed legacy validation code that is no longer applicable. Added unit tests in SchemaTest to verify functionality.

[git-p4: depot-paths = "//open/mondrian/": change = 11308]
  • Loading branch information
Will Gorman committed Jul 17, 2008
1 parent edc96a0 commit ea2b414
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 77 deletions.
4 changes: 0 additions & 4 deletions src/main/mondrian/resource/MondrianResource.xml
Expand Up @@ -380,10 +380,6 @@
<text>Duplicate parameter ''{0}'' in schema</text>
</exception>

<exception id="40280" name="DuplicateAliasInCube">
<text>Duplicate table alias ''{0}'' in cube ''{1}''</text>
</exception>

<exception id="40290" name="UnknownAggregator">
<text>Unknown aggregator ''{0}''; valid aggregators are: {1}</text>
</exception>
Expand Down
72 changes: 0 additions & 72 deletions src/main/mondrian/rolap/RolapCube.java
Expand Up @@ -557,78 +557,6 @@ private boolean findOriginalMembers(
return false;
}

protected void validate() {
// Make sure that tables referenced in dimensions in this cube have
// distinct aliases.
Map<String, List<Object>> aliases = new HashMap<String, List<Object>>();
List<Object> joinPath = new ArrayList<Object>();
joinPath.add(this);
for (Dimension dimension : dimensions) {
final Hierarchy[] hierarchies = dimension.getHierarchies();
for (Hierarchy hierarchy : hierarchies) {
MondrianDef.RelationOrJoin relation =
((RolapHierarchy) hierarchy).getRelation();
if (relation != null) {
final HierarchyUsage hierarchyUsage =
getFirstUsage(hierarchy);
joinPath.add(hierarchyUsage.getForeignKey());
validateRelation(
aliases,
relation,
joinPath);
joinPath.remove(joinPath.size() - 1);
}
}
}
}

private void validateRelation(
Map<String, List<Object>> aliases,
MondrianDef.RelationOrJoin relation,
List<Object> joinPath) {
if (relation instanceof MondrianDef.Join) {
MondrianDef.Join join = (MondrianDef.Join) relation;

validateRelation(aliases, join.left, joinPath);

int saveSize = joinPath.size();
flatten(relation, joinPath);
joinPath.add(join.leftKey);
joinPath.add(join.rightKey);
validateRelation(aliases, join.right, joinPath);
while (joinPath.size() > saveSize) {
joinPath.remove(joinPath.size() - 1);
}
} else {
MondrianDef.Relation table =
(MondrianDef.Relation) relation;
String alias = table.getAlias();
joinPath.add(relation);
joinPath.add(alias);
List joinPath2 = aliases.get(alias);
if (joinPath2 == null) {
aliases.put(alias, new ArrayList<Object>(joinPath));
} else {
if (!joinPath.equals(joinPath2)) {
throw MondrianResource.instance().DuplicateAliasInCube.ex(
alias, this.getName());
}
}
joinPath.remove(joinPath.size() - 1);
joinPath.remove(joinPath.size() - 1);
}
}

private void flatten(MondrianDef.RelationOrJoin relation, List<Object> joinPath) {
if (relation instanceof MondrianDef.Join) {
MondrianDef.Join join = (MondrianDef.Join) relation;
flatten(join.left, joinPath);
flatten(join.right, joinPath);
} else {
joinPath.add(relation);
}
}

protected Logger getLogger() {
return LOGGER;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/rolap/RolapSchema.java
Expand Up @@ -450,7 +450,7 @@ private void load(MondrianDef.Schema xmlSchema) {
for (MondrianDef.Cube xmlCube : xmlSchema.cubes) {
if (xmlCube.isEnabled()) {
RolapCube cube = new RolapCube(this, xmlSchema, xmlCube, true);
cube.validate();
Util.discard(cube);
}
}

Expand Down
129 changes: 129 additions & 0 deletions testsrc/main/mondrian/test/SchemaTest.java
Expand Up @@ -500,6 +500,135 @@ public void testDimensionsShareTableSameForeignKeys() {
"Row #7: 11,919\n"));

}

/**
* test hierarchy with completely different join path to fact table than
* first hierarchy. tables are auto-aliased as necessary to guarantee
* unique joins to the fact table.
*/
public void testSnowflakeHierarchyValidationNotNeeded() {
final TestContext testContext = TestContext.create(
null,
"<Cube name=\"AliasedDimensionsTesting\" defaultMeasure=\"Supply Time\">\n" +
" <Table name=\"sales_fact_1997\"/>\n" +
" <Dimension name=\"Store\" foreignKey=\"store_id\">\n" +
" <Hierarchy hasAll=\"true\" primaryKeyTable=\"store\" primaryKey=\"store_id\">\n" +
" <Join leftKey=\"region_id\" rightKey=\"region_id\">\n" +
" <Table name=\"store\"/>\n" +
" <Join leftKey=\"sales_district_id\" rightKey=\"promotion_id\">\n" +
" <Table name=\"region\"/>\n" +
" <Table name=\"promotion\"/>\n" +
" </Join>\n" +
" </Join>\n" +
" <Level name=\"Store Country\" table=\"store\" column=\"store_country\"/>\n" +
" <Level name=\"Store Region\" table=\"region\" column=\"sales_region\" />\n" +
" <Level name=\"Store Name\" table=\"store\" column=\"store_name\" />\n" +
" </Hierarchy>\n" +
" <Hierarchy name=\"MyHierarchy\" hasAll=\"true\" primaryKeyTable=\"customer\" primaryKey=\"customer_id\">\n" +
" <Join leftKey=\"customer_region_id\" rightKey=\"region_id\">\n" +
" <Table name=\"customer\"/>\n" +
" <Table name=\"region\"/>\n" +
" </Join>\n" +
" <Level name=\"Country\" table=\"customer\" column=\"country\" uniqueMembers=\"true\"/>\n" +
" <Level name=\"Region\" table=\"region\" column=\"sales_region\" uniqueMembers=\"true\"/>\n" +
" <Level name=\"City\" table=\"customer\" column=\"city\" uniqueMembers=\"false\"/>\n" +
" <Level name=\"Name\" table=\"customer\" column=\"customer_id\" type=\"Numeric\" uniqueMembers=\"true\"/>\n" +
" </Hierarchy>\n" +
" </Dimension>\n" +
" <Dimension name=\"Customers\" foreignKey=\"customer_id\">\n" +
" <Hierarchy hasAll=\"true\" allMemberName=\"All Customers\" primaryKeyTable=\"customer\" primaryKey=\"customer_id\">\n" +
" <Join leftKey=\"customer_region_id\" rightKey=\"region_id\">\n" +
" <Table name=\"customer\"/>\n" +
" <Table name=\"region\"/>\n" +
" </Join>\n" +
" <Level name=\"Country\" table=\"customer\" column=\"country\" uniqueMembers=\"true\"/>\n" +
" <Level name=\"Region\" table=\"region\" column=\"sales_region\" uniqueMembers=\"true\"/>\n" +
" <Level name=\"City\" table=\"customer\" column=\"city\" uniqueMembers=\"false\"/>\n" +
" <Level name=\"Name\" table=\"customer\" column=\"customer_id\" type=\"Numeric\" uniqueMembers=\"true\"/>\n" +
" </Hierarchy>\n" +
" </Dimension>\n" +
"<Measure name=\"Unit Sales\" column=\"unit_sales\" aggregator=\"sum\" formatString=\"Standard\"/>\n" +
"</Cube>",
null, null, null, null);

testContext.assertQueryReturns(
"select {[Store.MyHierarchy].[Mexico]} on rows," +
"{[Customers].[USA].[South West]} on columns" +
" from " +
"AliasedDimensionsTesting",
fold("Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Customers].[All Customers].[USA].[South West]}\n" +
"Axis #2:\n" +
"{[Store.MyHierarchy].[All Store.MyHierarchys].[Mexico]}\n" +
"Row #0: 51,298\n"));

}

/**
* test hierarchy with slightly different join path to fact table than
* first hierarchy. tables from first and second hierarchy should contain
* the same join aliases to the fact table.
*/
public void testSnowflakeHierarchyValidationNotNeeded2() {
final TestContext testContext = TestContext.create(
null,
"<Cube name=\"AliasedDimensionsTesting\" defaultMeasure=\"Supply Time\">\n" +
" <Table name=\"sales_fact_1997\"/>\n" +
" <Dimension name=\"Store\" foreignKey=\"store_id\">\n" +
" <Hierarchy hasAll=\"true\" primaryKeyTable=\"store\" primaryKey=\"store_id\">\n" +
" <Join leftKey=\"region_id\" rightKey=\"region_id\">\n" +
" <Table name=\"store\"/>\n" +
" <Join leftKey=\"sales_district_id\" rightKey=\"promotion_id\">\n" +
" <Table name=\"region\"/>\n" +
" <Table name=\"promotion\"/>\n" +
" </Join>\n" +
" </Join>\n" +
" <Level name=\"Store Country\" table=\"store\" column=\"store_country\"/>\n" +
" <Level name=\"Store Region\" table=\"region\" column=\"sales_region\" />\n" +
" <Level name=\"Store Name\" table=\"store\" column=\"store_name\" />\n" +
" </Hierarchy>\n" +
" <Hierarchy name=\"MyHierarchy\" hasAll=\"true\" primaryKeyTable=\"store\" primaryKey=\"store_id\">\n" +
" <Join leftKey=\"region_id\" rightKey=\"region_id\">\n" +
" <Table name=\"store\"/>\n" +
" <Table name=\"region\"/>\n" +
" </Join>\n" +
" <Level name=\"Store Country\" table=\"store\" column=\"store_country\"/>\n" +
" <Level name=\"Store Region\" table=\"region\" column=\"sales_region\" />\n" +
" <Level name=\"Store Name\" table=\"store\" column=\"store_name\" />\n" +
" </Hierarchy>\n" +
" </Dimension>\n" +
" <Dimension name=\"Customers\" foreignKey=\"customer_id\">\n" +
" <Hierarchy hasAll=\"true\" allMemberName=\"All Customers\" primaryKeyTable=\"customer\" primaryKey=\"customer_id\">\n" +
" <Join leftKey=\"customer_region_id\" rightKey=\"region_id\">\n" +
" <Table name=\"customer\"/>\n" +
" <Table name=\"region\"/>\n" +
" </Join>\n" +
" <Level name=\"Country\" table=\"customer\" column=\"country\" uniqueMembers=\"true\"/>\n" +
" <Level name=\"Region\" table=\"region\" column=\"sales_region\" uniqueMembers=\"true\"/>\n" +
" <Level name=\"City\" table=\"customer\" column=\"city\" uniqueMembers=\"false\"/>\n" +
" <Level name=\"Name\" table=\"customer\" column=\"customer_id\" type=\"Numeric\" uniqueMembers=\"true\"/>\n" +
" </Hierarchy>\n" +
"</Dimension>\n" +
"<Measure name=\"Unit Sales\" column=\"unit_sales\" aggregator=\"sum\" formatString=\"Standard\"/>\n" +
"</Cube>",
null, null, null, null);

testContext.assertQueryReturns(
"select {[Store.MyHierarchy].[USA].[South West]} on rows," +
"{[Customers].[USA].[South West]} on columns" +
" from " +
"AliasedDimensionsTesting",
fold("Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Customers].[All Customers].[USA].[South West]}\n" +
"Axis #2:\n" +
"{[Store.MyHierarchy].[All Store.MyHierarchys].[USA].[South West]}\n" +
"Row #0: 72,631\n"));

}

/**
* WG: This no longer throws an exception, it is now possible
Expand Down

0 comments on commit ea2b414

Please sign in to comment.