Skip to content

Commit

Permalink
mondrian: use the new alias interface for constraning multi level mem…
Browse files Browse the repository at this point in the history
…ber lists. Also fixed some tests that are failing in CruiseControl.

[git-p4: depot-paths = "//open/mondrian/": change = 9284]
  • Loading branch information
Rushan Chen committed May 18, 2007
1 parent 71d7518 commit 7cf3a8f
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/main/mondrian/rolap/ChildByNameConstraint.java
Expand Up @@ -51,6 +51,7 @@ public void addLevelConstraint(
query.addWhere(
SqlConstraintUtils.constrainLevel(
level,
levelToColumnMap,
query,
childName,
true));
Expand Down
71 changes: 65 additions & 6 deletions src/main/mondrian/rolap/SqlConstraintUtils.java
Expand Up @@ -208,6 +208,7 @@ public static void joinLevelTableToFactTable(
*
* @param sqlQuery the query to modify
* @param levelToColumnMap where to find each level's key
* @param relationNamesToStarTableMap map to disambiguate table aliases
* @param aggStar Definition of the aggregate table, or null
* @param parent the list of parent members
* @param strict defines the behavior if <code>parent</code>
Expand Down Expand Up @@ -241,6 +242,7 @@ public static void addMemberConstraint(
*
* @param sqlQuery the query to modify
* @param levelToColumnMap where to find each level's key
* @param relationNamesToStarTableMap map to disambiguate table aliases
* @param aggStar (not used)
* @param parents the list of parent members
* @param strict defines the behavior if <code>parents</code>
Expand Down Expand Up @@ -273,7 +275,12 @@ public static void addMemberConstraint(
if (crossJoin) {
RolapLevel level = parents.get(0).getLevel();
if (!level.isUnique() && !membersAreCrossProduct(parents)) {
constrainMultiLevelMembers(sqlQuery, parents, strict);
constrainMultiLevelMembers(
sqlQuery,
levelToColumnMap,
relationNamesToStarTableMap,
parents,
strict);
return;
}
}
Expand Down Expand Up @@ -371,16 +378,25 @@ private static LinkedHashSet<RolapMember> getUniqueParentMembers(
* list of members
*
* @param sqlQuery query containing the where clause
* @param levelToColumnMap where to find each level's key
* @param query the query that the sql expression will be added to
* @param members list of constraining members
* @param strict defines the behavior when calculated members are present
*/
private static void constrainMultiLevelMembers(
SqlQuery sqlQuery,
Map<RolapLevel, RolapStar.Column> levelToColumnMap,
Map<String, RolapStar.Table> relationNamesToStarTableMap,
List<RolapMember> members,
boolean strict)
{
if (sqlQuery.getDialect().supportsMultiValueInExpr()) {
if (generateMultiValueInExpr(sqlQuery, members, strict)) {
if (generateMultiValueInExpr(
sqlQuery,
levelToColumnMap,
relationNamesToStarTableMap,
members,
strict)) {
return;
}
}
Expand Down Expand Up @@ -410,15 +426,29 @@ private static void constrainMultiLevelMembers(
if (firstMember) {
RolapHierarchy hierarchy =
(RolapHierarchy) level.getHierarchy();
hierarchy.addToFrom(sqlQuery, level.getKeyExp());

RolapStar.Column column = levelToColumnMap.get(level);

if (column != null &&
relationNamesToStarTableMap != null) {
RolapStar.Table targetTable = column.getTable();
hierarchy.addToFrom(
sqlQuery,
relationNamesToStarTableMap,
targetTable);
} else {
hierarchy.addToFrom(sqlQuery, level.getKeyExp());
}
}

if (!firstLevel) {
condition += " and ";
} else {
firstLevel = false;
}
condition += constrainLevel(
level,
levelToColumnMap,
sqlQuery,
getColumnValue(
m.getSqlKey(),
Expand Down Expand Up @@ -489,6 +519,7 @@ private static String getColumnValue(
* Generates a sql expression constraining a level by some value
*
* @param level the level
* @param levelToColumnMap where to find each level's key
* @param query the query that the sql expression will be added to
* @param columnValue value constraining the level
* @param caseSensitive if true, need to handle case sensitivity of the
Expand All @@ -498,6 +529,7 @@ private static String getColumnValue(
*/
public static String constrainLevel(
RolapLevel level,
Map<RolapLevel, RolapStar.Column> levelToColumnMap,
SqlQuery query,
String columnValue,
boolean caseSensitive)
Expand All @@ -512,8 +544,11 @@ public static String constrainLevel(
// we presume that it is a string.
datatype = SqlQuery.Datatype.String;
}
String column = exp.getExpression(query);
String column =
level.getExpressionWithAlias(query, levelToColumnMap, exp);

String constraint;

if (RolapUtil.mdxNullLiteral.equalsIgnoreCase(columnValue)) {
constraint = column + " is " + RolapUtil.sqlNullLiteral;
} else {
Expand Down Expand Up @@ -547,13 +582,17 @@ public static String constrainLevel(
* of a query, provided the member values are all non-null
*
* @param sqlQuery query containing the where clause
* @param levelToColumnMap where to find each level's key
* @param relationNamesToStarTableMap map to disambiguate table aliases
* @param members list of constraining members
* @param strict defines the behavior when calculated members are present
*
* @return Whether it was possible to generate a multi-value IN expression
*/
private static boolean generateMultiValueInExpr(
SqlQuery sqlQuery,
Map<RolapLevel, RolapStar.Column> levelToColumnMap,
Map<String, RolapStar.Table> relationNamesToStarTableMap,
List<RolapMember> members,
boolean strict)
{
Expand Down Expand Up @@ -583,15 +622,35 @@ private static boolean generateMultiValueInExpr(
if (firstMember) {
RolapHierarchy hierarchy =
(RolapHierarchy) level.getHierarchy();
hierarchy.addToFrom(sqlQuery, level.getKeyExp());
RolapStar.Column column = levelToColumnMap.get(level);

if (column != null &&
relationNamesToStarTableMap != null) {
RolapStar.Table targetTable = column.getTable();
hierarchy.addToFrom(
sqlQuery,
relationNamesToStarTableMap,
targetTable);
} else {
hierarchy.addToFrom(sqlQuery, level.getKeyExp());
}

if (!firstLevel) {
columnBuf.append(",");
}
MondrianDef.Expression exp = level.getNameExp();

if (exp == null) {
exp = level.getKeyExp();
}
columnBuf.append(exp.getExpression(sqlQuery));

String columnString =
level.getExpressionWithAlias(
sqlQuery,
levelToColumnMap,
exp);

columnBuf.append(columnString);
}

if (firstLevel) {
Expand Down
10 changes: 6 additions & 4 deletions testsrc/main/mondrian/rolap/NonEmptyTest.java
Expand Up @@ -1771,9 +1771,11 @@ public void testIndependentSlicerMemberNonNative() {
MondrianProperties.instance().EnableNativeCrossJoin.get();
MondrianProperties.instance().EnableNativeCrossJoin.set(false);

// Get a fresh connection; Otherwise the mondrian property setting
// is not refreshed.
Connection conn = getTestContext().getFoodMartConnection(false);
TestContext context = getTestContext(conn);
context.assertQueryReturns(query, resultNonNative);
context.assertQueryReturns(query, fold(resultNonNative));

MondrianProperties.instance().EnableNativeCrossJoin.set(origNativeCJ);
}
Expand All @@ -1799,7 +1801,7 @@ public void testIndependentSlicerMemberNative() {

Connection conn = getTestContext().getFoodMartConnection(false);
TestContext context = getTestContext(conn);
context.assertQueryReturns(query, resultNative);
context.assertQueryReturns(query, fold(resultNative));

MondrianProperties.instance().EnableNativeCrossJoin.set(origNativeCJ);
}
Expand All @@ -1824,7 +1826,7 @@ public void testDependentSlicerMemberNonNative() {

Connection conn = getTestContext().getFoodMartConnection(false);
TestContext context = getTestContext(conn);
context.assertQueryReturns(query, resultNonNative);
context.assertQueryReturns(query, fold(resultNonNative));

MondrianProperties.instance().EnableNativeCrossJoin.set(origNativeCJ);
}
Expand All @@ -1849,7 +1851,7 @@ public void testDependentSlicerMemberNative() {

Connection conn = getTestContext().getFoodMartConnection(false);
TestContext context = getTestContext(conn);
context.assertQueryReturns(query, resultNative);
context.assertQueryReturns(query, fold(resultNative));

MondrianProperties.instance().EnableNativeCrossJoin.set(origNativeCJ);
}
Expand Down
54 changes: 47 additions & 7 deletions testsrc/main/mondrian/rolap/SharedDimensionTest.java
Expand Up @@ -27,7 +27,8 @@ public class SharedDimensionTest extends FoodMartTestCase {
" <Table name=\"employee\" alias=\"employee\" />\n" +
" <Table name=\"employee\" alias=\"employee_manager\" />\n" +
" </Join>\n" +
" <Level name=\"Manager\" table=\"employee_manager\" column=\"management_role\" uniqueMembers=\"true\"/>\n" +
" <Level name=\"Role\" table=\"employee_manager\" column=\"management_role\" uniqueMembers=\"true\"/>\n" +
" <Level name=\"Title\" table=\"employee_manager\" column=\"position_title\" uniqueMembers=\"false\"/>\n" +
" </Hierarchy>\n" +
"</Dimension>";

Expand Down Expand Up @@ -67,7 +68,7 @@ public class SharedDimensionTest extends FoodMartTestCase {
"with\n" +
" set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([*BASE_MEMBERS_Employee], [*BASE_MEMBERS_Store Type])'\n" +
" set [*BASE_MEMBERS_Measures] as '{[Measures].[Employee Store Sales], [Measures].[Employee Store Cost]}'\n" +
" set [*BASE_MEMBERS_Employee] as '[Employee].[Manager].Members'\n" +
" set [*BASE_MEMBERS_Employee] as '[Employee].[Role].Members'\n" +
" set [*NATIVE_MEMBERS_Employee] as 'Generate([*NATIVE_CJ_SET], {[Employee].CurrentMember})'\n" +
" set [*BASE_MEMBERS_Store Type] as '[Store Type].[Store Type].Members'\n" +
" set [*NATIVE_MEMBERS_Store Type] as 'Generate([*NATIVE_CJ_SET], {[Store Type].CurrentMember})'\n" +
Expand All @@ -81,7 +82,7 @@ public class SharedDimensionTest extends FoodMartTestCase {
"with\n" +
" set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([*BASE_MEMBERS_Employee], [*BASE_MEMBERS_Store Type])'\n" +
" set [*BASE_MEMBERS_Measures] as '{[Measures].[Employee Store Sales], [Measures].[Employee Store Cost]}'\n" +
" set [*BASE_MEMBERS_Employee] as '[Employee].[Manager].Members'\n" +
" set [*BASE_MEMBERS_Employee] as '[Employee].[Role].Members'\n" +
" set [*NATIVE_MEMBERS_Employee] as 'Generate([*NATIVE_CJ_SET], {[Employee].CurrentMember})'\n" +
" set [*BASE_MEMBERS_Store Type] as '[Store Type].[Store Type].Members'\n" +
" set [*NATIVE_MEMBERS_Store Type] as 'Generate([*NATIVE_CJ_SET], {[Store Type].CurrentMember})'\n" +
Expand All @@ -95,7 +96,7 @@ public class SharedDimensionTest extends FoodMartTestCase {
"with\n" +
" set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([*BASE_MEMBERS_Employee], [*BASE_MEMBERS_Store Type])'\n" +
" set [*BASE_MEMBERS_Measures] as '{[Measures].[Employee Store Sales], [Measures].[Employee Store Cost]}'\n" +
" set [*BASE_MEMBERS_Employee] as '[Employee].[Manager].Members'\n" +
" set [*BASE_MEMBERS_Employee] as '[Employee].[Role].Members'\n" +
" set [*NATIVE_MEMBERS_Employee] as 'Generate([*NATIVE_CJ_SET], {[Employee].CurrentMember})'\n" +
" set [*BASE_MEMBERS_Store Type] as '[Store Type].[Store Type].Members'\n" +
" set [*NATIVE_MEMBERS_Store Type] as 'Generate([*NATIVE_CJ_SET], {[Store Type].CurrentMember})'\n" +
Expand All @@ -117,9 +118,16 @@ public class SharedDimensionTest extends FoodMartTestCase {
"select {[Measures].[Employee Store Sales]} on columns,\n" +
"NonEmptyCrossJoin([Store Type].[Store Type].Members,\n" +
"{[Employee].[All Employees].[Middle Management],\n" +
"[Employee].[All Employees].[Store Management]})\n" +
" [Employee].[All Employees].[Store Management]})\n" +
"on rows from [Employee Store Analysis B]";

public static String queryNECJMultiLevelMemberList =
"select {[Employee Store Sales]} on columns, " +
"NonEmptyCrossJoin([Store Type].[Store Type].Members, " +
"{[Employee].[Store Management].[Store Manager], " +
" [Employee].[Senior Management].[President]}) " +
"on rows from [Employee Store Analysis B]";

public static String querySF1711865 =
"select NON EMPTY {[Product].[Product Family].Members} ON COLUMNS from [Sales 2]";

Expand Down Expand Up @@ -270,6 +278,19 @@ public class SharedDimensionTest extends FoodMartTestCase {
"Row #3: $5,932\n" +
"Row #4: $108,610\n";

public static String resultNECJMultiLevelMemberList =
"Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[Employee Store Sales]}\n" +
"Axis #2:\n" +
"{[Store Type].[All Store Types].[Deluxe Supermarket], [Employee].[All Employees].[Store Management].[Store Manager]}\n" +
"{[Store Type].[All Store Types].[Gourmet Supermarket], [Employee].[All Employees].[Store Management].[Store Manager]}\n" +
"{[Store Type].[All Store Types].[Supermarket], [Employee].[All Employees].[Store Management].[Store Manager]}\n" +
"Row #0: $1,783\n" +
"Row #1: $286\n" +
"Row #2: $1,020\n";

public static String resultSF1711865 =
"Axis #0:\n" +
"{}\n" +
Expand All @@ -280,7 +301,7 @@ public class SharedDimensionTest extends FoodMartTestCase {
"Row #0: 7,978\n" +
"Row #0: 62,445\n" +
"Row #0: 16,414\n";

public SharedDimensionTest() {
}

Expand Down Expand Up @@ -342,8 +363,27 @@ public void testNECJMemberList() {
null,
null);

testContext.assertQueryReturns(queryNECJMemberList, fold(resultNECJMemberList));
testContext.assertQueryReturns(queryNECJMemberList,
fold(resultNECJMemberList));
}

public void testNECJMultiLevelMemberList() {
// Schema has two cubes sharing a dimension.
// Query from the first cube.
// This is a case where not using alias not only affects performance,
// but also produces incorrect result.
TestContext testContext =
TestContext.create(
sharedDimension,
cubeA + "\n" + cubeB,
null,
null,
null);

testContext.assertQueryReturns(queryNECJMultiLevelMemberList,
fold(resultNECJMultiLevelMemberList));
}


public void testSF1711865() {
// Test for sourceforge.net bug 1711865
Expand Down

0 comments on commit 7cf3a8f

Please sign in to comment.