Skip to content

Commit

Permalink
MONDRIAN: Fix for bug (# 1785406) "Query already contains alias" exce…
Browse files Browse the repository at this point in the history
…ption

[git-p4: depot-paths = "//open/mondrian/": change = 10210]
  • Loading branch information
Ajit Joglekar committed Nov 19, 2007
1 parent ffa921e commit ef304f4
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 61 deletions.
3 changes: 3 additions & 0 deletions bin/megatest
Expand Up @@ -535,6 +535,9 @@ doAllTests()
doTest jdk1.5 access mondrian.olap.NullMemberRepresentation= mondrian.test.Class=mondrian.olap.NullMemberRepresentationTest
doTest jdk1.5 access mondrian.olap.NullMemberRepresentation=\(null\) mondrian.test.Class=mondrian.olap.NullMemberRepresentationTest
doTest jdk1.5 access mondrian.olap.NullMemberRepresentation=~Missing mondrian.test.Class=mondrian.olap.NullMemberRepresentationTest
doTest jdk1.5 access mondrian.test.Class=mondrian.rolap.FastBatchingCellReaderTest
doTest jdk1.5 derby mondrian.test.Class=mondrian.rolap.FastBatchingCellReaderTest
doTest jdk1.5 mysql mondrian.test.Class=mondrian.rolap.FastBatchingCellReaderTest

# mondrian.test.Class=mondrian.test.BasicQueryTest
# mondrian.test.Name=testQueryTimeout
Expand Down
102 changes: 41 additions & 61 deletions src/main/mondrian/rolap/RolapStar.java
Expand Up @@ -150,12 +150,12 @@ protected List<BitKey> initialValue() {
private List<AggStar> aggStars;

private DataSourceChangeListener changeListener;

// temporary model, should eventually use RolapStar.Table and RolapStar.Column
private StarNetworkNode factNode;
private Map<String, StarNetworkNode> nodeLookup =
private Map<String, StarNetworkNode> nodeLookup =
new HashMap<String, StarNetworkNode>();

/**
* Creates a RolapStar. Please use
* {@link RolapSchema.RolapStarRegistry#getOrCreateStar} to create a
Expand All @@ -173,7 +173,7 @@ protected List<BitKey> initialValue() {

// phase out and replace with Table, Column network
factNode = new StarNetworkNode(null, factTable.alias, null, null, null);

this.cubeToLevelToColumnMapMap =
new HashMap<RolapCube, Map<RolapLevel, Column>>();
this.cubeToRelationNamesToStarTableMapMap =
Expand All @@ -195,27 +195,27 @@ private class StarNetworkNode {
private MondrianDef.Relation origRel; // this is either a table or a view
private String foreignKey;
private String joinKey;
private StarNetworkNode(StarNetworkNode parent, String alias,
MondrianDef.Relation origRel, String foreignKey,

private StarNetworkNode(StarNetworkNode parent, String alias,
MondrianDef.Relation origRel, String foreignKey,
String joinKey) {
this.parent = parent;
this.origRel = origRel;
this.foreignKey = foreignKey;
this.joinKey = joinKey;
}

private boolean isCompatible(
StarNetworkNode compatibleParent, MondrianDef.Relation rel,
StarNetworkNode compatibleParent, MondrianDef.Relation rel,
String compatibleForeignKey, String compatibleJoinKey) {
return (parent == compatibleParent &&
return (parent == compatibleParent &&
origRel.getClass().equals(rel.getClass()) &&
foreignKey.equals(compatibleForeignKey) &&
foreignKey.equals(compatibleForeignKey) &&
joinKey.equals(compatibleJoinKey));
}
}
private MondrianDef.Relation cloneRelation(MondrianDef.Relation rel,

private MondrianDef.Relation cloneRelation(MondrianDef.Relation rel,
String possibleName) {
MondrianDef.Relation newrel = null;
if (rel instanceof MondrianDef.Table) {
Expand All @@ -232,15 +232,15 @@ private MondrianDef.Relation cloneRelation(MondrianDef.Relation rel,
}
return newrel;
}

/**
* Generates a unique relational join to the fact table via re-aliasing
* MondrianDef.Relations
*
*
* currently called in the RolapCubeHierarchy constructor. This should
* eventually be phased out and replaced with RolapStar.Table and
* eventually be phased out and replaced with RolapStar.Table and
* RolapStar.Column references
*
*
* @param rel the relation needing uniqueness
* @param factForeignKey the foreign key of the fact table
* @param primaryKey the join key of the relation
Expand All @@ -253,25 +253,25 @@ public MondrianDef.Relation getUniqueRelation(
return getUniqueRelation(
factNode, rel, factForeignKey, primaryKey, primaryKeyTable);
}

private MondrianDef.Relation getUniqueRelation(
StarNetworkNode parent, MondrianDef.Relation rel,
StarNetworkNode parent, MondrianDef.Relation rel,
String foreignKey, String joinKey, String joinKeyTable) {
if (rel == null) {
return null;
} else if (rel instanceof MondrianDef.Table
} else if (rel instanceof MondrianDef.Table
|| rel instanceof MondrianDef.View) {
int val = 0;
String newAlias =
String newAlias =
joinKeyTable != null ? joinKeyTable : rel.getAlias();
while (true) {
StarNetworkNode node = nodeLookup.get(newAlias);
if (node == null) {
if (val != 0) {
rel = cloneRelation(rel, newAlias);
}
node =
new StarNetworkNode(parent, newAlias, rel,
node =
new StarNetworkNode(parent, newAlias, rel,
foreignKey, joinKey);
nodeLookup.put(newAlias, node);
return rel;
Expand All @@ -287,36 +287,36 @@ private MondrianDef.Relation getUniqueRelation(
MondrianDef.Relation right = null;
if (join.getLeftAlias().equals(joinKeyTable)) {
// first manage left then right
left =
getUniqueRelation(parent, join.left, foreignKey,
left =
getUniqueRelation(parent, join.left, foreignKey,
joinKey, joinKeyTable);
parent = nodeLookup.get(left.getAlias());
right =
getUniqueRelation(parent, join.right, join.leftKey,
right =
getUniqueRelation(parent, join.right, join.leftKey,
join.rightKey, join.getRightAlias());
} else if (join.getRightAlias().equals(joinKeyTable)) {
// right side must equal
right =
getUniqueRelation(parent, join.right, foreignKey,
right =
getUniqueRelation(parent, join.right, foreignKey,
joinKey, joinKeyTable);
parent = nodeLookup.get(right.getAlias());
left =
getUniqueRelation(parent, join.left, join.rightKey,
left =
getUniqueRelation(parent, join.left, join.rightKey,
join.leftKey, join.getLeftAlias());
} else {
new MondrianException(
"failed to match primary key table to join tables");
}

if (join.left != left || join.right != right) {
join =
new MondrianDef.Join(left.getAlias(), join.leftKey,
join =
new MondrianDef.Join(left.getAlias(), join.leftKey,
left, right.getAlias(), join.rightKey, right);
}
return join;
}
return null;
}
}

/**
* Returns this RolapStar's column count. After a star has been created with
Expand Down Expand Up @@ -870,28 +870,8 @@ private Object getCell(CellRequest request, DataSource dataSource) {
Column[] columns = request.getConstrainedColumns();
Object[] values = request.getSingleValues();
Util.assertTrue(columns.length == values.length);
SqlQuery sqlQuery = getSqlQuery();
// add measure
Util.assertTrue(measure.getTable() == factTable);
factTable.addToFrom(sqlQuery, true, true);
sqlQuery.addSelect(
measure.aggregator.getExpression(
measure.generateExprString(sqlQuery)));
// add constraining dimensions
for (int i = 0; i < columns.length; i++) {
Object value = values[i];
if (value == null) {
continue; // not constrained
}
Column column = columns[i];
Table table = column.getTable();
if (table.isFunky()) {
// this is a funky dimension -- ignore for now
continue;
}
table.addToFrom(sqlQuery, true, true);
}
String sql = sqlQuery.toString();
String sql = CompoundQuerySpec.compoundGenerateSql(measure, columns,
request.getValueList(), request.getPredicateList());
final SqlStatement stmt =
RolapUtil.executeQuery(
dataSource, sql, "RolapStar.getCell",
Expand Down Expand Up @@ -1178,18 +1158,18 @@ public String generateExprString(SqlQuery query) {
* Get column cardinality from the schema cache if possible;
* otherwise issue a select count(distinct) query to retrieve
* the cardinality and stores it in the cache.
*
*
* @return the column cardinality.
*/
public int getCardinality() {
if (cardinality == -1) {
RolapStar star = getStar();
RolapSchema schema = star.getSchema();
Integer card =
Integer card =
schema.getCachedRelationExprCardinality(
table.getRelation(),
expression);

if (card != null) {
cardinality = card.intValue();
} else {
Expand All @@ -1198,7 +1178,7 @@ public int getCardinality() {
cardinality = getCardinality(star.getDataSource());
schema.putCachedRelationExprCardinality(
table.getRelation(),
expression,
expression,
cardinality);
}
}
Expand Down Expand Up @@ -1698,7 +1678,7 @@ private Column makeColumnForLevelExpr(
Column c = lookupColumnByExpression(xmlExpr);

RolapStar.Column column = null;
// Verify Column is not null and not the same as the
// Verify Column is not null and not the same as the
// nameColumn created previously (bug 1438285)
if (c != null && !c.equals(nameColumn)) {
// Yes, well just reuse it
Expand Down
105 changes: 105 additions & 0 deletions testsrc/main/mondrian/rolap/FastBatchingCellReaderTest.java
Expand Up @@ -1133,6 +1133,111 @@ public void testAggregateDistinctCount5() {

assertQuerySql(query, patterns);
}

public void testDistinctCountBug1785406() {
String query = "With \n" +
"Set [*BASE_MEMBERS_Product] as {[Product].[All Products].[Food].[Deli]}\n" +
"Set [*BASE_MEMBERS_Store] as {[Store].[All Stores].[USA].[WA]}\n" +
"Member [Product].[*CTX_MEMBER_SEL~SUM] As\n" +
"Aggregate([*BASE_MEMBERS_Product])\n" +
"Select\n" +
"{[Measures].[Customer Count]} on columns,\n" +
"NonEmptyCrossJoin([*BASE_MEMBERS_Store],{([Product].[*CTX_MEMBER_SEL~SUM])})\n" +
"on rows\n" +
"From [Sales]\n" +
"where ([Time].[1997])";
String expectedResult = "Axis #0:\n" +
"{[Time].[1997]}\n" +
"Axis #1:\n" +
"{[Measures].[Customer Count]}\n" +
"Axis #2:\n" +
"{[Store].[All Stores].[USA].[WA], [Product].[*CTX_MEMBER_SEL~SUM]}\n" +
"Row #0: 889\n";

String mysqlSql = "select count(distinct `sales_fact_1997`.`customer_id`) as `c` " +
"from `sales_fact_1997` as `sales_fact_1997`, `store` as `store`, " +
"`time_by_day` as `time_by_day`, `product_class` as `product_class`, " +
"`product` as `product` " +
"where `sales_fact_1997`.`store_id` = `store`.`store_id` " +
"and `store`.`store_state` = 'WA' " +
"and `sales_fact_1997`.`time_id` = `time_by_day`.`time_id` " +
"and `time_by_day`.`the_year` = 1997 " +
"and `sales_fact_1997`.`product_id` = `product`.`product_id` " +
"and `product`.`product_class_id` = `product_class`.`product_class_id` " +
"and (`product_class`.`product_department` = 'Deli' " +
"and `product_class`.`product_family` = 'Food')";
String msaccessSql = "select count(`c`) as `c0` " +
"from (select distinct `sales_fact_1997`.`customer_id` as `c` " +
"from `store` as `store`, `sales_fact_1997` as `sales_fact_1997`, " +
"`time_by_day` as `time_by_day`, `product_class` as `product_class`, " +
"`product` as `product` " +
"where `sales_fact_1997`.`store_id` = `store`.`store_id` " +
"and `store`.`store_state` = 'WA' " +
"and `sales_fact_1997`.`time_id` = `time_by_day`.`time_id` " +
"and `time_by_day`.`the_year` = 1997 " +
"and `sales_fact_1997`.`product_id` = `product`.`product_id` " +
"and `product`.`product_class_id` = `product_class`.`product_class_id` " +
"and (`product_class`.`product_department` = 'Deli' " +
"and `product_class`.`product_family` = 'Food')) as `dummyname`";
String derbySql = "select count(distinct \"sales_fact_1997\".\"customer_id\") as \"c\" " +
"from \"sales_fact_1997\" as \"sales_fact_1997\", " +
"\"store\" as \"store\", \"time_by_day\" as \"time_by_day\" " +
"where \"sales_fact_1997\".\"store_id\" = \"store\".\"store_id\" " +
"and \"store\".\"store_state\" = 'WA' " +
"and \"sales_fact_1997\".\"time_id\" = \"time_by_day\".\"time_id\" " +
"and \"time_by_day\".\"the_year\" = 1997";

SqlPattern[] patterns = {
new SqlPattern(SqlPattern.Dialect.ACCESS, msaccessSql, msaccessSql),
new SqlPattern(SqlPattern.Dialect.DERBY, derbySql, derbySql),
new SqlPattern(SqlPattern.Dialect.MYSQL, mysqlSql, mysqlSql)};

assertQuerySql(query, patterns);
assertQueryReturns(query,
fold(expectedResult));
}

public void testDistinctCountBug1785406_2() {
String query = "With Member [Product].[x] as 'Aggregate({Gender.CurrentMember})'\n" +
"member [Measures].[foo] as '([Product].[x],[Measures].[Customer Count])'\n" +
"select Filter([Gender].members,(Not IsEmpty([Measures].[foo]))) on 0 from Sales";
String expectedResult = "Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Gender].[All Gender]}\n" +
"{[Gender].[All Gender].[F]}\n" +
"{[Gender].[All Gender].[M]}\n" +
"Row #0: 266,773\n" +
"Row #0: 131,558\n" +
"Row #0: 135,215\n";
assertQueryReturns(query, fold(expectedResult));
String mysqlSql = "select count(distinct `sales_fact_1997`.`customer_id`) " +
"as `c` from `sales_fact_1997` as `sales_fact_1997`, " +
"`time_by_day` as `time_by_day` " +
"where `sales_fact_1997`.`time_id` = `time_by_day`.`time_id` " +
"and `time_by_day`.`the_year` = 1997";
String msaccessSql = "select count(`c`) as `c0` " +
"from (select distinct `sales_fact_1997`.`customer_id` as `c` " +
"from `time_by_day` as `time_by_day`, " +
"`sales_fact_1997` as `sales_fact_1997` " +
"where `sales_fact_1997`.`time_id` = `time_by_day`.`time_id` " +
"and `time_by_day`.`the_year` = 1997) as `dummyname`";
String derbySql = "select count(distinct \"sales_fact_1997\".\"customer_id\") " +
"as \"c\" from \"sales_fact_1997\" as \"sales_fact_1997\", " +
"\"time_by_day\" as \"time_by_day\" " +
"where \"sales_fact_1997\".\"time_id\" = \"time_by_day\".\"time_id\" " +
"and \"time_by_day\".\"the_year\" = 1997";
SqlPattern[] patterns = {
new SqlPattern(SqlPattern.Dialect.ACCESS, msaccessSql, msaccessSql),
new SqlPattern(SqlPattern.Dialect.DERBY, derbySql, derbySql),
new SqlPattern(SqlPattern.Dialect.MYSQL, mysqlSql, mysqlSql)};

assertQuerySql(query, patterns);
assertQueryReturns(query,
fold(expectedResult));
}


}

// End FastBatchingCellReaderTest.java

0 comments on commit ef304f4

Please sign in to comment.