Skip to content

Commit

Permalink
MONDRIAN: Fix bug: Internal error if dimension is based upon a query.
Browse files Browse the repository at this point in the history
[git-p4: depot-paths = "//open/mondrian/": change = 262]
  • Loading branch information
julianhyde committed Jan 7, 2003
1 parent fb7b202 commit 4812257
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 85 deletions.
101 changes: 53 additions & 48 deletions src/main/mondrian/rolap/RolapCube.java
Expand Up @@ -249,66 +249,70 @@ void register()
}
RolapStoredMeasure[] storedMeasures = (RolapStoredMeasure[])
list.toArray(new RolapStoredMeasure[list.size()]);
RolapStar star = RolapStar.Pool.instance().getOrCreateStar(
schema, this.fact);
// create measures (and stars for them, if necessary)
for (int i = 0; i < storedMeasures.length; i++) {
RolapStoredMeasure storedMeasure = storedMeasures[i];
RolapStar star = RolapStar.Pool.instance().getOrCreateStar(
schema, this.fact);
RolapStar.Measure measure = new RolapStar.Measure();
measure.table = star.factTable;
measure.expression = storedMeasure.expression;
measure.aggregator = storedMeasure.aggregator;
measure.isNumeric = true;
storedMeasure.starMeasure = measure; // reverse mapping
star.factTable.columns.add(measure);
// create dimension tables
RolapDimension[] dimensions =
(RolapDimension[]) this.getDimensions();
for (int j = 0; j < dimensions.length; j++) {
RolapDimension dimension = dimensions[j];
RolapHierarchy[] hierarchies = (RolapHierarchy[])
dimension.getHierarchies();
for (int k = 0; k < hierarchies.length; k++) {
RolapHierarchy hierarchy = hierarchies[k];
HierarchyUsage hierarchyUsage = schema.getUsage(hierarchy,this);
MondrianDef.Relation relation = hierarchy.getRelation();
if (relation == null) {
continue; // e.g. [Measures] hierarchy
}
RolapStar.Table table = star.factTable;
if (!relation.equals(table.relation)) {
RolapStar.Condition joinCondition = new RolapStar.Condition(
table.getAlias(), hierarchyUsage.foreignKey,
hierarchyUsage.primaryKeyTable.getAlias(),
hierarchyUsage.primaryKey);
table = table.addJoin(relation, joinCondition);
}
RolapLevel[] levels = (RolapLevel[]) hierarchy.getLevels();
for (int l = 0; l < levels.length; l++) {
RolapLevel level = levels[l];
if (level.nameExp == null) {
continue;
} else {
RolapStar.Column column = new RolapStar.Column();
if (level.nameExp instanceof MondrianDef.Column) {
String tableName = ((MondrianDef.Column) level.nameExp).table;
column.table = table.findAncestor(tableName);
if (column.table == null) {
throw Util.newError(
"Level '" + level.getUniqueName() +
"' of cube '" + this +
"' is invalid: table '" + tableName +
"' is not found in current scope");
}
} else {
column.table = table;
}
column.expression = level.nameExp;
column.isNumeric = (level.flags & RolapLevel.NUMERIC) != 0;
table.columns.add(column);
star.mapLevelToColumn.put(level, column);
}
// create dimension tables
RolapDimension[] dimensions = (RolapDimension[]) this.getDimensions();
for (int j = 0; j < dimensions.length; j++) {
registerDimension(dimensions[j]);
}
}

private void registerDimension(RolapDimension dimension) {
RolapStar star = RolapStar.Pool.instance().getOrCreateStar(
schema, this.fact);
RolapHierarchy[] hierarchies = (RolapHierarchy[])
dimension.getHierarchies();
for (int k = 0; k < hierarchies.length; k++) {
RolapHierarchy hierarchy = hierarchies[k];
HierarchyUsage hierarchyUsage = schema.getUsage(hierarchy,this);
MondrianDef.Relation relation = hierarchy.getRelation();
if (relation == null) {
continue; // e.g. [Measures] hierarchy
}
RolapStar.Table table = star.factTable;
if (!relation.equals(table.relation)) {
RolapStar.Condition joinCondition = new RolapStar.Condition(
table.getAlias(), hierarchyUsage.foreignKey,
hierarchyUsage.primaryKeyTable.getAlias(),
hierarchyUsage.primaryKey);
table = table.addJoin(relation, joinCondition);
}
RolapLevel[] levels = (RolapLevel[]) hierarchy.getLevels();
for (int l = 0; l < levels.length; l++) {
RolapLevel level = levels[l];
if (level.nameExp == null) {
continue;
} else {
RolapStar.Column column = new RolapStar.Column();
if (level.nameExp instanceof MondrianDef.Column) {
String tableName = ((MondrianDef.Column) level.nameExp).table;
column.table = table.findAncestor(tableName);
if (column.table == null) {
throw Util.newError(
"Level '" + level.getUniqueName() +
"' of cube '" + this +
"' is invalid: table '" + tableName +
"' is not found in current scope");
}
} else {
column.table = table;
}
column.expression = level.nameExp;
column.isNumeric = (level.flags & RolapLevel.NUMERIC) != 0;
table.columns.add(column);
star.mapLevelToColumn.put(level, column);
}
}
}
Expand Down Expand Up @@ -367,6 +371,7 @@ RolapDimension createDimension(MondrianDef.CubeDimension xmlCubeDimension) {
}
Util.assertTrue(localDimensionOrdinals[globalOrdinal] == -1);
localDimensionOrdinals[globalOrdinal] = localOrdinal;
registerDimension(dimension);
return dimension;
}
}
Expand Down
48 changes: 11 additions & 37 deletions src/main/mondrian/rolap/RolapStar.java
Expand Up @@ -151,34 +151,6 @@ Object getCell(CellRequest request)
}
}

/**
* Helper method, returns whether <code>relation</code> is a table named
* <code>factTable.factSchema</code>.
*/
static boolean matchesTable(
MondrianDef.Relation relation, String schema, String table) {
if (relation instanceof MondrianDef.Table) {
MondrianDef.Table t = (MondrianDef.Table) relation;
if (t.name.equals(table) &&
Util.equals(t.schema, schema)) {
return true;
}
}
return false;
}

// static class Segment
// {
// Object[][] keys;
// Object[] values;
// };

// private static class Axis
// {
// Column column;
// Vector values = new Vector();
// };

public static class Column
{
public Table table;
Expand Down Expand Up @@ -295,8 +267,10 @@ public Table(
Condition joinCondition) {
this.relation = relation;
Util.assertTrue(
relation instanceof MondrianDef.Table,
"todo: allow dimension which is not a Table, " + relation);
relation instanceof MondrianDef.Table ||
relation instanceof MondrianDef.View,
"todo: allow dimension which is not a Table or View, [" +
relation + "]");
this.parent = parent;
this.joinCondition = joinCondition;
Util.assertTrue((parent == null) == (joinCondition == null));
Expand All @@ -312,11 +286,11 @@ public String getAlias() {
synchronized Table addJoin(
MondrianDef.Relation relation,
RolapStar.Condition joinCondition) {
if (relation instanceof MondrianDef.Table) {
MondrianDef.Table table = (MondrianDef.Table) relation;
RolapStar.Table starTable = findChild(table);
if (relation instanceof MondrianDef.Table ||
relation instanceof MondrianDef.View) {
RolapStar.Table starTable = findChild(relation);
if (starTable == null) {
starTable = new RolapStar.Table(table, this, joinCondition);
starTable = new RolapStar.Table(relation, this, joinCondition);
starTable.star = this.star;
this.children.add(starTable);
}
Expand Down Expand Up @@ -351,13 +325,13 @@ synchronized Table addJoin(
}

/**
* Returns a child table which maps onto a given relation, or null if
* Returns a child relation which maps onto a given relation, or null if
* there is none.
*/
public Table findChild(MondrianDef.Table table) {
public Table findChild(MondrianDef.Relation relation) {
for (int i = 0; i < children.size(); i++) {
Table child = (Table) children.get(i);
if (matchesTable(child.relation, table.schema, table.name)) {
if (child.relation.equals(relation)) {
return child;
}
}
Expand Down
47 changes: 47 additions & 0 deletions src/main/mondrian/test/FoodMartTestCase.java
Expand Up @@ -1884,6 +1884,53 @@ public void testCatalogHierarchyBasedOnView() {
toString(axis.positions));
}

/**
* Run a query against a large hierarchy, to make sure that we can generate
* joins correctly. This probably won't work in MySQL.
*/
public void testCatalogHierarchyBasedOnView2() {
Schema schema = getConnection().getSchema();
final Cube salesCube = schema.lookupCube("Sales", true);
schema.createDimension(
salesCube,
"<Dimension name=\"ProductView\" foreignKey=\"product_id\">" + nl +
" <Hierarchy hasAll=\"true\" primaryKey=\"product_id\" primaryKeyTable=\"productView\">" + nl +
" <View alias=\"productView\">" + nl +
" <SQL dialect=\"generic\"><![CDATA[" + nl +
"SELECT *" + nl +
"FROM \"product\", \"product_class\"" + nl +
"WHERE \"product\".\"product_class_id\" = \"product_class\".\"product_class_id\"" + nl +
"]]>" + nl +
" </SQL>" + nl +
" </View>" + nl +
" <Level name=\"Product Family\" column=\"product_family\" uniqueMembers=\"true\"/>" + nl +
" <Level name=\"Product Department\" column=\"product_department\" uniqueMembers=\"false\"/>" + nl +
" <Level name=\"Product Category\" column=\"product_category\" uniqueMembers=\"false\"/>" + nl +
" <Level name=\"Product Subcategory\" column=\"product_subcategory\" uniqueMembers=\"false\"/>" + nl +
" <Level name=\"Brand Name\" column=\"brand_name\" uniqueMembers=\"false\"/>" + nl +
" <Level name=\"Product Name\" column=\"product_name\" uniqueMembers=\"true\"/>" + nl +
" </Hierarchy>" + nl +
"</Dimension>");
runQueryCheckResult(
"select {[Measures].[Unit Sales]} on columns," + nl +
" {[ProductView].[Drink].[Beverages].children} on rows" + nl +
"from Sales",

"Axis #0:" + nl +
"{}" + nl +
"Axis #1:" + nl +
"{[Measures].[Unit Sales]}" + nl +
"Axis #2:" + nl +
"{[ProductView].[All ProductViews].[Drink].[Beverages].[Carbonated Beverages]}" + nl +
"{[ProductView].[All ProductViews].[Drink].[Beverages].[Drinks]}" + nl +
"{[ProductView].[All ProductViews].[Drink].[Beverages].[Hot Beverages]}" + nl +
"{[ProductView].[All ProductViews].[Drink].[Beverages].[Pure Juice Beverages]}" + nl +
"Row #0: 3,407" + nl +
"Row #1: 2,469" + nl +
"Row #2: 4,301" + nl +
"Row #3: 3,396" + nl);
}

public void testMemberWithNullKey() {
runQueryCheckResult(
"select {[Measures].[Unit Sales]} on columns," + nl +
Expand Down

0 comments on commit 4812257

Please sign in to comment.