\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "",
// Virtual cube based on [Warehouse (Default USA)]
"\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "",
null, null, null);
}
public void testMemberVisibility() {
TestContext testContext = TestContext.instance().create(
null,
null,
"\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " [Measures].[Store Sales] - [Measures].[Store Cost]\n"
+ " \n"
+ "",
null,
null,
null);
Result result = testContext.executeQuery(
"select {[Measures].[Sales Count],\n"
+ " [Measures].[Store Cost],\n"
+ " [Measures].[Store Sales],\n"
+ " [Measures].[Units Shipped],\n"
+ " [Measures].[Profit]} on columns\n"
+ "from [Warehouse and Sales Member Visibility]");
assertVisibility(result, 0, "Sales Count", true); // explicitly visible
assertVisibility(
result, 1, "Store Cost", false); // explicitly invisible
assertVisibility(result, 2, "Store Sales", true); // visible by default
assertVisibility(
result, 3, "Units Shipped", false); // explicitly invisible
assertVisibility(result, 4, "Profit", false); // explicitly invisible
}
private void assertVisibility(
Result result,
int ordinal,
String expectedName,
boolean expectedVisibility)
{
List columnPositions = result.getAxes()[0].getPositions();
Member measure = columnPositions.get(ordinal).get(0);
assertEquals(expectedName, measure.getName());
assertEquals(
expectedVisibility,
measure.getPropertyValue(Property.VISIBLE.name));
}
/**
* Test an expression for the format_string of a calculated member that
* evaluates calculated members based on a virtual cube. One cube has cache
* turned on, the other cache turned off.
*
*
Since evaluation of the format_string used to happen after the
* aggregate cache was cleared, this used to fail, this should be solved
* with the caching of the format string.
*
*
Without caching of format string, the query returns green for all
* styles.
*/
public void testFormatStringExpressionCubeNoCache() {
TestContext testContext = TestContext.instance().create(
null,
null,
"\n"
+ "
\n"
+ "\n"
+ " \n"
+ " \n"
+ " \n"
+ "\n"
+ "\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " [Measures].[Store Sales] - [Measures].[Store Cost]\n"
+ " \n"
+ " \n"
+ " [Measures].[Profit] / [Measures].[Units Shipped]\n"
+ " 2.0), '|0.#|style=green', '|0.#|style=red')\"/>\n"
+ " \n"
+ "",
null,
null,
null);
testContext.assertQueryReturns(
"select {[Measures].[Profit Per Unit Shipped]} ON COLUMNS, "
+ "{[Store].[All Stores].[USA].[CA], [Store].[All Stores].[USA].[OR], [Store].[All Stores].[USA].[WA]} ON ROWS "
+ "from [Warehouse and Sales Format Expression Cube No Cache] "
+ "where [Time].[1997]",
"Axis #0:\n"
+ "{[Time].[1997]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Profit Per Unit Shipped]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "Row #0: |1.6|style=red\n"
+ "Row #1: |2.1|style=green\n"
+ "Row #2: |1.5|style=red\n");
}
public void testCalculatedMeasure() {
// calculated measures reference measures defined in the base cube
assertQueryReturns(
"select\n"
+ "{[Measures].[Profit Growth], "
+ "[Measures].[Profit], "
+ "[Measures].[Average Warehouse Sale] }\n"
+ "ON COLUMNS\n"
+ "from [Warehouse and Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Profit Growth]}\n"
+ "{[Measures].[Profit]}\n"
+ "{[Measures].[Average Warehouse Sale]}\n"
+ "Row #0: 0.0%\n"
+ "Row #0: $339,610.90\n"
+ "Row #0: $2.21\n");
}
public void testLostData() {
assertQueryReturns(
"select {[Time].[Time].Members} on columns,\n"
+ " {[Product].Children} on rows\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997]}\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q1].[2]}\n"
+ "{[Time].[1997].[Q1].[3]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q3]}\n"
+ "{[Time].[1997].[Q3].[7]}\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "{[Time].[1997].[Q3].[9]}\n"
+ "{[Time].[1997].[Q4]}\n"
+ "{[Time].[1997].[Q4].[10]}\n"
+ "{[Time].[1997].[Q4].[11]}\n"
+ "{[Time].[1997].[Q4].[12]}\n"
+ "{[Time].[1998]}\n"
+ "{[Time].[1998].[Q1]}\n"
+ "{[Time].[1998].[Q1].[1]}\n"
+ "{[Time].[1998].[Q1].[2]}\n"
+ "{[Time].[1998].[Q1].[3]}\n"
+ "{[Time].[1998].[Q2]}\n"
+ "{[Time].[1998].[Q2].[4]}\n"
+ "{[Time].[1998].[Q2].[5]}\n"
+ "{[Time].[1998].[Q2].[6]}\n"
+ "{[Time].[1998].[Q3]}\n"
+ "{[Time].[1998].[Q3].[7]}\n"
+ "{[Time].[1998].[Q3].[8]}\n"
+ "{[Time].[1998].[Q3].[9]}\n"
+ "{[Time].[1998].[Q4]}\n"
+ "{[Time].[1998].[Q4].[10]}\n"
+ "{[Time].[1998].[Q4].[11]}\n"
+ "{[Time].[1998].[Q4].[12]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Food]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: 24,597\n"
+ "Row #0: 5,976\n"
+ "Row #0: 1,910\n"
+ "Row #0: 1,951\n"
+ "Row #0: 2,115\n"
+ "Row #0: 5,895\n"
+ "Row #0: 1,948\n"
+ "Row #0: 2,039\n"
+ "Row #0: 1,908\n"
+ "Row #0: 6,065\n"
+ "Row #0: 2,205\n"
+ "Row #0: 1,921\n"
+ "Row #0: 1,939\n"
+ "Row #0: 6,661\n"
+ "Row #0: 1,898\n"
+ "Row #0: 2,344\n"
+ "Row #0: 2,419\n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #1: 191,940\n"
+ "Row #1: 47,809\n"
+ "Row #1: 15,604\n"
+ "Row #1: 15,142\n"
+ "Row #1: 17,063\n"
+ "Row #1: 44,825\n"
+ "Row #1: 14,393\n"
+ "Row #1: 15,055\n"
+ "Row #1: 15,377\n"
+ "Row #1: 47,440\n"
+ "Row #1: 17,036\n"
+ "Row #1: 15,741\n"
+ "Row #1: 14,663\n"
+ "Row #1: 51,866\n"
+ "Row #1: 14,232\n"
+ "Row #1: 18,278\n"
+ "Row #1: 19,356\n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #2: 50,236\n"
+ "Row #2: 12,506\n"
+ "Row #2: 4,114\n"
+ "Row #2: 3,864\n"
+ "Row #2: 4,528\n"
+ "Row #2: 11,890\n"
+ "Row #2: 3,838\n"
+ "Row #2: 3,987\n"
+ "Row #2: 4,065\n"
+ "Row #2: 12,343\n"
+ "Row #2: 4,522\n"
+ "Row #2: 4,035\n"
+ "Row #2: 3,786\n"
+ "Row #2: 13,497\n"
+ "Row #2: 3,828\n"
+ "Row #2: 4,648\n"
+ "Row #2: 5,021\n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n");
assertQueryReturns(
"select\n"
+ " {[Measures].[Unit Sales]} on 0,\n"
+ " {[Product].Children} on 1\n"
+ "from [Warehouse and Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Food]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: 24,597\n"
+ "Row #1: 191,940\n"
+ "Row #2: 50,236\n");
}
/**
* Tests a calc measure which combines a measures from the Sales cube with a
* measures from the Warehouse cube.
*/
public void testCalculatedMeasureAcrossCubes() {
assertQueryReturns(
"with member [Measures].[Shipped per Ordered] as ' [Measures].[Units Shipped] / [Measures].[Unit Sales] ', format_string='#.00%'\n"
+ " member [Measures].[Profit per Unit Shipped] as ' [Measures].[Profit] / [Measures].[Units Shipped] '\n"
+ "select\n"
+ " {[Measures].[Unit Sales], \n"
+ " [Measures].[Units Shipped],\n"
+ " [Measures].[Shipped per Ordered],\n"
+ " [Measures].[Profit per Unit Shipped]} on 0,\n"
+ " NON EMPTY Crossjoin([Product].Children, [Time].[1997].Children) on 1\n"
+ "from [Warehouse and Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Units Shipped]}\n"
+ "{[Measures].[Shipped per Ordered]}\n"
+ "{[Measures].[Profit per Unit Shipped]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink], [Time].[1997].[Q1]}\n"
+ "{[Product].[Drink], [Time].[1997].[Q2]}\n"
+ "{[Product].[Drink], [Time].[1997].[Q3]}\n"
+ "{[Product].[Drink], [Time].[1997].[Q4]}\n"
+ "{[Product].[Food], [Time].[1997].[Q1]}\n"
+ "{[Product].[Food], [Time].[1997].[Q2]}\n"
+ "{[Product].[Food], [Time].[1997].[Q3]}\n"
+ "{[Product].[Food], [Time].[1997].[Q4]}\n"
+ "{[Product].[Non-Consumable], [Time].[1997].[Q1]}\n"
+ "{[Product].[Non-Consumable], [Time].[1997].[Q2]}\n"
+ "{[Product].[Non-Consumable], [Time].[1997].[Q3]}\n"
+ "{[Product].[Non-Consumable], [Time].[1997].[Q4]}\n"
+ "Row #0: 5,976\n"
+ "Row #0: 4637.0\n"
+ "Row #0: 77.59%\n"
+ "Row #0: $1.50\n"
+ "Row #1: 5,895\n"
+ "Row #1: 4501.0\n"
+ "Row #1: 76.35%\n"
+ "Row #1: $1.60\n"
+ "Row #2: 6,065\n"
+ "Row #2: 6258.0\n"
+ "Row #2: 103.18%\n"
+ "Row #2: $1.15\n"
+ "Row #3: 6,661\n"
+ "Row #3: 5802.0\n"
+ "Row #3: 87.10%\n"
+ "Row #3: $1.38\n"
+ "Row #4: 47,809\n"
+ "Row #4: 37153.0\n"
+ "Row #4: 77.71%\n"
+ "Row #4: $1.64\n"
+ "Row #5: 44,825\n"
+ "Row #5: 35459.0\n"
+ "Row #5: 79.11%\n"
+ "Row #5: $1.62\n"
+ "Row #6: 47,440\n"
+ "Row #6: 41545.0\n"
+ "Row #6: 87.57%\n"
+ "Row #6: $1.47\n"
+ "Row #7: 51,866\n"
+ "Row #7: 34706.0\n"
+ "Row #7: 66.91%\n"
+ "Row #7: $1.91\n"
+ "Row #8: 12,506\n"
+ "Row #8: 9161.0\n"
+ "Row #8: 73.25%\n"
+ "Row #8: $1.76\n"
+ "Row #9: 11,890\n"
+ "Row #9: 9227.0\n"
+ "Row #9: 77.60%\n"
+ "Row #9: $1.65\n"
+ "Row #10: 12,343\n"
+ "Row #10: 9986.0\n"
+ "Row #10: 80.90%\n"
+ "Row #10: $1.59\n"
+ "Row #11: 13,497\n"
+ "Row #11: 9291.0\n"
+ "Row #11: 68.84%\n"
+ "Row #11: $1.86\n");
}
/**
* Tests a calc member defined in the cube.
*/
public void testCalculatedMemberInSchema() {
TestContext testContext = TestContext.instance().createSubstitutingCube(
"Warehouse and Sales",
null,
" \n"
+ " [Measures].[Units Shipped] / [Measures].[Unit Sales]\n"
+ " \n"
+ " \n");
testContext.assertQueryReturns(
"select\n"
+ " {[Measures].[Unit Sales], \n"
+ " [Measures].[Shipped per Ordered]} on 0,\n"
+ " NON EMPTY Crossjoin([Product].Children, [Time].[1997].Children) on 1\n"
+ "from [Warehouse and Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Shipped per Ordered]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink], [Time].[1997].[Q1]}\n"
+ "{[Product].[Drink], [Time].[1997].[Q2]}\n"
+ "{[Product].[Drink], [Time].[1997].[Q3]}\n"
+ "{[Product].[Drink], [Time].[1997].[Q4]}\n"
+ "{[Product].[Food], [Time].[1997].[Q1]}\n"
+ "{[Product].[Food], [Time].[1997].[Q2]}\n"
+ "{[Product].[Food], [Time].[1997].[Q3]}\n"
+ "{[Product].[Food], [Time].[1997].[Q4]}\n"
+ "{[Product].[Non-Consumable], [Time].[1997].[Q1]}\n"
+ "{[Product].[Non-Consumable], [Time].[1997].[Q2]}\n"
+ "{[Product].[Non-Consumable], [Time].[1997].[Q3]}\n"
+ "{[Product].[Non-Consumable], [Time].[1997].[Q4]}\n"
+ "Row #0: 5,976\n"
+ "Row #0: 77.6%\n"
+ "Row #1: 5,895\n"
+ "Row #1: 76.4%\n"
+ "Row #2: 6,065\n"
+ "Row #2: 103.2%\n"
+ "Row #3: 6,661\n"
+ "Row #3: 87.1%\n"
+ "Row #4: 47,809\n"
+ "Row #4: 77.7%\n"
+ "Row #5: 44,825\n"
+ "Row #5: 79.1%\n"
+ "Row #6: 47,440\n"
+ "Row #6: 87.6%\n"
+ "Row #7: 51,866\n"
+ "Row #7: 66.9%\n"
+ "Row #8: 12,506\n"
+ "Row #8: 73.3%\n"
+ "Row #9: 11,890\n"
+ "Row #9: 77.6%\n"
+ "Row #10: 12,343\n"
+ "Row #10: 80.9%\n"
+ "Row #11: 13,497\n"
+ "Row #11: 68.8%\n");
}
public void testAllMeasureMembers() {
// result should exclude measures that are not explicitly defined
// in the virtual cube (e.g., [Profit last Period])
assertQueryReturns(
"select\n"
+ "{[Measures].allMembers} on columns\n"
+ "from [Warehouse and Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Sales Count]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Invoice]}\n"
+ "{[Measures].[Supply Time]}\n"
+ "{[Measures].[Units Ordered]}\n"
+ "{[Measures].[Units Shipped]}\n"
+ "{[Measures].[Warehouse Cost]}\n"
+ "{[Measures].[Warehouse Profit]}\n"
+ "{[Measures].[Warehouse Sales]}\n"
+ "{[Measures].[Profit]}\n"
+ "{[Measures].[Profit Growth]}\n"
+ "{[Measures].[Average Warehouse Sale]}\n"
+ "{[Measures].[Profit Per Unit Shipped]}\n"
+ "Row #0: 86,837\n"
+ "Row #0: 225,627.23\n"
+ "Row #0: 565,238.13\n"
+ "Row #0: 266,773\n"
+ "Row #0: 102,278.409\n"
+ "Row #0: 10,425\n"
+ "Row #0: 227238.0\n"
+ "Row #0: 207726.0\n"
+ "Row #0: 89,043.253\n"
+ "Row #0: 107,727.635\n"
+ "Row #0: 196,770.888\n"
+ "Row #0: $339,610.90\n"
+ "Row #0: 0.0%\n"
+ "Row #0: $2.21\n"
+ "Row #0: $1.63\n");
}
/**
* Test a virtual cube where one of the dimensions contains an
* ordinalColumn property
*/
public void testOrdinalColumn() {
TestContext testContext = TestContext.instance().create(
null,
null,
"\n"
+ "\n"
+ "\n"
+ "\n"
+ "",
null,
null,
null);
testContext.assertQueryReturns(
"select {[Measures].[Org Salary]} on columns, "
+ "non empty "
+ "crossjoin([Store].[Store Country].members, [Position].[Store Management].children) "
+ "on rows from [Sales vs HR]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Org Salary]}\n"
+ "Axis #2:\n"
+ "{[Store].[Canada], [Position].[Store Management].[Store Manager]}\n"
+ "{[Store].[Canada], [Position].[Store Management].[Store Assistant Manager]}\n"
+ "{[Store].[Canada], [Position].[Store Management].[Store Shift Supervisor]}\n"
+ "{[Store].[Mexico], [Position].[Store Management].[Store Manager]}\n"
+ "{[Store].[Mexico], [Position].[Store Management].[Store Assistant Manager]}\n"
+ "{[Store].[Mexico], [Position].[Store Management].[Store Shift Supervisor]}\n"
+ "{[Store].[USA], [Position].[Store Management].[Store Manager]}\n"
+ "{[Store].[USA], [Position].[Store Management].[Store Assistant Manager]}\n"
+ "{[Store].[USA], [Position].[Store Management].[Store Shift Supervisor]}\n"
+ "Row #0: $462.86\n"
+ "Row #1: $394.29\n"
+ "Row #2: $565.71\n"
+ "Row #3: $13,254.55\n"
+ "Row #4: $11,443.64\n"
+ "Row #5: $17,705.46\n"
+ "Row #6: $4,069.80\n"
+ "Row #7: $3,417.72\n"
+ "Row #8: $5,145.96\n");
}
public void testDefaultMeasureProperty() {
TestContext testContext = TestContext.instance().create(
null,
null,
"\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "",
null,
null,
null);
String queryWithoutFilter =
"select"
+ " from [Sales vs Warehouse]";
String queryWithDeflaultMeasureFilter =
"select "
+ "from [Sales vs Warehouse] where measures.[Unit Sales]";
assertQueriesReturnSimilarResults(
queryWithoutFilter, queryWithDeflaultMeasureFilter, testContext);
}
/**
* Checks that native set caching considers base cubes in the cache key.
* Native sets referencing different base cubes do not share the cached
* result.
*/
public void testNativeSetCaching() {
// Only need to run this against one db to verify caching
// behavior is correct.
final Dialect dialect = getTestContext().getDialect();
if (dialect.getDatabaseProduct() != Dialect.DatabaseProduct.DERBY) {
return;
}
if (!MondrianProperties.instance().EnableNativeCrossJoin.get()
&& !MondrianProperties.instance().EnableNativeNonEmpty.get())
{
// Only run the tests if either native CrossJoin or native NonEmpty
// is enabled.
return;
}
String query1 =
"With "
+ "Set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([Product].[Product Family].Members, [Store].[Store Country].Members)' "
+ "Select "
+ "{[Store Sales]} on columns, "
+ "Non Empty Generate([*NATIVE_CJ_SET], {([Product].CurrentMember,[Store].CurrentMember)}) on rows "
+ "From [Warehouse and Sales]";
String query2 =
"With "
+ "Set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([Product].[Product Family].Members, [Store].[Store Country].Members)' "
+ "Select "
+ "{[Warehouse Sales]} on columns, "
+ "Non Empty Generate([*NATIVE_CJ_SET], {([Product].CurrentMember,[Store].CurrentMember)}) on rows "
+ "From [Warehouse and Sales]";
String derbyNecjSql1, derbyNecjSql2;
if (MondrianProperties.instance().EnableNativeCrossJoin.get()) {
derbyNecjSql1 =
"select "
+ "\"product_class\".\"product_family\", "
+ "\"store\".\"store_country\" "
+ "from "
+ "\"product\" as \"product\", "
+ "\"product_class\" as \"product_class\", "
+ "\"sales_fact_1997\" as \"sales_fact_1997\", "
+ "\"store\" as \"store\" "
+ "where "
+ "\"product\".\"product_class_id\" = \"product_class\".\"product_class_id\" "
+ "and \"sales_fact_1997\".\"product_id\" = \"product\".\"product_id\" "
+ "and \"sales_fact_1997\".\"store_id\" = \"store\".\"store_id\" "
+ "group by \"product_class\".\"product_family\", \"store\".\"store_country\" "
+ "order by 1 ASC, 2 ASC";
derbyNecjSql2 =
"select "
+ "\"product_class\".\"product_family\", "
+ "\"store\".\"store_country\" "
+ "from "
+ "\"product\" as \"product\", "
+ "\"product_class\" as \"product_class\", "
+ "\"inventory_fact_1997\" as \"inventory_fact_1997\", "
+ "\"store\" as \"store\" "
+ "where "
+ "\"product\".\"product_class_id\" = \"product_class\".\"product_class_id\" "
+ "and \"inventory_fact_1997\".\"product_id\" = \"product\".\"product_id\" "
+ "and \"inventory_fact_1997\".\"store_id\" = \"store\".\"store_id\" "
+ "group by \"product_class\".\"product_family\", \"store\".\"store_country\" "
+ "order by 1 ASC, 2 ASC";
} else {
// NECJ is truend off so native NECJ SQL will not be generated;
// however, because the NECJ set should not find match in the cache,
// each NECJ input will still be joined with the correct
// fact table if NonEmpty condition is natively evaluated.
derbyNecjSql1 =
"select "
+ "\"store\".\"store_country\" "
+ "from "
+ "\"store\" as \"store\", "
+ "\"sales_fact_1997\" as \"sales_fact_1997\" "
+ "where "
+ "\"sales_fact_1997\".\"store_id\" = \"store\".\"store_id\" "
+ "group by \"store\".\"store_country\" "
+ "order by 1 ASC";
derbyNecjSql2 =
"select "
+ "\"store\".\"store_country\" "
+ "from "
+ "\"store\" as \"store\", "
+ "\"inventory_fact_1997\" as \"inventory_fact_1997\" "
+ "where "
+ "\"inventory_fact_1997\".\"store_id\" = \"store\".\"store_id\" "
+ "group by \"store\".\"store_country\" "
+ "order by 1 ASC";
}
SqlPattern[] patterns1 = {
new SqlPattern(
Dialect.DatabaseProduct.DERBY, derbyNecjSql1, derbyNecjSql1)
};
SqlPattern[] patterns2 = {
new SqlPattern(
Dialect.DatabaseProduct.DERBY, derbyNecjSql2, derbyNecjSql2)
};
// Run query 1 with cleared cache;
// Make sure NECJ 1 is evaluated natively.
assertQuerySql(query1, patterns1, true);
// Now run query 2 with warm cache;
// Make sure NECJ 2 does not reuse the cache result from NECJ 1, and
// NECJ 2 is evaluated natively.
assertQuerySql(query2, patterns2, false);
}
/**
* Test case for bug
* MONDRIAN-322, "cube.getStar() throws NullPointerException".
* Happens when you aggregate distinct-count measures in a virtual cube.
*/
public void testBugMondrian322() {
final TestContext testContext = TestContext.instance().create(
null,
null,
"\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "",
null,
null,
null);
/*
* This test case does not actually reject the dimension constraint from
* an unrelated base cube. The reason is that the constraint contains an
* AllLevel member. Even though semantically constraining Cells using an
* non-existent dimension perhaps does not make sense; however, in the
* case where the constraint contains AllLevel member, the constraint
* can be considered "always true".
*
* See the next test case for a constraint that does not contain
* AllLevel member and hence cannot be satisfied. The cell should be
* empty.
*/
testContext.assertQueryReturns(
"with member [Warehouse].[x] as 'Aggregate([Warehouse].members)'\n"
+ "member [Measures].[foo] AS '([Warehouse].[x],[Measures].[Customer Count])'\n"
+ "select {[Measures].[foo]} on 0 from [Warehouse And Sales2]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[foo]}\n"
+ "Row #0: 5,581\n");
}
public void testBugMondrian322a() {
final TestContext testContext = TestContext.instance().create(
null,
null,
"\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "",
null,
null,
null);
testContext.assertQueryReturns(
"with member [Warehouse].[x] as 'Aggregate({[Warehouse].[Canada], [Warehouse].[USA]})'\n"
+ "member [Measures].[foo] AS '([Warehouse].[x],[Measures].[Customer Count])'\n"
+ "select {[Measures].[foo]} on 0 from [Warehouse And Sales2]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[foo]}\n"
+ "Row #0: \n");
}
/**
* Test case for bug
* MONDRIAN-352, "Caption is not set on RolapVirtualCubeMesure".
*/
public void testVirtualCubeMeasureCaption() {
TestContext testContext = TestContext.instance().create(
null,
"\n"
+ "
\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "\n",
"\n"
+ " \n"
+ " \n"
+ "",
null,
null,
null);
Result result = testContext.executeQuery(
"select {[Measures].[Store Sqft]} ON COLUMNS,"
+ "{[HCB]} ON ROWS "
+ "from [VirtualTestStore]");
Axis[] axes = result.getAxes();
List positions = axes[0].getPositions();
Member m0 = positions.get(0).get(0);
String caption = m0.getCaption();
assertEquals("Store Sqft Caption", caption);
}
/**
* Test that RolapCubeLevel is used correctly in the context of virtual
* cube.
*/
public void testRolapCubeLevelInVirtualCube() {
String query1 =
"With "
+ "Set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([*BASE_MEMBERS_Warehouse],[*BASE_MEMBERS_Time])' "
+ "Set [*NATIVE_MEMBERS_Warehouse] as 'Generate([*NATIVE_CJ_SET], {[Warehouse].CurrentMember})' "
+ "Set [*BASE_MEMBERS_Warehouse] as '[Warehouse].[Country].Members' "
+ "Set [*NATIVE_MEMBERS_Time] as 'Generate([*NATIVE_CJ_SET], {[Time].[Time].CurrentMember})' "
+ "Set [*BASE_MEMBERS_Time] as '[Time].[Month].Members' "
+ "Set [*BASE_MEMBERS_Measures] as '{[Measures].[*FORMATTED_MEASURE_0]}' Member [Measures].[*FORMATTED_MEASURE_0] as '[Measures].[Warehouse Sales]', FORMAT_STRING = '#,##0', SOLVE_ORDER=400 "
+ "Select [*BASE_MEMBERS_Measures] on columns, Non Empty Generate([*NATIVE_CJ_SET], {([Warehouse].currentMember,[Time].[Time].currentMember)}) on rows From [Warehouse and Sales] ";
String query2 =
"With "
+ "Set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([*BASE_MEMBERS_Warehouse],[*BASE_MEMBERS_Time])' "
+ "Set [*NATIVE_MEMBERS_Warehouse] as 'Generate([*NATIVE_CJ_SET], {[Warehouse].CurrentMember})' "
+ "Set [*BASE_MEMBERS_Warehouse] as '[Warehouse].[Country].Members' "
+ "Set [*NATIVE_MEMBERS_Time] as 'Generate([*NATIVE_CJ_SET], {[Time].[Time].CurrentMember})' "
+ "Set [*BASE_MEMBERS_Time] as 'Filter([Time].[Month].Members,[Time].[Time].CurrentMember Not In {[Time].[1997].[Q1].[2]})' "
+ "Set [*BASE_MEMBERS_Measures] as '{[Measures].[*FORMATTED_MEASURE_0]}' Member [Measures].[*FORMATTED_MEASURE_0] as '[Measures].[Warehouse Sales]', FORMAT_STRING = '#,##0', SOLVE_ORDER=400 "
+ "Select [*BASE_MEMBERS_Measures] on columns, Non Empty Generate([*NATIVE_CJ_SET], {([Warehouse].currentMember,[Time].[Time].currentMember)}) on rows From [Warehouse and Sales]";
executeQuery(query1);
/* The query with the filter should now succeed without NPE */
String result =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[*FORMATTED_MEASURE_0]}\n"
+ "Axis #2:\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q1].[1]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q1].[3]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q2].[4]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q2].[5]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q2].[6]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q3].[7]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q3].[8]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q3].[9]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q4].[10]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q4].[11]}\n"
+ "{[Warehouse].[USA], [Time].[1997].[Q4].[12]}\n"
+ "Row #0: 21,762\n"
+ "Row #1: 13,775\n"
+ "Row #2: 15,938\n"
+ "Row #3: 15,649\n"
+ "Row #4: 14,629\n"
+ "Row #5: 18,626\n"
+ "Row #6: 15,833\n"
+ "Row #7: 21,393\n"
+ "Row #8: 17,100\n"
+ "Row #9: 15,356\n"
+ "Row #10: 13,948\n";
assertQueryReturns(query2, result);
}
/**
* Tests that the logic to apply non empty context constraint in virtual
* cube is correct. The joins shouldn't be cartesian product.
*/
public void testNonEmptyCJConstraintOnVirtualCube() {
if (!MondrianProperties.instance().EnableNativeCrossJoin.get()) {
// Generated SQL is different if NonEmptyCrossJoin is evaluated in
// memory.
return;
}
String query =
"with "
+ "set [foo] as [Time].[Month].members "
+ "set [bar] as {[Store].[USA]} "
+ "Select {[Measures].[Warehouse Sales],[Measures].[Store Sales]} on columns, "
+ "nonemptycrossjoin([foo],[bar]) on rows "
+ "From [Warehouse and Sales] "
+ "Where ([Product].[All Products].[Food])";
// Note that for MySQL (because MySQL sorts NULLs first), because there
// is a UNION (which prevents us from sorting on column names or
// expressions) the ORDER BY clause should be something like
// ORDER BY ISNULL(1), 1 ASC, ISNULL(2), 2 ASC, ISNULL(3), 3 ASC,
// ISNULL(4), 4 ASC
// but ISNULL(1) isn't valid SQL, so we forego correct ordering of NULL
// values.
String mysqlSQL =
"select "
+ "`time_by_day`.`the_year` as `c0`, `time_by_day`.`quarter` as `c1`, `time_by_day`.`month_of_year` as `c2`, `store`.`store_country` as `c3` "
+ "from "
+ "`time_by_day` as `time_by_day`, `sales_fact_1997` as `sales_fact_1997`, "
+ "`store` as `store`, `product_class` as `product_class`, `product` as `product` "
+ "where "
+ "`sales_fact_1997`.`time_id` = `time_by_day`.`time_id` and `sales_fact_1997`.`store_id` = `store`.`store_id` and "
+ "`sales_fact_1997`.`product_id` = `product`.`product_id` and `product`.`product_class_id` = `product_class`.`product_class_id` and "
+ "`product_class`.`product_family` = 'Food' and (`store`.`store_country` = 'USA') "
+ "group by "
+ "`time_by_day`.`the_year`, `time_by_day`.`quarter`, `time_by_day`.`month_of_year`, `store`.`store_country` "
+ "union "
+ "select "
+ "`time_by_day`.`the_year` as `c0`, `time_by_day`.`quarter` as `c1`, `time_by_day`.`month_of_year` as `c2`, `store`.`store_country` as `c3` "
+ "from "
+ "`time_by_day` as `time_by_day`, `inventory_fact_1997` as `inventory_fact_1997`, `store` as `store`, "
+ "`product_class` as `product_class`, `product` as `product` "
+ "where "
+ "`inventory_fact_1997`.`time_id` = `time_by_day`.`time_id` and `inventory_fact_1997`.`store_id` = `store`.`store_id` and "
+ "`inventory_fact_1997`.`product_id` = `product`.`product_id` and `product`.`product_class_id` = `product_class`.`product_class_id` and "
+ "`product_class`.`product_family` = 'Food' and (`store`.`store_country` = 'USA') "
+ "group by "
+ "`time_by_day`.`the_year`, `time_by_day`.`quarter`, `time_by_day`.`month_of_year`, `store`.`store_country` "
+ "order by "
+ "1 ASC, 2 ASC, 3 ASC, 4 ASC";
String derbySQL =
"select "
+ "\"time_by_day\".\"the_year\", \"time_by_day\".\"quarter\", \"time_by_day\".\"month_of_year\", \"store\".\"store_country\" "
+ "from \"time_by_day\" as \"time_by_day\", \"sales_fact_1997\" as \"sales_fact_1997\", \"store\" as \"store\", "
+ "\"product_class\" as \"product_class\", \"product\" as \"product\" "
+ "where \"sales_fact_1997\".\"time_id\" = \"time_by_day\".\"time_id\" and \"sales_fact_1997\".\"store_id\" = \"store\".\"store_id\" and "
+ "\"sales_fact_1997\".\"product_id\" = \"product\".\"product_id\" and \"product\".\"product_class_id\" = \"product_class\".\"product_class_id\" and "
+ "\"product_class\".\"product_family\" = 'Food' and (\"store\".\"store_country\" = 'USA') "
+ "group by \"time_by_day\".\"the_year\", \"time_by_day\".\"quarter\", \"time_by_day\".\"month_of_year\", \"store\".\"store_country\" "
+ "union "
+ "select "
+ "\"time_by_day\".\"the_year\", \"time_by_day\".\"quarter\", \"time_by_day\".\"month_of_year\", \"store\".\"store_country\" "
+ "from \"time_by_day\" as \"time_by_day\", \"inventory_fact_1997\" as \"inventory_fact_1997\", \"store\" as \"store\", "
+ "\"product_class\" as \"product_class\", \"product\" as \"product\" "
+ "where \"inventory_fact_1997\".\"time_id\" = \"time_by_day\".\"time_id\" and \"inventory_fact_1997\".\"store_id\" = \"store\".\"store_id\" and "
+ "\"inventory_fact_1997\".\"product_id\" = \"product\".\"product_id\" and \"product\".\"product_class_id\" = \"product_class\".\"product_class_id\" and "
+ "\"product_class\".\"product_family\" = 'Food' and (\"store\".\"store_country\" = 'USA') "
+ "group by \"time_by_day\".\"the_year\", \"time_by_day\".\"quarter\", \"time_by_day\".\"month_of_year\", \"store\".\"store_country\" "
+ "order by 1 ASC, 2 ASC, 3 ASC, 4 ASC";
SqlPattern[] mysqlPattern = {
new SqlPattern(Dialect.DatabaseProduct.MYSQL, mysqlSQL, mysqlSQL),
new SqlPattern(Dialect.DatabaseProduct.DERBY, derbySQL, derbySQL)
};
String result =
"Axis #0:\n"
+ "{[Product].[Food]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Warehouse Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q1].[1], [Store].[USA]}\n"
+ "{[Time].[1997].[Q1].[2], [Store].[USA]}\n"
+ "{[Time].[1997].[Q1].[3], [Store].[USA]}\n"
+ "{[Time].[1997].[Q2].[4], [Store].[USA]}\n"
+ "{[Time].[1997].[Q2].[5], [Store].[USA]}\n"
+ "{[Time].[1997].[Q2].[6], [Store].[USA]}\n"
+ "{[Time].[1997].[Q3].[7], [Store].[USA]}\n"
+ "{[Time].[1997].[Q3].[8], [Store].[USA]}\n"
+ "{[Time].[1997].[Q3].[9], [Store].[USA]}\n"
+ "{[Time].[1997].[Q4].[10], [Store].[USA]}\n"
+ "{[Time].[1997].[Q4].[11], [Store].[USA]}\n"
+ "{[Time].[1997].[Q4].[12], [Store].[USA]}\n"
+ "Row #0: 16,083.015\n"
+ "Row #0: 32,993.12\n"
+ "Row #1: 9,298.379\n"
+ "Row #1: 32,139.91\n"
+ "Row #2: 10,129.659\n"
+ "Row #2: 36,128.29\n"
+ "Row #3: 11,415.462\n"
+ "Row #3: 30,747.21\n"
+ "Row #4: 11,358.086\n"
+ "Row #4: 31,896.24\n"
+ "Row #5: 10,425.768\n"
+ "Row #5: 32,792.55\n"
+ "Row #6: 13,684.193\n"
+ "Row #6: 36,324.76\n"
+ "Row #7: 11,332.797\n"
+ "Row #7: 33,842.75\n"
+ "Row #8: 15,667.978\n"
+ "Row #8: 31,640.09\n"
+ "Row #9: 11,902.18\n"
+ "Row #9: 30,337.12\n"
+ "Row #10: 10,144.841\n"
+ "Row #10: 38,709.15\n"
+ "Row #11: 9,705.561\n"
+ "Row #11: 41,484.40\n";
assertQuerySql(query, mysqlPattern, true);
assertQueryReturns(query, result);
}
/**
* Tests that the logic to apply non empty context constraint in virtual
* cube is correct. The joins shouldn't be cartesian product.
*/
public void testNonEmptyConstraintOnVirtualCubeWithCalcMeasure() {
if (!MondrianProperties.instance().EnableNativeNonEmpty.get()) {
// Generated SQL is different if NON EMPTY is evaluated in memory.
return;
}
String query =
"with "
+ "set [bar] as {[Store].[USA]} "
+ "member [Measures].[CalcMeasure] as '[Measures].[Warehouse Sales] / [Measures].[Store Sales]' "
+ "Select "
+ "{[Measures].[CalcMeasure]} on columns, "
+ "non empty([Product].[Product Family].Members) on rows "
+ "From [Warehouse and Sales] "
+ "where [bar]";
// Comments as for testNonEmptyCJConstraintOnVirtualCube. The ORDER BY
// clause should be "order by ISNULL(1), 1 ASC" but we will settle for
// "order by 1 ASC" and forego correct sorting of NULL values.
String mysqlSQL =
"select `product_class`.`product_family` as `c0` "
+ "from `product` as `product`, `product_class` as `product_class`, `sales_fact_1997` as `sales_fact_1997`, `store` as `store` "
+ "where `product`.`product_class_id` = `product_class`.`product_class_id` and `sales_fact_1997`.`product_id` = `product`.`product_id` and "
+ "`sales_fact_1997`.`store_id` = `store`.`store_id` and `store`.`store_country` = 'USA' "
+ "group by `product_class`.`product_family` "
+ "union "
+ "select `product_class`.`product_family` as `c0` "
+ "from `product` as `product`, `product_class` as `product_class`, `inventory_fact_1997` as `inventory_fact_1997`, `store` as `store` "
+ "where `product`.`product_class_id` = `product_class`.`product_class_id` and `inventory_fact_1997`.`product_id` = `product`.`product_id` and "
+ "`inventory_fact_1997`.`store_id` = `store`.`store_id` and `store`.`store_country` = 'USA' "
+ "group by `product_class`.`product_family` "
+ "order by 1 ASC";
String derbySQL =
"select \"product_class\".\"product_family\" "
+ "from \"product\" as \"product\", \"product_class\" as \"product_class\", \"sales_fact_1997\" as \"sales_fact_1997\", \"store\" as \"store\" "
+ "where \"product\".\"product_class_id\" = \"product_class\".\"product_class_id\" and \"sales_fact_1997\".\"product_id\" = \"product\".\"product_id\""
+ " and \"sales_fact_1997\".\"store_id\" = \"store\".\"store_id\" and \"store\".\"store_country\" = 'USA' "
+ "group by \"product_class\".\"product_family\" "
+ "union "
+ "select \"product_class\".\"product_family\" "
+ "from \"product\" as \"product\", \"product_class\" as \"product_class\", \"inventory_fact_1997\" as \"inventory_fact_1997\", \"store\" as \"store\" "
+ "where \"product\".\"product_class_id\" = \"product_class\".\"product_class_id\" and \"inventory_fact_1997\".\"product_id\" = \"product\".\"product_id\""
+ " and \"inventory_fact_1997\".\"store_id\" = \"store\".\"store_id\" and \"store\".\"store_country\" = 'USA' "
+ "group by \"product_class\".\"product_family\" "
+ "order by 1 ASC";
String result =
"Axis #0:\n"
+ "{[Store].[USA]}\n"
+ "Axis #1:\n"
+ "{[Measures].[CalcMeasure]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Food]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: 0.369\n"
+ "Row #1: 0.345\n"
+ "Row #2: 0.35\n";
SqlPattern[] mysqlPattern = {
new SqlPattern(
Dialect.DatabaseProduct.MYSQL, mysqlSQL, mysqlSQL),
new SqlPattern(
Dialect.DatabaseProduct.DERBY, derbySQL, derbySQL)
};
assertQuerySql(query, mysqlPattern, true);
assertQueryReturns(query, result);
}
/**
* Test case for bug
* MONDRIAN-902, "mondrian populating the same members on both axes".
*/
public void testBugMondrian902() {
Result result = executeQuery(
"SELECT\n"
+ "NON EMPTY CrossJoin(\n"
+ " [Education Level].[Education Level].Members,\n"
+ " CrossJoin(\n"
+ " [Product].[Product Family].Members,\n"
+ " [Store].[Store State].Members)) ON COLUMNS,\n"
+ "NON EMPTY CrossJoin(\n"
+ " [Promotions].[Promotion Name].Members,\n"
+ " [Marital Status].[Marital Status].Members) ON ROWS\n"
+ "FROM [Warehouse and Sales]");
assertEquals(
"[[Education Level].[Bachelors Degree], [Product].[Drink], [Store].[USA].[CA]]",
result.getAxes()[0].getPositions().get(0).toString());
assertEquals(45, result.getAxes()[0].getPositions().size());
// With bug MONDRIAN-902, this gave the same result as for axis #0:
assertEquals(
"[[Promotions].[Bag Stuffers], [Marital Status].[M]]",
result.getAxes()[1].getPositions().get(0).toString());
assertEquals(96, result.getAxes()[1].getPositions().size());
}
}
// End VirtualCubeTest.java
mondrian-3.4.1/testsrc/main/mondrian/rolap/RolapConnectionTest.java 0000644 0001750 0001750 00000043327 11735330606 025376 0 ustar drazzib drazzib /*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2004-2005 Julian Hyde
// Copyright (C) 2005-2011 Pentaho and others
// All Rights Reserved.
//
// jng, 16 April, 2004
*/
package mondrian.rolap;
import mondrian.olap.*;
import mondrian.spi.Dialect;
import mondrian.test.TestContext;
import mondrian.util.Pair;
import junit.framework.TestCase;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import javax.naming.*;
import javax.naming.spi.*;
import javax.sql.DataSource;
/**
* Unit test for {@link RolapConnection}.
*
* @author jng
* @since 16 April, 2004
*/
public class RolapConnectionTest extends TestCase {
private static final ThreadLocal THREAD_INITIAL_CONTEXT =
new ThreadLocal();
public RolapConnectionTest(String name) {
super(name);
}
protected void setUp() throws Exception {
super.setUp();
if (!NamingManager.hasInitialContextFactoryBuilder()) {
NamingManager.setInitialContextFactoryBuilder(
new InitialContextFactoryBuilder() {
public InitialContextFactory createInitialContextFactory(
Hashtable, ?> environment)
throws NamingException
{
return new InitialContextFactory() {
public Context getInitialContext(
Hashtable, ?> environment)
throws NamingException
{
return THREAD_INITIAL_CONTEXT.get();
}
};
}
}
);
}
}
public void testPooledConnectionWithProperties() throws SQLException {
Util.PropertyList properties =
TestContext.instance().getConnectionProperties().clone();
// Only the JDBC-ODBC bridge gives the error necessary for this
// test to succeed. So trivially succeed for all other JDBC
// drivers.
final String jdbc = properties.get("Jdbc");
if (jdbc != null
&& !jdbc.startsWith("jdbc:odbc:"))
{
return;
}
// JDBC-ODBC driver does not support UTF-16, so this test succeeds
// because creating the connection from the DataSource will fail.
properties.put("jdbc.charSet", "UTF-16");
final StringBuilder buf = new StringBuilder();
DataSource dataSource =
RolapConnection.createDataSource(null, properties, buf);
final String desc = buf.toString();
assertTrue(desc.startsWith("Jdbc="));
Connection connection;
try {
connection = dataSource.getConnection();
connection.close();
fail("Expected exception");
} catch (SQLException e) {
if (e.getClass().getName().equals(
"org.apache.commons.dbcp.DbcpException"))
{
// This is expected. (We use string-comparison so that the
// compiler doesn't warn about using a deprecated class.)
} else if (e.getClass() == SQLException.class
&& e.getCause() == null
&& e.getMessage() != null
&& e.getMessage().equals(""))
{
// This is expected, from a later version of Dbcp.
} else {
fail("Expected exception, but got a different one: " + e);
}
} catch (IllegalArgumentException e) {
handleIllegalArgumentException(properties, e);
} finally {
RolapConnectionPool.instance().clearPool();
}
}
public void testNonPooledConnectionWithProperties() {
Util.PropertyList properties =
TestContext.instance().getConnectionProperties().clone();
// Only the JDBC-ODBC bridge gives the error necessary for this
// test to succeed. So trivially succeed for all other JDBC
// drivers.
final String jdbc = properties.get("Jdbc");
if (jdbc != null
&& !jdbc.startsWith("jdbc:odbc:"))
{
return;
}
// This test is just like the test testPooledConnectionWithProperties
// except with non-pooled connections.
properties.put("jdbc.charSet", "UTF-16");
properties.put(RolapConnectionProperties.PoolNeeded.name(), "false");
final StringBuilder buf = new StringBuilder();
DataSource dataSource =
RolapConnection.createDataSource(null, properties, buf);
final String desc = buf.toString();
assertTrue(desc.startsWith("Jdbc="));
Connection connection = null;
try {
connection = dataSource.getConnection();
fail("Expected exception");
} catch (SQLException se) {
// this is expected
} catch (IllegalArgumentException e) {
handleIllegalArgumentException(properties, e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// ignore
}
}
}
}
/**
* Handle an {@link IllegalArgumentException} which occurs when have
* tried to create a connection with an illegal charset.
*/
private void handleIllegalArgumentException(
Util.PropertyList properties,
IllegalArgumentException e)
{
// Workaround Java bug #6504538 (see http://bugs.sun.com) with synopsis
// "DriverManager.getConnection throws IllegalArgumentException".
if (System.getProperties().getProperty("java.version")
.startsWith("1.6."))
{
properties.remove("jdbc.charSet");
final StringBuilder buf = new StringBuilder();
DataSource dataSource =
RolapConnection.createDataSource(null, properties, buf);
final String desc = buf.toString();
assertTrue(desc.startsWith("Jdbc="));
try {
Connection connection1 = dataSource.getConnection();
connection1.close();
} catch (SQLException e1) {
// ignore
}
} else {
fail("Expect IllegalArgumentException only in JDK 1.6, got " + e);
}
}
/**
* Tests that the FORMAT function uses the connection's locale.
*/
public void testFormatLocale() {
String expr = "FORMAT(1234.56, \"#,##.#\")";
checkLocale("es_ES", expr, "1.234,6", false);
checkLocale("es_MX", expr, "1,234.6", false);
checkLocale("en_US", expr, "1,234.6", false);
}
/**
* Tests that measures are formatted using the connection's locale.
*/
public void testFormatStringLocale() {
checkLocale("es_ES", "1234.56", "1.234,6", true);
checkLocale("es_MX", "1234.56", "1,234.6", true);
checkLocale("en_US", "1234.56", "1,234.6", true);
}
private static void checkLocale(
final String localeName, String expr, String expected, boolean isQuery)
{
TestContext testContextSpain = new TestContext() {
public mondrian.olap.Connection getConnection() {
Util.PropertyList properties =
Util.parseConnectString(getConnectString());
properties.put(
RolapConnectionProperties.Locale.name(),
localeName);
return DriverManager.getConnection(properties, null);
}
};
if (isQuery) {
String query = "WITH MEMBER [Measures].[Foo] AS '" + expr + "',\n"
+ " FORMAT_STRING = '#,##.#' \n"
+ "SELECT {[MEasures].[Foo]} ON COLUMNS FROM [Sales]";
String expected2 =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: " + expected + "\n";
testContextSpain.assertQueryReturns(query, expected2);
} else {
testContextSpain.assertExprReturns(expr, expected);
}
}
public void testConnectSansCatalogFails() {
Util.PropertyList properties =
TestContext.instance().getConnectionProperties().clone();
properties.remove(RolapConnectionProperties.Catalog.name());
properties.remove(RolapConnectionProperties.CatalogContent.name());
if (RolapUtil.SQL_LOGGER.isDebugEnabled()) {
RolapUtil.SQL_LOGGER.debug(
this.getName() + "\n [Connection Properties | " + properties
+ "]\n");
} else {
System.out.println(properties);
}
try {
DriverManager.getConnection(
properties,
null);
fail("expected exception");
} catch (MondrianException e) {
assertTrue(
e.getMessage().indexOf(
"Connect string must contain property 'Catalog' or "
+ "property 'CatalogContent'")
>= 0);
}
}
public void testJndiConnection() throws NamingException {
// Cannot guarantee that this test will work if they have chosen to
// resolve data sources other than by JNDI.
if (MondrianProperties.instance().DataSourceResolverClass.isSet()) {
return;
}
// get a regular connection
Util.PropertyList properties =
TestContext.instance().getConnectionProperties().clone();
final StringBuilder buf = new StringBuilder();
final DataSource dataSource =
RolapConnection.createDataSource(null, properties, buf);
// Don't know what the connect string is - it differs with database
// and with the user's set up - but we know that it contains a JDBC
// connect string. Best we can do is check that createDataSource is
// setting it to something.
final String desc = buf.toString();
assertTrue(desc, desc.startsWith("Jdbc="));
final List lookupCalls = new ArrayList();
// mock the JNDI naming manager to provide that datasource
THREAD_INITIAL_CONTEXT.set(
// Use lazy initialization. Otherwise during initialization of this
// initial context JNDI tries to create a default initial context
// and bumps into itself coming the other way.
new InitialContext(true) {
public Object lookup(String str) {
lookupCalls.add("Called");
return dataSource;
}
}
);
// Use the datasource property to connect to the database.
// Remove user and password, because some data sources (those using
// pools) don't allow you to override user.
Util.PropertyList properties2 =
TestContext.instance().getConnectionProperties().clone();
properties2.remove(RolapConnectionProperties.Jdbc.name());
properties2.remove(RolapConnectionProperties.JdbcUser.name());
properties2.remove(RolapConnectionProperties.JdbcPassword.name());
properties2.put(
RolapConnectionProperties.DataSource.name(), "jnditest");
DriverManager.getConnection(properties2, null);
// if we've made it here with lookupCalls,
// we've successfully used JNDI
assertTrue(lookupCalls.size() > 0);
}
public void testDataSourceOverrideUserPass()
throws SQLException, NamingException
{
// use the datasource property to connect to the database
Util.PropertyList properties =
TestContext.instance().getConnectionProperties().clone();
final Dialect dialect = TestContext.instance().getDialect();
if (dialect.getDatabaseProduct() == Dialect.DatabaseProduct.ACCESS) {
// Access doesn't accept user/password, so this test is pointless.
return;
}
final String jdbcUser =
properties.get(RolapConnectionProperties.JdbcUser.name());
final String jdbcPassword =
properties.get(RolapConnectionProperties.JdbcPassword.name());
if (jdbcUser == null || jdbcPassword == null) {
// Can only run this test if username and password are explicit.
return;
}
// Define a data source with bogus user and password.
properties.put(
RolapConnectionProperties.JdbcUser.name(),
"bogususer");
properties.put(
RolapConnectionProperties.JdbcPassword.name(),
"boguspassword");
properties.put(
RolapConnectionProperties.PoolNeeded.name(),
"false");
final StringBuilder buf = new StringBuilder();
final DataSource dataSource =
RolapConnection.createDataSource(null, properties, buf);
final String desc = buf.toString();
assertTrue(desc, desc.startsWith("Jdbc="));
assertTrue(
desc,
desc.indexOf("JdbcUser=bogususer; JdbcPassword=boguspassword")
>= 0);
final String jndiName = "jndiDataSource";
THREAD_INITIAL_CONTEXT.set(
new InitialContext() {
public Object lookup(String str) {
return str.equals(jndiName)
? dataSource
: null;
}
}
);
// Create a property list that we will use for the actual mondrian
// connection. Replace the original JDBC info with the data source we
// just created.
final Util.PropertyList properties2 = new Util.PropertyList();
for (Pair entry : properties) {
properties2.put(entry.getKey(), entry.getValue());
}
properties2.remove(RolapConnectionProperties.Jdbc.name());
properties2.put(
RolapConnectionProperties.DataSource.name(),
jndiName);
// With JdbcUser and JdbcPassword credentials in the mondrian connect
// string, the data source's "user" and "password" properties are
// overridden and the connection succeeds.
properties2.put(
RolapConnectionProperties.JdbcUser.name(),
jdbcUser);
properties2.put(
RolapConnectionProperties.JdbcPassword.name(),
jdbcPassword);
mondrian.olap.Connection connection = null;
try {
connection =
DriverManager.getConnection(properties2, null);
Query query = connection.parseQuery("select from [Sales]");
final Result result = connection.execute(query);
assertNotNull(result);
} finally {
if (connection != null) {
connection.close();
connection = null;
}
}
// If we don't specify JdbcUser and JdbcPassword in the mondrian
// connection properties, mondrian uses the data source's
// bogus credentials, and the connection fails.
properties2.remove(RolapConnectionProperties.JdbcUser.name());
properties2.remove(RolapConnectionProperties.JdbcPassword.name());
for (String poolNeeded : Arrays.asList("false", "true")) {
// Important to test with & without pooling. Connection pools
// typically do not let you change user, so it's important that
// mondrian handles these right.
properties2.put(
RolapConnectionProperties.PoolNeeded.name(), poolNeeded);
try {
connection = DriverManager.getConnection(properties2, null);
fail("Expected exception");
} catch (MondrianException e) {
final String s = TestContext.getStackTrace(e);
assertTrue(
s,
s.indexOf(
"Error while creating SQL connection: "
+ "DataSource=jndiDataSource") >= 0);
switch (dialect.getDatabaseProduct()) {
case DERBY:
assertTrue(
s,
s.indexOf(
"Caused by: java.sql.SQLException: "
+ "Schema 'BOGUSUSER' does not exist") >= 0);
break;
case ORACLE:
assertTrue(
s,
s.indexOf(
"Caused by: java.sql.SQLException: ORA-01017: "
+ "invalid username/password; logon denied") >= 0);
break;
case MYSQL:
assertTrue(
s,
s.indexOf(
"Caused by: java.sql.SQLException: Access denied "
+ "for user 'bogususer'@'localhost' (using "
+ "password: YES)") >= 0);
break;
case POSTGRESQL:
assertTrue(
s,
s.indexOf(
"Caused by: org.postgresql.util.PSQLException: "
+ "FATAL: password authentication failed for "
+ "user \"bogususer\"") >= 0);
break;
}
} finally {
if (connection != null) {
connection.close();
connection = null;
}
}
}
}
}
// End RolapConnectionTest.java
mondrian-3.4.1/testsrc/main/mondrian/rolap/SharedDimensionTest.java 0000644 0001750 0001750 00000041466 11735330606 025357 0 ustar drazzib drazzib /*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2005-2011 Pentaho and others
// All Rights Reserved.
*/
package mondrian.rolap;
import mondrian.test.FoodMartTestCase;
import mondrian.test.TestContext;
/**
* SharedDimensionTest tests shared dimensions.
*
* @author Rushan Chen
*/
public class SharedDimensionTest extends FoodMartTestCase {
public static final String sharedDimension =
"\n"
+ " \n"
+ " \n"
+ "
\n"
+ "
\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "";
// Base Cube A: use product_id as foreign key for Employee diemnsion
// because there exist rows satidfying the join condition
// "employee.employee_id = inventory_fact_1997.product_id"
public static final String cubeA =
"\n"
+ "
\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "";
// Base Cube B: use time_id as foreign key for Employee diemnsion
// because there exist rows satidfying the join condition
// "employee.employee_id = inventory_fact_1997.time_id"
public static final String cubeB =
"\n"
+ "
\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "";
public static final String virtualCube =
"\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "";
public static final String queryCubeA =
"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].[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"
+ "select\n"
+ " [*BASE_MEMBERS_Measures] ON COLUMNS,\n"
+ " NON EMPTY Generate([*NATIVE_CJ_SET], {([Employee].CurrentMember, [Store Type].CurrentMember)}) ON ROWS\n"
+ "from\n"
+ " [Employee Store Analysis A]";
public static final String queryCubeB =
"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].[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"
+ "select\n"
+ " [*BASE_MEMBERS_Measures] ON COLUMNS,\n"
+ " NON EMPTY Generate([*NATIVE_CJ_SET], {([Employee].CurrentMember, [Store Type].CurrentMember)}) ON ROWS\n"
+ "from\n"
+ " [Employee Store Analysis B]";
public static final String queryVirtualCube =
"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].[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"
+ "select\n"
+ " [*BASE_MEMBERS_Measures] ON COLUMNS,\n"
+ " NON EMPTY Generate([*NATIVE_CJ_SET], {([Employee].CurrentMember, [Store Type].CurrentMember)}) ON ROWS\n"
+ "from\n"
+ " [Employee Store Analysis]";
public static final String queryStoreCube =
"with set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([*BASE_MEMBERS_Store Type], [*BASE_MEMBERS_Store])'\n"
+ "set [*BASE_MEMBERS_Measures] as '{[Measures].[Store Sqft]}'\n"
+ "set [*BASE_MEMBERS_Store Type] as '[Store Type].[Store Type].Members'\n"
+ "set [*BASE_MEMBERS_Store] as '[Store].[Store State].Members'\n"
+ "select [*BASE_MEMBERS_Measures] ON COLUMNS,\n"
+ "Non Empty Generate([*NATIVE_CJ_SET], {[Store Type].CurrentMember}) on rows from [Store]";
public static final String queryNECJMemberList =
"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"
+ "on rows from [Employee Store Analysis B]";
public static final 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 final String querySF1711865 =
"select NON EMPTY {[Product].[Product Family].Members} ON COLUMNS from [Sales 2]";
public static final String resultCubeA =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Employee Store Sales]}\n"
+ "{[Measures].[Employee Store Cost]}\n"
+ "Axis #2:\n"
+ "{[Employee].[Middle Management], [Store Type].[Deluxe Supermarket]}\n"
+ "{[Employee].[Middle Management], [Store Type].[Supermarket]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Deluxe Supermarket]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Gourmet Supermarket]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Mid-Size Grocery]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Small Grocery]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Supermarket]}\n"
+ "{[Employee].[Store Management], [Store Type].[Deluxe Supermarket]}\n"
+ "{[Employee].[Store Management], [Store Type].[Gourmet Supermarket]}\n"
+ "{[Employee].[Store Management], [Store Type].[Mid-Size Grocery]}\n"
+ "{[Employee].[Store Management], [Store Type].[Small Grocery]}\n"
+ "{[Employee].[Store Management], [Store Type].[Supermarket]}\n"
+ "Row #0: $200\n"
+ "Row #0: $87\n"
+ "Row #1: $161\n"
+ "Row #1: $68\n"
+ "Row #2: $1,721\n"
+ "Row #2: $739\n"
+ "Row #3: $261\n"
+ "Row #3: $114\n"
+ "Row #4: $257\n"
+ "Row #4: $111\n"
+ "Row #5: $196\n"
+ "Row #5: $101\n"
+ "Row #6: $3,993\n"
+ "Row #6: $1,858\n"
+ "Row #7: $45,014\n"
+ "Row #7: $20,604\n"
+ "Row #8: $7,231\n"
+ "Row #8: $3,211\n"
+ "Row #9: $8,171\n"
+ "Row #9: $3,635\n"
+ "Row #10: $4,471\n"
+ "Row #10: $2,045\n"
+ "Row #11: $77,236\n"
+ "Row #11: $34,842\n";
public static final String resultCubeB =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Employee Store Sales]}\n"
+ "{[Measures].[Employee Store Cost]}\n"
+ "Axis #2:\n"
+ "{[Employee].[Store Management], [Store Type].[Deluxe Supermarket]}\n"
+ "{[Employee].[Store Management], [Store Type].[Gourmet Supermarket]}\n"
+ "{[Employee].[Store Management], [Store Type].[Mid-Size Grocery]}\n"
+ "{[Employee].[Store Management], [Store Type].[Small Grocery]}\n"
+ "{[Employee].[Store Management], [Store Type].[Supermarket]}\n"
+ "Row #0: $61,860\n"
+ "Row #0: $28,093\n"
+ "Row #1: $10,156\n"
+ "Row #1: $4,482\n"
+ "Row #2: $10,212\n"
+ "Row #2: $4,576\n"
+ "Row #3: $5,932\n"
+ "Row #3: $2,714\n"
+ "Row #4: $108,610\n"
+ "Row #4: $49,178\n";
public static final String resultVirtualCube =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Employee Store Sales]}\n"
+ "{[Measures].[Employee Store Cost]}\n"
+ "Axis #2:\n"
+ "{[Employee].[Middle Management], [Store Type].[Deluxe Supermarket]}\n"
+ "{[Employee].[Middle Management], [Store Type].[Supermarket]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Deluxe Supermarket]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Gourmet Supermarket]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Mid-Size Grocery]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Small Grocery]}\n"
+ "{[Employee].[Senior Management], [Store Type].[Supermarket]}\n"
+ "{[Employee].[Store Management], [Store Type].[Deluxe Supermarket]}\n"
+ "{[Employee].[Store Management], [Store Type].[Gourmet Supermarket]}\n"
+ "{[Employee].[Store Management], [Store Type].[Mid-Size Grocery]}\n"
+ "{[Employee].[Store Management], [Store Type].[Small Grocery]}\n"
+ "{[Employee].[Store Management], [Store Type].[Supermarket]}\n"
+ "Row #0: $200\n"
+ "Row #0: \n"
+ "Row #1: $161\n"
+ "Row #1: \n"
+ "Row #2: $1,721\n"
+ "Row #2: \n"
+ "Row #3: $261\n"
+ "Row #3: \n"
+ "Row #4: $257\n"
+ "Row #4: \n"
+ "Row #5: $196\n"
+ "Row #5: \n"
+ "Row #6: $3,993\n"
+ "Row #6: \n"
+ "Row #7: $45,014\n"
+ "Row #7: $28,093\n"
+ "Row #8: $7,231\n"
+ "Row #8: $4,482\n"
+ "Row #9: $8,171\n"
+ "Row #9: $4,576\n"
+ "Row #10: $4,471\n"
+ "Row #10: $2,714\n"
+ "Row #11: $77,236\n"
+ "Row #11: $49,178\n";
// This result is actually incorrect for native evaluation.
// Keep the test case here to test the SQL generation.
public static final String resultStoreCube =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Store Sqft]}\n"
+ "Axis #2:\n"
+ "{[Store Type].[Deluxe Supermarket]}\n"
+ "{[Store Type].[Gourmet Supermarket]}\n"
+ "{[Store Type].[Mid-Size Grocery]}\n"
+ "{[Store Type].[Small Grocery]}\n"
+ "{[Store Type].[Supermarket]}\n"
+ "Row #0: 146,045\n"
+ "Row #1: 47,447\n"
+ "Row #2: 109,343\n"
+ "Row #3: 75,281\n"
+ "Row #4: 193,480\n";
public static final String resultNECJMemberList =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Employee Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store Type].[Deluxe Supermarket], [Employee].[Store Management]}\n"
+ "{[Store Type].[Gourmet Supermarket], [Employee].[Store Management]}\n"
+ "{[Store Type].[Mid-Size Grocery], [Employee].[Store Management]}\n"
+ "{[Store Type].[Small Grocery], [Employee].[Store Management]}\n"
+ "{[Store Type].[Supermarket], [Employee].[Store Management]}\n"
+ "Row #0: $61,860\n"
+ "Row #1: $10,156\n"
+ "Row #2: $10,212\n"
+ "Row #3: $5,932\n"
+ "Row #4: $108,610\n";
public static final String resultNECJMultiLevelMemberList =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Employee Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store Type].[Deluxe Supermarket], [Employee].[Store Management].[Store Manager]}\n"
+ "{[Store Type].[Gourmet Supermarket], [Employee].[Store Management].[Store Manager]}\n"
+ "{[Store Type].[Supermarket], [Employee].[Store Management].[Store Manager]}\n"
+ "Row #0: $1,783\n"
+ "Row #1: $286\n"
+ "Row #2: $1,020\n";
public static final String resultSF1711865 =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Food]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: 7,978\n"
+ "Row #0: 62,445\n"
+ "Row #0: 16,414\n";
public SharedDimensionTest() {
}
public SharedDimensionTest(String name) {
super(name);
}
public void testA() {
// Schema has two cubes sharing a dimension.
// Query from the first cube.
TestContext testContext = getTestContextForSharedDimCubeACubeB();
testContext.assertQueryReturns(queryCubeA, resultCubeA);
}
public void testB() {
// Schema has two cubes sharing a dimension.
// Query from the second cube.
TestContext testContext = getTestContextForSharedDimCubeACubeB();
testContext.assertQueryReturns(queryCubeB, resultCubeB);
}
public void testVirtualCube() {
// Schema has two cubes sharing a dimension, and a virtual cube built
// over these two cubes.
// Query from the virtual cube.
TestContext testContext =
TestContext.instance().create(
sharedDimension,
cubeA + "\n" + cubeB,
virtualCube,
null,
null,
null);
testContext.assertQueryReturns(queryVirtualCube, resultVirtualCube);
}
public void testNECJMemberList() {
// Schema has two cubes sharing a dimension.
// Query from the second cube.
TestContext testContext = getTestContextForSharedDimCubeACubeB();
testContext.assertQueryReturns(
queryNECJMemberList,
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 = getTestContextForSharedDimCubeACubeB();
testContext.assertQueryReturns(
queryNECJMultiLevelMemberList,
resultNECJMultiLevelMemberList);
}
public void testSF1711865() {
// Test for sourceforge.net bug 1711865
// Use the default FoodMart schema
getTestContext().assertQueryReturns(querySF1711865, resultSF1711865);
}
public void testStoreCube() {
// Use the default FoodMart schema
getTestContext().assertQueryReturns(queryStoreCube, resultStoreCube);
}
private TestContext getTestContextForSharedDimCubeACubeB() {
return TestContext.instance().create(
sharedDimension,
cubeA + "\n" + cubeB,
null,
null,
null,
null);
}
}
// End SharedDimensionTest.java
mondrian-3.4.1/testsrc/main/mondrian/rolap/agg/ 0000755 0001750 0001750 00000000000 11735330606 021323 5 ustar drazzib drazzib mondrian-3.4.1/testsrc/main/mondrian/rolap/agg/SegmentLoaderTest.java 0000644 0001750 0001750 00000113104 11735330606 025557 0 ustar drazzib drazzib /*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2004-2005 Julian Hyde
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/
package mondrian.rolap.agg;
import mondrian.olap.*;
import mondrian.rolap.*;
import mondrian.server.*;
import mondrian.server.Statement;
import mondrian.spi.Dialect;
import mondrian.test.SqlPattern;
import mondrian.util.DelegatingInvocationHandler;
import java.lang.reflect.Proxy;
import java.sql.*;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
*
Test for SegmentLoader
*
* @author Thiyagu
* @since 06-Jun-2007
*/
public class SegmentLoaderTest extends BatchTestCase {
private Execution execution;
private Locus locus;
private SegmentCacheManager cacheMgr;
protected void setUp() throws Exception {
super.setUp();
final Statement statement =
((RolapConnection) getConnection()).getInternalStatement();
execution = new Execution(statement, 1000);
locus = new Locus(execution, null, null);
cacheMgr = execution.getMondrianStatement().getMondrianConnection()
.getServer().getAggregationManager().cacheMgr;
Locus.push(locus);
}
@Override
protected void tearDown() throws Exception {
Locus.pop(locus);
super.tearDown();
}
public void testRollup() throws Exception {
propSaver.set(
MondrianProperties.instance().DisableCaching,
true);
propSaver.set(
MondrianProperties.instance().SegmentCache,
MockSegmentCache.class.getName());
final String queryOracle =
"select \"store\".\"store_country\" as \"c0\", \"time_by_day\".\"the_year\" as \"c1\", sum(\"sales_fact_1997\".\"unit_sales\") as \"m0\" from \"store\" \"store\", \"sales_fact_1997\" \"sales_fact_1997\", \"time_by_day\" \"time_by_day\" where \"sales_fact_1997\".\"store_id\" = \"store\".\"store_id\" and \"store\".\"store_country\" = 'USA' and \"sales_fact_1997\".\"time_id\" = \"time_by_day\".\"time_id\" and \"time_by_day\".\"the_year\" = 1997 group by \"store\".\"store_country\", \"time_by_day\".\"the_year\"";
executeQuery(
"select {[Store].[Store Country].Members} on rows, {[Measures].[Unit Sales]} on columns from [Sales]");
getTestContext().flushSchemaCache();
assertQuerySqlOrNot(
getTestContext(),
"select {[Store].[Store Country].[USA]} on rows, {[Measures].[Unit Sales]} on columns from [Sales]",
new SqlPattern[] {
new SqlPattern(
Dialect.DatabaseProduct.ORACLE,
queryOracle,
queryOracle.length())
},
true,
true,
true);
}
public void testLoadWithMockResultsForLoadingSummaryAndDetailedSegments()
throws ExecutionException, InterruptedException
{
GroupingSet groupableSetsInfo = getGroupingSetRollupOnGender();
GroupingSet groupingSetsInfo = getDefaultGroupingSet();
ArrayList groupingSets =
new ArrayList();
groupingSets.add(groupingSetsInfo);
groupingSets.add(groupableSetsInfo);
SegmentLoader loader = new SegmentLoader(cacheMgr) {
SqlStatement createExecuteSql(
int cellRequestCount,
final GroupingSetsList groupingSetsList,
List compoundPredicateList)
{
return new MockSqlStatement(
cellRequestCount,
groupingSetsList,
getData(true));
}
};
final List>> segmentFutures =
new ArrayList>>();
loader.load(0, groupingSets, null, segmentFutures);
SegmentAxis[] axes = groupingSetsInfo.getAxes();
verifyYearAxis(axes[0]);
verifyProductFamilyAxis(axes[1]);
verifyProductDepartmentAxis(axes[2]);
verifyGenderAxis(axes[3]);
verifyUnitSalesDetailed(
getFor(
segmentFutures,
groupingSets.get(0).getSegments().get(0)));
axes = groupingSets.get(0).getAxes();
verifyYearAxis(axes[0]);
verifyProductFamilyAxis(axes[1]);
verifyProductDepartmentAxis(axes[2]);
verifyUnitSalesAggregate(
getFor(
segmentFutures,
groupingSets.get(1).getSegments().get(0)));
}
private ResultSet toResultSet(final List