/*
// 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) 2003-2005 Julian Hyde
// Copyright (C) 2005-2014 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap.fun;
import mondrian.olap.*;
import mondrian.resource.MondrianResource;
import mondrian.test.FoodMartTestCase;
import mondrian.test.TestContext;
import mondrian.udf.*;
import mondrian.util.Bug;
import junit.framework.Assert;
import junit.framework.ComparisonFailure;
import org.apache.log4j.Logger;
import org.eigenbase.xom.StringEscaper;
import java.io.*;
import java.util.*;
/**
* <code>FunctionTest</code> tests the functions defined in
* {@link BuiltinFunTable}.
*
* @author gjohnson
*/
public class FunctionTest extends FoodMartTestCase {
private static final Logger LOGGER = Logger.getLogger(FunctionTest.class);
private static final String months =
"[Time].[1997].[Q1].[1]\n"
+ "[Time].[1997].[Q1].[2]\n"
+ "[Time].[1997].[Q1].[3]\n"
+ "[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]\n"
+ "[Time].[1997].[Q2].[6]\n"
+ "[Time].[1997].[Q3].[7]\n"
+ "[Time].[1997].[Q3].[8]\n"
+ "[Time].[1997].[Q3].[9]\n"
+ "[Time].[1997].[Q4].[10]\n"
+ "[Time].[1997].[Q4].[11]\n"
+ "[Time].[1997].[Q4].[12]";
private static final String quarters =
"[Time].[1997].[Q1]\n"
+ "[Time].[1997].[Q2]\n"
+ "[Time].[1997].[Q3]\n"
+ "[Time].[1997].[Q4]";
private static final String year1997 = "[Time].[1997]";
private static final String hierarchized1997 =
year1997
+ "\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]";
private static final String NullNumericExpr =
" ([Measures].[Unit Sales],"
+ " [Customers].[All Customers].[USA].[CA].[Bellflower], "
+ " [Product].[All Products].[Drink].[Alcoholic Beverages]."
+ "[Beer and Wine].[Beer].[Good].[Good Imported Beer])";
private static final String TimeWeekly =
MondrianProperties.instance().SsasCompatibleNaming.get()
? "[Time].[Weekly]"
: "[Time.Weekly]";
// ~ Constructors ----------------------------------------------------------
/**
* Creates a FunctionTest.
*/
public FunctionTest() {
}
/**
* Creates a FuncionTest with an explicit name.
*
* @param s Test name
*/
public FunctionTest(String s) {
super(s);
}
// ~ Methods ---------------------------------------------------------------
// ~ Test methods ----------------------------------------------------------
/**
* Tests that Integeer.MIN_VALUE(-2147483648) does not cause NPE.
*/
public void testParallelPeriodMinValue() {
executeQuery(
"with "
+ "member [measures].[foo] as "
+ "'([Measures].[unit sales],"
+ "ParallelPeriod([Time].[Quarter], -2147483648))' "
+ "select "
+ "[measures].[foo] on columns, "
+ "[time].[1997].children on rows "
+ "from [sales]");
}
/**
* Tests that Integeer.MIN_VALUE(-2147483648) in Lag is handled correctly.
*/
public void testLagMinValue() {
executeQuery(
"with "
+ "member [measures].[foo] as "
+ "'([Measures].[unit sales], [Time].[1997].[Q1].Lag(-2147483648))' "
+ "select "
+ "[measures].[foo] on columns, "
+ "[time].[1997].children on rows "
+ "from [sales]");
}
/**
* Tests that ParallelPeriod with Aggregate function works
*/
public void testParallelPeriodWithSlicer() {
assertQueryReturns(
"With "
+ "Set [*NATIVE_CJ_SET] as 'NonEmptyCrossJoin([*BASE_MEMBERS_Time],[*BASE_MEMBERS_Product])' "
+ "Set [*BASE_MEMBERS_Measures] as '{[Measures].[*FORMATTED_MEASURE_0], [Measures].[*FORMATTED_MEASURE_1]}' "
+ "Set [*BASE_MEMBERS_Time] as '{[Time].[1997].[Q2].[6]}' "
+ "Set [*NATIVE_MEMBERS_Time] as 'Generate([*NATIVE_CJ_SET], {[Time].[Time].CurrentMember})' "
+ "Set [*BASE_MEMBERS_Product] as '{[Product].[All Products].[Drink],[Product].[All Products].[Food]}' "
+ "Set [*NATIVE_MEMBERS_Product] as 'Generate([*NATIVE_CJ_SET], {[Product].CurrentMember})' "
+ "Member [Measures].[*FORMATTED_MEASURE_0] as '[Measures].[Customer Count]', FORMAT_STRING = '#,##0', SOLVE_ORDER=400 "
+ "Member [Measures].[*FORMATTED_MEASURE_1] as "
+ "'([Measures].[Customer Count], ParallelPeriod([Time].[Quarter], 1, [Time].[Time].currentMember))', FORMAT_STRING = '#,##0', SOLVE_ORDER=-200 "
+ "Member [Product].[*FILTER_MEMBER] as 'Aggregate ([*NATIVE_MEMBERS_Product])', SOLVE_ORDER=-300 "
+ "Select "
+ "[*BASE_MEMBERS_Measures] on columns, Non Empty Generate([*NATIVE_CJ_SET], {([Time].[Time].CurrentMember)}) on rows "
+ "From [Sales] "
+ "Where ([Product].[*FILTER_MEMBER])",
"Axis #0:\n"
+ "{[Product].[*FILTER_MEMBER]}\n"
+ "Axis #1:\n"
+ "{[Measures].[*FORMATTED_MEASURE_0]}\n"
+ "{[Measures].[*FORMATTED_MEASURE_1]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "Row #0: 1,314\n"
+ "Row #0: 1,447\n");
}
public void testParallelperiodOnLevelsString() {
assertQueryReturns(
"with member Measures.[Prev Unit Sales] as 'parallelperiod(Levels(\"[Time].[Month]\"))'\n"
+ "select {[Measures].[Unit Sales], Measures.[Prev Unit Sales]} ON COLUMNS,\n"
+ "[Gender].members ON ROWS\n"
+ "from [Sales]\n"
+ "where [Time].[1997].[Q2].[5]",
"Axis #0:\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Prev Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Gender].[All Gender]}\n"
+ "{[Gender].[F]}\n"
+ "{[Gender].[M]}\n"
+ "Row #0: 21,081\n"
+ "Row #0: 20,179\n"
+ "Row #1: 10,536\n"
+ "Row #1: 9,990\n"
+ "Row #2: 10,545\n"
+ "Row #2: 10,189\n");
}
public void testParallelperiodOnStrToMember() {
assertQueryReturns(
"with member Measures.[Prev Unit Sales] as 'parallelperiod(strToMember(\"[Time].[1997].[Q2]\"))'\n"
+ "select {[Measures].[Unit Sales], Measures.[Prev Unit Sales]} ON COLUMNS,\n"
+ "[Gender].members ON ROWS\n"
+ "from [Sales]\n"
+ "where [Time].[1997].[Q2].[5]",
"Axis #0:\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Prev Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Gender].[All Gender]}\n"
+ "{[Gender].[F]}\n"
+ "{[Gender].[M]}\n"
+ "Row #0: 21,081\n"
+ "Row #0: 20,957\n"
+ "Row #1: 10,536\n"
+ "Row #1: 10,266\n"
+ "Row #2: 10,545\n"
+ "Row #2: 10,691\n");
assertQueryThrows(
"with member Measures.[Prev Unit Sales] as 'parallelperiod(strToMember(\"[Time].[Quarter]\"))'\n"
+ "select {[Measures].[Unit Sales], Measures.[Prev Unit Sales]} ON COLUMNS,\n"
+ "[Gender].members ON ROWS\n"
+ "from [Sales]\n"
+ "where [Time].[1997].[Q2].[5]",
"Cannot find MDX member '[Time].[Quarter]'. Make sure it is indeed a member and not a level or a hierarchy.");
}
public void testNumericLiteral() {
assertExprReturns("2", "2");
if (false) {
// The test is currently broken because the value 2.5 is formatted
// as "2". TODO: better default format string
assertExprReturns("2.5", "2.5");
}
assertExprReturns("-10.0", "-10");
getTestContext().assertExprDependsOn("1.5", "{}");
}
public void testStringLiteral() {
// single-quoted string
if (false) {
// TODO: enhance parser so that you can include a quoted string
// inside a WITH MEMBER clause
assertExprReturns("'foobar'", "foobar");
}
// double-quoted string
assertExprReturns("\"foobar\"", "foobar");
// literals don't depend on any dimensions
getTestContext().assertExprDependsOn("\"foobar\"", "{}");
}
public void testDimensionHierarchy() {
assertExprReturns("[Time].Dimension.Name", "Time");
}
public void testLevelDimension() {
assertExprReturns("[Time].[Year].Dimension.UniqueName", "[Time]");
}
public void testMemberDimension() {
assertExprReturns("[Time].[1997].[Q2].Dimension.UniqueName", "[Time]");
}
public void testDimensionsNumeric() {
getTestContext().assertExprDependsOn("Dimensions(2).Name", "{}");
getTestContext().assertMemberExprDependsOn(
"Dimensions(3).CurrentMember",
TestContext.allHiers());
assertExprReturns("Dimensions(2).Name", "Store Size in SQFT");
// bug 1426134 -- Dimensions(0) throws 'Index '0' out of bounds'
assertExprReturns("Dimensions(0).Name", "Measures");
assertExprThrows("Dimensions(-1).Name", "Index '-1' out of bounds");
assertExprThrows("Dimensions(100).Name", "Index '100' out of bounds");
// Since Dimensions returns a Hierarchy, can apply CurrentMember.
assertAxisReturns(
"Dimensions(3).CurrentMember",
"[Store Type].[All Store Types]");
}
public void testDimensionsString() {
getTestContext().assertExprDependsOn(
"Dimensions(\"foo\").UniqueName",
"{}");
getTestContext().assertMemberExprDependsOn(
"Dimensions(\"foo\").CurrentMember", TestContext.allHiers());
assertExprReturns("Dimensions(\"Store\").UniqueName", "[Store]");
// Since Dimensions returns a Hierarchy, can apply Children.
assertAxisReturns(
"Dimensions(\"Store\").Children",
"[Store].[Canada]\n"
+ "[Store].[Mexico]\n"
+ "[Store].[USA]");
}
public void testDimensionsDepends() {
final String expression =
"Crossjoin("
+ "{Dimensions(\"Measures\").CurrentMember.Hierarchy.CurrentMember}, "
+ "{Dimensions(\"Product\")})";
assertAxisReturns(
expression, "{[Measures].[Unit Sales], [Product].[All Products]}");
getTestContext().assertSetExprDependsOn(
expression, TestContext.allHiers());
}
public void testTime() {
assertExprReturns(
"[Time].[1997].[Q1].[1].Hierarchy.UniqueName", "[Time]");
}
public void testBasic9() {
assertExprReturns(
"[Gender].[All Gender].[F].Hierarchy.UniqueName", "[Gender]");
}
public void testFirstInLevel9() {
assertExprReturns(
"[Education Level].[All Education Levels].[Bachelors Degree].Hierarchy.UniqueName",
"[Education Level]");
}
public void testHierarchyAll() {
assertExprReturns(
"[Gender].[All Gender].Hierarchy.UniqueName", "[Gender]");
}
public void testNullMember() {
// MSAS fails here, but Mondrian doesn't.
assertExprReturns(
"[Gender].[All Gender].Parent.Level.UniqueName",
"[Gender].[(All)]");
// MSAS fails here, but Mondrian doesn't.
assertExprReturns(
"[Gender].[All Gender].Parent.Hierarchy.UniqueName", "[Gender]");
// MSAS fails here, but Mondrian doesn't.
assertExprReturns(
"[Gender].[All Gender].Parent.Dimension.UniqueName", "[Gender]");
// MSAS succeeds too
assertExprReturns(
"[Gender].[All Gender].Parent.Children.Count", "0");
if (isDefaultNullMemberRepresentation()) {
// MSAS returns "" here.
assertExprReturns(
"[Gender].[All Gender].Parent.UniqueName", "[Gender].[#null]");
// MSAS returns "" here.
assertExprReturns(
"[Gender].[All Gender].Parent.Name", "#null");
}
}
/**
* Tests use of NULL literal to generate a null cell value.
* Testcase is from bug 1440344.
*/
public void testNullValue() {
assertQueryReturns(
"with member [Measures].[X] as 'IIF([Measures].[Store Sales]>10000,[Measures].[Store Sales],Null)'\n"
+ "select\n"
+ "{[Measures].[X]} on columns,\n"
+ "{[Product].[Product Department].members} on rows\n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[X]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Product].[Drink].[Beverages]}\n"
+ "{[Product].[Drink].[Dairy]}\n"
+ "{[Product].[Food].[Baked Goods]}\n"
+ "{[Product].[Food].[Baking Goods]}\n"
+ "{[Product].[Food].[Breakfast Foods]}\n"
+ "{[Product].[Food].[Canned Foods]}\n"
+ "{[Product].[Food].[Canned Products]}\n"
+ "{[Product].[Food].[Dairy]}\n"
+ "{[Product].[Food].[Deli]}\n"
+ "{[Product].[Food].[Eggs]}\n"
+ "{[Product].[Food].[Frozen Foods]}\n"
+ "{[Product].[Food].[Meat]}\n"
+ "{[Product].[Food].[Produce]}\n"
+ "{[Product].[Food].[Seafood]}\n"
+ "{[Product].[Food].[Snack Foods]}\n"
+ "{[Product].[Food].[Snacks]}\n"
+ "{[Product].[Food].[Starchy Foods]}\n"
+ "{[Product].[Non-Consumable].[Carousel]}\n"
+ "{[Product].[Non-Consumable].[Checkout]}\n"
+ "{[Product].[Non-Consumable].[Health and Hygiene]}\n"
+ "{[Product].[Non-Consumable].[Household]}\n"
+ "{[Product].[Non-Consumable].[Periodicals]}\n"
+ "Row #0: 14,029.08\n"
+ "Row #1: 27,748.53\n"
+ "Row #2: \n"
+ "Row #3: 16,455.43\n"
+ "Row #4: 38,670.41\n"
+ "Row #5: \n"
+ "Row #6: 39,774.34\n"
+ "Row #7: \n"
+ "Row #8: 30,508.85\n"
+ "Row #9: 25,318.93\n"
+ "Row #10: \n"
+ "Row #11: 55,207.50\n"
+ "Row #12: \n"
+ "Row #13: 82,248.42\n"
+ "Row #14: \n"
+ "Row #15: 67,609.82\n"
+ "Row #16: 14,550.05\n"
+ "Row #17: 11,756.07\n"
+ "Row #18: \n"
+ "Row #19: \n"
+ "Row #20: 32,571.86\n"
+ "Row #21: 60,469.89\n"
+ "Row #22: \n");
}
public void testNullInMultiplication() {
assertExprReturns("NULL*1", "");
assertExprReturns("1*NULL", "");
assertExprReturns("NULL*NULL", "");
}
public void testNullInAddition() {
assertExprReturns("1+NULL", "1");
assertExprReturns("NULL+1", "1");
}
public void testNullInSubtraction() {
assertExprReturns("1-NULL", "1");
assertExprReturns("NULL-1", "-1");
}
public void testMemberLevel() {
assertExprReturns(
"[Time].[1997].[Q1].[1].Level.UniqueName",
"[Time].[Month]");
}
public void testLevelsNumeric() {
assertExprReturns("[Time].[Time].Levels(2).Name", "Month");
assertExprReturns("[Time].[Time].Levels(0).Name", "Year");
assertExprReturns("[Product].Levels(0).Name", "(All)");
}
public void testLevelsTooSmall() {
assertExprThrows(
"[Time].[Time].Levels(-1).Name", "Index '-1' out of bounds");
}
public void testLevelsTooLarge() {
assertExprThrows(
"[Time].[Time].Levels(8).Name", "Index '8' out of bounds");
}
public void testHierarchyLevelsString() {
assertExprReturns(
"[Time].[Time].Levels(\"Year\").UniqueName", "[Time].[Year]");
}
public void testHierarchyLevelsStringFail() {
assertExprThrows(
"[Time].[Time].Levels(\"nonexistent\").UniqueName",
"Level 'nonexistent' not found in hierarchy '[Time]'");
}
public void testLevelsString() {
assertExprReturns(
"Levels(\"[Time].[Year]\").UniqueName",
"[Time].[Year]");
}
public void testLevelsStringFail() {
assertExprThrows(
"Levels(\"nonexistent\").UniqueName",
"Level 'nonexistent' not found");
}
public void testIsEmptyQuery() {
String desiredResult =
"Axis #0:\n"
+ "{[Time].[1997].[Q4].[12], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth].[Portsmouth Imported Beer], [Measures].[Foo]}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "{[Store].[USA].[WA].[Bremerton]}\n"
+ "{[Store].[USA].[WA].[Seattle]}\n"
+ "{[Store].[USA].[WA].[Spokane]}\n"
+ "{[Store].[USA].[WA].[Tacoma]}\n"
+ "{[Store].[USA].[WA].[Walla Walla]}\n"
+ "{[Store].[USA].[WA].[Yakima]}\n"
+ "Row #0: 5\n"
+ "Row #0: 5\n"
+ "Row #0: 2\n"
+ "Row #0: 5\n"
+ "Row #0: 11\n"
+ "Row #0: 5\n"
+ "Row #0: 4\n";
assertQueryReturns(
"WITH MEMBER [Measures].[Foo] AS 'Iif(IsEmpty([Measures].[Unit Sales]), 5, [Measures].[Unit Sales])'\n"
+ "SELECT {[Store].[USA].[WA].children} on columns\n"
+ "FROM Sales\n"
+ "WHERE ([Time].[1997].[Q4].[12],\n"
+ " [Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth].[Portsmouth Imported Beer],\n"
+ " [Measures].[Foo])",
desiredResult);
assertQueryReturns(
"WITH MEMBER [Measures].[Foo] AS 'Iif([Measures].[Unit Sales] IS EMPTY, 5, [Measures].[Unit Sales])'\n"
+ "SELECT {[Store].[USA].[WA].children} on columns\n"
+ "FROM Sales\n"
+ "WHERE ([Time].[1997].[Q4].[12],\n"
+ " [Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth].[Portsmouth Imported Beer],\n"
+ " [Measures].[Foo])",
desiredResult);
assertQueryReturns(
"WITH MEMBER [Measures].[Foo] AS 'Iif([Measures].[Bar] IS EMPTY, 1, [Measures].[Bar])'\n"
+ "MEMBER [Measures].[Bar] AS 'CAST(\"42\" AS INTEGER)'\n"
+ "SELECT {[Measures].[Unit Sales], [Measures].[Foo]} on columns\n"
+ "FROM Sales\n"
+ "WHERE ([Time].[1998].[Q4].[12])",
"Axis #0:\n"
+ "{[Time].[1998].[Q4].[12]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: \n"
+ "Row #0: 42\n");
}
public void testIsEmptyWithAggregate() {
assertQueryReturns(
"WITH MEMBER [gender].[foo] AS 'isEmpty(Aggregate({[Gender].m}))' "
+ "SELECT {Gender.foo} on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Gender].[foo]}\n"
+ "Row #0: false\n");
}
public void testIsEmpty()
{
assertBooleanExprReturns("[Gender].[All Gender].Parent IS NULL", true);
// Any functions that return a member from parameters that
// include a member and that member is NULL also give a NULL.
// Not a runtime exception.
assertBooleanExprReturns(
"[Gender].CurrentMember.Parent.NextMember IS NULL",
true);
if (!Bug.BugMondrian207Fixed) {
return;
}
// When resolving a tuple's value in the cube, if there is
// at least one NULL member in the tuple should return a
// NULL cell value.
assertBooleanExprReturns(
"IsEmpty(([Time].currentMember.Parent, [Measures].[Unit Sales]))",
false);
assertBooleanExprReturns(
"IsEmpty(([Time].currentMember, [Measures].[Unit Sales]))",
false);
// EMPTY refers to a genuine cell value that exists in the cube space,
// and has no NULL members in the tuple,
// but has no fact data at that crossing,
// so it evaluates to EMPTY as a cell value.
assertBooleanExprReturns(
"IsEmpty(\n"
+ " ([Time].[1997].[Q4].[12],\n"
+ " [Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth].[Portsmouth Imported Beer],\n"
+ " [Store].[All Stores].[USA].[WA].[Bellingham]))", true);
assertBooleanExprReturns(
"IsEmpty(\n"
+ " ([Time].[1997].[Q4].[11],\n"
+ " [Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth].[Portsmouth Imported Beer],\n"
+ " [Store].[All Stores].[USA].[WA].[Bellingham]))", false);
// The empty set is neither EMPTY nor NULL.
// should give 0 as a result, not NULL and not EMPTY.
assertQueryReturns(
"WITH SET [empty set] AS '{}'\n"
+ " MEMBER [Measures].[Set Size] AS 'Count([empty set])'\n"
+ " MEMBER [Measures].[Set Size Is Empty] AS 'CASE WHEN IsEmpty([Measures].[Set Size]) THEN 1 ELSE 0 END '\n"
+ "SELECT [Measures].[Set Size] on columns", "");
assertQueryReturns(
"WITH SET [empty set] AS '{}'\n"
+ "WITH MEMBER [Measures].[Set Size] AS 'Count([empty set])'\n"
+ "SELECT [Measures].[Set Size] on columns", "");
// Run time errors are BAD things. They should not occur
// in almost all cases. In fact there should be no
// logically formed MDX that generates them. An ERROR
// value in a cell though is perfectly legal - e.g. a
// divide by 0.
// E.g.
String foo =
"WITH [Measures].[Ratio This Period to Previous] as\n"
+ "'([Measures].[Sales],[Time].CurrentMember/([Measures].[Sales],[Time].CurrentMember.PrevMember)'\n"
+ "SELECT [Measures].[Ratio This Period to Previous] ON COLUMNS,\n"
+ "[Time].Members ON ROWS\n"
+ "FROM ...";
// For the [Time].[All Time] row as well as the first
// year, first month etc, the PrevMember will evaluate to
// NULL, the tuple will evaluate to NULL and the division
// will implicitly convert the NULL to 0 and then evaluate
// to an ERROR value due to a divide by 0.
// This leads to another point: NULL and EMPTY values get
// implicitly converted to 0 when treated as numeric
// values for division and multiplication but for addition
// and subtraction, NULL is treated as NULL (5+NULL yields
// NULL).
// I have no idea about how EMPTY works. I.e. is does
// 5+EMPTY yield 5 or EMPTY or NULL or what?
// E.g.
String foo2 =
"WITH MEMBER [Measures].[5 plus empty] AS\n"
+ "'5+([Product].[All Products].[Ski boots],[Geography].[All Geography].[Hawaii])'\n"
+ "SELECT [Measures].[5 plus empty] ON COLUMNS\n"
+ "FROM ...";
// Does this yield EMPTY, 5, NULL or ERROR?
// Lastly, IS NULL and IS EMPTY are both legal and
// distinct. <<Object>> IS {<<Object>> | NULL} and
// <<Value>> IS EMPTY.
// E.g.
// a) [Time].CurrentMember.Parent IS [Time].[Year].[2004]
// is also a perfectly legal expression and better than
// [Time].CurrentMember.Parent.Name="2004".
// b) ([Measures].[Sales],[Time].FirstSibling) IS EMPTY is
// a legal expression.
// Microsoft's site says that the EMPTY value participates in 3 value
// logic e.g. TRUE AND EMPTY gives EMPTY, FALSE AND EMPTY gives FALSE.
// todo: test for this
}
public void testQueryWithoutValidMeasure() {
assertQueryReturns(
"with\n"
+ "member measures.[without VM] as ' [measures].[unit sales] '\n"
+ "select {measures.[without VM] } on 0,\n"
+ "[Warehouse].[Country].members on 1 from [warehouse and sales]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[without VM]}\n"
+ "Axis #2:\n"
+ "{[Warehouse].[Canada]}\n"
+ "{[Warehouse].[Mexico]}\n"
+ "{[Warehouse].[USA]}\n"
+ "Row #0: \n"
+ "Row #1: \n"
+ "Row #2: \n");
}
/** Tests the <code>ValidMeasure</code> function. */
public void testValidMeasure() {
assertQueryReturns(
"with\n"
+ "member measures.[with VM] as 'validmeasure([measures].[unit sales])'\n"
+ "select { measures.[with VM]} on 0,\n"
+ "[Warehouse].[Country].members on 1 from [warehouse and sales]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[with VM]}\n"
+ "Axis #2:\n"
+ "{[Warehouse].[Canada]}\n"
+ "{[Warehouse].[Mexico]}\n"
+ "{[Warehouse].[USA]}\n"
+ "Row #0: 266,773\n"
+ "Row #1: 266,773\n"
+ "Row #2: 266,773\n");
}
public void _testValidMeasureNonEmpty() {
// Note that [with VM2] is NULL where it needs to be - and therefore
// does not prevent NON EMPTY from eliminating empty rows.
assertQueryReturns(
"with set [Foo] as ' Crossjoin({[Time].Children}, {[Measures].[Warehouse Sales]}) '\n"
+ " member [Measures].[with VM] as 'ValidMeasure([Measures].[Unit Sales])'\n"
+ " member [Measures].[with VM2] as 'Iif(Count(Filter([Foo], not isempty([Measures].CurrentMember))) > 0, ValidMeasure([Measures].[Unit Sales]), NULL)'\n"
+ "select NON EMPTY Crossjoin({[Time].Children}, {[Measures].[with VM2], [Measures].[Warehouse Sales]}) ON COLUMNS,\n"
+ " NON EMPTY {[Warehouse].[All Warehouses].[USA].[WA].Children} ON ROWS\n"
+ "from [Warehouse and Sales]\n"
+ "where [Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]",
"Axis #0:\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "Axis #1:\n"
+ "{[Time].[1997].[Q1], [Measures].[with VM2]}\n"
+ "{[Time].[1997].[Q1], [Measures].[Warehouse Sales]}\n"
+ "{[Time].[1997].[Q2], [Measures].[with VM2]}\n"
+ "{[Time].[1997].[Q2], [Measures].[Warehouse Sales]}\n"
+ "{[Time].[1997].[Q3], [Measures].[with VM2]}\n"
+ "{[Time].[1997].[Q4], [Measures].[with VM2]}\n"
+ "Axis #2:\n"
+ "{[Warehouse].[USA].[WA].[Seattle]}\n"
+ "{[Warehouse].[USA].[WA].[Tacoma]}\n"
+ "{[Warehouse].[USA].[WA].[Yakima]}\n"
+ "Row #0: 26\n"
+ "Row #0: 34.793\n"
+ "Row #0: 25\n"
+ "Row #0: \n"
+ "Row #0: 36\n"
+ "Row #0: 28\n"
+ "Row #1: 26\n"
+ "Row #1: \n"
+ "Row #1: 25\n"
+ "Row #1: 64.615\n"
+ "Row #1: 36\n"
+ "Row #1: 28\n"
+ "Row #2: 26\n"
+ "Row #2: 79.657\n"
+ "Row #2: 25\n"
+ "Row #2: \n"
+ "Row #2: 36\n"
+ "Row #2: 28\n");
}
public void testValidMeasureTupleHasAnotherMember() {
assertQueryReturns(
"with\n"
+ "member measures.[with VM] as 'validmeasure(([measures].[unit sales],[customers].[all customers]))'\n"
+ "select { measures.[with VM]} on 0,\n"
+ "[Warehouse].[Country].members on 1 from [warehouse and sales]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[with VM]}\n"
+ "Axis #2:\n"
+ "{[Warehouse].[Canada]}\n"
+ "{[Warehouse].[Mexico]}\n"
+ "{[Warehouse].[USA]}\n"
+ "Row #0: 266,773\n"
+ "Row #1: 266,773\n"
+ "Row #2: 266,773\n");
}
public void testValidMeasureDepends() {
String s12 = TestContext.allHiersExcept("[Measures]");
getTestContext().assertExprDependsOn(
"ValidMeasure([Measures].[Unit Sales])", s12);
String s11 = TestContext.allHiersExcept("[Measures]", "[Time]");
getTestContext().assertExprDependsOn(
"ValidMeasure(([Measures].[Unit Sales], [Time].[1997].[Q1]))", s11);
String s1 = TestContext.allHiersExcept("[Measures]");
getTestContext().assertExprDependsOn(
"ValidMeasure(([Measures].[Unit Sales], "
+ "[Time].[Time].CurrentMember.Parent))",
s1);
}
public void testValidMeasureNonVirtualCube() {
// verify ValidMeasure used outside of a virtual cube
// is effectively a no-op.
assertQueryReturns(
"with member measures.vm as 'ValidMeasure(measures.[Store Sales])'"
+ " select measures.[vm] on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[vm]}\n"
+ "Row #0: 565,238.13\n");
assertQueryReturns(
"with member measures.vm as 'ValidMeasure((gender.f, measures.[Store Sales]))'"
+ " select measures.[vm] on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[vm]}\n"
+ "Row #0: 280,226.21\n");
}
/**
* This is a test for
* <a href="http://jira.pentaho.com/browse/MONDRIAN-2109">MONDRIAN-2109</a>
*
* <p>We can't allow calculated members in ValidMeasure so a proper message
* must be returned.
*/
public void testValidMeasureCalculatedMemberMeasure() {
// Check for failure.
assertQueryThrows(
"with member measures.calc as 'measures.[Warehouse sales]' \n"
+ "member measures.vm as 'ValidMeasure(measures.calc)' \n"
+ "select from [warehouse and sales]\n"
+ "where (measures.vm ,gender.f) \n",
"The function ValidMeasure cannot be used with the measure '[Measures].[calc]' because it is a calculated member.");
// Check the working version
assertQueryReturns(
"with \n"
+ "member measures.vm as 'ValidMeasure(measures.[warehouse sales])' \n"
+ "select from [warehouse and sales] where (measures.vm, gender.f) \n",
"Axis #0:\n"
+ "{[Measures].[vm], [Gender].[F]}\n"
+ "196,770.888");
}
public void testAncestor() {
Member member =
executeSingletonAxis(
"Ancestor([Store].[USA].[CA].[Los Angeles],[Store Country])");
Assert.assertEquals("USA", member.getName());
assertAxisThrows(
"Ancestor([Store].[USA].[CA].[Los Angeles],[Promotions].[Promotion Name])",
"Error while executing query");
}
public void testAncestorNumeric() {
Member member =
executeSingletonAxis(
"Ancestor([Store].[USA].[CA].[Los Angeles],1)");
Assert.assertEquals("CA", member.getName());
member =
executeSingletonAxis(
"Ancestor([Store].[USA].[CA].[Los Angeles], 0)");
Assert.assertEquals("Los Angeles", member.getName());
final TestContext testContextRagged =
getTestContext().withCube("[Sales Ragged]");
member =
testContextRagged.executeSingletonAxis(
"Ancestor([Store].[All Stores].[Vatican], 1)");
Assert.assertEquals("All Stores", member.getName());
member =
testContextRagged.executeSingletonAxis(
"Ancestor([Store].[USA].[Washington], 1)");
Assert.assertEquals("USA", member.getName());
// complicated way to say "1".
member =
testContextRagged.executeSingletonAxis(
"Ancestor([Store].[USA].[Washington], 7 * 6 - 41)");
Assert.assertEquals("USA", member.getName());
member =
testContextRagged.executeSingletonAxis(
"Ancestor([Store].[All Stores].[Vatican], 2)");
Assert.assertNull("Ancestor at 2 must be null", member);
member =
testContextRagged.executeSingletonAxis(
"Ancestor([Store].[All Stores].[Vatican], -5)");
Assert.assertNull("Ancestor at -5 must be null", member);
}
public void testAncestorHigher() {
Member member =
executeSingletonAxis(
"Ancestor([Store].[USA],[Store].[Store City])");
Assert.assertNull(member); // MSOLAP returns null
}
public void testAncestorSameLevel() {
Member member =
executeSingletonAxis(
"Ancestor([Store].[Canada],[Store].[Store Country])");
Assert.assertEquals("Canada", member.getName());
}
public void testAncestorWrongHierarchy() {
// MSOLAP gives error "Formula error - dimensions are not
// valid (they do not match) - in the Ancestor function"
assertAxisThrows(
"Ancestor([Gender].[M],[Store].[Store Country])",
"Error while executing query");
}
public void testAncestorAllLevel() {
Member member =
executeSingletonAxis(
"Ancestor([Store].[USA].[CA],[Store].Levels(0))");
Assert.assertTrue(member.isAll());
}
public void testAncestorWithHiddenParent() {
final TestContext testContext =
getTestContext().withCube("[Sales Ragged]");
Member member =
testContext.executeSingletonAxis(
"Ancestor([Store].[All Stores].[Israel].[Haifa], "
+ "[Store].[Store Country])");
assertNotNull("Member must not be null.", member);
Assert.assertEquals("Israel", member.getName());
}
public void testAncestorDepends() {
getTestContext().assertExprDependsOn(
"Ancestor([Store].CurrentMember, [Store].[Store Country]).Name",
"{[Store]}");
getTestContext().assertExprDependsOn(
"Ancestor([Store].[All Stores].[USA], "
+ "[Store].CurrentMember.Level).Name",
"{[Store]}");
getTestContext().assertExprDependsOn(
"Ancestor([Store].[All Stores].[USA], "
+ "[Store].[Store Country]).Name",
"{}");
getTestContext().assertExprDependsOn(
"Ancestor([Store].CurrentMember, 2+1).Name", "{[Store]}");
}
public void testAncestors() {
// Test that we can execute Ancestors by passing a level as
// the depth argument (PC hierarchy)
assertQueryReturns(
"with\n"
+ "set [*ancestors] as\n"
+ " 'Ancestors([Employees].[All Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long].[Adam Reynolds].[Joshua Huff].[Teanna Cobb], [Employees].[All Employees].Level)'\n"
+ "select\n"
+ " [*ancestors] on columns\n"
+ "from [HR]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long].[Adam Reynolds].[Joshua Huff]}\n"
+ "{[Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long].[Adam Reynolds]}\n"
+ "{[Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long]}\n"
+ "{[Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges]}\n"
+ "{[Employees].[Sheri Nowmer].[Derrick Whelply]}\n"
+ "{[Employees].[Sheri Nowmer]}\n"
+ "{[Employees].[All Employees]}\n"
+ "Row #0: $984.45\n"
+ "Row #0: $3,426.54\n"
+ "Row #0: $3,610.14\n"
+ "Row #0: $17,099.20\n"
+ "Row #0: $36,494.07\n"
+ "Row #0: $39,431.67\n"
+ "Row #0: $39,431.67\n");
// Test that we can execute Ancestors by passing a level as
// the depth argument (non PC hierarchy)
assertQueryReturns(
"with\n"
+ "set [*ancestors] as\n"
+ " 'Ancestors([Store].[USA].[CA].[Los Angeles], [Store].[Store Country])'\n"
+ "select\n"
+ " [*ancestors] on columns\n"
+ "from [Sales]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 74,748\n"
+ "Row #0: 266,773\n");
// Test that we can execute Ancestors by passing an integer as
// the depth argument (PC hierarchy)
assertQueryReturns(
"with\n"
+ "set [*ancestors] as\n"
+ " 'Ancestors([Employees].[All Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long].[Adam Reynolds].[Joshua Huff].[Teanna Cobb], 3)'\n"
+ "select\n"
+ " [*ancestors] on columns\n"
+ "from [HR]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long].[Adam Reynolds].[Joshua Huff]}\n"
+ "{[Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long].[Adam Reynolds]}\n"
+ "{[Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long]}\n"
+ "Row #0: $984.45\n"
+ "Row #0: $3,426.54\n"
+ "Row #0: $3,610.14\n");
// Test that we can execute Ancestors by passing an integer as
// the depth argument (non PC hierarchy)
assertQueryReturns(
"with\n"
+ "set [*ancestors] as\n"
+ " 'Ancestors([Store].[USA].[CA].[Los Angeles], 2)'\n"
+ "select\n"
+ " [*ancestors] on columns\n"
+ "from [Sales]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 74,748\n"
+ "Row #0: 266,773\n");
// Test that we can count the number of ancestors.
assertQueryReturns(
"with\n"
+ "set [*ancestors] as\n"
+ " 'Ancestors([Employees].[All Employees].[Sheri Nowmer].[Derrick Whelply].[Laurie Borges].[Eric Long].[Adam Reynolds].[Joshua Huff].[Teanna Cobb], [Employees].[All Employees].Level)'\n"
+ "member [Measures].[Depth] as\n"
+ " 'Count([*ancestors])'\n"
+ "select\n"
+ " [Measures].[Depth] on columns\n"
+ "from [HR]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Depth]}\n"
+ "Row #0: 7\n");
// test depth argument not a level
assertAxisThrows(
"Ancestors([Store].[USA].[CA].[Los Angeles],[Store])",
"Error while executing query");
}
public void testOrdinal() {
final TestContext testContext =
getTestContext().withCube("Sales Ragged");
Cell cell =
testContext.executeExprRaw(
"[Store].[All Stores].[Vatican].ordinal");
assertEquals(
"Vatican is at level 1.",
1,
((Number)cell.getValue()).intValue());
cell = testContext.executeExprRaw(
"[Store].[All Stores].[USA].[Washington].ordinal");
assertEquals(
"Washington is at level 3.",
3,
((Number) cell.getValue()).intValue());
}
public void testClosingPeriodNoArgs() {
getTestContext().assertMemberExprDependsOn(
"ClosingPeriod()", "{[Time]}");
// MSOLAP returns [1997].[Q4], because [Time].CurrentMember =
// [1997].
Member member = executeSingletonAxis("ClosingPeriod()");
Assert.assertEquals("[Time].[1997].[Q4]", member.getUniqueName());
}
public void testClosingPeriodLevel() {
getTestContext().assertMemberExprDependsOn(
"ClosingPeriod([Time].[Year])", "{[Time]}");
getTestContext().assertMemberExprDependsOn(
"([Measures].[Unit Sales], ClosingPeriod([Time].[Month]))",
"{[Time]}");
Member member;
member = executeSingletonAxis("ClosingPeriod([Year])");
Assert.assertEquals("[Time].[1997]", member.getUniqueName());
member = executeSingletonAxis("ClosingPeriod([Quarter])");
Assert.assertEquals("[Time].[1997].[Q4]", member.getUniqueName());
member = executeSingletonAxis("ClosingPeriod([Month])");
Assert.assertEquals("[Time].[1997].[Q4].[12]", member.getUniqueName());
assertQueryReturns(
"with member [Measures].[Closing Unit Sales] as "
+ "'([Measures].[Unit Sales], ClosingPeriod([Time].[Month]))'\n"
+ "select non empty {[Measures].[Closing Unit Sales]} on columns,\n"
+ " {Descendants([Time].[1997])} on rows\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Closing Unit Sales]}\n"
+ "Axis #2:\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"
+ "Row #0: 26,796\n"
+ "Row #1: 23,706\n"
+ "Row #2: 21,628\n"
+ "Row #3: 20,957\n"
+ "Row #4: 23,706\n"
+ "Row #5: 21,350\n"
+ "Row #6: 20,179\n"
+ "Row #7: 21,081\n"
+ "Row #8: 21,350\n"
+ "Row #9: 20,388\n"
+ "Row #10: 23,763\n"
+ "Row #11: 21,697\n"
+ "Row #12: 20,388\n"
+ "Row #13: 26,796\n"
+ "Row #14: 19,958\n"
+ "Row #15: 25,270\n"
+ "Row #16: 26,796\n");
assertQueryReturns(
"with member [Measures].[Closing Unit Sales] as '([Measures].[Unit Sales], ClosingPeriod([Time].[Month]))'\n"
+ "select {[Measures].[Unit Sales], [Measures].[Closing Unit Sales]} on columns,\n"
+ " {[Time].[1997], [Time].[1997].[Q1], [Time].[1997].[Q1].[1], [Time].[1997].[Q1].[3], [Time].[1997].[Q4].[12]} on rows\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Closing Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997]}\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q1].[3]}\n"
+ "{[Time].[1997].[Q4].[12]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 26,796\n"
+ "Row #1: 66,291\n"
+ "Row #1: 23,706\n"
+ "Row #2: 21,628\n"
+ "Row #2: 21,628\n"
+ "Row #3: 23,706\n"
+ "Row #3: 23,706\n"
+ "Row #4: 26,796\n"
+ "Row #4: 26,796\n");
}
public void testClosingPeriodLevelNotInTimeFails() {
assertAxisThrows(
"ClosingPeriod([Store].[Store City])",
"The <level> and <member> arguments to ClosingPeriod must be from "
+ "the same hierarchy. The level was from '[Store]' but the member "
+ "was from '[Time]'");
}
public void testClosingPeriodMember() {
if (false) {
// This test is mistaken. Valid forms are ClosingPeriod(<level>)
// and ClosingPeriod(<level>, <member>), but not
// ClosingPeriod(<member>)
Member member = executeSingletonAxis("ClosingPeriod([USA])");
Assert.assertEquals("WA", member.getName());
}
}
public void testClosingPeriodMemberLeaf() {
Member member;
if (false) {
// This test is mistaken. Valid forms are ClosingPeriod(<level>)
// and ClosingPeriod(<level>, <member>), but not
// ClosingPeriod(<member>)
member = executeSingletonAxis(
"ClosingPeriod([Time].[1997].[Q3].[8])");
Assert.assertNull(member);
} else if (isDefaultNullMemberRepresentation()) {
assertQueryReturns(
"with member [Measures].[Foo] as ClosingPeriod().uniquename\n"
+ "select {[Measures].[Foo]} on columns,\n"
+ " {[Time].[1997],\n"
+ " [Time].[1997].[Q2],\n"
+ " [Time].[1997].[Q2].[4]} on rows\n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "Row #0: [Time].[1997].[Q4]\n"
+ "Row #1: [Time].[1997].[Q2].[6]\n"
+ "Row #2: [Time].[#null]\n"
// MSAS returns "" here.
+ "");
}
}
public void testClosingPeriod() {
getTestContext().assertMemberExprDependsOn(
"ClosingPeriod([Time].[Month], [Time].[Time].CurrentMember)",
"{[Time]}");
String s1 = TestContext.allHiersExcept("[Measures]");
getTestContext().assertExprDependsOn(
"(([Measures].[Store Sales],"
+ " ClosingPeriod([Time].[Month], [Time].[Time].CurrentMember)) - "
+ "([Measures].[Store Cost],"
+ " ClosingPeriod([Time].[Month], [Time].[Time].CurrentMember)))",
s1);
getTestContext().assertMemberExprDependsOn(
"ClosingPeriod([Time].[Month], [Time].[1997].[Q3])", "{}");
assertAxisReturns(
"ClosingPeriod([Time].[Year], [Time].[1997].[Q3])", "");
assertAxisReturns(
"ClosingPeriod([Time].[Quarter], [Time].[1997].[Q3])",
"[Time].[1997].[Q3]");
assertAxisReturns(
"ClosingPeriod([Time].[Month], [Time].[1997].[Q3])",
"[Time].[1997].[Q3].[9]");
assertAxisReturns(
"ClosingPeriod([Time].[Quarter], [Time].[1997])",
"[Time].[1997].[Q4]");
assertAxisReturns(
"ClosingPeriod([Time].[Year], [Time].[1997])", "[Time].[1997]");
assertAxisReturns(
"ClosingPeriod([Time].[Month], [Time].[1997])",
"[Time].[1997].[Q4].[12]");
// leaf member
assertAxisReturns(
"ClosingPeriod([Time].[Year], [Time].[1997].[Q3].[8])", "");
assertAxisReturns(
"ClosingPeriod([Time].[Quarter], [Time].[1997].[Q3].[8])", "");
assertAxisReturns(
"ClosingPeriod([Time].[Month], [Time].[1997].[Q3].[8])",
"[Time].[1997].[Q3].[8]");
// non-Time dimension
assertAxisReturns(
"ClosingPeriod([Product].[Product Name], [Product].[All Products].[Drink])",
"[Product].[Drink].[Dairy].[Dairy].[Milk].[Gorilla].[Gorilla Whole Milk]");
assertAxisReturns(
"ClosingPeriod([Product].[Product Family], [Product].[All Products].[Drink])",
"[Product].[Drink]");
// 'all' level
assertAxisReturns(
"ClosingPeriod([Product].[(All)], [Product].[All Products].[Drink])",
"");
// ragged
getTestContext().withCube("[Sales Ragged]").assertAxisReturns(
"ClosingPeriod([Store].[Store City], [Store].[All Stores].[Israel])",
"[Store].[Israel].[Israel].[Tel Aviv]");
// Default member is [Time].[1997].
assertAxisReturns(
"ClosingPeriod([Time].[Month])", "[Time].[1997].[Q4].[12]");
assertAxisReturns("ClosingPeriod()", "[Time].[1997].[Q4]");
TestContext testContext = getTestContext().withCube("[Sales Ragged]");
testContext.assertAxisReturns(
"ClosingPeriod([Store].[Store State], [Store].[All Stores].[Israel])",
"");
testContext.assertAxisThrows(
"ClosingPeriod([Time].[Year], [Store].[All Stores].[Israel])",
"The <level> and <member> arguments to ClosingPeriod must be "
+ "from the same hierarchy. The level was from '[Time]' but "
+ "the member was from '[Store]'.");
}
public void testClosingPeriodBelow() {
Member member = executeSingletonAxis(
"ClosingPeriod([Quarter],[1997].[Q3].[8])");
Assert.assertNull(member);
}
public void testCousin1() {
Member member = executeSingletonAxis("Cousin([1997].[Q4],[1998])");
Assert.assertEquals("[Time].[1998].[Q4]", member.getUniqueName());
}
public void testCousin2() {
Member member = executeSingletonAxis(
"Cousin([1997].[Q4].[12],[1998].[Q1])");
Assert.assertEquals("[Time].[1998].[Q1].[3]", member.getUniqueName());
}
public void testCousinOverrun() {
Member member = executeSingletonAxis(
"Cousin([Customers].[USA].[CA].[San Jose],"
+ " [Customers].[USA].[OR])");
// CA has more cities than OR
Assert.assertNull(member);
}
public void testCousinThreeDown() {
Member member =
executeSingletonAxis(
"Cousin([Customers].[USA].[CA].[Berkeley].[Barbara Combs],"
+ " [Customers].[Mexico])");
// Barbara Combs is the 6th child
// of the 4th child (Berkeley)
// of the 1st child (CA)
// of USA
// Annmarie Hill is the 6th child
// of the 4th child (Tixapan)
// of the 1st child (DF)
// of Mexico
Assert.assertEquals(
"[Customers].[Mexico].[DF].[Tixapan].[Annmarie Hill]",
member.getUniqueName());
}
public void testCousinSameLevel() {
Member member =
executeSingletonAxis("Cousin([Gender].[M], [Gender].[F])");
Assert.assertEquals("F", member.getName());
}
public void testCousinHigherLevel() {
Member member =
executeSingletonAxis("Cousin([Time].[1997], [Time].[1998].[Q1])");
Assert.assertNull(member);
}
public void testCousinWrongHierarchy() {
assertAxisThrows(
"Cousin([Time].[1997], [Gender].[M])",
MondrianResource.instance().CousinHierarchyMismatch.str(
"[Time].[1997]",
"[Gender].[M]"));
}
public void testParent() {
getTestContext().assertMemberExprDependsOn(
"[Gender].Parent",
"{[Gender]}");
getTestContext().assertMemberExprDependsOn("[Gender].[M].Parent", "{}");
assertAxisReturns(
"{[Store].[USA].[CA].Parent}", "[Store].[USA]");
// root member has null parent
assertAxisReturns("{[Store].[All Stores].Parent}", "");
// parent of null member is null
assertAxisReturns("{[Store].[All Stores].Parent.Parent}", "");
}
public void testParentPC() {
final TestContext testContext = getTestContext().withCube("HR");
testContext.assertAxisReturns(
"[Employees].Parent",
"");
testContext.assertAxisReturns(
"[Employees].[Sheri Nowmer].Parent",
"[Employees].[All Employees]");
testContext.assertAxisReturns(
"[Employees].[Sheri Nowmer].[Derrick Whelply].Parent",
"[Employees].[Sheri Nowmer]");
testContext.assertAxisReturns(
"[Employees].Members.Item(3)",
"[Employees].[Sheri Nowmer].[Derrick Whelply].[Beverly Baker]");
testContext.assertAxisReturns(
"[Employees].Members.Item(3).Parent",
"[Employees].[Sheri Nowmer].[Derrick Whelply]");
testContext.assertAxisReturns(
"[Employees].AllMembers.Item(3).Parent",
"[Employees].[Sheri Nowmer].[Derrick Whelply]");
// Ascendants(<Member>) applied to parent-child hierarchy accessed via
// <Level>.Members
testContext.assertAxisReturns(
"Ascendants([Employees].Members.Item(73))",
"[Employees].[Sheri Nowmer].[Derrick Whelply].[Beverly Baker].[Jacqueline Wyllie].[Ralph Mccoy].[Bertha Jameson].[James Bailey]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Beverly Baker].[Jacqueline Wyllie].[Ralph Mccoy].[Bertha Jameson]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Beverly Baker].[Jacqueline Wyllie].[Ralph Mccoy]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Beverly Baker].[Jacqueline Wyllie]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Beverly Baker]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply]\n"
+ "[Employees].[Sheri Nowmer]\n"
+ "[Employees].[All Employees]");
}
public void testMembers() {
// <Level>.members
assertAxisReturns(
"{[Customers].[Country].Members}",
"[Customers].[Canada]\n"
+ "[Customers].[Mexico]\n"
+ "[Customers].[USA]");
// <Level>.members applied to 'all' level
assertAxisReturns(
"{[Customers].[(All)].Members}", "[Customers].[All Customers]");
// <Level>.members applied to measures dimension
// Note -- no cube-level calculated members are present
assertAxisReturns(
"{[Measures].[MeasuresLevel].Members}",
"[Measures].[Unit Sales]\n"
+ "[Measures].[Store Cost]\n"
+ "[Measures].[Store Sales]\n"
+ "[Measures].[Sales Count]\n"
+ "[Measures].[Customer Count]\n"
+ "[Measures].[Promotion Sales]");
// <Dimension>.members applied to Measures
assertAxisReturns(
"{[Measures].Members}",
"[Measures].[Unit Sales]\n"
+ "[Measures].[Store Cost]\n"
+ "[Measures].[Store Sales]\n"
+ "[Measures].[Sales Count]\n"
+ "[Measures].[Customer Count]\n"
+ "[Measures].[Promotion Sales]");
// <Dimension>.members applied to a query with calc measures
// Again, no calc measures are returned
switch (TestContext.instance().getDialect().getDatabaseProduct()) {
case INFOBRIGHT:
// Skip this test on Infobright, because [Promotion Sales] is
// defined wrong.
break;
default:
assertQueryReturns(
"with member [Measures].[Xxx] AS ' [Measures].[Unit Sales] '"
+ "select {[Measures].members} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Sales Count]}\n"
+ "{[Measures].[Customer Count]}\n"
+ "{[Measures].[Promotion Sales]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 225,627.23\n"
+ "Row #0: 565,238.13\n"
+ "Row #0: 86,837\n"
+ "Row #0: 5,581\n"
+ "Row #0: 151,211.21\n");
}
// <Level>.members applied to a query with calc measures
// Again, no calc measures are returned
switch (TestContext.instance().getDialect().getDatabaseProduct()) {
case INFOBRIGHT:
// Skip this test on Infobright, because [Promotion Sales] is
// defined wrong.
break;
default:
assertQueryReturns(
"with member [Measures].[Xxx] AS ' [Measures].[Unit Sales] '"
+ "select {[Measures].[Measures].members} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Sales Count]}\n"
+ "{[Measures].[Customer Count]}\n"
+ "{[Measures].[Promotion Sales]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 225,627.23\n"
+ "Row #0: 565,238.13\n"
+ "Row #0: 86,837\n"
+ "Row #0: 5,581\n"
+ "Row #0: 151,211.21\n");
}
}
public void testHierarchyMembers() {
assertAxisReturns(
"Head({[Time.Weekly].Members}, 10)",
"[Time].[Weekly].[All Weeklys]\n"
+ "[Time].[Weekly].[1997]\n"
+ "[Time].[Weekly].[1997].[1]\n"
+ "[Time].[Weekly].[1997].[1].[15]\n"
+ "[Time].[Weekly].[1997].[1].[16]\n"
+ "[Time].[Weekly].[1997].[1].[17]\n"
+ "[Time].[Weekly].[1997].[1].[18]\n"
+ "[Time].[Weekly].[1997].[1].[19]\n"
+ "[Time].[Weekly].[1997].[1].[20]\n"
+ "[Time].[Weekly].[1997].[2]");
assertAxisReturns(
"Tail({[Time.Weekly].Members}, 5)",
"[Time].[Weekly].[1998].[51].[5]\n"
+ "[Time].[Weekly].[1998].[51].[29]\n"
+ "[Time].[Weekly].[1998].[51].[30]\n"
+ "[Time].[Weekly].[1998].[52]\n"
+ "[Time].[Weekly].[1998].[52].[6]");
}
public void testAllMembers() {
// <Level>.allmembers
assertAxisReturns(
"{[Customers].[Country].allmembers}",
"[Customers].[Canada]\n"
+ "[Customers].[Mexico]\n"
+ "[Customers].[USA]");
// <Level>.allmembers applied to 'all' level
assertAxisReturns(
"{[Customers].[(All)].allmembers}", "[Customers].[All Customers]");
// <Level>.allmembers applied to measures dimension
// Note -- cube-level calculated members ARE present
assertAxisReturns(
"{[Measures].[MeasuresLevel].allmembers}",
"[Measures].[Unit Sales]\n"
+ "[Measures].[Store Cost]\n"
+ "[Measures].[Store Sales]\n"
+ "[Measures].[Sales Count]\n"
+ "[Measures].[Customer Count]\n"
+ "[Measures].[Promotion Sales]\n"
+ "[Measures].[Profit]\n"
+ "[Measures].[Profit Growth]\n"
+ "[Measures].[Profit last Period]");
// <Dimension>.allmembers applied to Measures
assertAxisReturns(
"{[Measures].allmembers}",
"[Measures].[Unit Sales]\n"
+ "[Measures].[Store Cost]\n"
+ "[Measures].[Store Sales]\n"
+ "[Measures].[Sales Count]\n"
+ "[Measures].[Customer Count]\n"
+ "[Measures].[Promotion Sales]\n"
+ "[Measures].[Profit]\n"
+ "[Measures].[Profit Growth]\n"
+ "[Measures].[Profit last Period]");
// <Dimension>.allmembers applied to a query with calc measures
// Calc measures are returned
switch (TestContext.instance().getDialect().getDatabaseProduct()) {
case INFOBRIGHT:
// Skip this test on Infobright, because [Promotion Sales] is
// defined wrong.
break;
default:
assertQueryReturns(
"with member [Measures].[Xxx] AS ' [Measures].[Unit Sales] '"
+ "select {[Measures].allmembers} on columns from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Sales Count]}\n"
+ "{[Measures].[Customer Count]}\n"
+ "{[Measures].[Promotion Sales]}\n"
+ "{[Measures].[Profit]}\n"
+ "{[Measures].[Profit Growth]}\n"
+ "{[Measures].[Profit last Period]}\n"
+ "{[Measures].[Xxx]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 225,627.23\n"
+ "Row #0: 565,238.13\n"
+ "Row #0: 86,837\n"
+ "Row #0: 5,581\n"
+ "Row #0: 151,211.21\n"
+ "Row #0: $339,610.90\n"
+ "Row #0: 0.0%\n"
+ "Row #0: $339,610.90\n"
+ "Row #0: 266,773\n");
}
// Calc measure members from schema and from query
switch (TestContext.instance().getDialect().getDatabaseProduct()) {
case INFOBRIGHT:
// Skip this test on Infobright, because [Promotion Sales] is
// defined wrong.
break;
default:
assertQueryReturns(
"WITH MEMBER [Measures].[Unit to Sales ratio] as\n"
+ " '[Measures].[Unit Sales] / [Measures].[Store Sales]', FORMAT_STRING='0.0%' "
+ "SELECT {[Measures].AllMembers} ON COLUMNS,"
+ "non empty({[Store].[Store State].Members}) ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Sales Count]}\n"
+ "{[Measures].[Customer Count]}\n"
+ "{[Measures].[Promotion Sales]}\n"
+ "{[Measures].[Profit]}\n"
+ "{[Measures].[Profit Growth]}\n"
+ "{[Measures].[Profit last Period]}\n"
+ "{[Measures].[Unit to Sales ratio]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "Row #0: 16,890\n"
+ "Row #0: 14,431.09\n"
+ "Row #0: 36,175.20\n"
+ "Row #0: 5,498\n"
+ "Row #0: 1,110\n"
+ "Row #0: 14,447.16\n"
+ "Row #0: $21,744.11\n"
+ "Row #0: 0.0%\n"
+ "Row #0: $21,744.11\n"
+ "Row #0: 46.7%\n"
+ "Row #1: 19,287\n"
+ "Row #1: 16,081.07\n"
+ "Row #1: 40,170.29\n"
+ "Row #1: 6,184\n"
+ "Row #1: 767\n"
+ "Row #1: 10,829.64\n"
+ "Row #1: $24,089.22\n"
+ "Row #1: 0.0%\n"
+ "Row #1: $24,089.22\n"
+ "Row #1: 48.0%\n"
+ "Row #2: 30,114\n"
+ "Row #2: 25,240.08\n"
+ "Row #2: 63,282.86\n"
+ "Row #2: 9,906\n"
+ "Row #2: 1,104\n"
+ "Row #2: 18,459.60\n"
+ "Row #2: $38,042.78\n"
+ "Row #2: 0.0%\n"
+ "Row #2: $38,042.78\n"
+ "Row #2: 47.6%\n");
}
// Calc member in query and schema not seen
switch (TestContext.instance().getDialect().getDatabaseProduct()) {
case INFOBRIGHT:
// Skip this test on Infobright, because [Promotion Sales] is
// defined wrong.
break;
default:
assertQueryReturns(
"WITH MEMBER [Measures].[Unit to Sales ratio] as '[Measures].[Unit Sales] / [Measures].[Store Sales]', FORMAT_STRING='0.0%' "
+ "SELECT {[Measures].AllMembers} ON COLUMNS,"
+ "non empty({[Store].[Store State].Members}) ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Sales Count]}\n"
+ "{[Measures].[Customer Count]}\n"
+ "{[Measures].[Promotion Sales]}\n"
+ "{[Measures].[Profit]}\n"
+ "{[Measures].[Profit Growth]}\n"
+ "{[Measures].[Profit last Period]}\n"
+ "{[Measures].[Unit to Sales ratio]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "Row #0: 16,890\n"
+ "Row #0: 14,431.09\n"
+ "Row #0: 36,175.20\n"
+ "Row #0: 5,498\n"
+ "Row #0: 1,110\n"
+ "Row #0: 14,447.16\n"
+ "Row #0: $21,744.11\n"
+ "Row #0: 0.0%\n"
+ "Row #0: $21,744.11\n"
+ "Row #0: 46.7%\n"
+ "Row #1: 19,287\n"
+ "Row #1: 16,081.07\n"
+ "Row #1: 40,170.29\n"
+ "Row #1: 6,184\n"
+ "Row #1: 767\n"
+ "Row #1: 10,829.64\n"
+ "Row #1: $24,089.22\n"
+ "Row #1: 0.0%\n"
+ "Row #1: $24,089.22\n"
+ "Row #1: 48.0%\n"
+ "Row #2: 30,114\n"
+ "Row #2: 25,240.08\n"
+ "Row #2: 63,282.86\n"
+ "Row #2: 9,906\n"
+ "Row #2: 1,104\n"
+ "Row #2: 18,459.60\n"
+ "Row #2: $38,042.78\n"
+ "Row #2: 0.0%\n"
+ "Row #2: $38,042.78\n"
+ "Row #2: 47.6%\n");
}
// Calc member in query and schema not seen
switch (TestContext.instance().getDialect().getDatabaseProduct()) {
case INFOBRIGHT:
// Skip this test on Infobright, because [Promotion Sales] is
// defined wrong.
break;
default:
assertQueryReturns(
"WITH MEMBER [Measures].[Unit to Sales ratio] as '[Measures].[Unit Sales] / [Measures].[Store Sales]', FORMAT_STRING='0.0%' "
+ "SELECT {[Measures].Members} ON COLUMNS,"
+ "non empty({[Store].[Store State].Members}) ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Sales Count]}\n"
+ "{[Measures].[Customer Count]}\n"
+ "{[Measures].[Promotion Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "Row #0: 16,890\n"
+ "Row #0: 14,431.09\n"
+ "Row #0: 36,175.20\n"
+ "Row #0: 5,498\n"
+ "Row #0: 1,110\n"
+ "Row #0: 14,447.16\n"
+ "Row #1: 19,287\n"
+ "Row #1: 16,081.07\n"
+ "Row #1: 40,170.29\n"
+ "Row #1: 6,184\n"
+ "Row #1: 767\n"
+ "Row #1: 10,829.64\n"
+ "Row #2: 30,114\n"
+ "Row #2: 25,240.08\n"
+ "Row #2: 63,282.86\n"
+ "Row #2: 9,906\n"
+ "Row #2: 1,104\n"
+ "Row #2: 18,459.60\n");
}
// Calc member in dimension based on level
assertQueryReturns(
"WITH MEMBER [Store].[USA].[CA plus OR] AS 'AGGREGATE({[Store].[USA].[CA], [Store].[USA].[OR]})' "
+ "SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,"
+ "non empty({[Store].[Store State].AllMembers}) ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "{[Store].[USA].[CA plus OR]}\n"
+ "Row #0: 16,890\n"
+ "Row #0: 36,175.20\n"
+ "Row #1: 19,287\n"
+ "Row #1: 40,170.29\n"
+ "Row #2: 30,114\n"
+ "Row #2: 63,282.86\n"
+ "Row #3: 36,177\n"
+ "Row #3: 76,345.49\n");
// Calc member in dimension based on level not seen
assertQueryReturns(
"WITH MEMBER [Store].[USA].[CA plus OR] AS 'AGGREGATE({[Store].[USA].[CA], [Store].[USA].[OR]})' "
+ "SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,"
+ "non empty({[Store].[Store Country].AllMembers}) ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 66,291\n"
+ "Row #0: 139,628.35\n");
}
public void testAddCalculatedMembers() {
//----------------------------------------------------
// AddCalculatedMembers: Calc member in dimension based on level
// included
//----------------------------------------------------
assertQueryReturns(
"WITH MEMBER [Store].[USA].[CA plus OR] AS 'AGGREGATE({[Store].[USA].[CA], [Store].[USA].[OR]})' "
+ "SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,"
+ "AddCalculatedMembers([Store].[USA].Children) ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "{[Store].[USA].[CA plus OR]}\n"
+ "Row #0: 16,890\n"
+ "Row #0: 36,175.20\n"
+ "Row #1: 19,287\n"
+ "Row #1: 40,170.29\n"
+ "Row #2: 30,114\n"
+ "Row #2: 63,282.86\n"
+ "Row #3: 36,177\n"
+ "Row #3: 76,345.49\n");
//----------------------------------------------------
// Calc member in dimension based on level included
// Calc members in measures in schema included
//----------------------------------------------------
assertQueryReturns(
"WITH MEMBER [Store].[USA].[CA plus OR] AS 'AGGREGATE({[Store].[USA].[CA], [Store].[USA].[OR]})' "
+ "SELECT AddCalculatedMembers({[Measures].[Unit Sales], [Measures].[Store Sales]}) ON COLUMNS,"
+ "AddCalculatedMembers([Store].[USA].Children) ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Profit]}\n"
+ "{[Measures].[Profit last Period]}\n"
+ "{[Measures].[Profit Growth]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "{[Store].[USA].[CA plus OR]}\n"
+ "Row #0: 16,890\n"
+ "Row #0: 36,175.20\n"
+ "Row #0: $21,744.11\n"
+ "Row #0: $21,744.11\n"
+ "Row #0: 0.0%\n"
+ "Row #1: 19,287\n"
+ "Row #1: 40,170.29\n"
+ "Row #1: $24,089.22\n"
+ "Row #1: $24,089.22\n"
+ "Row #1: 0.0%\n"
+ "Row #2: 30,114\n"
+ "Row #2: 63,282.86\n"
+ "Row #2: $38,042.78\n"
+ "Row #2: $38,042.78\n"
+ "Row #2: 0.0%\n"
+ "Row #3: 36,177\n"
+ "Row #3: 76,345.49\n"
+ "Row #3: $45,833.33\n"
+ "Row #3: $45,833.33\n"
+ "Row #3: 0.0%\n");
//----------------------------------------------------
// Two dimensions
//----------------------------------------------------
assertQueryReturns(
"SELECT AddCalculatedMembers({[Measures].[Unit Sales], [Measures].[Store Sales]}) ON COLUMNS,"
+ "{([Store].[USA].[CA], [Gender].[F])} ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Profit]}\n"
+ "{[Measures].[Profit last Period]}\n"
+ "{[Measures].[Profit Growth]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA], [Gender].[F]}\n"
+ "Row #0: 8,218\n"
+ "Row #0: 17,928.37\n"
+ "Row #0: $10,771.98\n"
+ "Row #0: $10,771.98\n"
+ "Row #0: 0.0%\n");
//----------------------------------------------------
// Should throw more than one dimension error
//----------------------------------------------------
assertAxisThrows(
"AddCalculatedMembers({([Store].[USA].[CA], [Gender].[F])})",
"Only single dimension members allowed in set for "
+ "AddCalculatedMembers");
}
public void testStripCalculatedMembers() {
assertAxisReturns(
"StripCalculatedMembers({[Measures].AllMembers})",
"[Measures].[Unit Sales]\n"
+ "[Measures].[Store Cost]\n"
+ "[Measures].[Store Sales]\n"
+ "[Measures].[Sales Count]\n"
+ "[Measures].[Customer Count]\n"
+ "[Measures].[Promotion Sales]");
// applied to empty set
assertAxisReturns("StripCalculatedMembers({[Gender].Parent})", "");
getTestContext().assertSetExprDependsOn(
"StripCalculatedMembers([Customers].CurrentMember.Children)",
"{[Customers]}");
// ----------------------------------------------------
// Calc members in dimension based on level stripped
// Actual members in measures left alone
// ----------------------------------------------------
assertQueryReturns(
"WITH MEMBER [Store].[USA].[CA plus OR] AS "
+ "'AGGREGATE({[Store].[USA].[CA], [Store].[USA].[OR]})' "
+ "SELECT StripCalculatedMembers({[Measures].[Unit Sales], "
+ "[Measures].[Store Sales]}) ON COLUMNS,"
+ "StripCalculatedMembers("
+ "AddCalculatedMembers([Store].[USA].Children)) ON ROWS "
+ "FROM Sales "
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "Row #0: 16,890\n"
+ "Row #0: 36,175.20\n"
+ "Row #1: 19,287\n"
+ "Row #1: 40,170.29\n"
+ "Row #2: 30,114\n"
+ "Row #2: 63,282.86\n");
}
public void testCurrentMember() {
// <Dimension>.CurrentMember
assertAxisReturns("[Gender].CurrentMember", "[Gender].[All Gender]");
// <Hierarchy>.CurrentMember
assertAxisReturns(
"[Gender].Hierarchy.CurrentMember", "[Gender].[All Gender]");
// <Level>.CurrentMember
// MSAS doesn't allow this, but Mondrian does: it implicitly casts
// level to hierarchy.
assertAxisReturns("[Store Name].CurrentMember", "[Store].[All Stores]");
}
public void testCurrentMemberDepends() {
getTestContext().assertMemberExprDependsOn(
"[Gender].CurrentMember",
"{[Gender]}");
getTestContext().assertExprDependsOn(
"[Gender].[M].Dimension.Name", "{}");
// implicit call to .CurrentMember when dimension is used as a member
// expression
getTestContext().assertMemberExprDependsOn(
"[Gender].[M].Dimension",
"{[Gender]}");
getTestContext().assertMemberExprDependsOn(
"[Gender].[M].Dimension.CurrentMember", "{[Gender]}");
getTestContext().assertMemberExprDependsOn(
"[Gender].[M].Dimension.CurrentMember.Parent", "{[Gender]}");
// [Customers] is short for [Customers].CurrentMember, so
// depends upon everything
getTestContext().assertExprDependsOn(
"[Customers]", TestContext.allHiers());
}
public void testCurrentMemberFromSlicer() {
Result result = executeQuery(
"with member [Measures].[Foo] as '[Gender].CurrentMember.Name'\n"
+ "select {[Measures].[Foo]} on columns\n"
+ "from Sales where ([Gender].[F])");
Assert.assertEquals("F", result.getCell(new int[]{0}).getValue());
}
public void testCurrentMemberFromDefaultMember() {
Result result = executeQuery(
"with member [Measures].[Foo] as"
+ " '[Time].[Time].CurrentMember.Name'\n"
+ "select {[Measures].[Foo]} on columns\n"
+ "from Sales");
Assert.assertEquals("1997", result.getCell(new int[]{0}).getValue());
}
public void testCurrentMemberMultiHierarchy() {
final String hierarchyName =
MondrianProperties.instance().SsasCompatibleNaming.get()
? "Weekly"
: "Time.Weekly";
final String queryString =
"with member [Measures].[Foo] as\n"
+ " 'IIf(([Time].[Time].CurrentMember.Hierarchy.Name = \""
+ hierarchyName
+ "\"), \n"
+ "[Measures].[Unit Sales], \n"
+ "- [Measures].[Unit Sales])'\n"
+ "select {[Measures].[Unit Sales], [Measures].[Foo]} ON COLUMNS,\n"
+ " {[Product].[Food].[Dairy]} ON ROWS\n"
+ "from [Sales]";
Result result =
executeQuery(
queryString + " where [Time].[1997]");
final int[] coords = {1, 0};
Assert.assertEquals(
"-12,885",
result.getCell(coords).getFormattedValue());
// As above, but context provided on rows axis as opposed to slicer.
final String queryString1 =
"with member [Measures].[Foo] as\n"
+ " 'IIf(([Time].[Time].CurrentMember.Hierarchy.Name = \""
+ hierarchyName
+ "\"), \n"
+ "[Measures].[Unit Sales], \n"
+ "- [Measures].[Unit Sales])'\n"
+ "select {[Measures].[Unit Sales], [Measures].[Foo]} ON COLUMNS,";
final String queryString2 =
"from [Sales]\n"
+ " where [Product].[Food].[Dairy] ";
result =
executeQuery(
queryString1 + " {[Time].[1997]} ON ROWS " + queryString2);
Assert.assertEquals(
"-12,885",
result.getCell(coords).getFormattedValue());
result =
executeQuery(
queryString + " where [Time.Weekly].[1997]");
Assert.assertEquals(
"-12,885",
result.getCell(coords).getFormattedValue());
result =
executeQuery(
queryString1 + " {[Time.Weekly].[1997]} ON ROWS "
+ queryString2);
Assert.assertEquals(
"-12,885",
result.getCell(coords).getFormattedValue());
}
public void testDefaultMember() {
// [Time] has no default member and no all, so the default member is
// the first member of the first level.
Result result =
executeQuery(
"select {[Time].[Time].DefaultMember} on columns\n"
+ "from Sales");
Assert.assertEquals(
"1997",
result.getAxes()[0].getPositions().get(0).get(0).getName());
// [Time].[Weekly] has an all member and no explicit default.
result =
executeQuery(
"select {[Time.Weekly].DefaultMember} on columns\n"
+ "from Sales");
Assert.assertEquals(
MondrianProperties.instance().SsasCompatibleNaming.get()
? "All Weeklys"
: "All Time.Weeklys",
result.getAxes()[0].getPositions().get(0).get(0).getName());
final String memberUname =
MondrianProperties.instance().SsasCompatibleNaming.get()
? "[Time2].[Weekly].[1997].[23]"
: "[Time2.Weekly].[1997].[23]";
TestContext testContext = TestContext.instance().createSubstitutingCube(
"Sales",
" <Dimension name=\"Time2\" type=\"TimeDimension\" foreignKey=\"time_id\">\n"
+ " <Hierarchy hasAll=\"false\" primaryKey=\"time_id\">\n"
+ " <Table name=\"time_by_day\"/>\n"
+ " <Level name=\"Year\" column=\"the_year\" type=\"Numeric\" uniqueMembers=\"true\"\n"
+ " levelType=\"TimeYears\"/>\n"
+ " <Level name=\"Quarter\" column=\"quarter\" uniqueMembers=\"false\"\n"
+ " levelType=\"TimeQuarters\"/>\n"
+ " <Level name=\"Month\" column=\"month_of_year\" uniqueMembers=\"false\" type=\"Numeric\"\n"
+ " levelType=\"TimeMonths\"/>\n"
+ " </Hierarchy>\n"
+ " <Hierarchy hasAll=\"true\" name=\"Weekly\" primaryKey=\"time_id\"\n"
+ " defaultMember=\""
+ memberUname
+ "\">\n"
+ " <Table name=\"time_by_day\"/>\n"
+ " <Level name=\"Year\" column=\"the_year\" type=\"Numeric\" uniqueMembers=\"true\"\n"
+ " levelType=\"TimeYears\"/>\n"
+ " <Level name=\"Week\" column=\"week_of_year\" type=\"Numeric\" uniqueMembers=\"false\"\n"
+ " levelType=\"TimeWeeks\"/>\n"
+ " <Level name=\"Day\" column=\"day_of_month\" uniqueMembers=\"false\" type=\"Numeric\"\n"
+ " levelType=\"TimeDays\"/>\n"
+ " </Hierarchy>\n"
+ " </Dimension>");
// In this variant of the schema, Time2.Weekly has an explicit default
// member.
result =
testContext.executeQuery(
"select {[Time2.Weekly].DefaultMember} on columns\n"
+ "from Sales");
Assert.assertEquals(
"23",
result.getAxes()[0].getPositions().get(0).get(0).getName());
}
public void testCurrentMemberFromAxis() {
Result result = executeQuery(
"with member [Measures].[Foo] as"
+ " '[Gender].CurrentMember.Name"
+ " || [Marital Status].CurrentMember.Name'\n"
+ "select {[Measures].[Foo]} on columns,\n"
+ " CrossJoin({[Gender].children},"
+ " {[Marital Status].children}) on rows\n"
+ "from Sales");
Assert.assertEquals("FM", result.getCell(new int[]{0, 0}).getValue());
}
/**
* When evaluating a calculated member, MSOLAP regards that
* calculated member as the current member of that dimension, so it
* cycles in this case. But I disagree; it is the previous current
* member, before the calculated member was expanded.
*/
public void testCurrentMemberInCalcMember() {
Result result = executeQuery(
"with member [Measures].[Foo] as '[Measures].CurrentMember.Name'\n"
+ "select {[Measures].[Foo]} on columns\n"
+ "from Sales");
Assert.assertEquals(
"Unit Sales", result.getCell(new int[]{0}).getValue());
}
/**
* Tests NamedSet.CurrentOrdinal combined with the Order function.
*/
public void testNamedSetCurrentOrdinalWithOrder() {
// The <Named Set>.CurrentOrdinal only works correctly when named sets
// are evaluated as iterables, and JDK 1.4 only supports lists.
if (Util.Retrowoven) {
return;
}
assertQueryReturns(
"with set [Time Regular] as [Time].[Time].Members\n"
+ " set [Time Reversed] as"
+ " Order([Time Regular], [Time Regular].CurrentOrdinal, BDESC)\n"
+ "select [Time Reversed] on 0\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1998].[Q4].[12]}\n"
+ "{[Time].[1998].[Q4].[11]}\n"
+ "{[Time].[1998].[Q4].[10]}\n"
+ "{[Time].[1998].[Q4]}\n"
+ "{[Time].[1998].[Q3].[9]}\n"
+ "{[Time].[1998].[Q3].[8]}\n"
+ "{[Time].[1998].[Q3].[7]}\n"
+ "{[Time].[1998].[Q3]}\n"
+ "{[Time].[1998].[Q2].[6]}\n"
+ "{[Time].[1998].[Q2].[5]}\n"
+ "{[Time].[1998].[Q2].[4]}\n"
+ "{[Time].[1998].[Q2]}\n"
+ "{[Time].[1998].[Q1].[3]}\n"
+ "{[Time].[1998].[Q1].[2]}\n"
+ "{[Time].[1998].[Q1].[1]}\n"
+ "{[Time].[1998].[Q1]}\n"
+ "{[Time].[1998]}\n"
+ "{[Time].[1997].[Q4].[12]}\n"
+ "{[Time].[1997].[Q4].[11]}\n"
+ "{[Time].[1997].[Q4].[10]}\n"
+ "{[Time].[1997].[Q4]}\n"
+ "{[Time].[1997].[Q3].[9]}\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "{[Time].[1997].[Q3].[7]}\n"
+ "{[Time].[1997].[Q3]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q1].[3]}\n"
+ "{[Time].[1997].[Q1].[2]}\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997]}\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 #0: 26,796\n"
+ "Row #0: 25,270\n"
+ "Row #0: 19,958\n"
+ "Row #0: 72,024\n"
+ "Row #0: 20,388\n"
+ "Row #0: 21,697\n"
+ "Row #0: 23,763\n"
+ "Row #0: 65,848\n"
+ "Row #0: 21,350\n"
+ "Row #0: 21,081\n"
+ "Row #0: 20,179\n"
+ "Row #0: 62,610\n"
+ "Row #0: 23,706\n"
+ "Row #0: 20,957\n"
+ "Row #0: 21,628\n"
+ "Row #0: 66,291\n"
+ "Row #0: 266,773\n");
}
/**
* Tests NamedSet.CurrentOrdinal combined with the Generate function.
*/
public void testNamedSetCurrentOrdinalWithGenerate() {
// The <Named Set>.CurrentOrdinal only works correctly when named sets
// are evaluated as iterables, and JDK 1.4 only supports lists.
if (Util.Retrowoven) {
return;
}
assertQueryReturns(
" with set [Time Regular] as [Time].[Time].Members\n"
+ "set [Every Other Time] as\n"
+ " Generate(\n"
+ " [Time Regular],\n"
+ " {[Time].[Time].Members.Item(\n"
+ " [Time Regular].CurrentOrdinal * 2)})\n"
+ "select [Every Other Time] on 0\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997]}\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q1].[3]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q3].[7]}\n"
+ "{[Time].[1997].[Q3].[9]}\n"
+ "{[Time].[1997].[Q4].[10]}\n"
+ "{[Time].[1997].[Q4].[12]}\n"
+ "{[Time].[1998].[Q1]}\n"
+ "{[Time].[1998].[Q1].[2]}\n"
+ "{[Time].[1998].[Q2]}\n"
+ "{[Time].[1998].[Q2].[5]}\n"
+ "{[Time].[1998].[Q3]}\n"
+ "{[Time].[1998].[Q3].[8]}\n"
+ "{[Time].[1998].[Q4]}\n"
+ "{[Time].[1998].[Q4].[11]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 21,628\n"
+ "Row #0: 23,706\n"
+ "Row #0: 20,179\n"
+ "Row #0: 21,350\n"
+ "Row #0: 23,763\n"
+ "Row #0: 20,388\n"
+ "Row #0: 19,958\n"
+ "Row #0: 26,796\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");
}
public void testNamedSetCurrentOrdinalWithFilter() {
// The <Named Set>.CurrentOrdinal only works correctly when named sets
// are evaluated as iterables, and JDK 1.4 only supports lists.
if (Util.Retrowoven) {
return;
}
assertQueryReturns(
"with set [Time Regular] as [Time].[Time].Members\n"
+ " set [Time Subset] as "
+ " Filter([Time Regular], [Time Regular].CurrentOrdinal = 3"
+ " or [Time Regular].CurrentOrdinal = 5)\n"
+ "select [Time Subset] on 0\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997].[Q1].[2]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "Row #0: 20,957\n"
+ "Row #0: 62,610\n");
}
public void testNamedSetCurrentOrdinalWithCrossjoin() {
// TODO:
}
public void testNamedSetCurrentOrdinalWithNonNamedSetFails() {
// a named set wrapped in {...} is not a named set, so CurrentOrdinal
// fails
assertQueryThrows(
"with set [Time Members] as [Time].Members\n"
+ "member [Measures].[Foo] as ' {[Time Members]}.CurrentOrdinal '\n"
+ "select {[Measures].[Unit Sales], [Measures].[Foo]} on 0,\n"
+ " {[Product].Children} on 1\n"
+ "from [Sales]",
"Not a named set");
// as above for Current function
assertQueryThrows(
"with set [Time Members] as [Time].Members\n"
+ "member [Measures].[Foo] as ' {[Time Members]}.Current.Name '\n"
+ "select {[Measures].[Unit Sales], [Measures].[Foo]} on 0,\n"
+ " {[Product].Children} on 1\n"
+ "from [Sales]",
"Not a named set");
// a set expression is not a named set, so CurrentOrdinal fails
assertQueryThrows(
"with member [Measures].[Foo] as\n"
+ " ' Head([Time].Members, 5).CurrentOrdinal '\n"
+ "select {[Measures].[Unit Sales], [Measures].[Foo]} on 0,\n"
+ " {[Product].Children} on 1\n"
+ "from [Sales]",
"Not a named set");
// as above for Current function
assertQueryThrows(
"with member [Measures].[Foo] as\n"
+ " ' Crossjoin([Time].Members, [Gender].Members).Current.Name '\n"
+ "select {[Measures].[Unit Sales], [Measures].[Foo]} on 0,\n"
+ " {[Product].Children} on 1\n"
+ "from [Sales]",
"Not a named set");
}
public void testDimensionDefaultMember() {
Member member = executeSingletonAxis("[Measures].DefaultMember");
Assert.assertEquals("Unit Sales", member.getName());
}
public void testDrilldownLevel() {
// Expect all children of USA
assertAxisReturns(
"DrilldownLevel({[Store].[USA]}, [Store].[Store Country])",
"[Store].[USA]\n"
+ "[Store].[USA].[CA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[WA]");
// Expect same set, because [USA] is already drilled
assertAxisReturns(
"DrilldownLevel({[Store].[USA], [Store].[USA].[CA]}, [Store].[Store Country])",
"[Store].[USA]\n"
+ "[Store].[USA].[CA]");
// Expect drill, because [USA] isn't already drilled. You can't
// drill down on [CA] and get to [USA]
assertAxisReturns(
"DrilldownLevel({[Store].[USA].[CA],[Store].[USA]}, [Store].[Store Country])",
"[Store].[USA].[CA]\n"
+ "[Store].[USA]\n"
+ "[Store].[USA].[CA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[WA]");
assertAxisReturns(
"DrilldownLevel({[Store].[USA].[CA],[Store].[USA]},, 0)",
"[Store].[USA].[CA]\n"
+ "[Store].[USA].[CA].[Alameda]\n"
+ "[Store].[USA].[CA].[Beverly Hills]\n"
+ "[Store].[USA].[CA].[Los Angeles]\n"
+ "[Store].[USA].[CA].[San Diego]\n"
+ "[Store].[USA].[CA].[San Francisco]\n"
+ "[Store].[USA]\n"
+ "[Store].[USA].[CA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[WA]");
assertAxisReturns(
"DrilldownLevel({[Store].[USA].[CA],[Store].[USA]} * {[Gender].Members},, 0)",
"{[Store].[USA].[CA], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[CA].[Alameda], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[CA].[Beverly Hills], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[CA].[Los Angeles], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[CA].[San Diego], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[CA].[San Francisco], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[CA], [Gender].[F]}\n"
+ "{[Store].[USA].[CA].[Alameda], [Gender].[F]}\n"
+ "{[Store].[USA].[CA].[Beverly Hills], [Gender].[F]}\n"
+ "{[Store].[USA].[CA].[Los Angeles], [Gender].[F]}\n"
+ "{[Store].[USA].[CA].[San Diego], [Gender].[F]}\n"
+ "{[Store].[USA].[CA].[San Francisco], [Gender].[F]}\n"
+ "{[Store].[USA].[CA], [Gender].[M]}\n"
+ "{[Store].[USA].[CA].[Alameda], [Gender].[M]}\n"
+ "{[Store].[USA].[CA].[Beverly Hills], [Gender].[M]}\n"
+ "{[Store].[USA].[CA].[Los Angeles], [Gender].[M]}\n"
+ "{[Store].[USA].[CA].[San Diego], [Gender].[M]}\n"
+ "{[Store].[USA].[CA].[San Francisco], [Gender].[M]}\n"
+ "{[Store].[USA], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[CA], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[OR], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[WA], [Gender].[All Gender]}\n"
+ "{[Store].[USA], [Gender].[F]}\n"
+ "{[Store].[USA].[CA], [Gender].[F]}\n"
+ "{[Store].[USA].[OR], [Gender].[F]}\n"
+ "{[Store].[USA].[WA], [Gender].[F]}\n"
+ "{[Store].[USA], [Gender].[M]}\n"
+ "{[Store].[USA].[CA], [Gender].[M]}\n"
+ "{[Store].[USA].[OR], [Gender].[M]}\n"
+ "{[Store].[USA].[WA], [Gender].[M]}");
assertAxisReturns(
"DrilldownLevel({[Store].[USA].[CA],[Store].[USA]} * {[Gender].Members},, 1)",
"{[Store].[USA].[CA], [Gender].[All Gender]}\n"
+ "{[Store].[USA].[CA], [Gender].[F]}\n"
+ "{[Store].[USA].[CA], [Gender].[M]}\n"
+ "{[Store].[USA].[CA], [Gender].[F]}\n"
+ "{[Store].[USA].[CA], [Gender].[M]}\n"
+ "{[Store].[USA], [Gender].[All Gender]}\n"
+ "{[Store].[USA], [Gender].[F]}\n"
+ "{[Store].[USA], [Gender].[M]}\n"
+ "{[Store].[USA], [Gender].[F]}\n"
+ "{[Store].[USA], [Gender].[M]}");
}
public void testDrilldownLevelTop() {
// <set>, <n>, <level>
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA]}, 2, [Store].[Store Country])",
"[Store].[USA]\n"
+ "[Store].[USA].[WA]\n"
+ "[Store].[USA].[CA]");
// similarly DrilldownLevelBottom
assertAxisReturns(
"DrilldownLevelBottom({[Store].[USA]}, 2, [Store].[Store Country])",
"[Store].[USA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[CA]");
// <set>, <n>
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA]}, 2)",
"[Store].[USA]\n"
+ "[Store].[USA].[WA]\n"
+ "[Store].[USA].[CA]");
// <n> greater than number of children
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA], [Store].[Canada]}, 4)",
"[Store].[USA]\n"
+ "[Store].[USA].[WA]\n"
+ "[Store].[USA].[CA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[Canada]\n"
+ "[Store].[Canada].[BC]");
// <n> negative
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA]}, 2 - 3)",
"[Store].[USA]");
// <n> zero
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA]}, 2 - 2)",
"[Store].[USA]");
// <n> null
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA]}, null)",
"[Store].[USA]");
// mixed bag, no level, all expanded
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA], "
+ "[Store].[USA].[CA].[San Francisco], "
+ "[Store].[All Stores], "
+ "[Store].[Canada].[BC]}, "
+ "2)",
"[Store].[USA]\n"
+ "[Store].[USA].[WA]\n"
+ "[Store].[USA].[CA]\n"
+ "[Store].[USA].[CA].[San Francisco]\n"
+ "[Store].[USA].[CA].[San Francisco].[Store 14]\n"
+ "[Store].[All Stores]\n"
+ "[Store].[USA]\n"
+ "[Store].[Canada]\n"
+ "[Store].[Canada].[BC]\n"
+ "[Store].[Canada].[BC].[Vancouver]\n"
+ "[Store].[Canada].[BC].[Victoria]");
// mixed bag, only specified level expanded
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA], "
+ "[Store].[USA].[CA].[San Francisco], "
+ "[Store].[All Stores], "
+ "[Store].[Canada].[BC]}, 2, [Store].[Store City])",
"[Store].[USA]\n"
+ "[Store].[USA].[CA].[San Francisco]\n"
+ "[Store].[USA].[CA].[San Francisco].[Store 14]\n"
+ "[Store].[All Stores]\n"
+ "[Store].[Canada].[BC]");
// bad level
assertAxisThrows(
"DrilldownLevelTop({[Store].[USA]}, 2, [Customers].[Country])",
"Level '[Customers].[Country]' not compatible with "
+ "member '[Store].[USA]'");
}
public void testDrilldownMemberEmptyExpr() {
// no level, with expression
assertAxisReturns(
"DrilldownLevelTop({[Store].[USA]}, 2, , [Measures].[Unit Sales])",
"[Store].[USA]\n"
+ "[Store].[USA].[WA]\n"
+ "[Store].[USA].[CA]");
// reverse expression
assertAxisReturns(
"DrilldownLevelTop("
+ "{[Store].[USA]}, 2, , - [Measures].[Unit Sales])",
"[Store].[USA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[CA]");
}
public void testDrilldownMember() {
// Expect all children of USA
assertAxisReturns(
"DrilldownMember({[Store].[USA]}, {[Store].[USA]})",
"[Store].[USA]\n"
+ "[Store].[USA].[CA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[WA]");
// Expect all children of USA.CA and USA.OR
assertAxisReturns(
"DrilldownMember({[Store].[USA].[CA], [Store].[USA].[OR]}, "
+ "{[Store].[USA].[CA], [Store].[USA].[OR], [Store].[USA].[WA]})",
"[Store].[USA].[CA]\n"
+ "[Store].[USA].[CA].[Alameda]\n"
+ "[Store].[USA].[CA].[Beverly Hills]\n"
+ "[Store].[USA].[CA].[Los Angeles]\n"
+ "[Store].[USA].[CA].[San Diego]\n"
+ "[Store].[USA].[CA].[San Francisco]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[OR].[Portland]\n"
+ "[Store].[USA].[OR].[Salem]");
// Second set is empty
assertAxisReturns(
"DrilldownMember({[Store].[USA]}, {})",
"[Store].[USA]");
// Drill down a leaf member
assertAxisReturns(
"DrilldownMember({[Store].[All Stores].[USA].[CA].[San Francisco].[Store 14]}, "
+ "{[Store].[USA].[CA].[San Francisco].[Store 14]})",
"[Store].[USA].[CA].[San Francisco].[Store 14]");
// Complex case with option recursive
assertAxisReturns(
"DrilldownMember({[Store].[All Stores].[USA]}, "
+ "{[Store].[All Stores].[USA], [Store].[All Stores].[USA].[CA], "
+ "[Store].[All Stores].[USA].[CA].[San Diego], [Store].[All Stores].[USA].[WA]}, "
+ "RECURSIVE)",
"[Store].[USA]\n"
+ "[Store].[USA].[CA]\n"
+ "[Store].[USA].[CA].[Alameda]\n"
+ "[Store].[USA].[CA].[Beverly Hills]\n"
+ "[Store].[USA].[CA].[Los Angeles]\n"
+ "[Store].[USA].[CA].[San Diego]\n"
+ "[Store].[USA].[CA].[San Diego].[Store 24]\n"
+ "[Store].[USA].[CA].[San Francisco]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[WA]\n"
+ "[Store].[USA].[WA].[Bellingham]\n"
+ "[Store].[USA].[WA].[Bremerton]\n"
+ "[Store].[USA].[WA].[Seattle]\n"
+ "[Store].[USA].[WA].[Spokane]\n"
+ "[Store].[USA].[WA].[Tacoma]\n"
+ "[Store].[USA].[WA].[Walla Walla]\n"
+ "[Store].[USA].[WA].[Yakima]");
// Sets of tuples
assertAxisReturns(
"DrilldownMember({([Store Type].[Supermarket], [Store].[USA])}, {[Store].[USA]})",
"{[Store Type].[Supermarket], [Store].[USA]}\n"
+ "{[Store Type].[Supermarket], [Store].[USA].[CA]}\n"
+ "{[Store Type].[Supermarket], [Store].[USA].[OR]}\n"
+ "{[Store Type].[Supermarket], [Store].[USA].[WA]}");
}
public void testFirstChildFirstInLevel() {
Member member = executeSingletonAxis("[Time].[1997].[Q4].FirstChild");
Assert.assertEquals("10", member.getName());
}
public void testFirstChildAll() {
Member member =
executeSingletonAxis("[Gender].[All Gender].FirstChild");
Assert.assertEquals("F", member.getName());
}
public void testFirstChildOfChildless() {
Member member =
executeSingletonAxis("[Gender].[All Gender].[F].FirstChild");
Assert.assertNull(member);
}
public void testFirstSiblingFirstInLevel() {
Member member = executeSingletonAxis("[Gender].[F].FirstSibling");
Assert.assertEquals("F", member.getName());
}
public void testFirstSiblingLastInLevel() {
Member member =
executeSingletonAxis("[Time].[1997].[Q4].FirstSibling");
Assert.assertEquals("Q1", member.getName());
}
public void testFirstSiblingAll() {
Member member =
executeSingletonAxis("[Gender].[All Gender].FirstSibling");
Assert.assertTrue(member.isAll());
}
public void testFirstSiblingRoot() {
// The [Measures] hierarchy does not have an 'all' member, so
// [Unit Sales] does not have a parent.
Member member =
executeSingletonAxis("[Measures].[Store Sales].FirstSibling");
Assert.assertEquals("Unit Sales", member.getName());
}
public void testFirstSiblingNull() {
Member member =
executeSingletonAxis("[Gender].[F].FirstChild.FirstSibling");
Assert.assertNull(member);
}
public void testLag() {
Member member = executeSingletonAxis("[Time].[1997].[Q4].[12].Lag(4)");
Assert.assertEquals("8", member.getName());
}
public void testLagFirstInLevel() {
Member member = executeSingletonAxis("[Gender].[F].Lag(1)");
Assert.assertNull(member);
}
public void testLagAll() {
Member member = executeSingletonAxis("[Gender].DefaultMember.Lag(2)");
Assert.assertNull(member);
}
public void testLagRoot() {
Member member = executeSingletonAxis("[Time].[1998].Lag(1)");
Assert.assertEquals("1997", member.getName());
}
public void testLagRootTooFar() {
Member member = executeSingletonAxis("[Time].[1998].Lag(2)");
Assert.assertNull(member);
}
public void testLastChild() {
Member member = executeSingletonAxis("[Gender].LastChild");
Assert.assertEquals("M", member.getName());
}
public void testLastChildLastInLevel() {
Member member = executeSingletonAxis("[Time].[1997].[Q4].LastChild");
Assert.assertEquals("12", member.getName());
}
public void testLastChildAll() {
Member member = executeSingletonAxis("[Gender].[All Gender].LastChild");
Assert.assertEquals("M", member.getName());
}
public void testLastChildOfChildless() {
Member member = executeSingletonAxis("[Gender].[M].LastChild");
Assert.assertNull(member);
}
public void testLastSibling() {
Member member = executeSingletonAxis("[Gender].[F].LastSibling");
Assert.assertEquals("M", member.getName());
}
public void testLastSiblingFirstInLevel() {
Member member = executeSingletonAxis("[Time].[1997].[Q1].LastSibling");
Assert.assertEquals("Q4", member.getName());
}
public void testLastSiblingAll() {
Member member =
executeSingletonAxis("[Gender].[All Gender].LastSibling");
Assert.assertTrue(member.isAll());
}
public void testLastSiblingRoot() {
// The [Time] hierarchy does not have an 'all' member, so
// [1997], [1998] do not have parents.
Member member = executeSingletonAxis("[Time].[1998].LastSibling");
Assert.assertEquals("1998", member.getName());
}
public void testLastSiblingNull() {
Member member =
executeSingletonAxis("[Gender].[F].FirstChild.LastSibling");
Assert.assertNull(member);
}
public void testLead() {
Member member = executeSingletonAxis("[Time].[1997].[Q2].[4].Lead(4)");
Assert.assertEquals("8", member.getName());
}
public void testLeadNegative() {
Member member = executeSingletonAxis("[Gender].[M].Lead(-1)");
Assert.assertEquals("F", member.getName());
}
public void testLeadLastInLevel() {
Member member = executeSingletonAxis("[Gender].[M].Lead(3)");
Assert.assertNull(member);
}
public void testLeadNull() {
Member member = executeSingletonAxis("[Gender].Parent.Lead(1)");
Assert.assertNull(member);
}
public void testLeadZero() {
Member member = executeSingletonAxis("[Gender].[F].Lead(0)");
Assert.assertEquals("F", member.getName());
}
public void testBasic2() {
Result result =
executeQuery(
"select {[Gender].[F].NextMember} ON COLUMNS from Sales");
assertEquals(
"M",
result.getAxes()[0].getPositions().get(0).get(0).getName());
}
public void testFirstInLevel2() {
Result result =
executeQuery(
"select {[Gender].[M].NextMember} ON COLUMNS from Sales");
assertEquals(0, result.getAxes()[0].getPositions().size());
}
public void testAll2() {
Result result =
executeQuery("select {[Gender].PrevMember} ON COLUMNS from Sales");
// previous to [Gender].[All] is null, so no members are returned
assertEquals(0, result.getAxes()[0].getPositions().size());
}
public void testBasic5() {
Result result =
executeQuery(
"select{ [Product].[All Products].[Drink].Parent} on columns "
+ "from Sales");
assertEquals(
"All Products",
result.getAxes()[0].getPositions().get(0).get(0).getName());
}
public void testFirstInLevel5() {
Result result =
executeQuery(
"select {[Time].[1997].[Q2].[4].Parent} on columns,"
+ "{[Gender].[M]} on rows from Sales");
assertEquals(
"Q2",
result.getAxes()[0].getPositions().get(0).get(0).getName());
}
public void testAll5() {
Result result =
executeQuery(
"select {[Time].[1997].[Q2].Parent} on columns,"
+ "{[Gender].[M]} on rows from Sales");
// previous to [Gender].[All] is null, so no members are returned
assertEquals(
"1997",
result.getAxes()[0].getPositions().get(0).get(0).getName());
}
public void testBasic() {
Result result =
executeQuery(
"select {[Gender].[M].PrevMember} ON COLUMNS from Sales");
assertEquals(
"F",
result.getAxes()[0].getPositions().get(0).get(0).getName());
}
public void testFirstInLevel() {
Result result =
executeQuery(
"select {[Gender].[F].PrevMember} ON COLUMNS from Sales");
assertEquals(0, result.getAxes()[0].getPositions().size());
}
public void testAll() {
Result result =
executeQuery("select {[Gender].PrevMember} ON COLUMNS from Sales");
// previous to [Gender].[All] is null, so no members are returned
assertEquals(0, result.getAxes()[0].getPositions().size());
}
public void testAggregateDepends() {
// Depends on everything except Measures, Gender
String s12 = TestContext.allHiersExcept("[Measures]", "[Gender]");
getTestContext().assertExprDependsOn(
"([Measures].[Unit Sales], [Gender].[F])", s12);
// Depends on everything except Customers, Measures, Gender
String s13 = TestContext.allHiersExcept("[Customers]", "[Gender]");
getTestContext().assertExprDependsOn(
"Aggregate([Customers].Members, ([Measures].[Unit Sales], [Gender].[F]))",
s13);
// Depends on everything except Customers
String s11 = TestContext.allHiersExcept("[Customers]");
getTestContext().assertExprDependsOn(
"Aggregate([Customers].Members)",
s11);
// Depends on the current member of the Product dimension, even though
// [Product].[All Products] is referenced from the expression.
String s1 = TestContext.allHiersExcept("[Customers]");
getTestContext().assertExprDependsOn(
"Aggregate(Filter([Customers].[City].Members, (([Measures].[Unit Sales] / ([Measures].[Unit Sales], [Product].[All Products])) > 0.1)))",
s1);
}
public void testAggregate() {
assertQueryReturns(
"WITH MEMBER [Store].[CA plus OR] AS 'AGGREGATE({[Store].[USA].[CA], [Store].[USA].[OR]})'\n"
+ "SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,\n"
+ " {[Store].[USA].[CA], [Store].[USA].[OR], [Store].[CA plus OR]} ON ROWS\n"
+ "FROM Sales\n"
+ "WHERE ([1997].[Q1])",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[CA plus OR]}\n"
+ "Row #0: 16,890\n"
+ "Row #0: 36,175.20\n"
+ "Row #1: 19,287\n"
+ "Row #1: 40,170.29\n"
+ "Row #2: 36,177\n"
+ "Row #2: 76,345.49\n");
}
public void testAggregate2() {
assertQueryReturns(
"WITH\n"
+ " Member [Time].[Time].[1st Half Sales] AS 'Aggregate({Time.[1997].[Q1], Time.[1997].[Q2]})'\n"
+ " Member [Time].[Time].[2nd Half Sales] AS 'Aggregate({Time.[1997].[Q3], Time.[1997].[Q4]})'\n"
+ " Member [Time].[Time].[Difference] AS 'Time.[2nd Half Sales] - Time.[1st Half Sales]'\n"
+ "SELECT\n"
+ " { [Store].[Store State].Members} ON COLUMNS,\n"
+ " { Time.[1st Half Sales], Time.[2nd Half Sales], Time.[Difference]} ON ROWS\n"
+ "FROM Sales\n"
+ "WHERE [Measures].[Store Sales]",
"Axis #0:\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #1:\n"
+ "{[Store].[Canada].[BC]}\n"
+ "{[Store].[Mexico].[DF]}\n"
+ "{[Store].[Mexico].[Guerrero]}\n"
+ "{[Store].[Mexico].[Jalisco]}\n"
+ "{[Store].[Mexico].[Veracruz]}\n"
+ "{[Store].[Mexico].[Yucatan]}\n"
+ "{[Store].[Mexico].[Zacatecas]}\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "Axis #2:\n"
+ "{[Time].[1st Half Sales]}\n"
+ "{[Time].[2nd Half Sales]}\n"
+ "{[Time].[Difference]}\n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: 74,571.95\n"
+ "Row #0: 71,943.17\n"
+ "Row #0: 125,779.50\n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: 84,595.89\n"
+ "Row #1: 70,333.90\n"
+ "Row #1: 138,013.72\n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: 10,023.94\n"
+ "Row #2: -1,609.27\n"
+ "Row #2: 12,234.22\n");
}
public void testAggregateWithIIF() {
assertQueryReturns(
"with member store.foo as 'iif(3>1,"
+ "aggregate({[Store].[All Stores].[USA].[OR]}),"
+ "aggregate({[Store].[All Stores].[USA].[CA]}))' "
+ "select {store.foo} on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[foo]}\n"
+ "Row #0: 67,659\n");
}
public void testAggregate2AllMembers() {
assertQueryReturns(
"WITH\n"
+ " Member [Time].[Time].[1st Half Sales] AS 'Aggregate({Time.[1997].[Q1], Time.[1997].[Q2]})'\n"
+ " Member [Time].[Time].[2nd Half Sales] AS 'Aggregate({Time.[1997].[Q3], Time.[1997].[Q4]})'\n"
+ " Member [Time].[Time].[Difference] AS 'Time.[2nd Half Sales] - Time.[1st Half Sales]'\n"
+ "SELECT\n"
+ " { [Store].[Store State].AllMembers} ON COLUMNS,\n"
+ " { Time.[1st Half Sales], Time.[2nd Half Sales], Time.[Difference]} ON ROWS\n"
+ "FROM Sales\n"
+ "WHERE [Measures].[Store Sales]",
"Axis #0:\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #1:\n"
+ "{[Store].[Canada].[BC]}\n"
+ "{[Store].[Mexico].[DF]}\n"
+ "{[Store].[Mexico].[Guerrero]}\n"
+ "{[Store].[Mexico].[Jalisco]}\n"
+ "{[Store].[Mexico].[Veracruz]}\n"
+ "{[Store].[Mexico].[Yucatan]}\n"
+ "{[Store].[Mexico].[Zacatecas]}\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "Axis #2:\n"
+ "{[Time].[1st Half Sales]}\n"
+ "{[Time].[2nd Half Sales]}\n"
+ "{[Time].[Difference]}\n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: 74,571.95\n"
+ "Row #0: 71,943.17\n"
+ "Row #0: 125,779.50\n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: \n"
+ "Row #1: 84,595.89\n"
+ "Row #1: 70,333.90\n"
+ "Row #1: 138,013.72\n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: \n"
+ "Row #2: 10,023.94\n"
+ "Row #2: -1,609.27\n"
+ "Row #2: 12,234.22\n");
}
public void testAggregateToSimulateCompoundSlicer() {
assertQueryReturns(
"WITH MEMBER [Time].[Time].[1997 H1] as 'Aggregate({[Time].[1997].[Q1], [Time].[1997].[Q2]})'\n"
+ " MEMBER [Education Level].[College or higher] as 'Aggregate({[Education Level].[Bachelors Degree], [Education Level].[Graduate Degree]})'\n"
+ "SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} on columns,\n"
+ " {[Product].children} on rows\n"
+ "FROM [Sales]\n"
+ "WHERE ([Time].[1997 H1], [Education Level].[College or higher], [Gender].[F])",
"Axis #0:\n"
+ "{[Time].[1997 H1], [Education Level].[College or higher], [Gender].[F]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Food]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: 1,797\n"
+ "Row #0: 3,620.49\n"
+ "Row #1: 15,002\n"
+ "Row #1: 31,931.88\n"
+ "Row #2: 3,845\n"
+ "Row #2: 8,173.22\n");
}
/**
* Tests behavior where CurrentMember occurs in calculated members and
* that member is a set.
*
* <p>Mosha discusses this behavior in the article
* <a href="http://www.mosha.com/msolap/articles/mdxmultiselectcalcs.htm">
* Multiselect friendly MDX calculations</a>.
*
* <p>Mondrian's behavior is consistent with MSAS 2K: it returns zeroes.
* SSAS 2005 returns an error, which can be fixed by reformulating the
* calculated members.
*
* @see mondrian.rolap.FastBatchingCellReaderTest#testAggregateDistinctCount()
*/
public void testMultiselectCalculations() {
assertQueryReturns(
"WITH\n"
+ "MEMBER [Measures].[Declining Stores Count] AS\n"
+ " ' Count(Filter(Descendants(Store.CurrentMember, Store.[Store Name]), [Store Sales] < ([Store Sales],Time.Time.PrevMember))) '\n"
+ " MEMBER \n"
+ " [Store].[XL_QZX] AS 'Aggregate ({ [Store].[All Stores].[USA].[WA] , [Store].[All Stores].[USA].[CA] })' \n"
+ "SELECT \n"
+ " NON EMPTY HIERARCHIZE(AddCalculatedMembers({DrillDownLevel({[Product].[All Products]})})) \n"
+ " DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON COLUMNS \n"
+ "FROM [Sales] \n"
+ "WHERE ([Measures].[Declining Stores Count], [Time].[1998].[Q3], [Store].[XL_QZX])",
"Axis #0:\n"
+ "{[Measures].[Declining Stores Count], [Time].[1998].[Q3], [Store].[XL_QZX]}\n"
+ "Axis #1:\n"
+ "{[Product].[All Products]}\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Food]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: .00\n"
+ "Row #0: .00\n"
+ "Row #0: .00\n"
+ "Row #0: .00\n");
}
public void testAvg() {
assertExprReturns(
"AVG({[Store].[All Stores].[USA].children},[Measures].[Store Sales])",
"188,412.71");
}
// todo: testAvgWithNulls
public void testCorrelation() {
assertExprReturns(
"Correlation({[Store].[All Stores].[USA].children}, [Measures].[Unit Sales], [Measures].[Store Sales]) * 1000000",
"999,906");
}
public void testCount() {
getTestContext().assertExprDependsOn(
"count(Crossjoin([Store].[All Stores].[USA].Children, {[Gender].children}), INCLUDEEMPTY)",
"{[Gender]}");
String s1 = TestContext.allHiersExcept("[Store]");
getTestContext().assertExprDependsOn(
"count(Crossjoin([Store].[All Stores].[USA].Children, "
+ "{[Gender].children}), EXCLUDEEMPTY)",
s1);
assertExprReturns(
"count({[Promotion Media].[Media Type].members})", "14");
// applied to an empty set
assertExprReturns("count({[Gender].Parent}, IncludeEmpty)", "0");
}
public void testCountExcludeEmpty() {
String s1 = TestContext.allHiersExcept("[Store]");
getTestContext().assertExprDependsOn(
"count(Crossjoin([Store].[USA].Children, {[Gender].children}), EXCLUDEEMPTY)",
s1);
assertQueryReturns(
"with member [Measures].[Promo Count] as \n"
+ " ' Count(Crossjoin({[Measures].[Unit Sales]},\n"
+ " {[Promotion Media].[Media Type].members}), EXCLUDEEMPTY)'\n"
+ "select {[Measures].[Unit Sales], [Measures].[Promo Count]} on columns,\n"
+ " {[Product].[Drink].[Beverages].[Carbonated Beverages].[Soda].children} on rows\n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Promo Count]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Beverages].[Carbonated Beverages].[Soda].[Excellent]}\n"
+ "{[Product].[Drink].[Beverages].[Carbonated Beverages].[Soda].[Fabulous]}\n"
+ "{[Product].[Drink].[Beverages].[Carbonated Beverages].[Soda].[Skinner]}\n"
+ "{[Product].[Drink].[Beverages].[Carbonated Beverages].[Soda].[Token]}\n"
+ "{[Product].[Drink].[Beverages].[Carbonated Beverages].[Soda].[Washington]}\n"
+ "Row #0: 738\n"
+ "Row #0: 14\n"
+ "Row #1: 632\n"
+ "Row #1: 13\n"
+ "Row #2: 655\n"
+ "Row #2: 14\n"
+ "Row #3: 735\n"
+ "Row #3: 14\n"
+ "Row #4: 647\n"
+ "Row #4: 12\n");
// applied to an empty set
assertExprReturns("count({[Gender].Parent}, ExcludeEmpty)", "0");
}
/**
* Tests that the 'null' value is regarded as empty, even if the underlying
* cell has fact table rows.
*
* <p>For a fuller test case, see
* {@link mondrian.xmla.XmlaCognosTest#testCognosMDXSuiteConvertedAdventureWorksToFoodMart_015()}
*/
public void testCountExcludeEmptyNull() {
assertQueryReturns(
"WITH MEMBER [Measures].[Foo] AS\n"
+ " Iif("
+ TestContext.hierarchyName("Time", "Time")
+ ".CurrentMember.Name = 'Q2', 1, NULL)\n"
+ " MEMBER [Measures].[Bar] AS\n"
+ " Iif("
+ TestContext.hierarchyName("Time", "Time")
+ ".CurrentMember.Name = 'Q2', 1, 0)\n"
+ " Member [Time].[Time].[CountExc] AS\n"
+ " Count([Time].[1997].Children, EXCLUDEEMPTY),\n"
+ " SOLVE_ORDER = 2\n"
+ " Member [Time].[Time].[CountInc] AS\n"
+ " Count([Time].[1997].Children, INCLUDEEMPTY),\n"
+ " SOLVE_ORDER = 2\n"
+ "SELECT {[Measures].[Foo],\n"
+ " [Measures].[Bar],\n"
+ " [Measures].[Unit Sales]} ON 0,\n"
+ " {[Time].[1997].Children,\n"
+ " [Time].[CountExc],\n"
+ " [Time].[CountInc]} ON 1\n"
+ "FROM [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "{[Measures].[Bar]}\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q3]}\n"
+ "{[Time].[1997].[Q4]}\n"
+ "{[Time].[CountExc]}\n"
+ "{[Time].[CountInc]}\n"
+ "Row #0: \n"
+ "Row #0: 0\n"
+ "Row #0: 66,291\n"
+ "Row #1: 1\n"
+ "Row #1: 1\n"
+ "Row #1: 62,610\n"
+ "Row #2: \n"
+ "Row #2: 0\n"
+ "Row #2: 65,848\n"
+ "Row #3: \n"
+ "Row #3: 0\n"
+ "Row #3: 72,024\n"
+ "Row #4: 1\n"
+ "Row #4: 4\n"
+ "Row #4: 4\n"
+ "Row #5: 4\n"
+ "Row #5: 4\n"
+ "Row #5: 4\n");
}
/**
* Testcase for
* <a href="http://jira.pentaho.com/browse/MONDRIAN-710">
* bug MONDRIAN-710, "Count with ExcludeEmpty throws an exception when the
* cube does not have a factCountMeasure"</a>.
*/
public void testCountExcludeEmptyOnCubeWithNoCountFacts() {
assertQueryReturns(
"WITH "
+ " MEMBER [Measures].[count] AS '"
+ " COUNT([Store Type].[Store Type].MEMBERS, EXCLUDEEMPTY)'"
+ " SELECT "
+ " {[Measures].[count]} ON AXIS(0)"
+ " FROM [Warehouse]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[count]}\n"
+ "Row #0: 5\n");
}
public void testCountExcludeEmptyOnVirtualCubeWithNoCountFacts() {
assertQueryReturns(
"WITH "
+ " MEMBER [Measures].[count] AS '"
+ " COUNT([Store].MEMBERS, EXCLUDEEMPTY)'"
+ " SELECT "
+ " {[Measures].[count]} ON AXIS(0)"
+ " FROM [Warehouse and Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[count]}\n"
+ "Row #0: 31\n");
}
// todo: testCountNull, testCountNoExp
public void testCovariance() {
assertExprReturns(
"Covariance({[Store].[All Stores].[USA].children}, [Measures].[Unit Sales], [Measures].[Store Sales])",
"1,355,761,899");
}
public void testCovarianceN() {
assertExprReturns(
"CovarianceN({[Store].[All Stores].[USA].children}, [Measures].[Unit Sales], [Measures].[Store Sales])",
"2,033,642,849");
}
public void testIIfNumeric() {
assertExprReturns(
"IIf(([Measures].[Unit Sales],[Product].[Drink].[Alcoholic Beverages].[Beer and Wine]) > 100, 45, 32)",
"45");
// Compare two members. The system needs to figure out that they are
// both numeric, and use the right overloaded version of ">", otherwise
// we'll get a ClassCastException at runtime.
assertExprReturns(
"IIf([Measures].[Unit Sales] > [Measures].[Store Sales], 45, 32)",
"32");
}
public void testMax() {
assertExprReturns(
"MAX({[Store].[All Stores].[USA].children},[Measures].[Store Sales])",
"263,793.22");
}
public void testMaxNegative() {
// Bug 1771928, "Max() works incorrectly with negative values"
assertQueryReturns(
"with \n"
+ " member [Customers].[Neg] as '-1'\n"
+ " member [Customers].[Min] as 'Min({[Customers].[Neg]})'\n"
+ " member [Customers].[Max] as 'Max({[Customers].[Neg]})'\n"
+ "select {[Customers].[Neg],[Customers].[Min],[Customers].[Max]} on 0\n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[Neg]}\n"
+ "{[Customers].[Min]}\n"
+ "{[Customers].[Max]}\n"
+ "Row #0: -1\n"
+ "Row #0: -1\n"
+ "Row #0: -1\n");
}
public void testMedian() {
assertExprReturns(
"MEDIAN({[Store].[All Stores].[USA].children},"
+ "[Measures].[Store Sales])",
"159,167.84");
// single value
assertExprReturns(
"MEDIAN({[Store].[All Stores].[USA]}, [Measures].[Store Sales])",
"565,238.13");
}
public void testMedian2() {
assertQueryReturns(
"WITH\n"
+ " Member [Time].[Time].[1st Half Sales] AS 'Sum({[Time].[1997].[Q1], [Time].[1997].[Q2]})'\n"
+ " Member [Time].[Time].[2nd Half Sales] AS 'Sum({[Time].[1997].[Q3], [Time].[1997].[Q4]})'\n"
+ " Member [Time].[Time].[Median] AS 'Median(Time.[Time].Members)'\n"
+ "SELECT\n"
+ " NON EMPTY { [Store].[Store Name].Members} ON COLUMNS,\n"
+ " { [Time].[1st Half Sales], [Time].[2nd Half Sales], [Time].[Median]} ON ROWS\n"
+ "FROM Sales\n"
+ "WHERE [Measures].[Store Sales]",
"Axis #0:\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA].[Beverly Hills].[Store 6]}\n"
+ "{[Store].[USA].[CA].[Los Angeles].[Store 7]}\n"
+ "{[Store].[USA].[CA].[San Diego].[Store 24]}\n"
+ "{[Store].[USA].[CA].[San Francisco].[Store 14]}\n"
+ "{[Store].[USA].[OR].[Portland].[Store 11]}\n"
+ "{[Store].[USA].[OR].[Salem].[Store 13]}\n"
+ "{[Store].[USA].[WA].[Bellingham].[Store 2]}\n"
+ "{[Store].[USA].[WA].[Bremerton].[Store 3]}\n"
+ "{[Store].[USA].[WA].[Seattle].[Store 15]}\n"
+ "{[Store].[USA].[WA].[Spokane].[Store 16]}\n"
+ "{[Store].[USA].[WA].[Tacoma].[Store 17]}\n"
+ "{[Store].[USA].[WA].[Walla Walla].[Store 22]}\n"
+ "{[Store].[USA].[WA].[Yakima].[Store 23]}\n"
+ "Axis #2:\n"
+ "{[Time].[1st Half Sales]}\n"
+ "{[Time].[2nd Half Sales]}\n"
+ "{[Time].[Median]}\n"
+ "Row #0: 20,801.04\n"
+ "Row #0: 25,421.41\n"
+ "Row #0: 26,275.11\n"
+ "Row #0: 2,074.39\n"
+ "Row #0: 28,519.18\n"
+ "Row #0: 43,423.99\n"
+ "Row #0: 2,140.99\n"
+ "Row #0: 25,502.08\n"
+ "Row #0: 25,293.50\n"
+ "Row #0: 23,265.53\n"
+ "Row #0: 34,926.91\n"
+ "Row #0: 2,159.60\n"
+ "Row #0: 12,490.89\n"
+ "Row #1: 24,949.20\n"
+ "Row #1: 29,123.87\n"
+ "Row #1: 28,156.03\n"
+ "Row #1: 2,366.79\n"
+ "Row #1: 26,539.61\n"
+ "Row #1: 43,794.29\n"
+ "Row #1: 2,598.24\n"
+ "Row #1: 27,394.22\n"
+ "Row #1: 27,350.57\n"
+ "Row #1: 26,368.93\n"
+ "Row #1: 39,917.05\n"
+ "Row #1: 2,546.37\n"
+ "Row #1: 11,838.34\n"
+ "Row #2: 4,577.35\n"
+ "Row #2: 5,211.38\n"
+ "Row #2: 4,722.87\n"
+ "Row #2: 398.24\n"
+ "Row #2: 5,039.50\n"
+ "Row #2: 7,374.59\n"
+ "Row #2: 410.22\n"
+ "Row #2: 4,924.04\n"
+ "Row #2: 4,569.13\n"
+ "Row #2: 4,511.68\n"
+ "Row #2: 6,630.91\n"
+ "Row #2: 419.51\n"
+ "Row #2: 2,169.48\n");
}
public void testPercentile() {
// same result as median
assertExprReturns(
"Percentile({[Store].[All Stores].[USA].children}, [Measures].[Store Sales], 50)",
"159,167.84");
// same result as min
assertExprReturns(
"Percentile({[Store].[All Stores].[USA].children}, [Measures].[Store Sales], 0)",
"142,277.07");
// same result as max
assertExprReturns(
"Percentile({[Store].[All Stores].[USA].children}, [Measures].[Store Sales], 100)",
"263,793.22");
// check some real percentile cases
assertExprReturns(
"Percentile({[Store].[All Stores].[USA].[WA].children}, [Measures].[Store Sales], 50)",
"49,634.46");
// lets return the second element of the 7 children 4,739.23
assertExprReturns(
"Percentile({[Store].[All Stores].[USA].[WA].children}, [Measures].[Store Sales], 100/7*2)",
"4,739.23");
assertExprReturns(
"Percentile({[Store].[All Stores].[USA].[WA].children}, [Measures].[Store Sales], 95)",
"67,162.28");
}
/**
* Testcase for bug
* <a href="http://jira.pentaho.com/browse/MONDRIAN-1045">MONDRIAN-1045,
* "When I use the Percentile function it cracks when there's only
* 1 register"</a>.
*/
public void testPercentileBugMondrian1045() {
assertExprReturns(
"Percentile({[Store].[All Stores].[USA]}, [Measures].[Store Sales], 50)",
"565,238.13");
assertExprReturns(
"Percentile({[Store].[All Stores].[USA]}, [Measures].[Store Sales], 40)",
"565,238.13");
assertExprReturns(
"Percentile({[Store].[All Stores].[USA]}, [Measures].[Store Sales], 95)",
"565,238.13");
}
public void testMin() {
assertExprReturns(
"MIN({[Store].[All Stores].[USA].children},[Measures].[Store Sales])",
"142,277.07");
}
public void testMinTuple() {
assertExprReturns(
"Min([Customers].[All Customers].[USA].Children, ([Measures].[Unit Sales], [Gender].[All Gender].[F]))",
"33,036");
}
public void testStdev() {
assertExprReturns(
"STDEV({[Store].[All Stores].[USA].children},[Measures].[Store Sales])",
"65,825.45");
}
public void testStdevP() {
assertExprReturns(
"STDEVP({[Store].[All Stores].[USA].children},[Measures].[Store Sales])",
"53,746.26");
}
public void testSumNoExp() {
assertExprReturns(
"SUM({[Promotion Media].[Media Type].members})", "266,773");
}
public void testValue() {
// VALUE is usually a cell property, not a member property.
// We allow it because MS documents it as a function, <Member>.VALUE.
assertExprReturns("[Measures].[Store Sales].VALUE", "565,238.13");
// Depends upon almost everything.
String s1 = TestContext.allHiersExcept("[Measures]");
getTestContext().assertExprDependsOn(
"[Measures].[Store Sales].VALUE", s1);
// We do not allow FORMATTED_VALUE.
assertExprThrows(
"[Measures].[Store Sales].FORMATTED_VALUE",
"MDX object '[Measures].[Store Sales].FORMATTED_VALUE' not found in cube 'Sales'");
assertExprReturns("[Measures].[Store Sales].NAME", "Store Sales");
// MS says that ID and KEY are standard member properties for
// OLE DB for OLAP, but not for XML/A. We don't support them.
assertExprThrows(
"[Measures].[Store Sales].ID",
"MDX object '[Measures].[Store Sales].ID' not found in cube 'Sales'");
// Error for KEY is slightly different than for ID. It doesn't matter
// very much.
//
// The error is different because KEY is registered as a Mondrian
// builtin property, but ID isn't. KEY cannot be evaluated in
// "<MEMBER>.KEY" syntax because there is not function defined. For
// other builtin properties, such as NAME, CAPTION there is a builtin
// function.
assertExprThrows(
"[Measures].[Store Sales].KEY",
"No function matches signature '<Member>.KEY'");
assertExprReturns("[Measures].[Store Sales].CAPTION", "Store Sales");
}
public void testVar() {
assertExprReturns(
"VAR({[Store].[All Stores].[USA].children},[Measures].[Store Sales])",
"4,332,990,493.69");
}
public void testVarP() {
assertExprReturns(
"VARP({[Store].[All Stores].[USA].children},[Measures].[Store Sales])",
"2,888,660,329.13");
}
/**
* Tests the AS operator, that gives an expression an alias.
*/
public void testAs() {
assertAxisReturns(
"Filter([Customers].Children as t,\n"
+ "t.Current.Name = 'USA')",
"[Customers].[USA]");
// 'AS' and the ':' operator have similar precedence, so it's worth
// checking that they play nice.
assertQueryReturns(
"select\n"
+ " filter(\n"
+ " [Time].[1997].[Q1].[2] : [Time].[1997].[Q3].[9] as t,"
+ " mod(t.CurrentOrdinal, 2) = 0) on 0\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997].[Q1].[2]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "Row #0: 20,957\n"
+ "Row #0: 20,179\n"
+ "Row #0: 21,350\n"
+ "Row #0: 21,697\n");
// AS member fails on SSAS with "The CHILDREN function expects a member
// expression for the 0 argument. A tuple set expression was used."
assertQueryThrows(
"select\n"
+ " {([Time].[1997].[Q1] as t).Children, \n"
+ " t.Parent } on 0 \n"
+ "from [Sales]",
"No function matches signature '<Set>.Children'");
// Set of members. OK.
assertQueryReturns(
"select Measures.[Unit Sales] on 0, \n"
+ " {[Time].[1997].Children as t, \n"
+ " Descendants(t, [Time].[Month])} on 1 \n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q3]}\n"
+ "{[Time].[1997].[Q4]}\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q1].[2]}\n"
+ "{[Time].[1997].[Q1].[3]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q3].[7]}\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "{[Time].[1997].[Q3].[9]}\n"
+ "{[Time].[1997].[Q4].[10]}\n"
+ "{[Time].[1997].[Q4].[11]}\n"
+ "{[Time].[1997].[Q4].[12]}\n"
+ "Row #0: 66,291\n"
+ "Row #1: 62,610\n"
+ "Row #2: 65,848\n"
+ "Row #3: 72,024\n"
+ "Row #4: 21,628\n"
+ "Row #5: 20,957\n"
+ "Row #6: 23,706\n"
+ "Row #7: 20,179\n"
+ "Row #8: 21,081\n"
+ "Row #9: 21,350\n"
+ "Row #10: 23,763\n"
+ "Row #11: 21,697\n"
+ "Row #12: 20,388\n"
+ "Row #13: 19,958\n"
+ "Row #14: 25,270\n"
+ "Row #15: 26,796\n");
// Alias a member. Implicitly becomes set. OK.
assertQueryReturns(
"select Measures.[Unit Sales] on 0,\n"
+ " {[Time].[1997] as t,\n"
+ " Descendants(t, [Time].[Month])} on 1\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997]}\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q1].[2]}\n"
+ "{[Time].[1997].[Q1].[3]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q3].[7]}\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "{[Time].[1997].[Q3].[9]}\n"
+ "{[Time].[1997].[Q4].[10]}\n"
+ "{[Time].[1997].[Q4].[11]}\n"
+ "{[Time].[1997].[Q4].[12]}\n"
+ "Row #0: 266,773\n"
+ "Row #1: 21,628\n"
+ "Row #2: 20,957\n"
+ "Row #3: 23,706\n"
+ "Row #4: 20,179\n"
+ "Row #5: 21,081\n"
+ "Row #6: 21,350\n"
+ "Row #7: 23,763\n"
+ "Row #8: 21,697\n"
+ "Row #9: 20,388\n"
+ "Row #10: 19,958\n"
+ "Row #11: 25,270\n"
+ "Row #12: 26,796\n");
// Alias a tuple. Implicitly becomes set. The error confirms that the
// named set's type is a set of tuples. SSAS gives error "Descendants
// function expects a member or set ..."
assertQueryThrows(
"select Measures.[Unit Sales] on 0,\n"
+ " {([Time].[1997], [Customers].[USA].[CA]) as t,\n"
+ " Descendants(t, [Time].[Month])} on 1\n"
+ "from [Sales]",
"Argument to Descendants function must be a member or set of members, not a set of tuples");
}
public void testAs2() {
// Named set and alias with same name (t) and a second alias (t2).
// Reference to t from within descendants resolves to alias, of type
// [Time], because it is nearer.
final String result =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales], [Gender].[F]}\n"
+ "{[Measures].[Unit Sales], [Gender].[M]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q3]}\n"
+ "{[Time].[1997].[Q4]}\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q4].[11]}\n"
+ "Row #0: 32,910\n"
+ "Row #0: 33,381\n"
+ "Row #1: 30,992\n"
+ "Row #1: 31,618\n"
+ "Row #2: 32,599\n"
+ "Row #2: 33,249\n"
+ "Row #3: 35,057\n"
+ "Row #3: 36,967\n"
+ "Row #4: 10,932\n"
+ "Row #4: 10,696\n"
+ "Row #5: 10,466\n"
+ "Row #5: 10,884\n"
+ "Row #6: 12,320\n"
+ "Row #6: 12,950\n";
assertQueryReturns(
"with set t as [Gender].Children\n"
+ "select\n"
+ " Measures.[Unit Sales] * t on 0,\n"
+ " {\n"
+ " [Time].[1997].Children as t,\n"
+ " Filter(\n"
+ " Descendants(t, [Time].[Month]) as t2,\n"
+ " Mod(t2.CurrentOrdinal, 5) = 0)\n"
+ " } on 1\n"
+ "from [Sales]",
result);
// Two aliases with same name. OK.
assertQueryReturns(
"select\n"
+ " Measures.[Unit Sales] * [Gender].Children as t on 0,\n"
+ " {[Time].[1997].Children as t,\n"
+ " Filter(\n"
+ " Descendants(t, [Time].[Month]) as t2,\n"
+ " Mod(t2.CurrentOrdinal, 5) = 0)\n"
+ " } on 1\n"
+ "from [Sales]",
result);
// Bug MONDRIAN-648 causes 'AS' to have lower precedence than '*'.
if (Bug.BugMondrian648Fixed) {
// Note that 'as' has higher precedence than '*'.
assertQueryReturns(
"select\n"
+ " Measures.[Unit Sales] * [Gender].Members as t on 0,\n"
+ " {t} on 1\n"
+ "from [Sales]",
"xxxxx");
}
// Reference to hierarchy on other axis.
// On SSAS 2005, finds t, and gives error,
// "The Gender hierarchy already appears in the Axis0 axis."
// On Mondrian, cannot find t. FIXME.
assertQueryThrows(
"select\n"
+ " Measures.[Unit Sales] * ([Gender].Members as t) on 0,\n"
+ " {t} on 1\n"
+ "from [Sales]",
"MDX object 't' not found in cube 'Sales'");
// As above, with parentheses. Tuple valued.
// On SSAS 2005, finds t, and gives error,
// "The Measures hierarchy already appears in the Axis0 axis."
// On Mondrian, cannot find t. FIXME.
assertQueryThrows(
"select\n"
+ " (Measures.[Unit Sales] * [Gender].Members) as t on 0,\n"
+ " {t} on 1\n"
+ "from [Sales]",
"MDX object 't' not found in cube 'Sales'");
// Calculated set, CurrentMember
assertQueryReturns(
"select Measures.[Unit Sales] on 0,\n"
+ " filter(\n"
+ " (Time.Month.Members * Gender.Members) as s,\n"
+ " (s.Current.Item(0).Parent, [Marital Status].[S], [Gender].[F]) > 17000) on 1\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[M]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[M]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[M]}\n"
+ "Row #0: 19,958\n"
+ "Row #1: 9,506\n"
+ "Row #2: 10,452\n"
+ "Row #3: 25,270\n"
+ "Row #4: 12,320\n"
+ "Row #5: 12,950\n"
+ "Row #6: 26,796\n"
+ "Row #7: 13,231\n"
+ "Row #8: 13,565\n");
// As above, but don't override [Gender] in filter condition. Note that
// the filter condition is evaluated in the context created by the
// filter set. So, only items with [All Gender] pass the filter.
assertQueryReturns(
"select Measures.[Unit Sales] on 0,\n"
+ " filter(\n"
+ " (Time.Month.Members * Gender.Members) as s,\n"
+ " (s.Current.Item(0).Parent, [Marital Status].[S]) > 35000) on 1\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[All Gender]}\n"
+ "Row #0: 19,958\n"
+ "Row #1: 25,270\n"
+ "Row #2: 26,796\n");
// Multiple definitions of alias within same axis
assertQueryReturns(
"select Measures.[Unit Sales] on 0,\n"
+ " generate(\n"
+ " [Marital Status].Children as s,\n"
+ " filter(\n"
+ " (Time.Month.Members * Gender.Members) as s,\n"
+ " (s.Current.Item(0).Parent, [Marital Status].[S], [Gender].[F]) > 17000),\n"
+ " ALL) on 1\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[M]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[M]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[M]}\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[10], [Gender].[M]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[11], [Gender].[M]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[All Gender]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[F]}\n"
+ "{[Time].[1997].[Q4].[12], [Gender].[M]}\n"
+ "Row #0: 19,958\n"
+ "Row #1: 9,506\n"
+ "Row #2: 10,452\n"
+ "Row #3: 25,270\n"
+ "Row #4: 12,320\n"
+ "Row #5: 12,950\n"
+ "Row #6: 26,796\n"
+ "Row #7: 13,231\n"
+ "Row #8: 13,565\n"
+ "Row #9: 19,958\n"
+ "Row #10: 9,506\n"
+ "Row #11: 10,452\n"
+ "Row #12: 25,270\n"
+ "Row #13: 12,320\n"
+ "Row #14: 12,950\n"
+ "Row #15: 26,796\n"
+ "Row #16: 13,231\n"
+ "Row #17: 13,565\n");
// Multiple definitions of alias within same axis.
//
// On SSAS 2005, gives error, "The CURRENT function cannot be called in
// current context because the 'x' set is not in scope". SSAS 2005 gives
// same error even if set does not exist.
assertQueryThrows(
"with member Measures.Foo as 'x.Current.Name'\n"
+ "select\n"
+ " {Measures.[Unit Sales], Measures.Foo} on 0,\n"
+ " generate(\n"
+ " [Marital Status].\n"
+ " Children as x,\n"
+ " filter(\n"
+ " Gender.Members as x,\n"
+ " (x.Current, [Marital Status].[S]) > 50000),\n"
+ " ALL) on 1\n"
+ "from [Sales]",
"MDX object 'x' not found in cube 'Sales'");
// As above, but set is not out of scope; it does not exist; but error
// should be the same.
assertQueryThrows(
"with member Measures.Foo as 'z.Current.Name'\n"
+ "select\n"
+ " {Measures.[Unit Sales], Measures.Foo} on 0,\n"
+ " generate(\n"
+ " [Marital Status].\n"
+ " Children as s,\n"
+ " filter(\n"
+ " Gender.Members as s,\n"
+ " (s.Current, [Marital Status].[S]) > 50000),\n"
+ " ALL) on 1\n"
+ "from [Sales]",
"MDX object 'z' not found in cube 'Sales'");
// 'set AS string' is invalid
assertQueryThrows(
"select Measures.[Unit Sales] on 0,\n"
+ " filter(\n"
+ " (Time.Month.Members * Gender.Members) as 'foo',\n"
+ " (s.Current.Item(0).Parent, [Marital Status].[S]) > 50000) on 1\n"
+ "from [Sales]",
"Syntax error at line 3, column 46, token ''foo''");
// 'set AS numeric' is invalid
assertQueryThrows(
"select Measures.[Unit Sales] on 0,\n"
+ " filter(\n"
+ " (Time.Month.Members * Gender.Members) as 1234,\n"
+ " (s.Current.Item(0).Parent, [Marital Status].[S]) > 50000) on 1\n"
+ "from [Sales]",
"Syntax error at line 3, column 46, token '1234'");
// 'numeric AS identifier' is invalid
assertQueryThrows(
"select Measures.[Unit Sales] on 0,\n"
+ " filter(\n"
+ " 123 * 456 as s,\n"
+ " (s.Current.Item(0).Parent, [Marital Status].[S]) > 50000) on 1\n"
+ "from [Sales]",
"No function matches signature '<Numeric Expression> AS <Set>'");
}
public void testAscendants() {
assertAxisReturns(
"Ascendants([Store].[USA].[CA])",
"[Store].[USA].[CA]\n"
+ "[Store].[USA]\n"
+ "[Store].[All Stores]");
}
public void testAscendantsAll() {
assertAxisReturns(
"Ascendants([Store].DefaultMember)", "[Store].[All Stores]");
}
public void testAscendantsNull() {
assertAxisReturns(
"Ascendants([Gender].[F].PrevMember)", "");
}
public void testBottomCount() {
assertAxisReturns(
"BottomCount({[Promotion Media].[Media Type].members}, 2, [Measures].[Unit Sales])",
"[Promotion Media].[Radio]\n"
+ "[Promotion Media].[Sunday Paper, Radio, TV]");
}
// todo: test unordered
public void testBottomPercent() {
assertAxisReturns(
"BottomPercent(Filter({[Store].[All Stores].[USA].[CA].Children, [Store].[All Stores].[USA].[OR].Children, [Store].[All Stores].[USA].[WA].Children}, ([Measures].[Unit Sales] > 0.0)), 100.0, [Measures].[Store Sales])",
"[Store].[USA].[CA].[San Francisco]\n"
+ "[Store].[USA].[WA].[Walla Walla]\n"
+ "[Store].[USA].[WA].[Bellingham]\n"
+ "[Store].[USA].[WA].[Yakima]\n"
+ "[Store].[USA].[CA].[Beverly Hills]\n"
+ "[Store].[USA].[WA].[Spokane]\n"
+ "[Store].[USA].[WA].[Seattle]\n"
+ "[Store].[USA].[WA].[Bremerton]\n"
+ "[Store].[USA].[CA].[San Diego]\n"
+ "[Store].[USA].[CA].[Los Angeles]\n"
+ "[Store].[USA].[OR].[Portland]\n"
+ "[Store].[USA].[WA].[Tacoma]\n"
+ "[Store].[USA].[OR].[Salem]");
assertAxisReturns(
"BottomPercent({[Promotion Media].[Media Type].members}, 1, [Measures].[Unit Sales])",
"[Promotion Media].[Radio]\n"
+ "[Promotion Media].[Sunday Paper, Radio, TV]");
}
// todo: test precision
public void testBottomSum() {
assertAxisReturns(
"BottomSum({[Promotion Media].[Media Type].members}, 5000, [Measures].[Unit Sales])",
"[Promotion Media].[Radio]\n"
+ "[Promotion Media].[Sunday Paper, Radio, TV]");
}
public void testExceptEmpty() {
// If left is empty, result is empty.
assertAxisReturns(
"Except(Filter([Gender].Members, 1=0), {[Gender].[M]})", "");
// If right is empty, result is left.
assertAxisReturns(
"Except({[Gender].[M]}, Filter([Gender].Members, 1=0))",
"[Gender].[M]");
}
/**
* Tests that Except() successfully removes crossjoined tuples
* from the axis results. Previously, this would fail by returning
* all tuples in the first argument to Except. bug 1439627
*/
public void testExceptCrossjoin() {
assertAxisReturns(
"Except(CROSSJOIN({[Promotion Media].[All Media]},\n"
+ " [Product].[All Products].Children),\n"
+ " CROSSJOIN({[Promotion Media].[All Media]},\n"
+ " {[Product].[All Products].[Drink]}))",
"{[Promotion Media].[All Media], [Product].[Food]}\n"
+ "{[Promotion Media].[All Media], [Product].[Non-Consumable]}");
}
public void testExtract() {
assertAxisReturns(
"Extract(\n"
+ "Crossjoin({[Gender].[F], [Gender].[M]},\n"
+ " {[Marital Status].Members}),\n"
+ "[Gender])",
"[Gender].[F]\n" + "[Gender].[M]");
// Extract(<set>) with no dimensions is not valid
assertAxisThrows(
"Extract(Crossjoin({[Gender].[F], [Gender].[M]}, {[Marital Status].Members}))",
"No function matches signature 'Extract(<Set>)'");
// Extract applied to non-constant dimension should fail
assertAxisThrows(
"Extract(Crossjoin([Gender].Members, [Store].Children), [Store].Hierarchy.Dimension)",
"not a constant hierarchy: [Store].Hierarchy.Dimension");
// Extract applied to non-constant hierarchy should fail
assertAxisThrows(
"Extract(Crossjoin([Gender].Members, [Store].Children), [Store].Hierarchy)",
"not a constant hierarchy: [Store].Hierarchy");
// Extract applied to set of members is OK (if silly). Duplicates are
// removed, as always.
assertAxisReturns(
"Extract({[Gender].[M], [Gender].Members}, [Gender])",
"[Gender].[M]\n"
+ "[Gender].[All Gender]\n"
+ "[Gender].[F]");
// Extract of hierarchy not in set fails
assertAxisThrows(
"Extract(Crossjoin([Gender].Members, [Store].Children), [Marital Status])",
"hierarchy [Marital Status] is not a hierarchy of the expression Crossjoin([Gender].Members, [Store].Children)");
// Extract applied to empty set returns empty set
assertAxisReturns(
"Extract(Crossjoin({[Gender].Parent}, [Store].Children), [Store])",
"");
// Extract applied to asymmetric set
assertAxisReturns(
"Extract(\n"
+ "{([Gender].[M], [Marital Status].[M]),\n"
+ " ([Gender].[F], [Marital Status].[M]),\n"
+ " ([Gender].[M], [Marital Status].[S])},\n"
+ "[Gender])",
"[Gender].[M]\n" + "[Gender].[F]");
// Extract applied to asymmetric set (other side)
assertAxisReturns(
"Extract(\n"
+ "{([Gender].[M], [Marital Status].[M]),\n"
+ " ([Gender].[F], [Marital Status].[M]),\n"
+ " ([Gender].[M], [Marital Status].[S])},\n"
+ "[Marital Status])",
"[Marital Status].[M]\n"
+ "[Marital Status].[S]");
// Extract more than one hierarchy
assertAxisReturns(
"Extract(\n"
+ "[Gender].Children * [Marital Status].Children * [Time].[1997].Children * [Store].[USA].Children,\n"
+ "[Time], [Marital Status])",
"{[Time].[1997].[Q1], [Marital Status].[M]}\n"
+ "{[Time].[1997].[Q2], [Marital Status].[M]}\n"
+ "{[Time].[1997].[Q3], [Marital Status].[M]}\n"
+ "{[Time].[1997].[Q4], [Marital Status].[M]}\n"
+ "{[Time].[1997].[Q1], [Marital Status].[S]}\n"
+ "{[Time].[1997].[Q2], [Marital Status].[S]}\n"
+ "{[Time].[1997].[Q3], [Marital Status].[S]}\n"
+ "{[Time].[1997].[Q4], [Marital Status].[S]}");
// Extract duplicate hierarchies fails
assertAxisThrows(
"Extract(\n"
+ "{([Gender].[M], [Marital Status].[M]),\n"
+ " ([Gender].[F], [Marital Status].[M]),\n"
+ " ([Gender].[M], [Marital Status].[S])},\n"
+ "[Gender], [Gender])",
"hierarchy [Gender] is extracted more than once");
}
/**
* Tests that TopPercent() operates succesfully on a
* axis of crossjoined tuples. previously, this would
* fail with a ClassCastException in FunUtil.java. bug 1440306
*/
public void testTopPercentCrossjoin() {
assertAxisReturns(
"{TopPercent(Crossjoin([Product].[Product Department].members,\n"
+ "[Time].[1997].children),10,[Measures].[Store Sales])}",
"{[Product].[Food].[Produce], [Time].[1997].[Q4]}\n"
+ "{[Product].[Food].[Produce], [Time].[1997].[Q1]}\n"
+ "{[Product].[Food].[Produce], [Time].[1997].[Q3]}");
}
public void testCrossjoinNested() {
assertAxisReturns(
" CrossJoin(\n"
+ " CrossJoin(\n"
+ " [Gender].members,\n"
+ " [Marital Status].members),\n"
+ " {[Store], [Store].children})",
"{[Gender].[All Gender], [Marital Status].[All Marital Status], [Store].[All Stores]}\n"
+ "{[Gender].[All Gender], [Marital Status].[All Marital Status], [Store].[Canada]}\n"
+ "{[Gender].[All Gender], [Marital Status].[All Marital Status], [Store].[Mexico]}\n"
+ "{[Gender].[All Gender], [Marital Status].[All Marital Status], [Store].[USA]}\n"
+ "{[Gender].[All Gender], [Marital Status].[M], [Store].[All Stores]}\n"
+ "{[Gender].[All Gender], [Marital Status].[M], [Store].[Canada]}\n"
+ "{[Gender].[All Gender], [Marital Status].[M], [Store].[Mexico]}\n"
+ "{[Gender].[All Gender], [Marital Status].[M], [Store].[USA]}\n"
+ "{[Gender].[All Gender], [Marital Status].[S], [Store].[All Stores]}\n"
+ "{[Gender].[All Gender], [Marital Status].[S], [Store].[Canada]}\n"
+ "{[Gender].[All Gender], [Marital Status].[S], [Store].[Mexico]}\n"
+ "{[Gender].[All Gender], [Marital Status].[S], [Store].[USA]}\n"
+ "{[Gender].[F], [Marital Status].[All Marital Status], [Store].[All Stores]}\n"
+ "{[Gender].[F], [Marital Status].[All Marital Status], [Store].[Canada]}\n"
+ "{[Gender].[F], [Marital Status].[All Marital Status], [Store].[Mexico]}\n"
+ "{[Gender].[F], [Marital Status].[All Marital Status], [Store].[USA]}\n"
+ "{[Gender].[F], [Marital Status].[M], [Store].[All Stores]}\n"
+ "{[Gender].[F], [Marital Status].[M], [Store].[Canada]}\n"
+ "{[Gender].[F], [Marital Status].[M], [Store].[Mexico]}\n"
+ "{[Gender].[F], [Marital Status].[M], [Store].[USA]}\n"
+ "{[Gender].[F], [Marital Status].[S], [Store].[All Stores]}\n"
+ "{[Gender].[F], [Marital Status].[S], [Store].[Canada]}\n"
+ "{[Gender].[F], [Marital Status].[S], [Store].[Mexico]}\n"
+ "{[Gender].[F], [Marital Status].[S], [Store].[USA]}\n"
+ "{[Gender].[M], [Marital Status].[All Marital Status], [Store].[All Stores]}\n"
+ "{[Gender].[M], [Marital Status].[All Marital Status], [Store].[Canada]}\n"
+ "{[Gender].[M], [Marital Status].[All Marital Status], [Store].[Mexico]}\n"
+ "{[Gender].[M], [Marital Status].[All Marital Status], [Store].[USA]}\n"
+ "{[Gender].[M], [Marital Status].[M], [Store].[All Stores]}\n"
+ "{[Gender].[M], [Marital Status].[M], [Store].[Canada]}\n"
+ "{[Gender].[M], [Marital Status].[M], [Store].[Mexico]}\n"
+ "{[Gender].[M], [Marital Status].[M], [Store].[USA]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Store].[All Stores]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Store].[Canada]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Store].[Mexico]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Store].[USA]}");
}
public void testCrossjoinSingletonTuples() {
assertAxisReturns(
"CrossJoin({([Gender].[M])}, {([Marital Status].[S])})",
"{[Gender].[M], [Marital Status].[S]}");
}
public void testCrossjoinSingletonTuplesNested() {
assertAxisReturns(
"CrossJoin({([Gender].[M])}, CrossJoin({([Marital Status].[S])}, [Store].children))",
"{[Gender].[M], [Marital Status].[S], [Store].[Canada]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Store].[Mexico]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Store].[USA]}");
}
public void testCrossjoinAsterisk() {
assertAxisReturns(
"{[Gender].[M]} * {[Marital Status].[S]}",
"{[Gender].[M], [Marital Status].[S]}");
}
public void testCrossjoinAsteriskTuple() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} ON COLUMNS, "
+ "NON EMPTY [Store].[All Stores] "
+ " * ([Product].[All Products], [Gender]) "
+ " * [Customers].[All Customers] ON ROWS "
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[All Stores], [Product].[All Products], [Gender].[All Gender], [Customers].[All Customers]}\n"
+ "Row #0: 266,773\n");
}
public void testCrossjoinAsteriskAssoc() {
assertAxisReturns(
"Order({[Gender].Children} * {[Marital Status].Children} * {[Time].[1997].[Q2].Children},"
+ "[Measures].[Unit Sales])",
"{[Gender].[F], [Marital Status].[M], [Time].[1997].[Q2].[4]}\n"
+ "{[Gender].[F], [Marital Status].[M], [Time].[1997].[Q2].[6]}\n"
+ "{[Gender].[F], [Marital Status].[M], [Time].[1997].[Q2].[5]}\n"
+ "{[Gender].[F], [Marital Status].[S], [Time].[1997].[Q2].[4]}\n"
+ "{[Gender].[F], [Marital Status].[S], [Time].[1997].[Q2].[5]}\n"
+ "{[Gender].[F], [Marital Status].[S], [Time].[1997].[Q2].[6]}\n"
+ "{[Gender].[M], [Marital Status].[M], [Time].[1997].[Q2].[4]}\n"
+ "{[Gender].[M], [Marital Status].[M], [Time].[1997].[Q2].[5]}\n"
+ "{[Gender].[M], [Marital Status].[M], [Time].[1997].[Q2].[6]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Time].[1997].[Q2].[6]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Time].[1997].[Q2].[4]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Time].[1997].[Q2].[5]}");
}
public void testCrossjoinAsteriskInsideBraces() {
assertAxisReturns(
"{[Gender].[M] * [Marital Status].[S] * [Time].[1997].[Q2].Children}",
"{[Gender].[M], [Marital Status].[S], [Time].[1997].[Q2].[4]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Time].[1997].[Q2].[5]}\n"
+ "{[Gender].[M], [Marital Status].[S], [Time].[1997].[Q2].[6]}");
}
public void testCrossJoinAsteriskQuery() {
assertQueryReturns(
"SELECT {[Measures].members * [1997].children} ON COLUMNS,\n"
+ " {[Store].[USA].children * [Position].[All Position].children} DIMENSION PROPERTIES [Store].[Store SQFT] ON ROWS\n"
+ "FROM [HR]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Org Salary], [Time].[1997].[Q1]}\n"
+ "{[Measures].[Org Salary], [Time].[1997].[Q2]}\n"
+ "{[Measures].[Org Salary], [Time].[1997].[Q3]}\n"
+ "{[Measures].[Org Salary], [Time].[1997].[Q4]}\n"
+ "{[Measures].[Count], [Time].[1997].[Q1]}\n"
+ "{[Measures].[Count], [Time].[1997].[Q2]}\n"
+ "{[Measures].[Count], [Time].[1997].[Q3]}\n"
+ "{[Measures].[Count], [Time].[1997].[Q4]}\n"
+ "{[Measures].[Number of Employees], [Time].[1997].[Q1]}\n"
+ "{[Measures].[Number of Employees], [Time].[1997].[Q2]}\n"
+ "{[Measures].[Number of Employees], [Time].[1997].[Q3]}\n"
+ "{[Measures].[Number of Employees], [Time].[1997].[Q4]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[CA], [Position].[Middle Management]}\n"
+ "{[Store].[USA].[CA], [Position].[Senior Management]}\n"
+ "{[Store].[USA].[CA], [Position].[Store Full Time Staf]}\n"
+ "{[Store].[USA].[CA], [Position].[Store Management]}\n"
+ "{[Store].[USA].[CA], [Position].[Store Temp Staff]}\n"
+ "{[Store].[USA].[OR], [Position].[Middle Management]}\n"
+ "{[Store].[USA].[OR], [Position].[Senior Management]}\n"
+ "{[Store].[USA].[OR], [Position].[Store Full Time Staf]}\n"
+ "{[Store].[USA].[OR], [Position].[Store Management]}\n"
+ "{[Store].[USA].[OR], [Position].[Store Temp Staff]}\n"
+ "{[Store].[USA].[WA], [Position].[Middle Management]}\n"
+ "{[Store].[USA].[WA], [Position].[Senior Management]}\n"
+ "{[Store].[USA].[WA], [Position].[Store Full Time Staf]}\n"
+ "{[Store].[USA].[WA], [Position].[Store Management]}\n"
+ "{[Store].[USA].[WA], [Position].[Store Temp Staff]}\n"
+ "Row #0: $275.40\n"
+ "Row #0: $275.40\n"
+ "Row #0: $275.40\n"
+ "Row #0: $275.40\n"
+ "Row #0: 27\n"
+ "Row #0: 27\n"
+ "Row #0: 27\n"
+ "Row #0: 27\n"
+ "Row #0: 9\n"
+ "Row #0: 9\n"
+ "Row #0: 9\n"
+ "Row #0: 9\n"
+ "Row #1: $837.00\n"
+ "Row #1: $837.00\n"
+ "Row #1: $837.00\n"
+ "Row #1: $837.00\n"
+ "Row #1: 24\n"
+ "Row #1: 24\n"
+ "Row #1: 24\n"
+ "Row #1: 24\n"
+ "Row #1: 8\n"
+ "Row #1: 8\n"
+ "Row #1: 8\n"
+ "Row #1: 8\n"
+ "Row #2: $1,728.45\n"
+ "Row #2: $1,727.02\n"
+ "Row #2: $1,727.72\n"
+ "Row #2: $1,726.55\n"
+ "Row #2: 357\n"
+ "Row #2: 357\n"
+ "Row #2: 357\n"
+ "Row #2: 357\n"
+ "Row #2: 119\n"
+ "Row #2: 119\n"
+ "Row #2: 119\n"
+ "Row #2: 119\n"
+ "Row #3: $473.04\n"
+ "Row #3: $473.04\n"
+ "Row #3: $473.04\n"
+ "Row #3: $473.04\n"
+ "Row #3: 51\n"
+ "Row #3: 51\n"
+ "Row #3: 51\n"
+ "Row #3: 51\n"
+ "Row #3: 17\n"
+ "Row #3: 17\n"
+ "Row #3: 17\n"
+ "Row #3: 17\n"
+ "Row #4: $401.35\n"
+ "Row #4: $405.73\n"
+ "Row #4: $400.61\n"
+ "Row #4: $402.31\n"
+ "Row #4: 120\n"
+ "Row #4: 120\n"
+ "Row #4: 120\n"
+ "Row #4: 120\n"
+ "Row #4: 40\n"
+ "Row #4: 40\n"
+ "Row #4: 40\n"
+ "Row #4: 40\n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #5: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #6: \n"
+ "Row #7: $1,343.62\n"
+ "Row #7: $1,342.61\n"
+ "Row #7: $1,342.57\n"
+ "Row #7: $1,343.65\n"
+ "Row #7: 279\n"
+ "Row #7: 279\n"
+ "Row #7: 279\n"
+ "Row #7: 279\n"
+ "Row #7: 93\n"
+ "Row #7: 93\n"
+ "Row #7: 93\n"
+ "Row #7: 93\n"
+ "Row #8: $286.74\n"
+ "Row #8: $286.74\n"
+ "Row #8: $286.74\n"
+ "Row #8: $286.74\n"
+ "Row #8: 30\n"
+ "Row #8: 30\n"
+ "Row #8: 30\n"
+ "Row #8: 30\n"
+ "Row #8: 10\n"
+ "Row #8: 10\n"
+ "Row #8: 10\n"
+ "Row #8: 10\n"
+ "Row #9: $333.20\n"
+ "Row #9: $332.65\n"
+ "Row #9: $331.28\n"
+ "Row #9: $332.43\n"
+ "Row #9: 99\n"
+ "Row #9: 99\n"
+ "Row #9: 99\n"
+ "Row #9: 99\n"
+ "Row #9: 33\n"
+ "Row #9: 33\n"
+ "Row #9: 33\n"
+ "Row #9: 33\n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #10: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #11: \n"
+ "Row #12: $2,768.60\n"
+ "Row #12: $2,769.18\n"
+ "Row #12: $2,766.78\n"
+ "Row #12: $2,769.50\n"
+ "Row #12: 579\n"
+ "Row #12: 579\n"
+ "Row #12: 579\n"
+ "Row #12: 579\n"
+ "Row #12: 193\n"
+ "Row #12: 193\n"
+ "Row #12: 193\n"
+ "Row #12: 193\n"
+ "Row #13: $736.29\n"
+ "Row #13: $736.29\n"
+ "Row #13: $736.29\n"
+ "Row #13: $736.29\n"
+ "Row #13: 81\n"
+ "Row #13: 81\n"
+ "Row #13: 81\n"
+ "Row #13: 81\n"
+ "Row #13: 27\n"
+ "Row #13: 27\n"
+ "Row #13: 27\n"
+ "Row #13: 27\n"
+ "Row #14: $674.70\n"
+ "Row #14: $674.54\n"
+ "Row #14: $676.26\n"
+ "Row #14: $676.48\n"
+ "Row #14: 201\n"
+ "Row #14: 201\n"
+ "Row #14: 201\n"
+ "Row #14: 201\n"
+ "Row #14: 67\n"
+ "Row #14: 67\n"
+ "Row #14: 67\n"
+ "Row #14: 67\n");
}
/**
* Testcase for bug 1889745, "StackOverflowError while resolving
* crossjoin". The problem occurs when a calculated member that references
* itself is referenced in a crossjoin.
*/
public void testCrossjoinResolve() {
assertQueryReturns(
"with\n"
+ "member [Measures].[Filtered Unit Sales] as\n"
+ " 'IIf((([Measures].[Unit Sales] > 50000.0)\n"
+ " OR ([Product].CurrentMember.Level.UniqueName <>\n"
+ " \"[Product].[Product Family]\")),\n"
+ " IIf(((Count([Product].CurrentMember.Children) = 0.0)),\n"
+ " [Measures].[Unit Sales],\n"
+ " Sum([Product].CurrentMember.Children,\n"
+ " [Measures].[Filtered Unit Sales])),\n"
+ " NULL)'\n"
+ "select NON EMPTY {crossjoin({[Measures].[Filtered Unit Sales]},\n"
+ "{[Gender].[M], [Gender].[F]})} ON COLUMNS,\n"
+ "NON EMPTY {[Product].[All Products]} ON ROWS\n"
+ "from [Sales]\n"
+ "where [Time].[1997]",
"Axis #0:\n"
+ "{[Time].[1997]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Filtered Unit Sales], [Gender].[M]}\n"
+ "{[Measures].[Filtered Unit Sales], [Gender].[F]}\n"
+ "Axis #2:\n"
+ "{[Product].[All Products]}\n"
+ "Row #0: 97,126\n"
+ "Row #0: 94,814\n");
}
/**
* Test case for bug 1911832, "Exception converting immutable list to array
* in JDK 1.5".
*/
public void testCrossjoinOrder() {
assertQueryReturns(
"WITH\n"
+ "\n"
+ "SET [S1] AS 'CROSSJOIN({[Time].[1997]}, {[Gender].[Gender].MEMBERS})'\n"
+ "\n"
+ "SELECT CROSSJOIN(ORDER([S1], [Measures].[Unit Sales], BDESC),\n"
+ "{[Measures].[Unit Sales]}) ON AXIS(0)\n"
+ "FROM [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997], [Gender].[M], [Measures].[Unit Sales]}\n"
+ "{[Time].[1997], [Gender].[F], [Measures].[Unit Sales]}\n"
+ "Row #0: 135,215\n"
+ "Row #0: 131,558\n");
}
public void testCrossjoinDupHierarchyFails() {
assertQueryThrows(
"select [Measures].[Unit Sales] ON COLUMNS,\n"
+ " CrossJoin({[Time].[Quarter].[Q1]}, {[Time].[Month].[5]}) ON ROWS\n"
+ "from [Sales]",
"Tuple contains more than one member of hierarchy '[Time]'.");
// now with Item, for kicks
assertQueryThrows(
"select [Measures].[Unit Sales] ON COLUMNS,\n"
+ " CrossJoin({[Time].[Quarter].[Q1]}, {[Time].[Month].[5]}).Item(0) ON ROWS\n"
+ "from [Sales]",
"Tuple contains more than one member of hierarchy '[Time]'.");
// same query using explicit tuple
assertQueryThrows(
"select [Measures].[Unit Sales] ON COLUMNS,\n"
+ " ([Time].[Quarter].[Q1], [Time].[Month].[5]) ON ROWS\n"
+ "from [Sales]",
"Tuple contains more than one member of hierarchy '[Time]'.");
}
/**
* Tests cases of different hierarchies in the same dimension.
* (Compare to {@link #testCrossjoinDupHierarchyFails()}). Not an error.
*/
public void testCrossjoinDupDimensionOk() {
final String expectedResult =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q1], [Time].[Weekly].[1997].[10]}\n"
+ "Row #0: 4,395\n";
final String timeWeekly = TestContext.hierarchyName("Time", "Weekly");
assertQueryReturns(
"select [Measures].[Unit Sales] ON COLUMNS,\n"
+ " CrossJoin({[Time].[Quarter].[Q1]}, {"
+ timeWeekly + ".[1997].[10]}) ON ROWS\n"
+ "from [Sales]",
expectedResult);
// now with Item, for kicks
assertQueryReturns(
"select [Measures].[Unit Sales] ON COLUMNS,\n"
+ " CrossJoin({[Time].[Quarter].[Q1]}, {"
+ timeWeekly + ".[1997].[10]}).Item(0) ON ROWS\n"
+ "from [Sales]",
expectedResult);
// same query using explicit tuple
assertQueryReturns(
"select [Measures].[Unit Sales] ON COLUMNS,\n"
+ " ([Time].[Quarter].[Q1], "
+ timeWeekly + ".[1997].[10]) ON ROWS\n"
+ "from [Sales]",
expectedResult);
}
public void testDescendantsM() {
assertAxisReturns(
"Descendants([Time].[1997].[Q1])",
"[Time].[1997].[Q1]\n"
+ "[Time].[1997].[Q1].[1]\n"
+ "[Time].[1997].[Q1].[2]\n"
+ "[Time].[1997].[Q1].[3]");
}
public void testDescendantsDepends() {
getTestContext().assertSetExprDependsOn(
"Descendants([Time].[Time].CurrentMember)",
"{[Time]}");
}
public void testDescendantsML() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Month])",
months);
}
public void testDescendantsMLSelf() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Quarter], SELF)",
quarters);
}
public void testDescendantsMLLeaves() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Year], LEAVES)",
"");
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Quarter], LEAVES)",
"");
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Month], LEAVES)",
months);
assertAxisReturns(
"Descendants([Gender], [Gender].[Gender], leaves)",
"[Gender].[F]\n" + "[Gender].[M]");
}
public void testDescendantsMLLeavesRagged() {
// no cities are at leaf level
final TestContext raggedContext =
getTestContext().withCube("[Sales Ragged]");
raggedContext.assertAxisReturns(
"Descendants([Store].[Israel], [Store].[Store City], leaves)",
"");
// all cities are leaves
raggedContext.assertAxisReturns(
"Descendants([Geography].[Israel], [Geography].[City], leaves)",
"[Geography].[Israel].[Israel].[Haifa]\n"
+ "[Geography].[Israel].[Israel].[Tel Aviv]");
// No state is a leaf (not even Israel, which is both a country and a
// a state, or Vatican, with is a country/state/city)
raggedContext.assertAxisReturns(
"Descendants([Geography], [Geography].[State], leaves)",
"");
// The Vatican is a nation with no children (they're all celibate,
// you know).
raggedContext.assertAxisReturns(
"Descendants([Geography], [Geography].[Country], leaves)",
"[Geography].[Vatican]");
}
public void testDescendantsMNLeaves() {
// leaves at depth 0 returns the member itself
assertAxisReturns(
"Descendants([Time].[1997].[Q2].[4], 0, Leaves)",
"[Time].[1997].[Q2].[4]");
// leaves at depth > 0 returns the member itself
assertAxisReturns(
"Descendants([Time].[1997].[Q2].[4], 100, Leaves)",
"[Time].[1997].[Q2].[4]");
// leaves at depth < 0 returns all descendants
assertAxisReturns(
"Descendants([Time].[1997].[Q2], -1, Leaves)",
"[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]\n"
+ "[Time].[1997].[Q2].[6]");
// leaves at depth 0 returns the member itself
assertAxisReturns(
"Descendants([Time].[1997].[Q2], 0, Leaves)",
"[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]\n"
+ "[Time].[1997].[Q2].[6]");
assertAxisReturns(
"Descendants([Time].[1997].[Q2], 3, Leaves)",
"[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]\n"
+ "[Time].[1997].[Q2].[6]");
}
public void testDescendantsMLSelfBefore() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Quarter], SELF_AND_BEFORE)",
year1997 + "\n" + quarters);
}
public void testDescendantsMLSelfBeforeAfter() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Quarter], SELF_BEFORE_AFTER)",
hierarchized1997);
}
public void testDescendantsMLBefore() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Quarter], BEFORE)", year1997);
}
public void testDescendantsMLBeforeAfter() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Quarter], BEFORE_AND_AFTER)",
year1997 + "\n" + months);
}
public void testDescendantsMLAfter() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Quarter], AFTER)", months);
}
public void testDescendantsMLAfterEnd() {
assertAxisReturns(
"Descendants([Time].[1997], [Time].[Month], AFTER)", "");
}
public void testDescendantsM0() {
assertAxisReturns(
"Descendants([Time].[1997], 0)", year1997);
}
public void testDescendantsM2() {
assertAxisReturns(
"Descendants([Time].[1997], 2)", months);
}
public void testDescendantsM2Self() {
assertAxisReturns(
"Descendants([Time].[1997], 2, Self)", months);
}
public void testDescendantsM2Leaves() {
assertAxisReturns(
"Descendants([Time].[1997], 2, Leaves)", months);
}
public void testDescendantsMFarLeaves() {
assertAxisReturns(
"Descendants([Time].[1997], 10000, Leaves)", months);
}
public void testDescendantsMEmptyLeaves() {
assertAxisReturns(
"Descendants([Time].[1997], , Leaves)",
months);
}
public void testDescendantsMEmptyLeavesFail() {
assertAxisThrows(
"Descendants([Time].[1997],)",
"No function matches signature 'Descendants(<Member>, <Empty>)");
}
public void testDescendantsMEmptyLeavesFail2() {
assertAxisThrows(
"Descendants([Time].[1997], , AFTER)",
"depth must be specified unless DESC_FLAG is LEAVES");
}
public void testDescendantsMFarSelf() {
assertAxisReturns(
"Descendants([Time].[1997], 10000, Self)",
"");
}
public void testDescendantsMNY() {
assertAxisReturns(
"Descendants([Time].[1997], 1, BEFORE_AND_AFTER)",
year1997 + "\n" + months);
}
public void testDescendants2ndHier() {
assertAxisReturns(
"Descendants([Time.Weekly].[1997].[10], [Time.Weekly].[Day])",
"[Time].[Weekly].[1997].[10].[1]\n"
+ "[Time].[Weekly].[1997].[10].[23]\n"
+ "[Time].[Weekly].[1997].[10].[24]\n"
+ "[Time].[Weekly].[1997].[10].[25]\n"
+ "[Time].[Weekly].[1997].[10].[26]\n"
+ "[Time].[Weekly].[1997].[10].[27]\n"
+ "[Time].[Weekly].[1997].[10].[28]");
}
public void testDescendantsParentChild() {
getTestContext().withCube("HR").assertAxisReturns(
"Descendants([Employees], 2)",
"[Employees].[Sheri Nowmer].[Derrick Whelply]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence]\n"
+ "[Employees].[Sheri Nowmer].[Maya Gutierrez]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra]\n"
+ "[Employees].[Sheri Nowmer].[Rebecca Kanagaki]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz]\n"
+ "[Employees].[Sheri Nowmer].[Donna Arnold]");
}
public void testDescendantsParentChildBefore() {
getTestContext().withCube("HR").assertAxisReturns(
"Descendants([Employees], 2, BEFORE)",
"[Employees].[All Employees]\n"
+ "[Employees].[Sheri Nowmer]");
}
public void testDescendantsParentChildLeaves() {
final TestContext testContext = getTestContext().withCube("HR");
if (Bug.avoidSlowTestOnLucidDB(testContext.getDialect())) {
return;
}
// leaves, restricted by level
testContext.assertAxisReturns(
"Descendants([Employees].[All Employees].[Sheri Nowmer].[Michael Spence], [Employees].[Employee Id], LEAVES)",
"[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[John Brooks]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Todd Logan]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Joshua Several]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[James Thomas]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Robert Vessa]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Bronson Jacobs]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Rebecca Barley]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Emilio Alvaro]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Becky Waters]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[A. Joyce Jarvis]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Ruby Sue Styles]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Lisa Roy]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Ingrid Burkhardt]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Todd Whitney]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Barbara Wisnewski]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Karren Burkhardt]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[John Long]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Edwin Olenzek]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Jessie Valerio]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Robert Ahlering]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Megan Burke]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Mary Sandidge].[Karel Bates]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[James Tran]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Shelley Crow]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Anne Sims]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Clarence Tatman]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Jan Nelsen]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Jeanie Glenn]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Peggy Smith]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Tish Duff]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Anita Lucero]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Stephen Burton]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Amy Consentino]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Stacie Mcanich]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Mary Browning]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Alexandra Wellington]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Cory Bacugalupi]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Stacy Rizzi]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Mike White]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Marty Simpson]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Robert Jones]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Raul Casts]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Bridget Browqett]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Monk Skonnard].[Kay Kartz]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Jeanette Cole]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Phyllis Huntsman]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Hannah Arakawa]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Wathalee Steuber]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Pamela Cox]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Helen Lutes]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Linda Ecoffey]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Katherine Swint]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Dianne Slattengren]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Ronald Heymsfield]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Steven Whitehead]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[William Sotelo]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Beth Stanley]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Jill Markwood]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Mildred Valentine]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Suzann Reams]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Audrey Wold]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Susan French]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Trish Pederson]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Eric Renn]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Elizabeth Catalano]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Christopher Beck].[Eric Coleman]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Catherine Abel]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Emilo Miller]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Daniel Wolter].[Michael John Troyer].[Hazel Walker]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Sara Pettengill].[Linda Blasingame]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Sara Pettengill].[Jackie Blackwell]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Sara Pettengill].[John Ortiz]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Sara Pettengill].[Stacey Tearpak]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Sara Pettengill].[Fannye Weber]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Sara Pettengill].[Diane Kabbes]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Sara Pettengill].[Brenda Heaney]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Sara Pettengill].[Judith Karavites]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Jauna Elson]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Nancy Hirota]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Marie Moya]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Nicky Chesnut]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Karen Hall]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Greg Narberes]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Anna Townsend]\n"
+ "[Employees].[Sheri Nowmer].[Michael Spence].[Dianne Collins].[Lawrence Hurkett].[Carol Ann Rockne]");
// leaves, restricted by depth
testContext.assertAxisReturns(
"Descendants([Employees], 1, LEAVES)", "");
testContext.assertAxisReturns(
"Descendants([Employees], 2, LEAVES)",
"[Employees].[Sheri Nowmer].[Roberta Damstra].[Jennifer Cooper]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Peggy Petty]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Jessica Olguin]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Phyllis Burchett]\n"
+ "[Employees].[Sheri Nowmer].[Rebecca Kanagaki].[Juanita Sharp]\n"
+ "[Employees].[Sheri Nowmer].[Rebecca Kanagaki].[Sandra Brunner]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Ernest Staton]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Rose Sims]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Lauretta De Carlo]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Mary Williams]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Terri Burke]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Audrey Osborn]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Brian Binai]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Concepcion Lozada]\n"
+ "[Employees].[Sheri Nowmer].[Donna Arnold].[Howard Bechard]\n"
+ "[Employees].[Sheri Nowmer].[Donna Arnold].[Doris Carter]");
testContext.assertAxisReturns(
"Descendants([Employees], 3, LEAVES)",
"[Employees].[Sheri Nowmer].[Roberta Damstra].[Jennifer Cooper]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Peggy Petty]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Jessica Olguin]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Phyllis Burchett]\n"
+ "[Employees].[Sheri Nowmer].[Rebecca Kanagaki].[Juanita Sharp]\n"
+ "[Employees].[Sheri Nowmer].[Rebecca Kanagaki].[Sandra Brunner]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Ernest Staton]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Rose Sims]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Lauretta De Carlo]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Mary Williams]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Terri Burke]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Audrey Osborn]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Brian Binai]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz].[Concepcion Lozada]\n"
+ "[Employees].[Sheri Nowmer].[Donna Arnold].[Howard Bechard]\n"
+ "[Employees].[Sheri Nowmer].[Donna Arnold].[Doris Carter]");
// note that depth is RELATIVE to the starting member
testContext.assertAxisReturns(
"Descendants([Employees].[Sheri Nowmer].[Roberta Damstra], 1, LEAVES)",
"[Employees].[Sheri Nowmer].[Roberta Damstra].[Jennifer Cooper]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Peggy Petty]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Jessica Olguin]\n"
+ "[Employees].[Sheri Nowmer].[Roberta Damstra].[Phyllis Burchett]");
// Howard Bechard is a leaf member -- appears even at depth 0
testContext.assertAxisReturns(
"Descendants([Employees].[All Employees].[Sheri Nowmer].[Donna Arnold].[Howard Bechard], 0, LEAVES)",
"[Employees].[Sheri Nowmer].[Donna Arnold].[Howard Bechard]");
testContext.assertAxisReturns(
"Descendants([Employees].[All Employees].[Sheri Nowmer].[Donna Arnold].[Howard Bechard], 1, LEAVES)",
"[Employees].[Sheri Nowmer].[Donna Arnold].[Howard Bechard]");
testContext.assertExprReturns(
"Count(Descendants([Employees], 2, LEAVES))", "16");
testContext.assertExprReturns(
"Count(Descendants([Employees], 3, LEAVES))", "16");
testContext.assertExprReturns(
"Count(Descendants([Employees], 4, LEAVES))", "63");
testContext.assertExprReturns(
"Count(Descendants([Employees], 999, LEAVES))", "1,044");
// Negative depth acts like +infinity (per MSAS). Run the test several
// times because we had a non-deterministic bug here.
for (int i = 0; i < 100; ++i) {
testContext.assertExprReturns(
"Count(Descendants([Employees], -1, LEAVES))", "1,044");
}
}
public void testDescendantsSBA() {
assertAxisReturns(
"Descendants([Time].[1997], 1, SELF_BEFORE_AFTER)",
hierarchized1997);
}
public void testDescendantsSet() {
assertAxisReturns(
"Descendants({[Time].[1997].[Q4], [Time].[1997].[Q2]}, 1)",
"[Time].[1997].[Q4].[10]\n"
+ "[Time].[1997].[Q4].[11]\n"
+ "[Time].[1997].[Q4].[12]\n"
+ "[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]\n"
+ "[Time].[1997].[Q2].[6]");
assertAxisReturns(
"Descendants({[Time].[1997]}, [Time].[Month], LEAVES)",
months);
}
public void testDescendantsSetEmpty() {
assertAxisThrows(
"Descendants({}, 1)",
"Cannot deduce type of set");
assertAxisReturns(
"Descendants(Filter({[Time].[Time].Members}, 1=0), 1)",
"");
}
public void testRange() {
assertAxisReturns(
"[Time].[1997].[Q1].[2] : [Time].[1997].[Q2].[5]",
"[Time].[1997].[Q1].[2]\n"
+ "[Time].[1997].[Q1].[3]\n"
+ "[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]"); // not parents
// testcase for bug XXXXX: braces required
assertQueryReturns(
"with set [Set1] as '[Product].[Drink]:[Product].[Food]' \n"
+ "\n"
+ "select [Set1] on columns, {[Measures].defaultMember} on rows \n"
+ "\n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Food]}\n"
+ "Axis #2:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Row #0: 24,597\n"
+ "Row #0: 191,940\n");
}
/**
* tests that a null passed in returns an empty set in range function
*/
public void testNullRange() {
assertAxisReturns(
"[Time].[1997].[Q1].[2] : NULL", //[Time].[1997].[Q2].[5]
""); // Empty Set
}
/**
* tests that an exception is thrown if both parameters in a range function
* are null.
*/
public void testTwoNullRange() {
assertAxisThrows(
"NULL : NULL",
"Mondrian Error:Failed to parse query 'select {NULL : NULL} on columns from Sales'");
}
/**
* Large dimensions use a different member reader, therefore need to
* be tested separately.
*/
public void testRangeLarge() {
assertAxisReturns(
"[Customers].[USA].[CA].[San Francisco] : [Customers].[USA].[WA].[Bellingham]",
"[Customers].[USA].[CA].[San Francisco]\n"
+ "[Customers].[USA].[CA].[San Gabriel]\n"
+ "[Customers].[USA].[CA].[San Jose]\n"
+ "[Customers].[USA].[CA].[Santa Cruz]\n"
+ "[Customers].[USA].[CA].[Santa Monica]\n"
+ "[Customers].[USA].[CA].[Spring Valley]\n"
+ "[Customers].[USA].[CA].[Torrance]\n"
+ "[Customers].[USA].[CA].[West Covina]\n"
+ "[Customers].[USA].[CA].[Woodland Hills]\n"
+ "[Customers].[USA].[OR].[Albany]\n"
+ "[Customers].[USA].[OR].[Beaverton]\n"
+ "[Customers].[USA].[OR].[Corvallis]\n"
+ "[Customers].[USA].[OR].[Lake Oswego]\n"
+ "[Customers].[USA].[OR].[Lebanon]\n"
+ "[Customers].[USA].[OR].[Milwaukie]\n"
+ "[Customers].[USA].[OR].[Oregon City]\n"
+ "[Customers].[USA].[OR].[Portland]\n"
+ "[Customers].[USA].[OR].[Salem]\n"
+ "[Customers].[USA].[OR].[W. Linn]\n"
+ "[Customers].[USA].[OR].[Woodburn]\n"
+ "[Customers].[USA].[WA].[Anacortes]\n"
+ "[Customers].[USA].[WA].[Ballard]\n"
+ "[Customers].[USA].[WA].[Bellingham]");
}
public void testRangeStartEqualsEnd() {
assertAxisReturns(
"[Time].[1997].[Q3].[7] : [Time].[1997].[Q3].[7]",
"[Time].[1997].[Q3].[7]");
}
public void testRangeStartEqualsEndLarge() {
assertAxisReturns(
"[Customers].[USA].[CA] : [Customers].[USA].[CA]",
"[Customers].[USA].[CA]");
}
public void testRangeEndBeforeStart() {
assertAxisReturns(
"[Time].[1997].[Q3].[7] : [Time].[1997].[Q2].[5]",
"[Time].[1997].[Q2].[5]\n"
+ "[Time].[1997].[Q2].[6]\n"
+ "[Time].[1997].[Q3].[7]"); // same as if reversed
}
public void testRangeEndBeforeStartLarge() {
assertAxisReturns(
"[Customers].[USA].[WA] : [Customers].[USA].[CA]",
"[Customers].[USA].[CA]\n"
+ "[Customers].[USA].[OR]\n"
+ "[Customers].[USA].[WA]");
}
public void testRangeBetweenDifferentLevelsIsError() {
assertAxisThrows(
"[Time].[1997].[Q2] : [Time].[1997].[Q2].[5]",
"Members must belong to the same level");
}
public void testRangeBoundedByAll() {
assertAxisReturns(
"[Gender] : [Gender]",
"[Gender].[All Gender]");
}
public void testRangeBoundedByAllLarge() {
assertAxisReturns(
"[Customers].DefaultMember : [Customers]",
"[Customers].[All Customers]");
}
public void testRangeBoundedByNull() {
assertAxisReturns(
"[Gender].[F] : [Gender].[M].NextMember",
"");
}
public void testRangeBoundedByNullLarge() {
assertAxisReturns(
"[Customers].PrevMember : [Customers].[USA].[OR]",
"");
}
public void testSetContainingLevelFails() {
assertAxisThrows(
"[Store].[Store City]",
"No function matches signature '{<Level>}'");
}
public void testBug715177() {
assertQueryReturns(
"WITH MEMBER [Product].[Non-Consumable].[Other] AS\n"
+ " 'Sum(Except( [Product].[Product Department].Members,\n"
+ " TopCount([Product].[Product Department].Members, 3)),\n"
+ " Measures.[Unit Sales])'\n"
+ "SELECT\n"
+ " { [Measures].[Unit Sales] } ON COLUMNS,\n"
+ " { TopCount([Product].[Product Department].Members,3),\n"
+ " [Product].[Non-Consumable].[Other] } ON ROWS\n"
+ "FROM [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Product].[Drink].[Beverages]}\n"
+ "{[Product].[Drink].[Dairy]}\n"
+ "{[Product].[Non-Consumable].[Other]}\n"
+ "Row #0: 6,838\n"
+ "Row #1: 13,573\n"
+ "Row #2: 4,186\n"
+ "Row #3: 242,176\n");
}
public void testBug714707() {
// Same issue as bug 715177 -- "children" returns immutable
// list, which set operator must make mutable.
assertAxisReturns(
"{[Store].[USA].[CA].children, [Store].[USA]}",
"[Store].[USA].[CA].[Alameda]\n"
+ "[Store].[USA].[CA].[Beverly Hills]\n"
+ "[Store].[USA].[CA].[Los Angeles]\n"
+ "[Store].[USA].[CA].[San Diego]\n"
+ "[Store].[USA].[CA].[San Francisco]\n"
+ "[Store].[USA]");
}
public void testBug715177c() {
assertAxisReturns(
"Order(TopCount({[Store].[USA].[CA].children},"
+ " [Measures].[Unit Sales], 2), [Measures].[Unit Sales])",
"[Store].[USA].[CA].[Alameda]\n"
+ "[Store].[USA].[CA].[San Francisco]\n"
+ "[Store].[USA].[CA].[Beverly Hills]\n"
+ "[Store].[USA].[CA].[San Diego]\n"
+ "[Store].[USA].[CA].[Los Angeles]");
}
public void testFormatFixed() {
assertExprReturns(
"Format(12.2, \"#,##0.00\")",
"12.20");
}
public void testFormatVariable() {
assertExprReturns(
"Format(1234.5, \"#,#\" || \"#0.00\")",
"1,234.50");
}
public void testFormatMember() {
assertExprReturns(
"Format([Store].[USA].[CA], \"#,#\" || \"#0.00\")",
"74,748.00");
}
public void testIIf() {
assertExprReturns(
"IIf(([Measures].[Unit Sales],[Product].[Drink].[Alcoholic Beverages].[Beer and Wine]) > 100, \"Yes\",\"No\")",
"Yes");
}
public void testIIfWithNullAndNumber() {
assertExprReturns(
"IIf(([Measures].[Unit Sales],[Product].[Drink].[Alcoholic Beverages].[Beer and Wine]) > 100, null,20)",
"");
assertExprReturns(
"IIf(([Measures].[Unit Sales],[Product].[Drink].[Alcoholic Beverages].[Beer and Wine]) > 100, 20,null)",
"20");
}
public void testIIfWithStringAndNull()
{
assertExprReturns(
"IIf(([Measures].[Unit Sales],[Product].[Drink].[Alcoholic Beverages].[Beer and Wine]) > 100, null,\"foo\")",
"");
assertExprReturns(
"IIf(([Measures].[Unit Sales],[Product].[Drink].[Alcoholic Beverages].[Beer and Wine]) > 100, \"foo\",null)",
"foo");
}
public void testIsEmptyWithNull()
{
assertExprReturns(
"iif (isempty(null), \"is empty\", \"not is empty\")",
"is empty");
assertExprReturns("iif (isempty(null), 1, 2)", "1");
}
public void testIIfMember() {
assertAxisReturns(
"IIf(1 > 2,[Store].[USA],[Store].[Canada].[BC])",
"[Store].[Canada].[BC]");
}
public void testIIfLevel() {
assertExprReturns(
"IIf(1 > 2, [Store].[Store Country],[Store].[Store City]).Name",
"Store City");
}
public void testIIfHierarchy() {
assertExprReturns(
"IIf(1 > 2, [Time], [Store]).Name",
"Store");
// Call Iif(<Logical>, <Dimension>, <Hierarchy>). Argument #3, the
// hierarchy [Time.Weekly] is implicitly converted to
// the dimension [Time] to match argument #2 which is a dimension.
assertExprReturns(
"IIf(1 > 2, [Time], [Time.Weekly]).Name",
"Time");
}
public void testIIfDimension() {
assertExprReturns(
"IIf(1 > 2, [Store], [Time]).Name",
"Time");
}
public void testIIfSet() {
assertAxisReturns(
"IIf(1 > 2, {[Store].[USA], [Store].[USA].[CA]}, {[Store].[Mexico], [Store].[USA].[OR]})",
"[Store].[Mexico]\n"
+ "[Store].[USA].[OR]");
}
public void testDimensionCaption() {
assertExprReturns("[Time].[1997].Dimension.Caption", "Time");
}
public void testHierarchyCaption() {
assertExprReturns("[Time].[1997].Hierarchy.Caption", "Time");
}
public void testLevelCaption() {
assertExprReturns("[Time].[1997].Level.Caption", "Year");
}
public void testMemberCaption() {
assertExprReturns("[Time].[1997].Caption", "1997");
}
public void testDimensionName() {
assertExprReturns("[Time].[1997].Dimension.Name", "Time");
}
public void testHierarchyName() {
assertExprReturns("[Time].[1997].Hierarchy.Name", "Time");
}
public void testLevelName() {
assertExprReturns("[Time].[1997].Level.Name", "Year");
}
public void testMemberName() {
assertExprReturns("[Time].[1997].Name", "1997");
// dimension name
assertExprReturns("[Store].Name", "Store");
// member name
assertExprReturns("[Store].DefaultMember.Name", "All Stores");
if (isDefaultNullMemberRepresentation()) {
// name of null member
assertExprReturns("[Store].Parent.Name", "#null");
}
}
public void testDimensionUniqueName() {
assertExprReturns(
"[Gender].DefaultMember.Dimension.UniqueName",
"[Gender]");
}
public void testHierarchyUniqueName() {
assertExprReturns(
"[Gender].DefaultMember.Hierarchy.UniqueName",
"[Gender]");
}
public void testLevelUniqueName() {
assertExprReturns(
"[Gender].DefaultMember.Level.UniqueName",
"[Gender].[(All)]");
}
public void testMemberUniqueName() {
assertExprReturns(
"[Gender].DefaultMember.UniqueName",
"[Gender].[All Gender]");
}
public void testMemberUniqueNameOfNull() {
if (isDefaultNullMemberRepresentation()) {
assertExprReturns(
"[Measures].[Unit Sales].FirstChild.UniqueName",
"[Measures].[#null]"); // MSOLAP gives "" here
}
}
public void testCoalesceEmptyDepends() {
getTestContext().assertExprDependsOn(
"coalesceempty([Time].[1997], [Gender].[M])",
TestContext.allHiers());
String s1 = TestContext.allHiersExcept("[Measures]", "[Time]");
getTestContext().assertExprDependsOn(
"coalesceempty(([Measures].[Unit Sales], [Time].[1997]),"
+ " ([Measures].[Store Sales], [Time].[1997].[Q2]))",
s1);
}
public void testCoalesceEmpty() {
// [DF] is all null and [WA] has numbers for 1997 but not for 1998.
Result result = executeQuery(
"with\n"
+ " member Measures.[Coal1] as 'coalesceempty(([Time].[1997], Measures.[Store Sales]), ([Time].[1998], Measures.[Store Sales]))'\n"
+ " member Measures.[Coal2] as 'coalesceempty(([Time].[1997], Measures.[Unit Sales]), ([Time].[1998], Measures.[Unit Sales]))'\n"
+ "select \n"
+ " {Measures.[Coal1], Measures.[Coal2]} on columns,\n"
+ " {[Store].[All Stores].[Mexico].[DF], [Store].[All Stores].[USA].[WA]} on rows\n"
+ "from \n"
+ " [Sales]");
checkDataResults(
new Double[][]{
new Double[]{null, null},
new Double[]{new Double(263793.22), new Double(124366)}
},
result,
0.001);
result = executeQuery(
"with\n"
+ " member Measures.[Sales Per Customer] as 'Measures.[Sales Count] / Measures.[Customer Count]'\n"
+ " member Measures.[Coal] as 'coalesceempty(([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " Measures.[Sales Per Customer])'\n"
+ "select \n"
+ " {Measures.[Sales Per Customer], Measures.[Coal]} on columns,\n"
+ " {[Store].[All Stores].[Mexico].[DF], [Store].[All Stores].[USA].[WA]} on rows\n"
+ "from \n"
+ " [Sales]\n"
+ "where\n"
+ " ([Time].[1997].[Q2])");
checkDataResults(
new Double[][]{
new Double[]{null, null},
new Double[]{new Double(8.963), new Double(8.963)}
},
result,
0.001);
result = executeQuery(
"with\n"
+ " member Measures.[Sales Per Customer] as 'Measures.[Sales Count] / Measures.[Customer Count]'\n"
+ " member Measures.[Coal] as 'coalesceempty(([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " ([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " ([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " ([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " ([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " ([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " ([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " ([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " Measures.[Sales Per Customer])'\n"
+ "select \n"
+ " {Measures.[Sales Per Customer], Measures.[Coal]} on columns,\n"
+ " {[Store].[All Stores].[Mexico].[DF], [Store].[All Stores].[USA].[WA]} on rows\n"
+ "from \n"
+ " [Sales]\n"
+ "where\n"
+ " ([Time].[1997].[Q2])");
checkDataResults(
new Double[][]{
new Double[]{null, null},
new Double[]{new Double(8.963), new Double(8.963)}
},
result,
0.001);
}
public void testBrokenContextBug() {
Result result = executeQuery(
"with\n"
+ " member Measures.[Sales Per Customer] as 'Measures.[Sales Count] / Measures.[Customer Count]'\n"
+ " member Measures.[Coal] as 'coalesceempty(([Measures].[Sales Per Customer], [Store].[All Stores].[Mexico].[DF]),\n"
+ " Measures.[Sales Per Customer])'\n"
+ "select \n"
+ " {Measures.[Coal]} on columns,\n"
+ " {[Store].[All Stores].[USA].[WA]} on rows\n"
+ "from \n"
+ " [Sales]\n"
+ "where\n"
+ " ([Time].[1997].[Q2])");
checkDataResults(new Double[][]{{new Double(8.963)}}, result, 0.001);
}
/**
* Tests the function <code><Set>.Item(<Integer>)</code>.
*/
public void testSetItemInt() {
assertAxisReturns(
"{[Customers].[All Customers].[USA].[OR].[Lebanon].[Mary Frances Christian]}.Item(0)",
"[Customers].[USA].[OR].[Lebanon].[Mary Frances Christian]");
assertAxisReturns(
"{[Customers].[All Customers].[USA],"
+ "[Customers].[All Customers].[USA].[WA],"
+ "[Customers].[All Customers].[USA].[CA],"
+ "[Customers].[All Customers].[USA].[OR].[Lebanon].[Mary Frances Christian]}.Item(2)",
"[Customers].[USA].[CA]");
assertAxisReturns(
"{[Customers].[All Customers].[USA],"
+ "[Customers].[All Customers].[USA].[WA],"
+ "[Customers].[All Customers].[USA].[CA],"
+ "[Customers].[All Customers].[USA].[OR].[Lebanon].[Mary Frances Christian]}.Item(100 / 50 - 1)",
"[Customers].[USA].[WA]");
assertAxisReturns(
"{([Time].[1997].[Q1].[1], [Customers].[All Customers].[USA]),"
+ "([Time].[1997].[Q1].[2], [Customers].[All Customers].[USA].[WA]),"
+ "([Time].[1997].[Q1].[3], [Customers].[All Customers].[USA].[CA]),"
+ "([Time].[1997].[Q2].[4], [Customers].[All Customers].[USA].[OR].[Lebanon].[Mary Frances Christian])}"
+ ".Item(100 / 50 - 1)",
"{[Time].[1997].[Q1].[2], [Customers].[USA].[WA]}");
// given index out of bounds, item returns null
assertAxisReturns(
"{[Customers].[All Customers].[USA],"
+ "[Customers].[All Customers].[USA].[WA],"
+ "[Customers].[All Customers].[USA].[CA],"
+ "[Customers].[All Customers].[USA].[OR].[Lebanon].[Mary Frances Christian]}.Item(-1)",
"");
// given index out of bounds, item returns null
assertAxisReturns(
"{[Customers].[All Customers].[USA],"
+ "[Customers].[All Customers].[USA].[WA],"
+ "[Customers].[All Customers].[USA].[CA],"
+ "[Customers].[All Customers].[USA].[OR].[Lebanon].[Mary Frances Christian]}.Item(4)",
"");
}
/**
* Tests the function <code><Set>.Item(<String> [,...])</code>.
*/
public void testSetItemString() {
assertAxisReturns(
"{[Gender].[M], [Gender].[F]}.Item(\"M\")",
"[Gender].[M]");
assertAxisReturns(
"{CrossJoin([Gender].Members, [Marital Status].Members)}.Item(\"M\", \"S\")",
"{[Gender].[M], [Marital Status].[S]}");
// MSAS fails with "duplicate dimensions across (independent) axes".
// (That's a bug in MSAS.)
assertAxisReturns(
"{CrossJoin([Gender].Members, [Marital Status].Members)}.Item(\"M\", \"M\")",
"{[Gender].[M], [Marital Status].[M]}");
// None found.
assertAxisReturns(
"{[Gender].[M], [Gender].[F]}.Item(\"X\")", "");
assertAxisReturns(
"{CrossJoin([Gender].Members, [Marital Status].Members)}.Item(\"M\", \"F\")",
"");
assertAxisReturns(
"CrossJoin([Gender].Members, [Marital Status].Members).Item(\"S\", \"M\")",
"");
assertAxisThrows(
"CrossJoin([Gender].Members, [Marital Status].Members).Item(\"M\")",
"Argument count does not match set's cardinality 2");
}
public void testTuple() {
assertExprReturns(
"([Gender].[M], "
+ "[Time].[Time].Children.Item(2), "
+ "[Measures].[Unit Sales])",
"33,249");
// Calc calls MemberValue with 3 args -- more efficient than
// constructing a tuple.
assertExprCompilesTo(
"([Gender].[M], [Time].[Time].Children.Item(2), [Measures].[Unit Sales])",
"MemberArrayValueCalc(name=MemberArrayValueCalc, class=class mondrian.calc.impl.MemberArrayValueCalc, type=SCALAR, resultStyle=VALUE)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Gender].[M]>, resultStyle=VALUE_NOT_NULL, value=[Gender].[M])\n"
+ " Item(name=Item, class=class mondrian.olap.fun.SetItemFunDef$5, type=MemberType<hierarchy=[Time]>, resultStyle=VALUE)\n"
+ " Children(name=Children, class=class mondrian.olap.fun.BuiltinFunTable$22$1, type=SetType<MemberType<hierarchy=[Time]>>, resultStyle=LIST)\n"
+ " CurrentMemberFixed(hierarchy=[Time], name=CurrentMemberFixed, class=class mondrian.olap.fun.HierarchyCurrentMemberFunDef$FixedCalcImpl, type=MemberType<hierarchy=[Time]>, resultStyle=VALUE)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=DecimalType(0), resultStyle=VALUE_NOT_NULL, value=2)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Unit Sales]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Unit Sales])\n");
}
/**
* Tests whether the tuple operator can be applied to arguments of various
* types. See bug 1491699
* "ClassCastException in mondrian.calc.impl.GenericCalc.evaluat".
*/
public void testTupleArgTypes() {
// can coerce dimensions (if they have a unique hierarchy) and
// hierarchies to members
assertExprReturns(
"([Gender], [Time].[Time])",
"266,773");
// can coerce hierarchy to member
assertExprReturns(
"([Gender].[M], " + TimeWeekly + ")", "135,215");
// cannot coerce level to member
assertAxisThrows(
"{([Gender].[M], [Store].[Store City])}",
"No function matches signature '(<Member>, <Level>)'");
// coerce args (hierarchy, member, member, dimension)
assertAxisReturns(
"{([Time.Weekly], [Measures].[Store Sales], [Marital Status].[M], [Promotion Media])}",
"{[Time].[Weekly].[All Weeklys], [Measures].[Store Sales], [Marital Status].[M], [Promotion Media].[All Media]}");
// usage of different hierarchies in the [Time] dimension
assertAxisReturns(
"{([Time.Weekly], [Measures].[Store Sales], [Marital Status].[M], [Time].[Time])}",
"{[Time].[Weekly].[All Weeklys], [Measures].[Store Sales], [Marital Status].[M], [Time].[1997]}");
// two usages of the [Time].[Weekly] hierarchy
if (MondrianProperties.instance().SsasCompatibleNaming.get()) {
assertAxisThrows(
"{([Time].[Weekly], [Measures].[Store Sales], [Marital Status].[M], [Time].[Weekly])}",
"Tuple contains more than one member of hierarchy '[Time].[Weekly]'.");
} else {
assertAxisThrows(
"{([Time.Weekly], [Measures].[Store Sales], [Marital Status].[M], [Time.Weekly])}",
"Tuple contains more than one member of hierarchy '[Time.Weekly]'.");
}
// cannot coerce integer to member
assertAxisThrows(
"{([Gender].[M], 123)}",
"No function matches signature '(<Member>, <Numeric Expression>)'");
}
public void testTupleItem() {
assertAxisReturns(
"([Time].[1997].[Q1].[1], [Customers].[All Customers].[USA].[OR], [Gender].[All Gender].[M]).item(2)",
"[Gender].[M]");
assertAxisReturns(
"([Time].[1997].[Q1].[1], [Customers].[All Customers].[USA].[OR], [Gender].[All Gender].[M]).item(1)",
"[Customers].[USA].[OR]");
assertAxisReturns(
"{[Time].[1997].[Q1].[1]}.item(0)",
"[Time].[1997].[Q1].[1]");
assertAxisReturns(
"{[Time].[1997].[Q1].[1]}.Item(0).Item(0)",
"[Time].[1997].[Q1].[1]");
// given out of bounds index, item returns null
assertAxisReturns(
"([Time].[1997].[Q1].[1], [Customers].[All Customers].[USA].[OR], [Gender].[All Gender].[M]).item(-1)",
"");
// given out of bounds index, item returns null
assertAxisReturns(
"([Time].[1997].[Q1].[1], [Customers].[All Customers].[USA].[OR], [Gender].[All Gender].[M]).item(500)",
"");
// empty set
assertExprReturns(
"Filter([Gender].members, 1 = 0).Item(0)",
"");
// empty set of unknown type
assertExprReturns(
"{}.Item(3)",
"");
// past end of set
assertExprReturns(
"{[Gender].members}.Item(4)",
"");
// negative index
assertExprReturns(
"{[Gender].members}.Item(-50)",
"");
}
public void testTupleAppliedToUnknownHierarchy() {
// manifestation of bug 1735821
assertQueryReturns(
"with \n"
+ "member [Product].[Test] as '([Product].[Food],Dimensions(0).defaultMember)' \n"
+ "select \n"
+ "{[Product].[Test], [Product].[Food]} on columns, \n"
+ "{[Measures].[Store Sales]} on rows \n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Product].[Test]}\n"
+ "{[Product].[Food]}\n"
+ "Axis #2:\n"
+ "{[Measures].[Store Sales]}\n"
+ "Row #0: 191,940.00\n"
+ "Row #0: 409,035.59\n");
}
public void testTupleDepends()
{
getTestContext().assertMemberExprDependsOn(
"([Store].[USA], [Gender].[F])", "{}");
getTestContext().assertMemberExprDependsOn(
"([Store].[USA], [Gender])", "{[Gender]}");
// in a scalar context, the expression depends on everything except
// the explicitly stated dimensions
getTestContext().assertExprDependsOn(
"([Store].[USA], [Gender])",
TestContext.allHiersExcept("[Store]"));
// The result should be all dims except [Gender], but there's a small
// bug in MemberValueCalc.dependsOn where we escalate 'might depend' to
// 'depends' and we return that it depends on all dimensions.
getTestContext().assertExprDependsOn(
"(Dimensions('Store').CurrentMember, [Gender].[F])",
TestContext.allHiers());
}
public void testItemNull()
{
// In the following queries, MSAS returns 'Formula error - object type
// is not valid - in an <object> base class. An error occurred during
// attempt to get cell value'. This is because in MSAS, Item is a COM
// function, and COM doesn't like null pointers.
//
// Mondrian represents null members as actual objects, so its behavior
// is different.
// MSAS returns error here.
assertExprReturns(
"Filter([Gender].members, 1 = 0).Item(0).Dimension.Name",
"Gender");
// MSAS returns error here.
assertExprReturns(
"Filter([Gender].members, 1 = 0).Item(0).Parent",
"");
assertExprReturns(
"(Filter([Store].members, 0 = 0).Item(0).Item(0),"
+ "Filter([Store].members, 0 = 0).Item(0).Item(0))",
"266,773");
if (isDefaultNullMemberRepresentation()) {
// MSAS returns error here.
assertExprReturns(
"Filter([Gender].members, 1 = 0).Item(0).Name",
"#null");
}
}
public void testTupleNull() {
// if a tuple contains any null members, it evaluates to null
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns,\n"
+ " { ([Gender].[M], [Store]),\n"
+ " ([Gender].[F], [Store].parent),\n"
+ " ([Gender].parent, [Store])} on rows\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Gender].[M], [Store].[All Stores]}\n"
+ "Row #0: 135,215\n");
// the set function eliminates tuples which are wholly or partially
// null
assertAxisReturns(
"([Gender].parent, [Marital Status]),\n" // part null
+ " ([Gender].[M], [Marital Status].parent),\n" // part null
+ " ([Gender].parent, [Marital Status].parent),\n" // wholly null
+ " ([Gender].[M], [Marital Status])", // not null
"{[Gender].[M], [Marital Status].[All Marital Status]}");
if (isDefaultNullMemberRepresentation()) {
// The tuple constructor returns a null tuple if one of its
// arguments is null -- and the Item function returns null if the
// tuple is null.
assertExprReturns(
"([Gender].parent, [Marital Status]).Item(0).Name",
"#null");
assertExprReturns(
"([Gender].parent, [Marital Status]).Item(1).Name",
"#null");
}
}
private void checkDataResults(
Double[][] expected,
Result result,
final double tolerance)
{
int[] coords = new int[2];
for (int row = 0; row < expected.length; row++) {
coords[1] = row;
for (int col = 0; col < expected[0].length; col++) {
coords[0] = col;
Cell cell = result.getCell(coords);
final Double expectedValue = expected[row][col];
if (expectedValue == null) {
assertTrue("Expected null value", cell.isNull());
} else if (cell.isNull()) {
fail(
"Cell at (" + row + ", " + col
+ ") was null, but was expecting "
+ expectedValue);
} else {
assertEquals(
"Incorrect value returned at ("
+ row + ", " + col + ")",
expectedValue,
((Number) cell.getValue()).doubleValue(),
tolerance);
}
}
}
}
public void testLevelMemberExpressions() {
// Should return Beverly Hills in California.
assertAxisReturns(
"[Store].[Store City].[Beverly Hills]",
"[Store].[USA].[CA].[Beverly Hills]");
// There are two months named "1" in the time dimension: one
// for 1997 and one for 1998. <Level>.<Member> should return
// the first one.
assertAxisReturns("[Time].[Month].[1]", "[Time].[1997].[Q1].[1]");
// Shouldn't be able to find a member named "Q1" on the month level.
assertAxisThrows(
"[Time].[Month].[Q1]",
"MDX object '[Time].[Month].[Q1]' not found in cube");
}
public void testCaseTestMatch() {
assertExprReturns(
"CASE WHEN 1=0 THEN \"first\" WHEN 1=1 THEN \"second\" WHEN 1=2 THEN \"third\" ELSE \"fourth\" END",
"second");
}
public void testCaseTestMatchElse() {
assertExprReturns(
"CASE WHEN 1=0 THEN \"first\" ELSE \"fourth\" END",
"fourth");
}
public void testCaseTestMatchNoElse() {
assertExprReturns(
"CASE WHEN 1=0 THEN \"first\" END",
"");
}
/**
* Testcase for bug 1799391, "Case Test function throws class cast
* exception"
*/
public void testCaseTestReturnsMemberBug1799391() {
assertQueryReturns(
"WITH\n"
+ " MEMBER [Product].[CaseTest] AS\n"
+ " 'CASE\n"
+ " WHEN [Gender].CurrentMember IS [Gender].[M] THEN [Gender].[F]\n"
+ " ELSE [Gender].[F]\n"
+ " END'\n"
+ " \n"
+ "SELECT {[Product].[CaseTest]} ON 0, {[Gender].[M]} ON 1 FROM Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Product].[CaseTest]}\n"
+ "Axis #2:\n"
+ "{[Gender].[M]}\n"
+ "Row #0: 131,558\n");
assertAxisReturns(
"CASE WHEN 1+1 = 2 THEN [Gender].[F] ELSE [Gender].[F].Parent END",
"[Gender].[F]");
// try case match for good measure
assertAxisReturns(
"CASE 1 WHEN 2 THEN [Gender].[F] ELSE [Gender].[F].Parent END",
"[Gender].[All Gender]");
}
public void testCaseMatch() {
assertExprReturns(
"CASE 2 WHEN 1 THEN \"first\" WHEN 2 THEN \"second\" WHEN 3 THEN \"third\" ELSE \"fourth\" END",
"second");
}
public void testCaseMatchElse() {
assertExprReturns(
"CASE 7 WHEN 1 THEN \"first\" ELSE \"fourth\" END",
"fourth");
}
public void testCaseMatchNoElse() {
assertExprReturns(
"CASE 8 WHEN 0 THEN \"first\" END",
"");
}
public void testCaseTypeMismatch() {
// type mismatch between case and else
assertAxisThrows(
"CASE 1 WHEN 1 THEN 2 ELSE \"foo\" END",
"No function matches signature");
// type mismatch between case and case
assertAxisThrows(
"CASE 1 WHEN 1 THEN 2 WHEN 2 THEN \"foo\" ELSE 3 END",
"No function matches signature");
// type mismatch between value and case
assertAxisThrows(
"CASE 1 WHEN \"foo\" THEN 2 ELSE 3 END",
"No function matches signature");
// non-boolean condition
assertAxisThrows(
"CASE WHEN 1 = 2 THEN 3 WHEN 4 THEN 5 ELSE 6 END",
"No function matches signature");
}
/**
* Testcase for
* <a href="http://jira.pentaho.com/browse/MONDRIAN-853">
* bug MONDRIAN-853, "When using CASE WHEN in a CalculatedMember values are
* not returned the way expected"</a>.
*/
public void testCaseTuple() {
// The case in the bug, simplified. With the bug, returns a member array
// "[Lmondrian.olap.Member;@151b0a5". Type deduction should realize
// that the result is a scalar, therefore a tuple (represented by a
// member array) needs to be evaluated to a scalar. I think that if we
// get the type deduction right, the MDX exp compiler will handle the
// rest.
if (false)
assertExprReturns(
"case 1 when 0 then 1.5\n"
+ " else ([Gender].[M], [Measures].[Unit Sales]) end",
"135,215");
// "case when" variant always worked
assertExprReturns(
"case when 1=0 then 1.5\n"
+ " else ([Gender].[M], [Measures].[Unit Sales]) end",
"135,215");
// case 2: cannot deduce type (tuple x) vs. (tuple y). Should be able
// to deduce that the result type is tuple-type<member-type<Gender>,
// member-type<Measures>>.
if (false)
assertExprReturns(
"case when 1=0 then ([Gender].[M], [Measures].[Store Sales])\n"
+ " else ([Gender].[M], [Measures].[Unit Sales]) end",
"xxx");
// case 3: mixture of member & tuple. Should be able to deduce that
// result type is an expression.
if (false)
assertExprReturns(
"case when 1=0 then ([Measures].[Store Sales])\n"
+ " else ([Gender].[M], [Measures].[Unit Sales]) end",
"xxx");
}
public void testPropertiesExpr() {
assertExprReturns(
"[Store].[USA].[CA].[Beverly Hills].[Store 6].Properties(\"Store Type\")",
"Gourmet Supermarket");
}
/**
* Test case for bug
* <a href="http://jira.pentaho.com/browse/MONDRIAN-1227">MONDRIAN-1227,
* "Properties function does not implicitly convert dimension to member; has
* documentation typos"</a>.
*/
public void testPropertiesOnDimension() {
// [Store] is a dimension. When called with a property like FirstChild,
// it is implicitly converted to a member.
assertAxisReturns("[Store].FirstChild", "[Store].[Canada]");
// The same should happen with the <Member>.Properties(<String>)
// function; now the bug is fixed, it does. Dimension is implicitly
// converted to member.
assertExprReturns(
"[Store].Properties('MEMBER_UNIQUE_NAME')",
"[Store].[All Stores]");
// Hierarchy is implicitly converted to member.
assertExprReturns(
"[Store].[USA].Hierarchy.Properties('MEMBER_UNIQUE_NAME')",
"[Store].[All Stores]");
}
/**
* Tests that non-existent property throws an error. *
*/
public void testPropertiesNonExistent() {
assertExprThrows(
"[Store].[USA].[CA].[Beverly Hills].[Store 6].Properties(\"Foo\")",
"Property 'Foo' is not valid for");
}
public void testPropertiesFilter() {
Result result = executeQuery(
"SELECT { [Store Sales] } ON COLUMNS,\n"
+ " TOPCOUNT(Filter( [Store].[Store Name].Members,\n"
+ " [Store].CurrentMember.Properties(\"Store Type\") = \"Supermarket\"),\n"
+ " 10, [Store Sales]) ON ROWS\n"
+ "FROM [Sales]");
Assert.assertEquals(8, result.getAxes()[1].getPositions().size());
}
public void testPropertyInCalculatedMember() {
Result result = executeQuery(
"WITH MEMBER [Measures].[Store Sales per Sqft]\n"
+ "AS '[Measures].[Store Sales] / "
+ " [Store].CurrentMember.Properties(\"Store Sqft\")'\n"
+ "SELECT \n"
+ " {[Measures].[Unit Sales], [Measures].[Store Sales per Sqft]} ON COLUMNS,\n"
+ " {[Store].[Store Name].members} ON ROWS\n"
+ "FROM Sales");
Member member;
Cell cell;
member = result.getAxes()[1].getPositions().get(18).get(0);
Assert.assertEquals(
"[Store].[USA].[WA].[Bellingham].[Store 2]",
member.getUniqueName());
cell = result.getCell(new int[]{0, 18});
Assert.assertEquals("2,237", cell.getFormattedValue());
cell = result.getCell(new int[]{1, 18});
Assert.assertEquals(".17", cell.getFormattedValue());
member = result.getAxes()[1].getPositions().get(3).get(0);
Assert.assertEquals(
"[Store].[Mexico].[DF].[San Andres].[Store 21]",
member.getUniqueName());
cell = result.getCell(new int[]{0, 3});
Assert.assertEquals("", cell.getFormattedValue());
cell = result.getCell(new int[]{1, 3});
Assert.assertEquals("", cell.getFormattedValue());
}
public void testOpeningPeriod() {
assertAxisReturns(
"OpeningPeriod([Time].[Month], [Time].[1997].[Q3])",
"[Time].[1997].[Q3].[7]");
assertAxisReturns(
"OpeningPeriod([Time].[Quarter], [Time].[1997])",
"[Time].[1997].[Q1]");
assertAxisReturns(
"OpeningPeriod([Time].[Year], [Time].[1997])", "[Time].[1997]");
assertAxisReturns(
"OpeningPeriod([Time].[Month], [Time].[1997])",
"[Time].[1997].[Q1].[1]");
assertAxisReturns(
"OpeningPeriod([Product].[Product Name], [Product].[All Products].[Drink])",
"[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]");
getTestContext().withCube("[Sales Ragged]").assertAxisReturns(
"OpeningPeriod([Store].[Store City], [Store].[All Stores].[Israel])",
"[Store].[Israel].[Israel].[Haifa]");
getTestContext().withCube("[Sales Ragged]").assertAxisReturns(
"OpeningPeriod([Store].[Store State], [Store].[All Stores].[Israel])",
"");
// Default member is [Time].[1997].
assertAxisReturns(
"OpeningPeriod([Time].[Month])", "[Time].[1997].[Q1].[1]");
assertAxisReturns("OpeningPeriod()", "[Time].[1997].[Q1]");
TestContext testContext = getTestContext().withCube("[Sales Ragged]");
testContext.assertAxisThrows(
"OpeningPeriod([Time].[Year], [Store].[All Stores].[Israel])",
"The <level> and <member> arguments to OpeningPeriod must be "
+ "from the same hierarchy. The level was from '[Time]' but "
+ "the member was from '[Store]'.");
assertAxisThrows(
"OpeningPeriod([Store].[Store City])",
"The <level> and <member> arguments to OpeningPeriod must be "
+ "from the same hierarchy. The level was from '[Store]' but "
+ "the member was from '[Time]'.");
}
/**
* This tests new NULL functionality exception throwing
*
*/
public void testOpeningPeriodNull() {
assertAxisThrows(
"OpeningPeriod([Time].[Month], NULL)",
"Mondrian Error:Failed to parse query 'select {OpeningPeriod([Time].[Month], NULL)} on columns from Sales'");
}
public void testLastPeriods() {
assertAxisReturns(
"LastPeriods(0, [Time].[1998])", "");
assertAxisReturns(
"LastPeriods(1, [Time].[1998])", "[Time].[1998]");
assertAxisReturns(
"LastPeriods(-1, [Time].[1998])", "[Time].[1998]");
assertAxisReturns(
"LastPeriods(2, [Time].[1998])",
"[Time].[1997]\n" + "[Time].[1998]");
assertAxisReturns(
"LastPeriods(-2, [Time].[1997])",
"[Time].[1997]\n" + "[Time].[1998]");
assertAxisReturns(
"LastPeriods(5000, [Time].[1998])",
"[Time].[1997]\n" + "[Time].[1998]");
assertAxisReturns(
"LastPeriods(-5000, [Time].[1997])",
"[Time].[1997]\n" + "[Time].[1998]");
assertAxisReturns(
"LastPeriods(2, [Time].[1998].[Q2])",
"[Time].[1998].[Q1]\n" + "[Time].[1998].[Q2]");
assertAxisReturns(
"LastPeriods(4, [Time].[1998].[Q2])",
"[Time].[1997].[Q3]\n"
+ "[Time].[1997].[Q4]\n"
+ "[Time].[1998].[Q1]\n"
+ "[Time].[1998].[Q2]");
assertAxisReturns(
"LastPeriods(-2, [Time].[1997].[Q2])",
"[Time].[1997].[Q2]\n" + "[Time].[1997].[Q3]");
assertAxisReturns(
"LastPeriods(-4, [Time].[1997].[Q2])",
"[Time].[1997].[Q2]\n"
+ "[Time].[1997].[Q3]\n"
+ "[Time].[1997].[Q4]\n"
+ "[Time].[1998].[Q1]");
assertAxisReturns(
"LastPeriods(5000, [Time].[1998].[Q2])",
"[Time].[1997].[Q1]\n"
+ "[Time].[1997].[Q2]\n"
+ "[Time].[1997].[Q3]\n"
+ "[Time].[1997].[Q4]\n"
+ "[Time].[1998].[Q1]\n"
+ "[Time].[1998].[Q2]");
assertAxisReturns(
"LastPeriods(-5000, [Time].[1998].[Q2])",
"[Time].[1998].[Q2]\n"
+ "[Time].[1998].[Q3]\n"
+ "[Time].[1998].[Q4]");
assertAxisReturns(
"LastPeriods(2, [Time].[1998].[Q2].[5])",
"[Time].[1998].[Q2].[4]\n" + "[Time].[1998].[Q2].[5]");
assertAxisReturns(
"LastPeriods(12, [Time].[1998].[Q2].[5])",
"[Time].[1997].[Q2].[6]\n"
+ "[Time].[1997].[Q3].[7]\n"
+ "[Time].[1997].[Q3].[8]\n"
+ "[Time].[1997].[Q3].[9]\n"
+ "[Time].[1997].[Q4].[10]\n"
+ "[Time].[1997].[Q4].[11]\n"
+ "[Time].[1997].[Q4].[12]\n"
+ "[Time].[1998].[Q1].[1]\n"
+ "[Time].[1998].[Q1].[2]\n"
+ "[Time].[1998].[Q1].[3]\n"
+ "[Time].[1998].[Q2].[4]\n"
+ "[Time].[1998].[Q2].[5]");
assertAxisReturns(
"LastPeriods(-2, [Time].[1998].[Q2].[4])",
"[Time].[1998].[Q2].[4]\n" + "[Time].[1998].[Q2].[5]");
assertAxisReturns(
"LastPeriods(-12, [Time].[1997].[Q2].[6])",
"[Time].[1997].[Q2].[6]\n"
+ "[Time].[1997].[Q3].[7]\n"
+ "[Time].[1997].[Q3].[8]\n"
+ "[Time].[1997].[Q3].[9]\n"
+ "[Time].[1997].[Q4].[10]\n"
+ "[Time].[1997].[Q4].[11]\n"
+ "[Time].[1997].[Q4].[12]\n"
+ "[Time].[1998].[Q1].[1]\n"
+ "[Time].[1998].[Q1].[2]\n"
+ "[Time].[1998].[Q1].[3]\n"
+ "[Time].[1998].[Q2].[4]\n"
+ "[Time].[1998].[Q2].[5]");
assertAxisReturns(
"LastPeriods(2, [Gender].[M])",
"[Gender].[F]\n" + "[Gender].[M]");
assertAxisReturns(
"LastPeriods(-2, [Gender].[F])",
"[Gender].[F]\n" + "[Gender].[M]");
assertAxisReturns(
"LastPeriods(2, [Gender])", "[Gender].[All Gender]");
assertAxisReturns(
"LastPeriods(2, [Gender].Parent)", "");
}
public void testParallelPeriod() {
assertAxisReturns(
"parallelperiod([Time].[Quarter], 1, [Time].[1998].[Q1])",
"[Time].[1997].[Q4]");
assertAxisReturns(
"parallelperiod([Time].[Quarter], -1, [Time].[1997].[Q1])",
"[Time].[1997].[Q2]");
assertAxisReturns(
"parallelperiod([Time].[Year], 1, [Time].[1998].[Q1])",
"[Time].[1997].[Q1]");
assertAxisReturns(
"parallelperiod([Time].[Year], 1, [Time].[1998].[Q1].[1])",
"[Time].[1997].[Q1].[1]");
// No args, therefore finds parallel period to [Time].[1997], which
// would be [Time].[1996], except that that doesn't exist, so null.
assertAxisReturns("ParallelPeriod()", "");
// Parallel period to [Time].[1997], which would be [Time].[1996],
// except that that doesn't exist, so null.
assertAxisReturns(
"ParallelPeriod([Time].[Year], 1, [Time].[1997])", "");
// one parameter, level 2 above member
if (isDefaultNullMemberRepresentation()) {
assertQueryReturns(
"WITH MEMBER [Measures].[Foo] AS \n"
+ " ' ParallelPeriod([Time].[Year]).UniqueName '\n"
+ "SELECT {[Measures].[Foo]} ON COLUMNS\n"
+ "FROM [Sales]\n"
+ "WHERE [Time].[1997].[Q3].[8]",
"Axis #0:\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: [Time].[#null]\n");
}
// one parameter, level 1 above member
assertQueryReturns(
"WITH MEMBER [Measures].[Foo] AS \n"
+ " ' ParallelPeriod([Time].[Quarter]).UniqueName '\n"
+ "SELECT {[Measures].[Foo]} ON COLUMNS\n"
+ "FROM [Sales]\n"
+ "WHERE [Time].[1997].[Q3].[8]",
"Axis #0:\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: [Time].[1997].[Q2].[5]\n");
// one parameter, level same as member
assertQueryReturns(
"WITH MEMBER [Measures].[Foo] AS \n"
+ " ' ParallelPeriod([Time].[Month]).UniqueName '\n"
+ "SELECT {[Measures].[Foo]} ON COLUMNS\n"
+ "FROM [Sales]\n"
+ "WHERE [Time].[1997].[Q3].[8]",
"Axis #0:\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: [Time].[1997].[Q3].[7]\n");
// one parameter, level below member
if (isDefaultNullMemberRepresentation()) {
assertQueryReturns(
"WITH MEMBER [Measures].[Foo] AS \n"
+ " ' ParallelPeriod([Time].[Month]).UniqueName '\n"
+ "SELECT {[Measures].[Foo]} ON COLUMNS\n"
+ "FROM [Sales]\n"
+ "WHERE [Time].[1997].[Q3]",
"Axis #0:\n"
+ "{[Time].[1997].[Q3]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: [Time].[#null]\n");
}
}
public void _testParallelPeriodThrowsException() {
assertQueryThrows(
"select {parallelperiod([Time].[Year], 1)} on columns "
+ "from [Sales] where ([Time].[1998].[Q1].[2])",
"This should say something about Time appearing on two different axes (slicer an columns)");
}
public void testParallelPeriodDepends() {
getTestContext().assertMemberExprDependsOn(
"ParallelPeriod([Time].[Quarter], 2.0)", "{[Time]}");
getTestContext().assertMemberExprDependsOn(
"ParallelPeriod([Time].[Quarter], 2.0, [Time].[1997].[Q3])", "{}");
getTestContext().assertMemberExprDependsOn(
"ParallelPeriod()",
"{[Time]}");
getTestContext().assertMemberExprDependsOn(
"ParallelPeriod([Product].[Food])", "{[Product]}");
// [Gender].[M] is used here as a numeric expression!
// The numeric expression DOES depend upon [Product].
// The expression as a whole depends upon everything except [Gender].
String s1 = TestContext.allHiersExcept("[Gender]");
getTestContext().assertMemberExprDependsOn(
"ParallelPeriod([Product].[Product Family], [Gender].[M], [Product].[Food])",
s1);
// As above
String s11 = TestContext.allHiersExcept("[Gender]");
getTestContext().assertMemberExprDependsOn(
"ParallelPeriod([Product].[Product Family], [Gender].[M])", s11);
getTestContext().assertSetExprDependsOn(
"parallelperiod([Time].[Time].CurrentMember)",
"{[Time]}");
}
public void testParallelPeriodLevelLag() {
assertQueryReturns(
"with member [Measures].[Prev Unit Sales] as "
+ " '([Measures].[Unit Sales], parallelperiod([Time].[Quarter], 2))' "
+ "select "
+ " crossjoin({[Measures].[Unit Sales], [Measures].[Prev Unit Sales]}, {[Marital Status].[All Marital Status].children}) on columns, "
+ " {[Time].[1997].[Q3]} on rows "
+ "from "
+ " [Sales] ",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales], [Marital Status].[M]}\n"
+ "{[Measures].[Unit Sales], [Marital Status].[S]}\n"
+ "{[Measures].[Prev Unit Sales], [Marital Status].[M]}\n"
+ "{[Measures].[Prev Unit Sales], [Marital Status].[S]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q3]}\n"
+ "Row #0: 32,815\n"
+ "Row #0: 33,033\n"
+ "Row #0: 33,101\n"
+ "Row #0: 33,190\n");
}
public void testParallelPeriodLevel() {
assertQueryReturns(
"with "
+ " member [Measures].[Prev Unit Sales] as "
+ " '([Measures].[Unit Sales], parallelperiod([Time].[Quarter]))' "
+ "select "
+ " crossjoin({[Measures].[Unit Sales], [Measures].[Prev Unit Sales]}, {[Marital Status].[All Marital Status].[M]}) on columns, "
+ " {[Time].[1997].[Q3].[8]} on rows "
+ "from "
+ " [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales], [Marital Status].[M]}\n"
+ "{[Measures].[Prev Unit Sales], [Marital Status].[M]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "Row #0: 10,957\n"
+ "Row #0: 10,280\n");
}
public void testPlus() {
getTestContext().assertExprDependsOn("1 + 2", "{}");
String s1 = TestContext.allHiersExcept("[Measures]", "[Gender]");
getTestContext().assertExprDependsOn(
"([Measures].[Unit Sales], [Gender].[F]) + 2", s1);
assertExprReturns("1+2", "3");
assertExprReturns("5 + " + NullNumericExpr, "5"); // 5 + null --> 5
assertExprReturns(NullNumericExpr + " + " + NullNumericExpr, "");
assertExprReturns(NullNumericExpr + " + 0", "0");
}
public void testMinus() {
assertExprReturns("1-3", "-2");
assertExprReturns("5 - " + NullNumericExpr, "5"); // 5 - null --> 5
assertExprReturns(NullNumericExpr + " - - 2", "2");
assertExprReturns(NullNumericExpr + " - " + NullNumericExpr, "");
}
public void testMinus_bug1234759()
{
assertQueryReturns(
"WITH MEMBER [Customers].[USAMinusMexico]\n"
+ "AS '([Customers].[All Customers].[USA] - [Customers].[All Customers].[Mexico])'\n"
+ "SELECT {[Measures].[Unit Sales]} ON COLUMNS,\n"
+ "{[Customers].[All Customers].[USA], [Customers].[All Customers].[Mexico],\n"
+ "[Customers].[USAMinusMexico]} ON ROWS\n"
+ "FROM [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[Mexico]}\n"
+ "{[Customers].[USAMinusMexico]}\n"
+ "Row #0: 266,773\n"
+ "Row #1: \n"
+ "Row #2: 266,773\n"
// with bug 1234759, this was null
+ "");
}
public void testMinusAssociativity() {
// right-associative would give 11-(7-5) = 9, which is wrong
assertExprReturns("11-7-5", "-1");
}
public void testMultiply() {
assertExprReturns("4*7", "28");
assertExprReturns("5 * " + NullNumericExpr, ""); // 5 * null --> null
assertExprReturns(NullNumericExpr + " * - 2", "");
assertExprReturns(NullNumericExpr + " - " + NullNumericExpr, "");
}
public void testMultiplyPrecedence() {
assertExprReturns("3 + 4 * 5 + 6", "29");
assertExprReturns("5 * 24 / 4 * 2", "60");
assertExprReturns("48 / 4 / 2", "6");
}
/**
* Bug 774807 caused expressions to be mistaken for the crossjoin
* operator.
*/
public void testMultiplyBug774807() {
final String desiredResult =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[All Stores]}\n"
+ "Axis #2:\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[A]}\n"
+ "Row #0: 565,238.13\n"
+ "Row #1: 319,494,143,605.90\n";
assertQueryReturns(
"WITH MEMBER [Measures].[A] AS\n"
+ " '([Measures].[Store Sales] * [Measures].[Store Sales])'\n"
+ "SELECT {[Store]} ON COLUMNS,\n"
+ " {[Measures].[Store Sales], [Measures].[A]} ON ROWS\n"
+ "FROM Sales", desiredResult);
// as above, no parentheses
assertQueryReturns(
"WITH MEMBER [Measures].[A] AS\n"
+ " '[Measures].[Store Sales] * [Measures].[Store Sales]'\n"
+ "SELECT {[Store]} ON COLUMNS,\n"
+ " {[Measures].[Store Sales], [Measures].[A]} ON ROWS\n"
+ "FROM Sales", desiredResult);
// as above, plus 0
assertQueryReturns(
"WITH MEMBER [Measures].[A] AS\n"
+ " '[Measures].[Store Sales] * [Measures].[Store Sales] + 0'\n"
+ "SELECT {[Store]} ON COLUMNS,\n"
+ " {[Measures].[Store Sales], [Measures].[A]} ON ROWS\n"
+ "FROM Sales", desiredResult);
}
public void testDivide() {
assertExprReturns("10 / 5", "2");
assertExprReturns(NullNumericExpr + " / - 2", "");
assertExprReturns(NullNumericExpr + " / " + NullNumericExpr, "");
boolean origNullDenominatorProducesNull =
MondrianProperties.instance().NullDenominatorProducesNull.get();
try {
// default behavior
MondrianProperties.instance().NullDenominatorProducesNull.set(
false);
assertExprReturns("-2 / " + NullNumericExpr, "Infinity");
assertExprReturns("0 / 0", "NaN");
assertExprReturns("-3 / (2 - 2)", "-Infinity");
assertExprReturns("NULL/1", "");
assertExprReturns("NULL/NULL", "");
assertExprReturns("1/NULL", "Infinity");
// when NullOrZeroDenominatorProducesNull is set to true
MondrianProperties.instance().NullDenominatorProducesNull.set(true);
assertExprReturns("-2 / " + NullNumericExpr, "");
assertExprReturns("0 / 0", "NaN");
assertExprReturns("-3 / (2 - 2)", "-Infinity");
assertExprReturns("NULL/1", "");
assertExprReturns("NULL/NULL", "");
assertExprReturns("1/NULL", "");
} finally {
MondrianProperties.instance().NullDenominatorProducesNull.set(
origNullDenominatorProducesNull);
}
}
public void testDividePrecedence() {
assertExprReturns("24 / 4 / 2 * 10 - -1", "31");
}
public void testMod() {
// the following tests are consistent with excel xp
assertExprReturns("mod(11, 3)", "2");
assertExprReturns("mod(-12, 3)", "0");
// can handle non-ints, using the formula MOD(n, d) = n - d * INT(n / d)
assertExprReturns("mod(7.2, 3)", 1.2, 0.0001);
assertExprReturns("mod(7.2, 3.2)", .8, 0.0001);
assertExprReturns("mod(7.2, -3.2)", -2.4, 0.0001);
// per Excel doc "sign of result is same as divisor"
assertExprReturns("mod(3, 2)", "1");
assertExprReturns("mod(-3, 2)", "1");
assertExprReturns("mod(3, -2)", "-1");
assertExprReturns("mod(-3, -2)", "-1");
assertExprThrows(
"mod(4, 0)",
"java.lang.ArithmeticException: / by zero");
assertExprThrows(
"mod(0, 0)",
"java.lang.ArithmeticException: / by zero");
}
public void testUnaryMinus() {
assertExprReturns("-3", "-3");
}
public void testUnaryMinusMember() {
assertExprReturns(
"- ([Measures].[Unit Sales],[Gender].[F])",
"-131,558");
}
public void testUnaryMinusPrecedence() {
assertExprReturns("1 - -10.5 * 2 -3", "19");
}
public void testNegativeZero() {
assertExprReturns("-0.0", "0");
}
public void testNegativeZero1() {
assertExprReturns("-(0.0)", "0");
}
public void testNegativeZeroSubtract() {
assertExprReturns("-0.0 - 0.0", "0");
}
public void testNegativeZeroMultiply() {
assertExprReturns("-1 * 0", "0");
}
public void testNegativeZeroDivide() {
assertExprReturns("-0.0 / 2", "0");
}
public void testString() {
// The String(Integer,Char) function requires us to implicitly cast a
// string to a char.
assertQueryReturns(
"with member measures.x as 'String(3, \"yahoo\")'\n"
+ "select measures.x on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[x]}\n"
+ "Row #0: yyy\n");
// String is converted to char by taking first character
assertExprReturns("String(3, \"yahoo\")", "yyy"); // SSAS agrees
// Integer is converted to char by converting to string and taking first
// character
if (Bug.Ssas2005Compatible) {
// SSAS2005 can implicitly convert an integer (32) to a string, and
// then to a char by taking the first character. Mondrian requires
// an explicit cast.
assertExprReturns("String(3, 32)", "333");
assertExprReturns("String(8, -5)", "--------");
} else {
assertExprReturns("String(3, Cast(32 as string))", "333");
assertExprReturns("String(8, Cast(-5 as string))", "--------");
}
// Error if length<0
assertExprReturns("String(0, 'x')", ""); // SSAS agrees
assertExprThrows(
"String(-1, 'x')", "NegativeArraySizeException"); // SSAS agrees
assertExprThrows(
"String(-200, 'x')", "NegativeArraySizeException"); // SSAS agrees
}
public void testStringConcat() {
assertExprReturns(
" \"foo\" || \"bar\" ",
"foobar");
}
public void testStringConcat2() {
assertExprReturns(
" \"foo\" || [Gender].[M].Name || \"\" ",
"fooM");
}
public void testAnd() {
assertBooleanExprReturns(" 1=1 AND 2=2 ", true);
}
public void testAnd2() {
assertBooleanExprReturns(" 1=1 AND 2=0 ", false);
}
public void testOr() {
assertBooleanExprReturns(" 1=0 OR 2=0 ", false);
}
public void testOr2() {
assertBooleanExprReturns(" 1=0 OR 0=0 ", true);
}
public void testOrAssociativity1() {
// Would give 'false' if OR were stronger than AND (wrong!)
assertBooleanExprReturns(" 1=1 AND 1=0 OR 1=1 ", true);
}
public void testOrAssociativity2() {
// Would give 'false' if OR were stronger than AND (wrong!)
assertBooleanExprReturns(" 1=1 OR 1=0 AND 1=1 ", true);
}
public void testOrAssociativity3() {
assertBooleanExprReturns(" (1=0 OR 1=1) AND 1=1 ", true);
}
public void testXor() {
assertBooleanExprReturns(" 1=1 XOR 2=2 ", false);
}
public void testXorAssociativity() {
// Would give 'false' if XOR were stronger than AND (wrong!)
assertBooleanExprReturns(" 1 = 1 AND 1 = 1 XOR 1 = 0 ", true);
}
public void testNonEmptyCrossJoin() {
// NonEmptyCrossJoin needs to evaluate measures to find out whether
// cells are empty, so it implicitly depends upon all dimensions.
String s1 = TestContext.allHiersExcept("[Store]");
getTestContext().assertSetExprDependsOn(
"NonEmptyCrossJoin([Store].[USA].Children, [Gender].Children)", s1);
assertAxisReturns(
"NonEmptyCrossJoin("
+ "[Customers].[All Customers].[USA].[CA].Children, "
+ "[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].Children)",
"{[Customers].[USA].[CA].[Bellflower], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[Downey], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}\n"
+ "{[Customers].[USA].[CA].[Glendale], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}\n"
+ "{[Customers].[USA].[CA].[Glendale], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[Grossmont], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[Imperial Beach], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[La Jolla], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}\n"
+ "{[Customers].[USA].[CA].[Lincoln Acres], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}\n"
+ "{[Customers].[USA].[CA].[Lincoln Acres], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[Long Beach], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[Los Angeles], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}\n"
+ "{[Customers].[USA].[CA].[Newport Beach], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}\n"
+ "{[Customers].[USA].[CA].[Pomona], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}\n"
+ "{[Customers].[USA].[CA].[Pomona], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[San Gabriel], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[West Covina], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}\n"
+ "{[Customers].[USA].[CA].[West Covina], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Light Beer]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills], [Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good].[Good Imported Beer]}");
// empty set
assertAxisReturns(
"NonEmptyCrossJoin({Gender.Parent}, {Store.Parent})", "");
assertAxisReturns(
"NonEmptyCrossJoin({Store.Parent}, Gender.Children)", "");
assertAxisReturns("NonEmptyCrossJoin(Store.Members, {})", "");
// same dimension twice
// todo: should throw
if (false) {
assertAxisThrows(
"NonEmptyCrossJoin({Store.[USA]}, {Store.[USA].[CA]})",
"xxx");
}
}
public void testNot() {
assertBooleanExprReturns(" NOT 1=1 ", false);
}
public void testNotNot() {
assertBooleanExprReturns(" NOT NOT 1=1 ", true);
}
public void testNotAssociativity() {
assertBooleanExprReturns(" 1=1 AND NOT 1=1 OR NOT 1=1 AND 1=1 ", false);
}
public void testIsNull() {
assertBooleanExprReturns(" Store.[All Stores] IS NULL ", false);
assertBooleanExprReturns(" Store.[All Stores].parent IS NULL ", true);
}
public void testIsMember() {
assertBooleanExprReturns(
" Store.[USA].parent IS Store.[All Stores]", true);
assertBooleanExprReturns(
" [Store].[USA].[CA].parent IS [Store].[Mexico]", false);
}
public void testIsString() {
assertExprThrows(
" [Store].[USA].Name IS \"USA\" ",
"No function matches signature '<String> IS <String>'");
}
public void testIsNumeric() {
assertExprThrows(
" [Store].[USA].Level.Ordinal IS 25 ",
"No function matches signature '<Numeric Expression> IS <Numeric Expression>'");
}
public void testIsTuple() {
assertBooleanExprReturns(
" (Store.[USA], Gender.[M]) IS (Store.[USA], Gender.[M])", true);
assertBooleanExprReturns(
" (Store.[USA], Gender.[M]) IS (Gender.[M], Store.[USA])", true);
assertBooleanExprReturns(
" (Store.[USA], Gender.[M]) IS (Gender.[M], Store.[USA]) "
+ "OR [Gender] IS NULL",
true);
assertBooleanExprReturns(
" (Store.[USA], Gender.[M]) IS (Gender.[M], Store.[USA]) "
+ "AND [Gender] IS NULL",
false);
assertBooleanExprReturns(
" (Store.[USA], Gender.[M]) IS (Store.[USA], Gender.[F])",
false);
assertBooleanExprReturns(
" (Store.[USA], Gender.[M]) IS (Store.[USA])",
false);
assertBooleanExprReturns(
" (Store.[USA], Gender.[M]) IS Store.[USA]",
false);
}
public void testIsLevel() {
assertBooleanExprReturns(
" Store.[USA].level IS Store.[Store Country] ", true);
assertBooleanExprReturns(
" Store.[USA].[CA].level IS Store.[Store Country] ", false);
}
public void testIsHierarchy() {
assertBooleanExprReturns(
" Store.[USA].hierarchy IS Store.[Mexico].hierarchy ", true);
assertBooleanExprReturns(
" Store.[USA].hierarchy IS Gender.[M].hierarchy ", false);
}
public void testIsDimension() {
assertBooleanExprReturns(" Store.[USA].dimension IS Store ", true);
assertBooleanExprReturns(" Gender.[M].dimension IS Store ", false);
}
public void testStringEquals() {
assertBooleanExprReturns(" \"foo\" = \"bar\" ", false);
}
public void testStringEqualsAssociativity() {
assertBooleanExprReturns(" \"foo\" = \"fo\" || \"o\" ", true);
}
public void testStringEqualsEmpty() {
assertBooleanExprReturns(" \"\" = \"\" ", true);
}
public void testEq() {
assertBooleanExprReturns(" 1.0 = 1 ", true);
assertBooleanExprReturns(
"[Product].CurrentMember.Level.Ordinal = 2.0", false);
checkNullOp("=");
}
public void testStringNe() {
assertBooleanExprReturns(" \"foo\" <> \"bar\" ", true);
}
public void testNe() {
assertBooleanExprReturns(" 2 <> 1.0 + 1.0 ", false);
checkNullOp("<>");
}
public void testNeInfinity() {
// Infinity does not equal itself
assertBooleanExprReturns("(1 / 0) <> (1 / 0)", false);
}
public void testLt() {
assertBooleanExprReturns(" 2 < 1.0 + 1.0 ", false);
checkNullOp("<");
}
public void testLe() {
assertBooleanExprReturns(" 2 <= 1.0 + 1.0 ", true);
checkNullOp("<=");
}
public void testGt() {
assertBooleanExprReturns(" 2 > 1.0 + 1.0 ", false);
checkNullOp(">");
}
public void testGe() {
assertBooleanExprReturns(" 2 > 1.0 + 1.0 ", false);
checkNullOp(">=");
}
private void checkNullOp(final String op) {
assertBooleanExprReturns(" 0 " + op + " " + NullNumericExpr, false);
assertBooleanExprReturns(NullNumericExpr + " " + op + " 0", false);
assertBooleanExprReturns(
NullNumericExpr + " " + op + " " + NullNumericExpr, false);
}
public void testDistinctTwoMembers() {
getTestContext().withCube("HR").assertAxisReturns(
"Distinct({[Employees].[All Employees].[Sheri Nowmer].[Donna Arnold],"
+ "[Employees].[Sheri Nowmer].[Donna Arnold]})",
"[Employees].[Sheri Nowmer].[Donna Arnold]");
}
public void testDistinctThreeMembers() {
getTestContext().withCube("HR").assertAxisReturns(
"Distinct({[Employees].[All Employees].[Sheri Nowmer].[Donna Arnold],"
+ "[Employees].[All Employees].[Sheri Nowmer].[Darren Stanz],"
+ "[Employees].[All Employees].[Sheri Nowmer].[Donna Arnold]})",
"[Employees].[Sheri Nowmer].[Donna Arnold]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz]");
}
public void testDistinctFourMembers() {
getTestContext().withCube("HR").assertAxisReturns(
"Distinct({[Employees].[All Employees].[Sheri Nowmer].[Donna Arnold],"
+ "[Employees].[All Employees].[Sheri Nowmer].[Darren Stanz],"
+ "[Employees].[All Employees].[Sheri Nowmer].[Donna Arnold],"
+ "[Employees].[All Employees].[Sheri Nowmer].[Darren Stanz]})",
"[Employees].[Sheri Nowmer].[Donna Arnold]\n"
+ "[Employees].[Sheri Nowmer].[Darren Stanz]");
}
public void testDistinctTwoTuples() {
getTestContext().assertAxisReturns(
"Distinct({([Time].[1997],[Store].[All Stores].[Mexico]), "
+ "([Time].[1997], [Store].[All Stores].[Mexico])})",
"{[Time].[1997], [Store].[Mexico]}");
}
public void testDistinctSomeTuples() {
getTestContext().assertAxisReturns(
"Distinct({([Time].[1997],[Store].[All Stores].[Mexico]), "
+ "crossjoin({[Time].[1997]},{[Store].[All Stores].children})})",
"{[Time].[1997], [Store].[Mexico]}\n"
+ "{[Time].[1997], [Store].[Canada]}\n"
+ "{[Time].[1997], [Store].[USA]}");
}
/**
* Make sure that slicer is in force when expression is applied
* on axis, E.g. select filter([Customers].members, [Unit Sales] > 100)
* from sales where ([Time].[1998])
*/
public void testFilterWithSlicer() {
Result result = executeQuery(
"select {[Measures].[Unit Sales]} on columns,\n"
+ " filter([Customers].[USA].children,\n"
+ " [Measures].[Unit Sales] > 20000) on rows\n"
+ "from Sales\n"
+ "where ([Time].[1997].[Q1])");
Axis rows = result.getAxes()[1];
// if slicer were ignored, there would be 3 rows
Assert.assertEquals(1, rows.getPositions().size());
Cell cell = result.getCell(new int[]{0, 0});
Assert.assertEquals("30,114", cell.getFormattedValue());
}
public void testFilterCompound() {
Result result = executeQuery(
"select {[Measures].[Unit Sales]} on columns,\n"
+ " Filter(\n"
+ " CrossJoin(\n"
+ " [Gender].Children,\n"
+ " [Customers].[USA].Children),\n"
+ " [Measures].[Unit Sales] > 9500) on rows\n"
+ "from Sales\n"
+ "where ([Time].[1997].[Q1])");
List<Position> rows = result.getAxes()[1].getPositions();
Assert.assertEquals(3, rows.size());
Assert.assertEquals("F", rows.get(0).get(0).getName());
Assert.assertEquals("WA", rows.get(0).get(1).getName());
Assert.assertEquals("M", rows.get(1).get(0).getName());
Assert.assertEquals("OR", rows.get(1).get(1).getName());
Assert.assertEquals("M", rows.get(2).get(0).getName());
Assert.assertEquals("WA", rows.get(2).get(1).getName());
}
public void testGenerateDepends() {
getTestContext().assertSetExprDependsOn(
"Generate([Product].CurrentMember.Children, Crossjoin({[Product].CurrentMember}, Crossjoin([Store].[Store State].Members, [Store Type].Members)), ALL)",
"{[Product]}");
getTestContext().assertSetExprDependsOn(
"Generate([Product].[All Products].Children, Crossjoin({[Product].CurrentMember}, Crossjoin([Store].[Store State].Members, [Store Type].Members)), ALL)",
"{}");
getTestContext().assertSetExprDependsOn(
"Generate({[Store].[USA], [Store].[USA].[CA]}, {[Store].CurrentMember.Children})",
"{}");
getTestContext().assertSetExprDependsOn(
"Generate({[Store].[USA], [Store].[USA].[CA]}, {[Gender].CurrentMember})",
"{[Gender]}");
getTestContext().assertSetExprDependsOn(
"Generate({[Store].[USA], [Store].[USA].[CA]}, {[Gender].[M]})",
"{}");
}
public void testGenerate() {
assertAxisReturns(
"Generate({[Store].[USA], [Store].[USA].[CA]}, {[Store].CurrentMember.Children})",
"[Store].[USA].[CA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[WA]\n"
+ "[Store].[USA].[CA].[Alameda]\n"
+ "[Store].[USA].[CA].[Beverly Hills]\n"
+ "[Store].[USA].[CA].[Los Angeles]\n"
+ "[Store].[USA].[CA].[San Diego]\n"
+ "[Store].[USA].[CA].[San Francisco]");
}
public void testGenerateNonSet() {
// SSAS implicitly converts arg #2 to a set
assertAxisReturns(
"Generate({[Store].[USA], [Store].[USA].[CA]}, [Store].PrevMember, ALL)",
"[Store].[Mexico]\n"
+ "[Store].[Mexico].[Zacatecas]");
// SSAS implicitly converts arg #1 to a set
assertAxisReturns(
"Generate([Store].[USA], [Store].PrevMember, ALL)",
"[Store].[Mexico]");
}
public void testGenerateAll() {
assertAxisReturns(
"Generate({[Store].[USA].[CA], [Store].[USA].[OR].[Portland]},"
+ " Ascendants([Store].CurrentMember),"
+ " ALL)",
"[Store].[USA].[CA]\n"
+ "[Store].[USA]\n"
+ "[Store].[All Stores]\n"
+ "[Store].[USA].[OR].[Portland]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA]\n"
+ "[Store].[All Stores]");
}
public void testGenerateUnique() {
assertAxisReturns(
"Generate({[Store].[USA].[CA], [Store].[USA].[OR].[Portland]},"
+ " Ascendants([Store].CurrentMember))",
"[Store].[USA].[CA]\n"
+ "[Store].[USA]\n"
+ "[Store].[All Stores]\n"
+ "[Store].[USA].[OR].[Portland]\n"
+ "[Store].[USA].[OR]");
}
public void testGenerateUniqueTuple() {
assertAxisReturns(
"Generate({([Store].[USA].[CA],[Product].[All Products]), "
+ "([Store].[USA].[CA],[Product].[All Products])},"
+ "{([Store].CurrentMember, [Product].CurrentMember)})",
"{[Store].[USA].[CA], [Product].[All Products]}");
}
public void testGenerateCrossJoin() {
// Note that the different regions have different Top 2.
assertAxisReturns(
"Generate({[Store].[USA].[CA], [Store].[USA].[CA].[San Francisco]},\n"
+ " CrossJoin({[Store].CurrentMember},\n"
+ " TopCount([Product].[Brand Name].members, \n"
+ " 2,\n"
+ " [Measures].[Unit Sales])))",
"{[Store].[USA].[CA], [Product].[Food].[Produce].[Vegetables].[Fresh Vegetables].[Hermanos]}\n"
+ "{[Store].[USA].[CA], [Product].[Food].[Produce].[Vegetables].[Fresh Vegetables].[Tell Tale]}\n"
+ "{[Store].[USA].[CA].[San Francisco], [Product].[Food].[Produce].[Vegetables].[Fresh Vegetables].[Ebony]}\n"
+ "{[Store].[USA].[CA].[San Francisco], [Product].[Food].[Produce].[Vegetables].[Fresh Vegetables].[High Top]}");
}
public void testGenerateString() {
assertExprReturns(
"Generate({Time.[1997], Time.[1998]},"
+ " Time.[Time].CurrentMember.Name)",
"19971998");
assertExprReturns(
"Generate({Time.[1997], Time.[1998]},"
+ " Time.[Time].CurrentMember.Name, \" and \")",
"1997 and 1998");
}
public void testHead() {
assertAxisReturns(
"Head([Store].Children, 2)",
"[Store].[Canada]\n"
+ "[Store].[Mexico]");
}
public void testHeadNegative() {
assertAxisReturns(
"Head([Store].Children, 2 - 3)",
"");
}
public void testHeadDefault() {
assertAxisReturns(
"Head([Store].Children)",
"[Store].[Canada]");
}
public void testHeadOvershoot() {
assertAxisReturns(
"Head([Store].Children, 2 + 2)",
"[Store].[Canada]\n"
+ "[Store].[Mexico]\n"
+ "[Store].[USA]");
}
public void testHeadEmpty() {
assertAxisReturns(
"Head([Gender].[F].Children, 2)",
"");
assertAxisReturns(
"Head([Gender].[F].Children)",
"");
}
/**
* Test case for bug 2488492, "Union between calc mem and head function
* throws exception"
*/
public void testHeadBug() {
assertQueryReturns(
"SELECT\n"
+ " UNION(\n"
+ " {([Customers].CURRENTMEMBER)},\n"
+ " HEAD(\n"
+ " {([Customers].CURRENTMEMBER)},\n"
+ " IIF(\n"
+ " COUNT(\n"
+ " FILTER(\n"
+ " DESCENDANTS(\n"
+ " [Customers].CURRENTMEMBER,\n"
+ " [Customers].[Country]),\n"
+ " [Measures].[Unit Sales] >= 66),\n"
+ " INCLUDEEMPTY)> 0,\n"
+ " 1,\n"
+ " 0)),\n"
+ " ALL)\n"
+ " ON AXIS(0)\n"
+ "FROM\n"
+ " [Sales]\n",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[All Customers]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 266,773\n");
assertQueryReturns(
"WITH\n"
+ " MEMBER\n"
+ " [Customers].[COG_OQP_INT_t2]AS '1',\n"
+ " SOLVE_ORDER = 65535\n"
+ "SELECT\n"
+ " UNION(\n"
+ " {([Customers].[COG_OQP_INT_t2])},\n"
+ " HEAD(\n"
+ " {([Customers].CURRENTMEMBER)},\n"
+ " IIF(\n"
+ " COUNT(\n"
+ " FILTER(\n"
+ " DESCENDANTS(\n"
+ " [Customers].CURRENTMEMBER,\n"
+ " [Customers].[Country]),\n"
+ " [Measures].[Unit Sales]>= 66),\n"
+ " INCLUDEEMPTY)> 0,\n"
+ " 1,\n"
+ " 0)),\n"
+ " ALL)\n"
+ " ON AXIS(0)\n"
+ "FROM\n"
+ " [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[COG_OQP_INT_t2]}\n"
+ "{[Customers].[All Customers]}\n"
+ "Row #0: 1\n"
+ "Row #0: 266,773\n");
// More minimal test case. Also demonstrates similar problem with Tail.
assertAxisReturns(
"Union(\n"
+ " Union(\n"
+ " Tail([Customers].[USA].[CA].Children, 2),\n"
+ " Head([Customers].[USA].[WA].Children, 2),\n"
+ " ALL),\n"
+ " Tail([Customers].[USA].[OR].Children, 2),"
+ " ALL)",
"[Customers].[USA].[CA].[West Covina]\n"
+ "[Customers].[USA].[CA].[Woodland Hills]\n"
+ "[Customers].[USA].[WA].[Anacortes]\n"
+ "[Customers].[USA].[WA].[Ballard]\n"
+ "[Customers].[USA].[OR].[W. Linn]\n"
+ "[Customers].[USA].[OR].[Woodburn]");
}
public void testHierarchize() {
assertAxisReturns(
"Hierarchize(\n"
+ " {[Product].[All Products], "
+ " [Product].[Food],\n"
+ " [Product].[Drink],\n"
+ " [Product].[Non-Consumable],\n"
+ " [Product].[Food].[Eggs],\n"
+ " [Product].[Drink].[Dairy]})",
"[Product].[All Products]\n"
+ "[Product].[Drink]\n"
+ "[Product].[Drink].[Dairy]\n"
+ "[Product].[Food]\n"
+ "[Product].[Food].[Eggs]\n"
+ "[Product].[Non-Consumable]");
}
public void testHierarchizePost() {
assertAxisReturns(
"Hierarchize(\n"
+ " {[Product].[All Products], "
+ " [Product].[Food],\n"
+ " [Product].[Food].[Eggs],\n"
+ " [Product].[Drink].[Dairy]},\n"
+ " POST)",
"[Product].[Drink].[Dairy]\n"
+ "[Product].[Food].[Eggs]\n"
+ "[Product].[Food]\n"
+ "[Product].[All Products]");
}
public void testHierarchizePC() {
getTestContext().withCube("HR").assertAxisReturns(
"Hierarchize(\n"
+ " { Subset([Employees].Members, 90, 10),\n"
+ " Head([Employees].Members, 5) })",
"[Employees].[All Employees]\n"
+ "[Employees].[Sheri Nowmer]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Beverly Baker]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Beverly Baker].[Shauna Wyro]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Leopoldo Renfro]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Donna Brockett]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Laurie Anderson]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Louis Gomez]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Melvin Glass]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Kristin Cohen]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Susan Kharman]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Gordon Kirschner]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Geneva Kouba]\n"
+ "[Employees].[Sheri Nowmer].[Derrick Whelply].[Pedro Castillo].[Lin Conley].[Paul Tays].[Cheryl Thorton].[Tricia Clark]");
}
public void testHierarchizeCrossJoinPre() {
assertAxisReturns(
"Hierarchize(\n"
+ " CrossJoin(\n"
+ " {[Product].[All Products], "
+ " [Product].[Food],\n"
+ " [Product].[Food].[Eggs],\n"
+ " [Product].[Drink].[Dairy]},\n"
+ " [Gender].MEMBERS),\n"
+ " PRE)",
"{[Product].[All Products], [Gender].[All Gender]}\n"
+ "{[Product].[All Products], [Gender].[F]}\n"
+ "{[Product].[All Products], [Gender].[M]}\n"
+ "{[Product].[Drink].[Dairy], [Gender].[All Gender]}\n"
+ "{[Product].[Drink].[Dairy], [Gender].[F]}\n"
+ "{[Product].[Drink].[Dairy], [Gender].[M]}\n"
+ "{[Product].[Food], [Gender].[All Gender]}\n"
+ "{[Product].[Food], [Gender].[F]}\n"
+ "{[Product].[Food], [Gender].[M]}\n"
+ "{[Product].[Food].[Eggs], [Gender].[All Gender]}\n"
+ "{[Product].[Food].[Eggs], [Gender].[F]}\n"
+ "{[Product].[Food].[Eggs], [Gender].[M]}");
}
public void testHierarchizeCrossJoinPost() {
assertAxisReturns(
"Hierarchize(\n"
+ " CrossJoin(\n"
+ " {[Product].[All Products], "
+ " [Product].[Food],\n"
+ " [Product].[Food].[Eggs],\n"
+ " [Product].[Drink].[Dairy]},\n"
+ " [Gender].MEMBERS),\n"
+ " POST)",
"{[Product].[Drink].[Dairy], [Gender].[F]}\n"
+ "{[Product].[Drink].[Dairy], [Gender].[M]}\n"
+ "{[Product].[Drink].[Dairy], [Gender].[All Gender]}\n"
+ "{[Product].[Food].[Eggs], [Gender].[F]}\n"
+ "{[Product].[Food].[Eggs], [Gender].[M]}\n"
+ "{[Product].[Food].[Eggs], [Gender].[All Gender]}\n"
+ "{[Product].[Food], [Gender].[F]}\n"
+ "{[Product].[Food], [Gender].[M]}\n"
+ "{[Product].[Food], [Gender].[All Gender]}\n"
+ "{[Product].[All Products], [Gender].[F]}\n"
+ "{[Product].[All Products], [Gender].[M]}\n"
+ "{[Product].[All Products], [Gender].[All Gender]}");
}
/**
* Tests that the Hierarchize function works correctly when applied to
* a level whose ordering is determined by an 'ordinal' property.
* TODO: fix this test (bug 1220787)
*
* WG: Note that this is disabled right now due to its impact on other
* tests later on within the test suite, specifically XMLA tests that
* return a list of cubes. We could run this test after XMLA, or clear
* out the cache to solve this.
*/
public void testHierarchizeOrdinal() {
TestContext context = getTestContext().withCube("[Sales_Hierarchize]");
final Connection connection = context.getConnection();
connection.getSchema().createCube(
"<Cube name=\"Sales_Hierarchize\">\n"
+ " <Table name=\"sales_fact_1997\"/>\n"
+ " <Dimension name=\"Time_Alphabetical\" type=\"TimeDimension\" foreignKey=\"time_id\">\n"
+ " <Hierarchy hasAll=\"false\" primaryKey=\"time_id\">\n"
+ " <Table name=\"time_by_day\"/>\n"
+ " <Level name=\"Year\" column=\"the_year\" type=\"Numeric\" uniqueMembers=\"true\"\n"
+ " levelType=\"TimeYears\"/>\n"
+ " <Level name=\"Quarter\" column=\"quarter\" uniqueMembers=\"false\"\n"
+ " levelType=\"TimeQuarters\"/>\n"
+ " <Level name=\"Month\" column=\"month_of_year\" uniqueMembers=\"false\" type=\"Numeric\"\n"
+ " ordinalColumn=\"the_month\"\n"
+ " levelType=\"TimeMonths\"/>\n"
+ " </Hierarchy>\n"
+ " </Dimension>\n"
+ "\n"
+ " <Dimension name=\"Month_Alphabetical\" type=\"TimeDimension\" foreignKey=\"time_id\">\n"
+ " <Hierarchy hasAll=\"false\" primaryKey=\"time_id\">\n"
+ " <Table name=\"time_by_day\"/>\n"
+ " <Level name=\"Month\" column=\"month_of_year\" uniqueMembers=\"false\" type=\"Numeric\"\n"
+ " ordinalColumn=\"the_month\"\n"
+ " levelType=\"TimeMonths\"/>\n"
+ " </Hierarchy>\n"
+ " </Dimension>\n"
+ "\n"
+ " <Measure name=\"Unit Sales\" column=\"unit_sales\" aggregator=\"sum\"\n"
+ " formatString=\"Standard\"/>\n"
+ "</Cube>");
// The [Time_Alphabetical] is ordered alphabetically by month
context.assertAxisReturns(
"Hierarchize([Time_Alphabetical].members)",
"[Time_Alphabetical].[1997]\n"
+ "[Time_Alphabetical].[1997].[Q1]\n"
+ "[Time_Alphabetical].[1997].[Q1].[2]\n"
+ "[Time_Alphabetical].[1997].[Q1].[1]\n"
+ "[Time_Alphabetical].[1997].[Q1].[3]\n"
+ "[Time_Alphabetical].[1997].[Q2]\n"
+ "[Time_Alphabetical].[1997].[Q2].[4]\n"
+ "[Time_Alphabetical].[1997].[Q2].[6]\n"
+ "[Time_Alphabetical].[1997].[Q2].[5]\n"
+ "[Time_Alphabetical].[1997].[Q3]\n"
+ "[Time_Alphabetical].[1997].[Q3].[8]\n"
+ "[Time_Alphabetical].[1997].[Q3].[7]\n"
+ "[Time_Alphabetical].[1997].[Q3].[9]\n"
+ "[Time_Alphabetical].[1997].[Q4]\n"
+ "[Time_Alphabetical].[1997].[Q4].[12]\n"
+ "[Time_Alphabetical].[1997].[Q4].[11]\n"
+ "[Time_Alphabetical].[1997].[Q4].[10]\n"
+ "[Time_Alphabetical].[1998]\n"
+ "[Time_Alphabetical].[1998].[Q1]\n"
+ "[Time_Alphabetical].[1998].[Q1].[2]\n"
+ "[Time_Alphabetical].[1998].[Q1].[1]\n"
+ "[Time_Alphabetical].[1998].[Q1].[3]\n"
+ "[Time_Alphabetical].[1998].[Q2]\n"
+ "[Time_Alphabetical].[1998].[Q2].[4]\n"
+ "[Time_Alphabetical].[1998].[Q2].[6]\n"
+ "[Time_Alphabetical].[1998].[Q2].[5]\n"
+ "[Time_Alphabetical].[1998].[Q3]\n"
+ "[Time_Alphabetical].[1998].[Q3].[8]\n"
+ "[Time_Alphabetical].[1998].[Q3].[7]\n"
+ "[Time_Alphabetical].[1998].[Q3].[9]\n"
+ "[Time_Alphabetical].[1998].[Q4]\n"
+ "[Time_Alphabetical].[1998].[Q4].[12]\n"
+ "[Time_Alphabetical].[1998].[Q4].[11]\n"
+ "[Time_Alphabetical].[1998].[Q4].[10]");
// The [Month_Alphabetical] is a single-level hierarchy ordered
// alphabetically by month.
context.assertAxisReturns(
"Hierarchize([Month_Alphabetical].members)",
"[Month_Alphabetical].[4]\n"
+ "[Month_Alphabetical].[8]\n"
+ "[Month_Alphabetical].[12]\n"
+ "[Month_Alphabetical].[2]\n"
+ "[Month_Alphabetical].[1]\n"
+ "[Month_Alphabetical].[7]\n"
+ "[Month_Alphabetical].[6]\n"
+ "[Month_Alphabetical].[3]\n"
+ "[Month_Alphabetical].[5]\n"
+ "[Month_Alphabetical].[11]\n"
+ "[Month_Alphabetical].[10]\n"
+ "[Month_Alphabetical].[9]");
// clear the cache so that future tests don't fail that expect a
// specific set of cubes
TestContext.instance().flushSchemaCache();
}
public void testIntersectAll() {
// Note: duplicates retained from left, not from right; and order is
// preserved.
assertAxisReturns(
"Intersect({[Time].[1997].[Q2], [Time].[1997], [Time].[1997].[Q1], [Time].[1997].[Q2]}, "
+ "{[Time].[1998], [Time].[1997], [Time].[1997].[Q2], [Time].[1997]}, "
+ "ALL)",
"[Time].[1997].[Q2]\n"
+ "[Time].[1997]\n"
+ "[Time].[1997].[Q2]");
}
public void testIntersect() {
// Duplicates not preserved. Output in order that first duplicate
// occurred.
assertAxisReturns(
"Intersect(\n"
+ " {[Time].[1997].[Q2], [Time].[1997], [Time].[1997].[Q1], [Time].[1997].[Q2]}, "
+ "{[Time].[1998], [Time].[1997], [Time].[1997].[Q2], [Time].[1997]})",
"[Time].[1997].[Q2]\n"
+ "[Time].[1997]");
}
public void testIntersectTuples() {
assertAxisReturns(
"Intersect(\n"
+ " {([Time].[1997].[Q2], [Gender].[M]),\n"
+ " ([Time].[1997], [Gender].[F]),\n"
+ " ([Time].[1997].[Q1], [Gender].[M]),\n"
+ " ([Time].[1997].[Q2], [Gender].[M])},\n"
+ " {([Time].[1998], [Gender].[F]),\n"
+ " ([Time].[1997], [Gender].[F]),\n"
+ " ([Time].[1997].[Q2], [Gender].[M]),\n"
+ " ([Time].[1997], [Gender])})",
"{[Time].[1997].[Q2], [Gender].[M]}\n"
+ "{[Time].[1997], [Gender].[F]}");
}
public void testIntersectRightEmpty() {
assertAxisReturns(
"Intersect({[Time].[1997]}, {})",
"");
}
public void testIntersectLeftEmpty() {
assertAxisReturns(
"Intersect({}, {[Store].[USA].[CA]})",
"");
}
public void testOrderDepends() {
// Order(<Set>, <Value Expression>) depends upon everything
// <Value Expression> depends upon, except the dimensions of <Set>.
// Depends upon everything EXCEPT [Product], [Measures],
// [Marital Status], [Gender].
String s11 = TestContext.allHiersExcept(
"[Product]", "[Measures]", "[Marital Status]", "[Gender]");
getTestContext().assertSetExprDependsOn(
"Order("
+ " Crossjoin([Gender].MEMBERS, [Product].MEMBERS),"
+ " ([Measures].[Unit Sales], [Marital Status].[S]),"
+ " ASC)",
s11);
// Depends upon everything EXCEPT [Product], [Measures],
// [Marital Status]. Does depend upon [Gender].
String s12 = TestContext.allHiersExcept(
"[Product]", "[Measures]", "[Marital Status]");
getTestContext().assertSetExprDependsOn(
"Order("
+ " Crossjoin({[Gender].CurrentMember}, [Product].MEMBERS),"
+ " ([Measures].[Unit Sales], [Marital Status].[S]),"
+ " ASC)",
s12);
// Depends upon everything except [Measures].
String s13 = TestContext.allHiersExcept("[Measures]");
getTestContext().assertSetExprDependsOn(
"Order("
+ " Crossjoin("
+ " [Gender].CurrentMember.Children, "
+ " [Marital Status].CurrentMember.Children), "
+ " [Measures].[Unit Sales], "
+ " BDESC)",
s13);
String s1 = TestContext.allHiersExcept(
"[Measures]", "[Store]", "[Product]", "[Time]");
getTestContext().assertSetExprDependsOn(
" Order(\n"
+ " CrossJoin(\n"
+ " {[Product].[All Products].[Food].[Eggs],\n"
+ " [Product].[All Products].[Food].[Seafood],\n"
+ " [Product].[All Products].[Drink].[Alcoholic Beverages]},\n"
+ " {[Store].[USA].[WA].[Seattle],\n"
+ " [Store].[USA].[CA],\n"
+ " [Store].[USA].[OR]}),\n"
+ " ([Time].[1997].[Q1], [Measures].[Unit Sales]),\n"
+ " ASC)",
s1);
}
public void testOrderCalc() {
if (Util.Retrowoven) {
// If retrowoven, we don't use Iterable, so plans are different.
return;
}
// [Measures].[Unit Sales] is a constant member, so it is evaluated in
// a ContextCalc.
assertAxisCompilesTo(
"order([Product].children, [Measures].[Unit Sales])",
"ContextCalc(name=ContextCalc, class=class mondrian.olap.fun.OrderFunDef$ContextCalc, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Unit Sales]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Unit Sales])\n"
+ " CalcImpl(name=CalcImpl, class=class mondrian.olap.fun.OrderFunDef$CalcImpl, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST, direction=ASC)\n"
+ " Children(name=Children, class=class mondrian.olap.fun.BuiltinFunTable$22$1, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=LIST)\n"
+ " CurrentMemberFixed(hierarchy=[Product], name=CurrentMemberFixed, class=class mondrian.olap.fun.HierarchyCurrentMemberFunDef$FixedCalcImpl, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n"
+ " ValueCalc(name=ValueCalc, class=class mondrian.calc.impl.ValueCalc, type=SCALAR, resultStyle=VALUE)\n");
// [Time].[1997] is constant, and is evaluated in a ContextCalc.
// [Product].Parent is variable, and is evaluated inside the loop.
assertAxisCompilesTo(
"order([Product].children,"
+ " ([Time].[1997], [Product].CurrentMember.Parent))",
"ContextCalc(name=ContextCalc, class=class mondrian.olap.fun.OrderFunDef$ContextCalc, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Time].[1997]>, resultStyle=VALUE_NOT_NULL, value=[Time].[1997])\n"
+ " CalcImpl(name=CalcImpl, class=class mondrian.olap.fun.OrderFunDef$CalcImpl, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST, direction=ASC)\n"
+ " Children(name=Children, class=class mondrian.olap.fun.BuiltinFunTable$22$1, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=LIST)\n"
+ " CurrentMemberFixed(hierarchy=[Product], name=CurrentMemberFixed, class=class mondrian.olap.fun.HierarchyCurrentMemberFunDef$FixedCalcImpl, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n"
+ " MemberValueCalc(name=MemberValueCalc, class=class mondrian.calc.impl.MemberValueCalc, type=SCALAR, resultStyle=VALUE)\n"
+ " Parent(name=Parent, class=class mondrian.olap.fun.BuiltinFunTable$15$1, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n"
+ " CurrentMemberFixed(hierarchy=[Product], name=CurrentMemberFixed, class=class mondrian.olap.fun.HierarchyCurrentMemberFunDef$FixedCalcImpl, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n");
// No ContextCalc this time. All members are non-variable.
assertAxisCompilesTo(
"order([Product].children, [Product].CurrentMember.Parent)",
"CalcImpl(name=CalcImpl, class=class mondrian.olap.fun.OrderFunDef$CalcImpl, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST, direction=ASC)\n"
+ " Children(name=Children, class=class mondrian.olap.fun.BuiltinFunTable$22$1, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=LIST)\n"
+ " CurrentMemberFixed(hierarchy=[Product], name=CurrentMemberFixed, class=class mondrian.olap.fun.HierarchyCurrentMemberFunDef$FixedCalcImpl, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n"
+ " MemberValueCalc(name=MemberValueCalc, class=class mondrian.calc.impl.MemberValueCalc, type=SCALAR, resultStyle=VALUE)\n"
+ " Parent(name=Parent, class=class mondrian.olap.fun.BuiltinFunTable$15$1, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n"
+ " CurrentMemberFixed(hierarchy=[Product], name=CurrentMemberFixed, class=class mondrian.olap.fun.HierarchyCurrentMemberFunDef$FixedCalcImpl, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n");
// List expression is dependent on one of the constant calcs. It cannot
// be pulled up, so [Gender].[M] is not in the ContextCalc.
// Note that there is no CopyListCalc - because Filter creates its own
// mutable copy.
// Under JDK 1.4, needs an extra converter from list to iterator,
// because JDK 1.4 doesn't support the ITERABLE result style.
assertAxisCompilesTo(
"order(filter([Product].children, [Measures].[Unit Sales] > 1000), "
+ "([Gender].[M], [Measures].[Store Sales]))",
Util.Retrowoven
? ""
+ "ContextCalc(name=ContextCalc, class=class mondrian.olap.fun.OrderFunDef$ContextCalc, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Store Sales]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Store Sales])\n"
+ " MemberCalcImpl(name=MemberCalcImpl, class=class mondrian.olap.fun.OrderFunDef$MemberCalcImpl, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST, direction=ASC)\n"
+ " MemberListIterCalc(name=MemberListIterCalc, class=class mondrian.calc.impl.AbstractExpCompiler$MemberListIterCalc, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=ITERABLE)\n"
+ " ImmutableMemberListCalc(name=ImmutableMemberListCalc, class=class mondrian.olap.fun.FilterFunDef$ImmutableMemberListCalc, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST)\n"
+ " Children(name=Children, class=class mondrian.olap.fun.BuiltinFunTable$22$1, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=LIST)\n"
+ " CurrentMemberFixed(hierarchy=[Product], name=CurrentMemberFixed, class=class mondrian.olap.fun.HierarchyCurrentMemberFunDef$FixedCalcImpl, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n"
+ " >(name=>, class=class mondrian.olap.fun.BuiltinFunTable$63$1, type=BOOLEAN, resultStyle=VALUE)\n"
+ " MemberValueCalc(name=MemberValueCalc, class=class mondrian.calc.impl.MemberValueCalc, type=SCALAR, resultStyle=VALUE)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Unit Sales]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Unit Sales])\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=NUMERIC, resultStyle=VALUE_NOT_NULL, value=1000.0)\n"
+ " MemberValueCalc(name=MemberValueCalc, class=class mondrian.calc.impl.MemberValueCalc, type=SCALAR, resultStyle=VALUE)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Gender].[M]>, resultStyle=VALUE_NOT_NULL, value=[Gender].[M])\n"
: ""
+ "ContextCalc(name=ContextCalc, class=class mondrian.olap.fun.OrderFunDef$ContextCalc, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Store Sales]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Store Sales])\n"
+ " CalcImpl(name=CalcImpl, class=class mondrian.olap.fun.OrderFunDef$CalcImpl, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=MUTABLE_LIST, direction=ASC)\n"
+ " ImmutableIterCalc(name=ImmutableIterCalc, class=class mondrian.olap.fun.FilterFunDef$ImmutableIterCalc, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=ITERABLE)\n"
+ " Children(name=Children, class=class mondrian.olap.fun.BuiltinFunTable$22$1, type=SetType<MemberType<hierarchy=[Product]>>, resultStyle=LIST)\n"
+ " CurrentMemberFixed(hierarchy=[Product], name=CurrentMemberFixed, class=class mondrian.olap.fun.HierarchyCurrentMemberFunDef$FixedCalcImpl, type=MemberType<hierarchy=[Product]>, resultStyle=VALUE)\n"
+ " >(name=>, class=class mondrian.olap.fun.BuiltinFunTable$63$1, type=BOOLEAN, resultStyle=VALUE)\n"
+ " MemberValueCalc(name=MemberValueCalc, class=class mondrian.calc.impl.MemberValueCalc, type=SCALAR, resultStyle=VALUE)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Unit Sales]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Unit Sales])\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=NUMERIC, resultStyle=VALUE_NOT_NULL, value=1000.0)\n"
+ " MemberValueCalc(name=MemberValueCalc, class=class mondrian.calc.impl.MemberValueCalc, type=SCALAR, resultStyle=VALUE)\n"
+ " Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Gender].[M]>, resultStyle=VALUE_NOT_NULL, value=[Gender].[M])\n");
}
/**
* Verifies that the order function works with a defined member.
* See this forum post for additional information:
* http://forums.pentaho.com/showthread.php?p=179473#post179473
*/
public void testOrderWithMember() {
assertQueryReturns(
"with member [Measures].[Product Name Length] as "
+ "'LEN([Product].CurrentMember.Name)'\n"
+ "select {[Measures].[Product Name Length]} ON COLUMNS,\n"
+ "Order([Product].[All Products].Children, "
+ "[Measures].[Product Name Length], BASC) ON ROWS\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Product Name Length]}\n"
+ "Axis #2:\n"
+ "{[Product].[Food]}\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: 4\n"
+ "Row #1: 5\n"
+ "Row #2: 14\n");
}
/**
* test case for bug # 1797159, Potential MDX Order Non Empty Problem
*
*/
public void testOrderNonEmpty() {
assertQueryReturns(
"select NON EMPTY [Gender].Members ON COLUMNS,\n"
+ "NON EMPTY Order([Product].[All Products].[Drink].Children,\n"
+ "[Gender].[All Gender].[F], ASC) ON ROWS\n"
+ "from [Sales]\n"
+ "where ([Customers].[All Customers].[USA].[CA].[San Francisco],\n"
+ " [Time].[1997])",
"Axis #0:\n"
+ "{[Customers].[USA].[CA].[San Francisco], [Time].[1997]}\n"
+ "Axis #1:\n"
+ "{[Gender].[All Gender]}\n"
+ "{[Gender].[F]}\n"
+ "{[Gender].[M]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Beverages]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages]}\n"
+ "Row #0: 2\n"
+ "Row #0: \n"
+ "Row #0: 2\n"
+ "Row #1: 4\n"
+ "Row #1: 2\n"
+ "Row #1: 2\n");
}
public void testOrder() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns,\n"
+ " order({\n"
+ " [Product].[All Products].[Drink],\n"
+ " [Product].[All Products].[Drink].[Beverages],\n"
+ " [Product].[All Products].[Drink].[Dairy],\n"
+ " [Product].[All Products].[Food],\n"
+ " [Product].[All Products].[Food].[Baked Goods],\n"
+ " [Product].[All Products].[Food].[Eggs],\n"
+ " [Product].[All Products]},\n"
+ " [Measures].[Unit Sales]) on rows\n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[All Products]}\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Drink].[Dairy]}\n"
+ "{[Product].[Drink].[Beverages]}\n"
+ "{[Product].[Food]}\n"
+ "{[Product].[Food].[Eggs]}\n"
+ "{[Product].[Food].[Baked Goods]}\n"
+ "Row #0: 266,773\n"
+ "Row #1: 24,597\n"
+ "Row #2: 4,186\n"
+ "Row #3: 13,573\n"
+ "Row #4: 191,940\n"
+ "Row #5: 4,132\n"
+ "Row #6: 7,870\n");
}
public void testOrderParentsMissing() {
// Paradoxically, [Alcoholic Beverages] comes before
// [Eggs] even though it has a larger value, because
// its parent [Drink] has a smaller value than [Food].
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns,"
+ " order({\n"
+ " [Product].[All Products].[Drink].[Alcoholic Beverages],\n"
+ " [Product].[All Products].[Food].[Eggs]},\n"
+ " [Measures].[Unit Sales], ASC) on rows\n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Product].[Food].[Eggs]}\n"
+ "Row #0: 6,838\n"
+ "Row #1: 4,132\n");
}
public void testOrderCrossJoinBreak() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns,\n"
+ " Order(\n"
+ " CrossJoin(\n"
+ " [Gender].children,\n"
+ " [Marital Status].children),\n"
+ " [Measures].[Unit Sales],\n"
+ " BDESC) on rows\n"
+ "from Sales\n"
+ "where [Time].[1997].[Q1]",
"Axis #0:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Gender].[M], [Marital Status].[S]}\n"
+ "{[Gender].[F], [Marital Status].[M]}\n"
+ "{[Gender].[M], [Marital Status].[M]}\n"
+ "{[Gender].[F], [Marital Status].[S]}\n"
+ "Row #0: 17,070\n"
+ "Row #1: 16,790\n"
+ "Row #2: 16,311\n"
+ "Row #3: 16,120\n");
}
public void testOrderCrossJoin() {
// Note:
// 1. [Alcoholic Beverages] collates before [Eggs] and
// [Seafood] because its parent, [Drink], is less
// than [Food]
// 2. [Seattle] generally sorts after [CA] and [OR]
// because invisible parent [WA] is greater.
assertQueryReturns(
"select CrossJoin(\n"
+ " {[Time].[1997],\n"
+ " [Time].[1997].[Q1]},\n"
+ " {[Measures].[Unit Sales]}) on columns,\n"
+ " Order(\n"
+ " CrossJoin(\n"
+ " {[Product].[All Products].[Food].[Eggs],\n"
+ " [Product].[All Products].[Food].[Seafood],\n"
+ " [Product].[All Products].[Drink].[Alcoholic Beverages]},\n"
+ " {[Store].[USA].[WA].[Seattle],\n"
+ " [Store].[USA].[CA],\n"
+ " [Store].[USA].[OR]}),\n"
+ " ([Time].[1997].[Q1], [Measures].[Unit Sales]),\n"
+ " ASC) on rows\n"
+ "from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997], [Measures].[Unit Sales]}\n"
+ "{[Time].[1997].[Q1], [Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Alcoholic Beverages], [Store].[USA].[OR]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages], [Store].[USA].[CA]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages], [Store].[USA].[WA].[Seattle]}\n"
+ "{[Product].[Food].[Seafood], [Store].[USA].[CA]}\n"
+ "{[Product].[Food].[Seafood], [Store].[USA].[OR]}\n"
+ "{[Product].[Food].[Seafood], [Store].[USA].[WA].[Seattle]}\n"
+ "{[Product].[Food].[Eggs], [Store].[USA].[CA]}\n"
+ "{[Product].[Food].[Eggs], [Store].[USA].[OR]}\n"
+ "{[Product].[Food].[Eggs], [Store].[USA].[WA].[Seattle]}\n"
+ "Row #0: 1,680\n"
+ "Row #0: 393\n"
+ "Row #1: 1,936\n"
+ "Row #1: 431\n"
+ "Row #2: 635\n"
+ "Row #2: 142\n"
+ "Row #3: 441\n"
+ "Row #3: 91\n"
+ "Row #4: 451\n"
+ "Row #4: 107\n"
+ "Row #5: 217\n"
+ "Row #5: 44\n"
+ "Row #6: 1,116\n"
+ "Row #6: 240\n"
+ "Row #7: 1,119\n"
+ "Row #7: 251\n"
+ "Row #8: 373\n"
+ "Row #8: 57\n");
}
public void testOrderHierarchicalDesc() {
assertAxisReturns(
"Order(\n"
+ " {[Product].[All Products], "
+ " [Product].[Food],\n"
+ " [Product].[Drink],\n"
+ " [Product].[Non-Consumable],\n"
+ " [Product].[Food].[Eggs],\n"
+ " [Product].[Drink].[Dairy]},\n"
+ " [Measures].[Unit Sales],\n"
+ " DESC)",
"[Product].[All Products]\n"
+ "[Product].[Food]\n"
+ "[Product].[Food].[Eggs]\n"
+ "[Product].[Non-Consumable]\n"
+ "[Product].[Drink]\n"
+ "[Product].[Drink].[Dairy]");
}
public void testOrderCrossJoinDesc() {
assertAxisReturns(
"Order(\n"
+ " CrossJoin(\n"
+ " {[Gender].[M], [Gender].[F]},\n"
+ " {[Product].[All Products], "
+ " [Product].[Food],\n"
+ " [Product].[Drink],\n"
+ " [Product].[Non-Consumable],\n"
+ " [Product].[Food].[Eggs],\n"
+ " [Product].[Drink].[Dairy]}),\n"
+ " [Measures].[Unit Sales],\n"
+ " DESC)",
"{[Gender].[M], [Product].[All Products]}\n"
+ "{[Gender].[M], [Product].[Food]}\n"
+ "{[Gender].[M], [Product].[Food].[Eggs]}\n"
+ "{[Gender].[M], [Product].[Non-Consumable]}\n"
+ "{[Gender].[M], [Product].[Drink]}\n"
+ "{[Gender].[M], [Product].[Drink].[Dairy]}\n"
+ "{[Gender].[F], [Product].[All Products]}\n"
+ "{[Gender].[F], [Product].[Food]}\n"
+ "{[Gender].[F], [Product].[Food].[Eggs]}\n"
+ "{[Gender].[F], [Product].[Non-Consumable]}\n"
+ "{[Gender].[F], [Product].[Drink]}\n"
+ "{[Gender].[F], [Product].[Drink].[Dairy]}");
}
public void testOrderBug656802() {
// Note:
// 1. [Alcoholic Beverages] collates before [Eggs] and
// [Seafood] because its parent, [Drink], is less
// than [Food]
// 2. [Seattle] generally sorts after [CA] and [OR]
// because invisible parent [WA] is greater.
assertQueryReturns(
"select {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON columns, \n"
+ "Order(\n"
+ " ToggleDrillState(\n"
+ " {([Promotion Media].[All Media], [Product].[All Products])},\n"
+ " {[Product].[All Products]}), \n"
+ " [Measures].[Unit Sales], DESC) ON rows \n"
+ "from [Sales] where ([Time].[1997])",
"Axis #0:\n"
+ "{[Time].[1997]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Promotion Media].[All Media], [Product].[All Products]}\n"
+ "{[Promotion Media].[All Media], [Product].[Food]}\n"
+ "{[Promotion Media].[All Media], [Product].[Non-Consumable]}\n"
+ "{[Promotion Media].[All Media], [Product].[Drink]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 225,627.23\n"
+ "Row #0: 565,238.13\n"
+ "Row #1: 191,940\n"
+ "Row #1: 163,270.72\n"
+ "Row #1: 409,035.59\n"
+ "Row #2: 50,236\n"
+ "Row #2: 42,879.28\n"
+ "Row #2: 107,366.33\n"
+ "Row #3: 24,597\n"
+ "Row #3: 19,477.23\n"
+ "Row #3: 48,836.21\n");
}
public void testOrderBug712702_Simplified() {
assertQueryReturns(
"SELECT Order({[Time].[Year].members}, [Measures].[Unit Sales]) on columns\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1998]}\n"
+ "{[Time].[1997]}\n"
+ "Row #0: \n"
+ "Row #0: 266,773\n");
}
public void testOrderBug712702_Original() {
assertQueryReturns(
"with member [Measures].[Average Unit Sales] as 'Avg(Descendants([Time].[Time].CurrentMember, [Time].[Month]), \n"
+ "[Measures].[Unit Sales])' \n"
+ "member [Measures].[Max Unit Sales] as 'Max(Descendants([Time].[Time].CurrentMember, [Time].[Month]), [Measures].[Unit Sales])' \n"
+ "select {[Measures].[Average Unit Sales], [Measures].[Max Unit Sales], [Measures].[Unit Sales]} ON columns, \n"
+ " NON EMPTY Order(\n"
+ " Crossjoin(\n"
+ " {[Store].[USA].[OR].[Portland],\n"
+ " [Store].[USA].[OR].[Salem],\n"
+ " [Store].[USA].[OR].[Salem].[Store 13],\n"
+ " [Store].[USA].[CA].[San Francisco],\n"
+ " [Store].[USA].[CA].[San Diego],\n"
+ " [Store].[USA].[CA].[Beverly Hills],\n"
+ " [Store].[USA].[CA].[Los Angeles],\n"
+ " [Store].[USA].[WA].[Walla Walla],\n"
+ " [Store].[USA].[WA].[Bellingham],\n"
+ " [Store].[USA].[WA].[Yakima],\n"
+ " [Store].[USA].[WA].[Spokane],\n"
+ " [Store].[USA].[WA].[Seattle], \n"
+ " [Store].[USA].[WA].[Bremerton],\n"
+ " [Store].[USA].[WA].[Tacoma]},\n"
+ " [Time].[Year].Members), \n"
+ " [Measures].[Average Unit Sales], ASC) ON rows\n"
+ "from [Sales] ",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Average Unit Sales]}\n"
+ "{[Measures].[Max Unit Sales]}\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[OR].[Portland], [Time].[1997]}\n"
+ "{[Store].[USA].[OR].[Salem], [Time].[1997]}\n"
+ "{[Store].[USA].[OR].[Salem].[Store 13], [Time].[1997]}\n"
+ "{[Store].[USA].[CA].[San Francisco], [Time].[1997]}\n"
+ "{[Store].[USA].[CA].[Beverly Hills], [Time].[1997]}\n"
+ "{[Store].[USA].[CA].[San Diego], [Time].[1997]}\n"
+ "{[Store].[USA].[CA].[Los Angeles], [Time].[1997]}\n"
+ "{[Store].[USA].[WA].[Walla Walla], [Time].[1997]}\n"
+ "{[Store].[USA].[WA].[Bellingham], [Time].[1997]}\n"
+ "{[Store].[USA].[WA].[Yakima], [Time].[1997]}\n"
+ "{[Store].[USA].[WA].[Spokane], [Time].[1997]}\n"
+ "{[Store].[USA].[WA].[Bremerton], [Time].[1997]}\n"
+ "{[Store].[USA].[WA].[Seattle], [Time].[1997]}\n"
+ "{[Store].[USA].[WA].[Tacoma], [Time].[1997]}\n"
+ "Row #0: 2,173\n"
+ "Row #0: 2,933\n"
+ "Row #0: 26,079\n"
+ "Row #1: 3,465\n"
+ "Row #1: 5,891\n"
+ "Row #1: 41,580\n"
+ "Row #2: 3,465\n"
+ "Row #2: 5,891\n"
+ "Row #2: 41,580\n"
+ "Row #3: 176\n"
+ "Row #3: 222\n"
+ "Row #3: 2,117\n"
+ "Row #4: 1,778\n"
+ "Row #4: 2,545\n"
+ "Row #4: 21,333\n"
+ "Row #5: 2,136\n"
+ "Row #5: 2,686\n"
+ "Row #5: 25,635\n"
+ "Row #6: 2,139\n"
+ "Row #6: 2,669\n"
+ "Row #6: 25,663\n"
+ "Row #7: 184\n"
+ "Row #7: 301\n"
+ "Row #7: 2,203\n"
+ "Row #8: 186\n"
+ "Row #8: 275\n"
+ "Row #8: 2,237\n"
+ "Row #9: 958\n"
+ "Row #9: 1,163\n"
+ "Row #9: 11,491\n"
+ "Row #10: 1,966\n"
+ "Row #10: 2,634\n"
+ "Row #10: 23,591\n"
+ "Row #11: 2,048\n"
+ "Row #11: 2,623\n"
+ "Row #11: 24,576\n"
+ "Row #12: 2,084\n"
+ "Row #12: 2,304\n"
+ "Row #12: 25,011\n"
+ "Row #13: 2,938\n"
+ "Row #13: 3,818\n"
+ "Row #13: 35,257\n");
}
public void testOrderEmpty() {
assertQueryReturns(
"select \n"
+ " Order("
+ " {},"
+ " [Customers].currentMember, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n");
}
public void testOrderOne() {
assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]},"
+ " [Customers].currentMember, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "Row #0: 75\n");
}
public void testOrderKeyEmpty() {
assertQueryReturns(
"select \n"
+ " Order("
+ " {},"
+ " [Customers].currentMember.OrderKey, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n");
}
public void testOrderKeyOne() {
assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]},"
+ " [Customers].currentMember.OrderKey, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "Row #0: 75\n");
}
public void testOrderDesc() {
// based on olap4j's OlapTest.testSortDimension
assertQueryReturns(
"SELECT\n"
+ "{[Measures].[Store Sales]} ON COLUMNS,\n"
+ "{Order(\n"
+ " {{[Product].[Drink], [Product].[Drink].Children}},\n"
+ " [Product].CurrentMember.Name,\n"
+ " DESC)} ON ROWS\n"
+ "FROM [Sales]\n"
+ "WHERE {[Time].[1997].[Q3].[7]}",
"Axis #0:\n"
+ "{[Time].[1997].[Q3].[7]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Drink].[Dairy]}\n"
+ "{[Product].[Drink].[Beverages]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages]}\n"
+ "Row #0: 4,409.58\n"
+ "Row #1: 629.69\n"
+ "Row #2: 2,477.02\n"
+ "Row #3: 1,302.87\n");
}
public void testOrderMemberMemberValueExpNew() {
propSaver.set(
MondrianProperties.instance().CompareSiblingsByOrderKey,
true);
// Use a fresh connection to make sure bad member ordinals haven't
// been assigned by previous tests.
final TestContext context = getTestContext().withFreshConnection();
try {
context.assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Customers].currentMember.OrderKey, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n");
} finally {
if (context != null) {
context.close();
}
}
}
public void testOrderMemberMemberValueExpNew1() {
// sort by default measure
propSaver.set(
MondrianProperties.instance().CompareSiblingsByOrderKey, true);
// Use a fresh connection to make sure bad member ordinals haven't
// been assigned by previous tests.
final TestContext context = getTestContext().withFreshConnection();
try {
context.assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Customers].currentMember, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n");
} finally {
context.close();
}
}
public void testOrderMemberDefaultFlag1() {
// flags not specified default to ASC - sort by default measure
assertQueryReturns(
"with \n"
+ " Member [Measures].[Zero] as '0' \n"
+ "select \n"
+ " Order("
+ " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Customers].currentMember.OrderKey) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n");
}
public void testOrderMemberDefaultFlag2() {
// flags not specified default to ASC
assertQueryReturns(
"with \n"
+ " Member [Measures].[Zero] as '0' \n"
+ "select \n"
+ " Order("
+ " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Measures].[Store Cost]) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n");
}
public void testOrderMemberMemberValueExpHierarchy() {
// Santa Monica and Woodland Hills both don't have orderkey
// members are sorted by the order of their keys
assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Customers].currentMember.OrderKey, DESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n");
}
public void testOrderMemberMultiKeysMemberValueExp1() {
// sort by unit sales and then customer id (Adeline = 6442, Abe = 570)
assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Measures].[Unit Sales], BDESC, [Customers].currentMember.OrderKey, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n"
+ "Row #0: 33\n");
}
public void testOrderMemberMultiKeysMemberValueExp2() {
propSaver.set(
MondrianProperties.instance().CompareSiblingsByOrderKey, true);
// Use a fresh connection to make sure bad member ordinals haven't
// been assigned by previous tests.
final TestContext context = getTestContext().withFreshConnection();
try {
context.assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Customers].currentMember.Parent.Parent.OrderKey, BASC, [Customers].currentMember.OrderKey, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n");
} finally {
context.close();
}
}
public void testOrderMemberMultiKeysMemberValueExpDepends() {
// should preserve order of Abe and Adeline (note second key is [Time])
assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Measures].[Unit Sales], BDESC, [Time].[Time].currentMember, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n"
+ "Row #0: 33\n");
}
public void testOrderTupleSingleKeysNew() {
propSaver.set(
MondrianProperties.instance().CompareSiblingsByOrderKey, true);
// Use a fresh connection to make sure bad member ordinals haven't
// been assigned by previous tests.
final TestContext context = getTestContext().withFreshConnection();
try {
context.assertQueryReturns(
"with \n"
+ " set [NECJ] as \n"
+ " 'NonEmptyCrossJoin( \n"
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " {[Store].[USA].[WA].[Seattle],\n"
+ " [Store].[USA].[CA],\n"
+ " [Store].[USA].[OR]})'\n"
+ "select \n"
+ " Order([NECJ], [Customers].currentMember.OrderKey, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun], [Store].[USA].[CA]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young], [Store].[USA].[CA]}\n"
+ "{[Customers].[USA].[WA].[Issaquah].[Abe Tramel], [Store].[USA].[WA].[Seattle]}\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n");
} finally {
context.close();
}
}
public void testOrderTupleSingleKeysNew1() {
propSaver.set(
MondrianProperties.instance().CompareSiblingsByOrderKey, true);
// Use a fresh connection to make sure bad member ordinals haven't
// been assigned by previous tests.
final TestContext context = getTestContext().withFreshConnection();
try {
context.assertQueryReturns(
"with \n"
+ " set [NECJ] as \n"
+ " 'NonEmptyCrossJoin( \n"
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " {[Store].[USA].[WA].[Seattle],\n"
+ " [Store].[USA].[CA],\n"
+ " [Store].[USA].[OR]})'\n"
+ "select \n"
+ " Order([NECJ], [Store].currentMember.OrderKey, DESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[WA].[Issaquah].[Abe Tramel], [Store].[USA].[WA].[Seattle]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young], [Store].[USA].[CA]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun], [Store].[USA].[CA]}\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n");
} finally {
context.close();
}
}
public void testOrderTupleMultiKeys1() {
assertQueryReturns(
"with \n"
+ " set [NECJ] as \n"
+ " 'NonEmptyCrossJoin( \n"
+ " {[Store].[USA].[CA],\n"
+ " [Store].[USA].[WA]},\n"
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]})' \n"
+ "select \n"
+ " Order([NECJ], [Store].currentMember.OrderKey, BDESC, [Measures].[Unit Sales], BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA], [Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "{[Store].[USA].[CA], [Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Store].[USA].[CA], [Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n");
}
public void testOrderTupleMultiKeys2() {
assertQueryReturns(
"with \n"
+ " set [NECJ] as \n"
+ " 'NonEmptyCrossJoin( \n"
+ " {[Store].[USA].[CA],\n"
+ " [Store].[USA].[WA]},\n"
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]})' \n"
+ "select \n"
+ " Order([NECJ], [Measures].[Unit Sales], BDESC, Ancestor([Customers].currentMember, [Customers].[Name]).OrderKey, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA], [Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Store].[USA].[CA], [Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Store].[USA].[WA], [Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n"
+ "Row #0: 33\n");
}
public void testOrderTupleMultiKeys3() {
// WA unit sales is greater than CA unit sales
// Santa Monica unit sales (2660) is greater that Woodland hills (2516)
assertQueryReturns(
"with \n"
+ " set [NECJ] as \n"
+ " 'NonEmptyCrossJoin( \n"
+ " {[Store].[USA].[CA],\n"
+ " [Store].[USA].[WA]},\n"
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]})' \n"
+ "select \n"
+ " Order([NECJ], [Measures].[Unit Sales], DESC, Ancestor([Customers].currentMember, [Customers].[Name]), BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA], [Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "{[Store].[USA].[CA], [Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Store].[USA].[CA], [Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "Row #0: 33\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n");
}
public void testOrderTupleMultiKeyswithVCube() {
// WA unit sales is greater than CA unit sales
propSaver.set(
MondrianProperties.instance().CompareSiblingsByOrderKey, true);
// Use a fresh connection to make sure bad member ordinals haven't
// been assigned by previous tests.
// a non-sense cube just to test ordering by order key
TestContext context = TestContext.instance().create(
null,
null,
"<VirtualCube name=\"Sales vs HR\">\n"
+ "<VirtualCubeDimension cubeName=\"Sales\" name=\"Customers\"/>\n"
+ "<VirtualCubeDimension cubeName=\"HR\" name=\"Position\"/>\n"
+ "<VirtualCubeMeasure cubeName=\"HR\" name=\"[Measures].[Org Salary]\"/>\n"
+ "</VirtualCube>",
null, null, null);
context.assertQueryReturns(
"with \n"
+ " set [CJ] as \n"
+ " 'CrossJoin( \n"
+ " {[Position].[Store Management].children},\n"
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]})' \n"
+ "select \n"
+ " [Measures].[Org Salary] on columns, \n"
+ " Order([CJ], [Position].currentMember.OrderKey, BASC, Ancestor([Customers].currentMember, [Customers].[Name]).OrderKey, BDESC) \n"
+ "on rows \n"
+ "from [Sales vs HR]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Org Salary]}\n"
+ "Axis #2:\n"
+ "{[Position].[Store Management].[Store Manager], [Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Position].[Store Management].[Store Manager], [Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Position].[Store Management].[Store Manager], [Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "{[Position].[Store Management].[Store Assistant Manager], [Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Position].[Store Management].[Store Assistant Manager], [Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Position].[Store Management].[Store Assistant Manager], [Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "{[Position].[Store Management].[Store Shift Supervisor], [Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Position].[Store Management].[Store Shift Supervisor], [Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Position].[Store Management].[Store Shift Supervisor], [Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "Row #0: \n"
+ "Row #1: \n"
+ "Row #2: \n"
+ "Row #3: \n"
+ "Row #4: \n"
+ "Row #5: \n"
+ "Row #6: \n"
+ "Row #7: \n"
+ "Row #8: \n");
}
public void testOrderConstant1() {
// sort by customerId (Abel = 7851, Adeline = 6442, Abe = 570)
assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Customers].[USA].OrderKey, BDESC, [Customers].currentMember.OrderKey, BASC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "Row #0: 33\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n");
}
public void testOrderDiffrentDim() {
assertQueryReturns(
"select \n"
+ " Order("
+ " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel],"
+ " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young],"
+ " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]},"
+ " [Product].currentMember.OrderKey, BDESC, [Gender].currentMember.OrderKey, BDESC) \n"
+ "on 0 from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n"
+ "Row #0: 33\n"
+ "Row #0: 75\n"
+ "Row #0: 33\n");
}
public void testUnorder() {
assertAxisReturns(
"Unorder([Gender].members)",
"[Gender].[All Gender]\n"
+ "[Gender].[F]\n"
+ "[Gender].[M]");
assertAxisReturns(
"Unorder(Order([Gender].members, -[Measures].[Unit Sales]))",
"[Gender].[All Gender]\n"
+ "[Gender].[M]\n"
+ "[Gender].[F]");
assertAxisReturns(
"Unorder(Crossjoin([Gender].members, [Marital Status].Children))",
"{[Gender].[All Gender], [Marital Status].[M]}\n"
+ "{[Gender].[All Gender], [Marital Status].[S]}\n"
+ "{[Gender].[F], [Marital Status].[M]}\n"
+ "{[Gender].[F], [Marital Status].[S]}\n"
+ "{[Gender].[M], [Marital Status].[M]}\n"
+ "{[Gender].[M], [Marital Status].[S]}");
// implicitly convert member to set
assertAxisReturns(
"Unorder([Gender].[M])",
"[Gender].[M]");
assertAxisThrows(
"Unorder(1 + 3)",
"No function matches signature 'Unorder(<Numeric Expression>)'");
assertAxisThrows(
"Unorder([Gender].[M], 1 + 3)",
"No function matches signature 'Unorder(<Member>, <Numeric Expression>)'");
assertQueryReturns(
"select {[Measures].[Store Sales], [Measures].[Unit Sales]} on 0,\n"
+ " Unorder([Gender].Members) on 1\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Gender].[All Gender]}\n"
+ "{[Gender].[F]}\n"
+ "{[Gender].[M]}\n"
+ "Row #0: 565,238.13\n"
+ "Row #0: 266,773\n"
+ "Row #1: 280,226.21\n"
+ "Row #1: 131,558\n"
+ "Row #2: 285,011.92\n"
+ "Row #2: 135,215\n");
}
public void testSiblingsA() {
assertAxisReturns(
"{[Time].[1997].Siblings}",
"[Time].[1997]\n"
+ "[Time].[1998]");
}
public void testSiblingsB() {
assertAxisReturns(
"{[Store].Siblings}",
"[Store].[All Stores]");
}
public void testSiblingsC() {
assertAxisReturns(
"{[Store].[USA].[CA].Siblings}",
"[Store].[USA].[CA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[WA]");
}
public void testSiblingsD() {
// The null member has no siblings -- not even itself
assertAxisReturns("{[Gender].Parent.Siblings}", "");
assertExprReturns(
"count ([Gender].parent.siblings, includeempty)", "0");
}
public void testSubset() {
assertAxisReturns(
"Subset([Promotion Media].Children, 7, 2)",
"[Promotion Media].[Product Attachment]\n"
+ "[Promotion Media].[Radio]");
}
public void testSubsetNegativeCount() {
assertAxisReturns(
"Subset([Promotion Media].Children, 3, -1)",
"");
}
public void testSubsetNegativeStart() {
assertAxisReturns(
"Subset([Promotion Media].Children, -2, 4)",
"");
}
public void testSubsetDefault() {
assertAxisReturns(
"Subset([Promotion Media].Children, 11)",
"[Promotion Media].[Sunday Paper, Radio]\n"
+ "[Promotion Media].[Sunday Paper, Radio, TV]\n"
+ "[Promotion Media].[TV]");
}
public void testSubsetOvershoot() {
assertAxisReturns(
"Subset([Promotion Media].Children, 15)",
"");
}
public void testSubsetEmpty() {
assertAxisReturns(
"Subset([Gender].[F].Children, 1)",
"");
assertAxisReturns(
"Subset([Gender].[F].Children, 1, 3)",
"");
}
public void testTail() {
assertAxisReturns(
"Tail([Store].Children, 2)",
"[Store].[Mexico]\n"
+ "[Store].[USA]");
}
public void testTailNegative() {
assertAxisReturns(
"Tail([Store].Children, 2 - 3)",
"");
}
public void testTailDefault() {
assertAxisReturns(
"Tail([Store].Children)",
"[Store].[USA]");
}
public void testTailOvershoot() {
assertAxisReturns(
"Tail([Store].Children, 2 + 2)",
"[Store].[Canada]\n"
+ "[Store].[Mexico]\n"
+ "[Store].[USA]");
}
public void testTailEmpty() {
assertAxisReturns(
"Tail([Gender].[F].Children, 2)",
"");
assertAxisReturns(
"Tail([Gender].[F].Children)",
"");
}
public void testToggleDrillState() {
assertAxisReturns(
"ToggleDrillState({[Customers].[USA],[Customers].[Canada]},"
+ "{[Customers].[USA],[Customers].[USA].[CA]})",
"[Customers].[USA]\n"
+ "[Customers].[USA].[CA]\n"
+ "[Customers].[USA].[OR]\n"
+ "[Customers].[USA].[WA]\n"
+ "[Customers].[Canada]");
}
public void testToggleDrillState2() {
assertAxisReturns(
"ToggleDrillState([Product].[Product Department].members, "
+ "{[Product].[All Products].[Food].[Snack Foods]})",
"[Product].[Drink].[Alcoholic Beverages]\n"
+ "[Product].[Drink].[Beverages]\n"
+ "[Product].[Drink].[Dairy]\n"
+ "[Product].[Food].[Baked Goods]\n"
+ "[Product].[Food].[Baking Goods]\n"
+ "[Product].[Food].[Breakfast Foods]\n"
+ "[Product].[Food].[Canned Foods]\n"
+ "[Product].[Food].[Canned Products]\n"
+ "[Product].[Food].[Dairy]\n"
+ "[Product].[Food].[Deli]\n"
+ "[Product].[Food].[Eggs]\n"
+ "[Product].[Food].[Frozen Foods]\n"
+ "[Product].[Food].[Meat]\n"
+ "[Product].[Food].[Produce]\n"
+ "[Product].[Food].[Seafood]\n"
+ "[Product].[Food].[Snack Foods]\n"
+ "[Product].[Food].[Snack Foods].[Snack Foods]\n"
+ "[Product].[Food].[Snacks]\n"
+ "[Product].[Food].[Starchy Foods]\n"
+ "[Product].[Non-Consumable].[Carousel]\n"
+ "[Product].[Non-Consumable].[Checkout]\n"
+ "[Product].[Non-Consumable].[Health and Hygiene]\n"
+ "[Product].[Non-Consumable].[Household]\n"
+ "[Product].[Non-Consumable].[Periodicals]");
}
public void testToggleDrillState3() {
assertAxisReturns(
"ToggleDrillState("
+ "{[Time].[1997].[Q1],"
+ " [Time].[1997].[Q2],"
+ " [Time].[1997].[Q2].[4],"
+ " [Time].[1997].[Q2].[6],"
+ " [Time].[1997].[Q3]},"
+ "{[Time].[1997].[Q2]})",
"[Time].[1997].[Q1]\n"
+ "[Time].[1997].[Q2]\n"
+ "[Time].[1997].[Q3]");
}
// bug 634860
public void testToggleDrillStateTuple() {
assertAxisReturns(
"ToggleDrillState(\n"
+ "{([Store].[USA].[CA],"
+ " [Product].[All Products].[Drink].[Alcoholic Beverages]),\n"
+ " ([Store].[USA],"
+ " [Product].[All Products].[Drink])},\n"
+ "{[Store].[All stores].[USA].[CA]})",
"{[Store].[USA].[CA], [Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Store].[USA].[CA].[Alameda], [Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Store].[USA].[CA].[Beverly Hills], [Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Store].[USA].[CA].[Los Angeles], [Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Store].[USA].[CA].[San Diego], [Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Store].[USA].[CA].[San Francisco], [Product].[Drink].[Alcoholic Beverages]}\n"
+ "{[Store].[USA], [Product].[Drink]}");
}
public void testToggleDrillStateRecursive() {
// We expect this to fail.
assertQueryThrows(
"Select \n"
+ " ToggleDrillState(\n"
+ " {[Store].[USA]}, \n"
+ " {[Store].[USA]}, recursive) on Axis(0) \n"
+ "from [Sales]\n",
"'RECURSIVE' is not supported in ToggleDrillState.");
}
public void testTopCount() {
assertAxisReturns(
"TopCount({[Promotion Media].[Media Type].members}, 2, [Measures].[Unit Sales])",
"[Promotion Media].[No Media]\n"
+ "[Promotion Media].[Daily Paper, Radio, TV]");
}
public void testTopCountTuple() {
assertAxisReturns(
"TopCount([Customers].[Name].members,2,(Time.[1997].[Q1],[Measures].[Store Sales]))",
"[Customers].[USA].[WA].[Spokane].[Grace McLaughlin]\n"
+ "[Customers].[USA].[WA].[Spokane].[Matt Bellah]");
}
public void testTopCountEmpty() {
assertAxisReturns(
"TopCount(Filter({[Promotion Media].[Media Type].members}, 1=0), 2, [Measures].[Unit Sales])",
"");
}
public void testTopCountDepends() {
checkTopBottomCountPercentDepends("TopCount");
checkTopBottomCountPercentDepends("TopPercent");
checkTopBottomCountPercentDepends("TopSum");
checkTopBottomCountPercentDepends("BottomCount");
checkTopBottomCountPercentDepends("BottomPercent");
checkTopBottomCountPercentDepends("BottomSum");
}
private void checkTopBottomCountPercentDepends(String fun) {
String s1 =
TestContext.allHiersExcept("[Measures]", "[Promotion Media]");
getTestContext().assertSetExprDependsOn(
fun
+ "({[Promotion Media].[Media Type].members}, "
+ "2, [Measures].[Unit Sales])",
s1);
if (fun.endsWith("Count")) {
getTestContext().assertSetExprDependsOn(
fun + "({[Promotion Media].[Media Type].members}, 2)",
"{}");
}
}
/**
* Tests TopCount applied to a large result set.
*
* <p>Before optimizing (see FunUtil.partialSort), on a 2-core 32-bit 2.4GHz
* machine, the 1st query took 14.5 secs, the 2nd query took 5.0 secs.
* After optimizing, who knows?
*/
public void testTopCountHuge() {
// TODO convert printfs to trace
final String query =
"SELECT [Measures].[Store Sales] ON 0,\n"
+ "TopCount([Time].[Month].members * "
+ "[Customers].[Name].members, 3, [Measures].[Store Sales]) ON 1\n"
+ "FROM [Sales]";
final String desiredResult =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q1].[3], [Customers].[USA].[WA].[Spokane].[George Todero]}\n"
+ "{[Time].[1997].[Q3].[7], [Customers].[USA].[WA].[Spokane].[James Horvat]}\n"
+ "{[Time].[1997].[Q4].[11], [Customers].[USA].[WA].[Olympia].[Charles Stanley]}\n"
+ "Row #0: 234.83\n"
+ "Row #1: 199.46\n"
+ "Row #2: 191.90\n";
long now = System.currentTimeMillis();
assertQueryReturns(query, desiredResult);
LOGGER.info("first query took " + (System.currentTimeMillis() - now));
now = System.currentTimeMillis();
assertQueryReturns(query, desiredResult);
LOGGER.info("second query took " + (System.currentTimeMillis() - now));
}
public void testTopPercent() {
assertAxisReturns(
"TopPercent({[Promotion Media].[Media Type].members}, 70, [Measures].[Unit Sales])",
"[Promotion Media].[No Media]");
}
// todo: test precision
public void testTopSum() {
assertAxisReturns(
"TopSum({[Promotion Media].[Media Type].members}, 200000, [Measures].[Unit Sales])",
"[Promotion Media].[No Media]\n"
+ "[Promotion Media].[Daily Paper, Radio, TV]");
}
public void testTopSumEmpty() {
assertAxisReturns(
"TopSum(Filter({[Promotion Media].[Media Type].members}, 1=0), "
+ "200000, [Measures].[Unit Sales])",
"");
}
public void testUnionAll() {
assertAxisReturns(
"Union({[Gender].[M]}, {[Gender].[F]}, ALL)",
"[Gender].[M]\n"
+ "[Gender].[F]"); // order is preserved
}
public void testUnionAllTuple() {
// With the bug, the last 8 rows are repeated.
assertQueryReturns(
"with \n"
+ "set [Set1] as 'Crossjoin({[Time].[1997].[Q1]:[Time].[1997].[Q4]},{[Store].[USA].[CA]:[Store].[USA].[OR]})'\n"
+ "set [Set2] as 'Crossjoin({[Time].[1997].[Q2]:[Time].[1997].[Q3]},{[Store].[Mexico].[DF]:[Store].[Mexico].[Veracruz]})'\n"
+ "select \n"
+ "{[Measures].[Unit Sales]} ON COLUMNS,\n"
+ "Union([Set1], [Set2], ALL) ON ROWS\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q1], [Store].[USA].[CA]}\n"
+ "{[Time].[1997].[Q1], [Store].[USA].[OR]}\n"
+ "{[Time].[1997].[Q2], [Store].[USA].[CA]}\n"
+ "{[Time].[1997].[Q2], [Store].[USA].[OR]}\n"
+ "{[Time].[1997].[Q3], [Store].[USA].[CA]}\n"
+ "{[Time].[1997].[Q3], [Store].[USA].[OR]}\n"
+ "{[Time].[1997].[Q4], [Store].[USA].[CA]}\n"
+ "{[Time].[1997].[Q4], [Store].[USA].[OR]}\n"
+ "{[Time].[1997].[Q2], [Store].[Mexico].[DF]}\n"
+ "{[Time].[1997].[Q2], [Store].[Mexico].[Guerrero]}\n"
+ "{[Time].[1997].[Q2], [Store].[Mexico].[Jalisco]}\n"
+ "{[Time].[1997].[Q2], [Store].[Mexico].[Veracruz]}\n"
+ "{[Time].[1997].[Q3], [Store].[Mexico].[DF]}\n"
+ "{[Time].[1997].[Q3], [Store].[Mexico].[Guerrero]}\n"
+ "{[Time].[1997].[Q3], [Store].[Mexico].[Jalisco]}\n"
+ "{[Time].[1997].[Q3], [Store].[Mexico].[Veracruz]}\n"
+ "Row #0: 16,890\n"
+ "Row #1: 19,287\n"
+ "Row #2: 18,052\n"
+ "Row #3: 15,079\n"
+ "Row #4: 18,370\n"
+ "Row #5: 16,940\n"
+ "Row #6: 21,436\n"
+ "Row #7: 16,353\n"
+ "Row #8: \n"
+ "Row #9: \n"
+ "Row #10: \n"
+ "Row #11: \n"
+ "Row #12: \n"
+ "Row #13: \n"
+ "Row #14: \n"
+ "Row #15: \n");
}
public void testUnion() {
assertAxisReturns(
"Union({[Store].[USA], [Store].[USA], [Store].[USA].[OR]}, "
+ "{[Store].[USA].[CA], [Store].[USA]})",
"[Store].[USA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[CA]");
}
public void testUnionEmptyBoth() {
assertAxisReturns(
"Union({}, {})",
"");
}
public void testUnionEmptyRight() {
assertAxisReturns(
"Union({[Gender].[M]}, {})",
"[Gender].[M]");
}
public void testUnionTuple() {
assertAxisReturns(
"Union({"
+ " ([Gender].[M], [Marital Status].[S]),"
+ " ([Gender].[F], [Marital Status].[S])"
+ "}, {"
+ " ([Gender].[M], [Marital Status].[M]),"
+ " ([Gender].[M], [Marital Status].[S])"
+ "})",
"{[Gender].[M], [Marital Status].[S]}\n"
+ "{[Gender].[F], [Marital Status].[S]}\n"
+ "{[Gender].[M], [Marital Status].[M]}");
}
public void testUnionTupleDistinct() {
assertAxisReturns(
"Union({"
+ " ([Gender].[M], [Marital Status].[S]),"
+ " ([Gender].[F], [Marital Status].[S])"
+ "}, {"
+ " ([Gender].[M], [Marital Status].[M]),"
+ " ([Gender].[M], [Marital Status].[S])"
+ "}, Distinct)",
"{[Gender].[M], [Marital Status].[S]}\n"
+ "{[Gender].[F], [Marital Status].[S]}\n"
+ "{[Gender].[M], [Marital Status].[M]}");
}
public void testUnionQuery() {
Result result = executeQuery(
"select {[Measures].[Unit Sales], "
+ "[Measures].[Store Cost], "
+ "[Measures].[Store Sales]} on columns,\n"
+ " Hierarchize(\n"
+ " Union(\n"
+ " Crossjoin(\n"
+ " Crossjoin([Gender].[All Gender].children,\n"
+ " [Marital Status].[All Marital Status].children),\n"
+ " Crossjoin([Customers].[All Customers].children,\n"
+ " [Product].[All Products].children) ),\n"
+ " Crossjoin({([Gender].[All Gender].[M], [Marital Status].[All Marital Status].[M])},\n"
+ " Crossjoin(\n"
+ " [Customers].[All Customers].[USA].children,\n"
+ " [Product].[All Products].children) ) )) on rows\n"
+ "from Sales where ([Time].[1997])");
final Axis rowsAxis = result.getAxes()[1];
Assert.assertEquals(45, rowsAxis.getPositions().size());
}
public void testItemMember() {
assertExprReturns(
"Descendants([Time].[1997], [Time].[Month]).Item(1).Item(0).UniqueName",
"[Time].[1997].[Q1].[2]");
// Access beyond the list yields the Null member.
if (isDefaultNullMemberRepresentation()) {
assertExprReturns(
"[Time].[1997].Children.Item(6).UniqueName", "[Time].[#null]");
assertExprReturns(
"[Time].[1997].Children.Item(-1).UniqueName", "[Time].[#null]");
}
}
public void testItemTuple() {
assertExprReturns(
"CrossJoin([Gender].[All Gender].children, "
+ "[Time].[1997].[Q2].children).Item(0).Item(1).UniqueName",
"[Time].[1997].[Q2].[4]");
}
public void testStrToMember() {
assertExprReturns(
"StrToMember(\"[Time].[1997].[Q2].[4]\").Name",
"4");
}
public void testStrToMemberUniqueName() {
assertExprReturns(
"StrToMember(\"[Store].[USA].[CA]\").Name",
"CA");
}
public void testStrToMemberFullyQualifiedName() {
assertExprReturns(
"StrToMember(\"[Store].[All Stores].[USA].[CA]\").Name",
"CA");
}
public void testStrToMemberNull() {
// SSAS 2005 gives "#Error An MDX expression was expected. An empty
// expression was specified."
assertExprThrows(
"StrToMember(null).Name",
"An MDX expression was expected. An empty expression was specified");
assertExprThrows(
"StrToSet(null, [Gender]).Count",
"An MDX expression was expected. An empty expression was specified");
assertExprThrows(
"StrToTuple(null, [Gender]).Name",
"An MDX expression was expected. An empty expression was specified");
}
/**
* Testcase for
* <a href="http://jira.pentaho.com/browse/MONDRIAN-560">
* bug MONDRIAN-560, "StrToMember function doesn't use IgnoreInvalidMembers
* option"</a>.
*/
public void testStrToMemberIgnoreInvalidMembers() {
final MondrianProperties properties = MondrianProperties.instance();
propSaver.set(properties.IgnoreInvalidMembersDuringQuery, true);
// [Product].[Drugs] is invalid, becomes null member, and is dropped
// from list
assertQueryReturns(
"select \n"
+ " {[Product].[Food],\n"
+ " StrToMember(\"[Product].[Drugs]\")} on columns,\n"
+ " {[Measures].[Unit Sales]} on rows\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Product].[Food]}\n"
+ "Axis #2:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Row #0: 191,940\n");
// Hierarchy is inferred from leading edge
assertExprReturns(
"StrToMember(\"[Marital Status].[Separated]\").Hierarchy.Name",
"Marital Status");
// Null member is returned
assertExprReturns(
"StrToMember(\"[Marital Status].[Separated]\").Name",
"#null");
// Use longest valid prefix, so get [Time].[Weekly] rather than just
// [Time].
final String timeWeekly = TestContext.hierarchyName("Time", "Weekly");
assertExprReturns(
"StrToMember(\"" + timeWeekly
+ ".[1996].[Q1]\").Hierarchy.UniqueName",
timeWeekly);
// If hierarchy is invalid, throw an error even though
// IgnoreInvalidMembersDuringQuery is set.
assertExprThrows(
"StrToMember(\"[Unknown Hierarchy].[Invalid].[Member]\").Name",
"MDX object '[Unknown Hierarchy].[Invalid].[Member]' not found in cube 'Sales'");
assertExprThrows(
"StrToMember(\"[Unknown Hierarchy].[Invalid]\").Name",
"MDX object '[Unknown Hierarchy].[Invalid]' not found in cube 'Sales'");
assertExprThrows(
"StrToMember(\"[Unknown Hierarchy]\").Name",
"MDX object '[Unknown Hierarchy]' not found in cube 'Sales'");
assertAxisThrows(
"StrToMember(\"\")",
"MDX object '' not found in cube 'Sales'");
propSaver.set(properties.IgnoreInvalidMembersDuringQuery, false);
assertQueryThrows(
"select \n"
+ " {[Product].[Food],\n"
+ " StrToMember(\"[Product].[Drugs]\")} on columns,\n"
+ " {[Measures].[Unit Sales]} on rows\n"
+ "from [Sales]",
"Member '[Product].[Drugs]' not found");
assertExprThrows(
"StrToMember(\"[Marital Status].[Separated]\").Hierarchy.Name",
"Member '[Marital Status].[Separated]' not found");
}
public void testStrToTuple() {
// single dimension yields member
assertAxisReturns(
"{StrToTuple(\"[Time].[1997].[Q2]\", [Time])}",
"[Time].[1997].[Q2]");
// multiple dimensions yield tuple
assertAxisReturns(
"{StrToTuple(\"([Gender].[F], [Time].[1997].[Q2])\", [Gender], [Time])}",
"{[Gender].[F], [Time].[1997].[Q2]}");
// todo: test for garbage at end of string
}
public void testStrToTupleIgnoreInvalidMembers() {
final MondrianProperties properties = MondrianProperties.instance();
propSaver.set(properties.IgnoreInvalidMembersDuringQuery, true);
// If any member is invalid, the whole tuple is null.
assertAxisReturns(
"StrToTuple(\"([Gender].[M], [Marital Status].[Separated])\","
+ " [Gender], [Marital Status])",
"");
}
public void testStrToTupleDuHierarchiesFails() {
assertAxisThrows(
"{StrToTuple(\"([Gender].[F], [Time].[1997].[Q2], [Gender].[M])\", [Gender], [Time], [Gender])}",
"Tuple contains more than one member of hierarchy '[Gender]'.");
}
public void testStrToTupleDupHierInSameDimensions() {
assertAxisThrows(
"{StrToTuple("
+ "\"([Gender].[F], "
+ "[Time].[1997].[Q2], "
+ "[Time].[Weekly].[1997].[10])\","
+ " [Gender], "
+ TestContext.hierarchyName("Time", "Weekly")
+ ", [Gender])}",
"Tuple contains more than one member of hierarchy '[Gender]'.");
}
public void testStrToTupleDepends() {
getTestContext().assertMemberExprDependsOn(
"StrToTuple(\"[Time].[1997].[Q2]\", [Time])",
"{}");
// converted to scalar, depends set is larger
getTestContext().assertExprDependsOn(
"StrToTuple(\"[Time].[1997].[Q2]\", [Time])",
TestContext.allHiersExcept("[Time]"));
getTestContext().assertMemberExprDependsOn(
"StrToTuple(\"[Time].[1997].[Q2], [Gender].[F]\", [Time], [Gender])",
"{}");
getTestContext().assertExprDependsOn(
"StrToTuple(\"[Time].[1997].[Q2], [Gender].[F]\", [Time], [Gender])",
TestContext.allHiersExcept("[Time]", "[Gender]"));
}
public void testStrToSet() {
// TODO: handle text after '}'
// TODO: handle string which ends too soon
// TODO: handle spaces before first '{'
// TODO: test spaces before unbracketed names,
// e.g. "{Gender. M, Gender. F }".
assertAxisReturns(
"StrToSet("
+ " \"{[Gender].[F], [Gender].[M]}\","
+ " [Gender])",
"[Gender].[F]\n"
+ "[Gender].[M]");
assertAxisThrows(
"StrToSet("
+ " \"{[Gender].[F], [Time].[1997]}\","
+ " [Gender])",
"member is of wrong hierarchy");
// whitespace ok
assertAxisReturns(
"StrToSet("
+ " \" { [Gender] . [F] ,[Gender].[M] } \","
+ " [Gender])",
"[Gender].[F]\n"
+ "[Gender].[M]");
// tuples
assertAxisReturns(
"StrToSet("
+ "\""
+ "{"
+ " ([Gender].[F], [Time].[1997].[Q2]), "
+ " ([Gender].[M], [Time].[1997])"
+ "}"
+ "\","
+ " [Gender],"
+ " [Time])",
"{[Gender].[F], [Time].[1997].[Q2]}\n"
+ "{[Gender].[M], [Time].[1997]}");
// matches unique name
assertAxisReturns(
"StrToSet("
+ "\""
+ "{"
+ " [Store].[USA].[CA], "
+ " [Store].[All Stores].[USA].OR,"
+ " [Store].[All Stores]. [USA] . [WA]"
+ "}"
+ "\","
+ " [Store])",
"[Store].[USA].[CA]\n"
+ "[Store].[USA].[OR]\n"
+ "[Store].[USA].[WA]");
}
public void testStrToSetDupDimensionsFails() {
assertAxisThrows(
"StrToSet("
+ "\""
+ "{"
+ " ([Gender].[F], [Time].[1997].[Q2], [Gender].[F]), "
+ " ([Gender].[M], [Time].[1997], [Gender].[F])"
+ "}"
+ "\","
+ " [Gender],"
+ " [Time],"
+ " [Gender])",
"Tuple contains more than one member of hierarchy '[Gender]'.");
}
public void testStrToSetIgnoreInvalidMembers() {
final MondrianProperties properties = MondrianProperties.instance();
propSaver.set(properties.IgnoreInvalidMembersDuringQuery, true);
assertAxisReturns(
"StrToSet("
+ "\""
+ "{"
+ " [Product].[Food],"
+ " [Product].[Food].[You wouldn't like],"
+ " [Product].[Drink].[You would like],"
+ " [Product].[Drink].[Dairy]"
+ "}"
+ "\","
+ " [Product])",
"[Product].[Food]\n"
+ "[Product].[Drink].[Dairy]");
assertAxisReturns(
"StrToSet("
+ "\""
+ "{"
+ " ([Gender].[M], [Product].[Food]),"
+ " ([Gender].[F], [Product].[Food].[You wouldn't like]),"
+ " ([Gender].[M], [Product].[Drink].[You would like]),"
+ " ([Gender].[F], [Product].[Drink].[Dairy])"
+ "}"
+ "\","
+ " [Gender], [Product])",
"{[Gender].[M], [Product].[Food]}\n"
+ "{[Gender].[F], [Product].[Drink].[Dairy]}");
}
public void testYtd() {
assertAxisReturns(
"Ytd()",
"[Time].[1997]");
assertAxisReturns(
"Ytd([Time].[1997].[Q3])",
"[Time].[1997].[Q1]\n"
+ "[Time].[1997].[Q2]\n"
+ "[Time].[1997].[Q3]");
assertAxisReturns(
"Ytd([Time].[1997].[Q2].[4])",
"[Time].[1997].[Q1].[1]\n"
+ "[Time].[1997].[Q1].[2]\n"
+ "[Time].[1997].[Q1].[3]\n"
+ "[Time].[1997].[Q2].[4]");
assertAxisThrows(
"Ytd([Store])",
"Argument to function 'Ytd' must belong to Time hierarchy");
getTestContext().assertSetExprDependsOn(
"Ytd()",
"{[Time], " + TimeWeekly + "}");
getTestContext().assertSetExprDependsOn(
"Ytd([Time].[1997].[Q2])",
"{}");
}
/**
* Testcase for
* <a href="http://jira.pentaho.com/browse/MONDRIAN-458">
* bug MONDRIAN-458, "error deducing type of Ytd/Qtd/Mtd functions within
* Generate"</a>.
*/
public void testGeneratePlusXtd() {
assertAxisReturns(
"generate(\n"
+ " {[Time].[1997].[Q1].[2], [Time].[1997].[Q3].[7]},\n"
+ " {Ytd( [Time].[Time].currentMember)})",
"[Time].[1997].[Q1].[1]\n"
+ "[Time].[1997].[Q1].[2]\n"
+ "[Time].[1997].[Q1].[3]\n"
+ "[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]\n"
+ "[Time].[1997].[Q2].[6]\n"
+ "[Time].[1997].[Q3].[7]");
assertAxisReturns(
"generate(\n"
+ " {[Time].[1997].[Q1].[2], [Time].[1997].[Q3].[7]},\n"
+ " {Ytd( [Time].[Time].currentMember)}, ALL)",
"[Time].[1997].[Q1].[1]\n"
+ "[Time].[1997].[Q1].[2]\n"
+ "[Time].[1997].[Q1].[1]\n"
+ "[Time].[1997].[Q1].[2]\n"
+ "[Time].[1997].[Q1].[3]\n"
+ "[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]\n"
+ "[Time].[1997].[Q2].[6]\n"
+ "[Time].[1997].[Q3].[7]");
assertExprReturns(
"count(generate({[Time].[1997].[Q4].[11]},"
+ " {Qtd( [Time].[Time].currentMember)}))",
2, 0);
assertExprReturns(
"count(generate({[Time].[1997].[Q4].[11]},"
+ " {Mtd( [Time].[Time].currentMember)}))",
1, 0);
}
public void testQtd() {
// zero args
assertQueryReturns(
"with member [Measures].[Foo] as ' SetToStr(Qtd()) '\n"
+ "select {[Measures].[Foo]} on columns\n"
+ "from [Sales]\n"
+ "where [Time].[1997].[Q2].[5]",
"Axis #0:\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: {[Time].[1997].[Q2].[4], [Time].[1997].[Q2].[5]}\n");
// one arg, a month
assertAxisReturns(
"Qtd([Time].[1997].[Q2].[5])",
"[Time].[1997].[Q2].[4]\n"
+ "[Time].[1997].[Q2].[5]");
// one arg, a quarter
assertAxisReturns(
"Qtd([Time].[1997].[Q2])",
"[Time].[1997].[Q2]");
// one arg, a year
assertAxisReturns(
"Qtd([Time].[1997])",
"");
assertAxisThrows(
"Qtd([Store])",
"Argument to function 'Qtd' must belong to Time hierarchy");
}
public void testMtd() {
// zero args
assertQueryReturns(
"with member [Measures].[Foo] as ' SetToStr(Mtd()) '\n"
+ "select {[Measures].[Foo]} on columns\n"
+ "from [Sales]\n"
+ "where [Time].[1997].[Q2].[5]",
"Axis #0:\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: {[Time].[1997].[Q2].[5]}\n");
// one arg, a month
assertAxisReturns(
"Mtd([Time].[1997].[Q2].[5])",
"[Time].[1997].[Q2].[5]");
// one arg, a quarter
assertAxisReturns(
"Mtd([Time].[1997].[Q2])",
"");
// one arg, a year
assertAxisReturns(
"Mtd([Time].[1997])",
"");
assertAxisThrows(
"Mtd([Store])",
"Argument to function 'Mtd' must belong to Time hierarchy");
}
public void testPeriodsToDate() {
getTestContext().assertSetExprDependsOn("PeriodsToDate()", "{[Time]}");
getTestContext().assertSetExprDependsOn(
"PeriodsToDate([Time].[Year])",
"{[Time]}");
getTestContext().assertSetExprDependsOn(
"PeriodsToDate([Time].[Year], [Time].[1997].[Q2].[5])", "{}");
// two args
assertAxisReturns(
"PeriodsToDate([Time].[Quarter], [Time].[1997].[Q2].[5])",
"[Time].[1997].[Q2].[4]\n" + "[Time].[1997].[Q2].[5]");
// equivalent to above
assertAxisReturns(
"TopCount("
+ " Descendants("
+ " Ancestor("
+ " [Time].[1997].[Q2].[5], [Time].[Quarter]),"
+ " [Time].[1997].[Q2].[5].Level),"
+ " 1).Item(0) : [Time].[1997].[Q2].[5]",
"[Time].[1997].[Q2].[4]\n" + "[Time].[1997].[Q2].[5]");
// one arg
assertQueryReturns(
"with member [Measures].[Foo] as ' SetToStr(PeriodsToDate([Time].[Quarter])) '\n"
+ "select {[Measures].[Foo]} on columns\n"
+ "from [Sales]\n"
+ "where [Time].[1997].[Q2].[5]",
"Axis #0:\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: {[Time].[1997].[Q2].[4], [Time].[1997].[Q2].[5]}\n");
// zero args
assertQueryReturns(
"with member [Measures].[Foo] as ' SetToStr(PeriodsToDate()) '\n"
+ "select {[Measures].[Foo]} on columns\n"
+ "from [Sales]\n"
+ "where [Time].[1997].[Q2].[5]",
"Axis #0:\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: {[Time].[1997].[Q2].[4], [Time].[1997].[Q2].[5]}\n");
// zero args, evaluated at a member which is at the top level.
// The default level is the level above the current member -- so
// choosing a member at the highest level might trip up the
// implementation.
assertQueryReturns(
"with member [Measures].[Foo] as ' SetToStr(PeriodsToDate()) '\n"
+ "select {[Measures].[Foo]} on columns\n"
+ "from [Sales]\n"
+ "where [Time].[1997]",
"Axis #0:\n"
+ "{[Time].[1997]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Foo]}\n"
+ "Row #0: {}\n");
// Testcase for bug 1598379, which caused NPE because the args[0].type
// knew its dimension but not its hierarchy.
assertQueryReturns(
"with member [Measures].[Position] as\n"
+ " 'Sum("
+ "PeriodsToDate([Time].[Time].Levels(0),"
+ " [Time].[Time].CurrentMember), "
+ "[Measures].[Store Sales])'\n"
+ "select {[Time].[1997],\n"
+ " [Time].[1997].[Q1],\n"
+ " [Time].[1997].[Q1].[1],\n"
+ " [Time].[1997].[Q1].[2],\n"
+ " [Time].[1997].[Q1].[3]} ON COLUMNS,\n"
+ "{[Measures].[Store Sales], [Measures].[Position] } 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"
+ "Axis #2:\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Position]}\n"
+ "Row #0: 565,238.13\n"
+ "Row #0: 139,628.35\n"
+ "Row #0: 45,539.69\n"
+ "Row #0: 44,058.79\n"
+ "Row #0: 50,029.87\n"
+ "Row #1: 565,238.13\n"
+ "Row #1: 139,628.35\n"
+ "Row #1: 45,539.69\n"
+ "Row #1: 89,598.48\n"
+ "Row #1: 139,628.35\n");
assertQueryReturns(
"select\n"
+ "{[Measures].[Unit Sales]} on columns,\n"
+ "periodstodate(\n"
+ " [Product].[Product Category],\n"
+ " [Product].[Food].[Baked Goods].[Bread].[Muffins]) on rows\n"
+ "from [Sales]\n"
+ "",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Bagels]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 815\n"
+ "Row #1: 3,497\n"
+ "");
// TODO: enable
if (false) {
assertExprThrows(
"Sum(PeriodsToDate([Time.Weekly].[Year], [Time].CurrentMember), [Measures].[Unit Sales])",
"wrong dimension");
}
}
public void testSetToStr() {
assertExprReturns(
"SetToStr([Time].[Time].children)",
"{[Time].[1997].[Q1], [Time].[1997].[Q2], [Time].[1997].[Q3], [Time].[1997].[Q4]}");
// Now, applied to tuples
assertExprReturns(
"SetToStr({CrossJoin([Marital Status].children, {[Gender].[M]})})",
"{"
+ "([Marital Status].[M], [Gender].[M]), "
+ "([Marital Status].[S], [Gender].[M])"
+ "}");
}
public void testTupleToStr() {
// Applied to a dimension (which becomes a member)
assertExprReturns(
"TupleToStr([Product])",
"[Product].[All Products]");
// Applied to a dimension (invalid because has no default hierarchy)
if (MondrianProperties.instance().SsasCompatibleNaming.get()) {
assertExprThrows(
"TupleToStr([Time])",
"The 'Time' dimension contains more than one hierarchy, "
+ "therefore the hierarchy must be explicitly specified.");
} else {
assertExprReturns(
"TupleToStr([Time])",
"[Time].[1997]");
}
// Applied to a hierarchy
assertExprReturns(
"TupleToStr([Time].[Time])",
"[Time].[1997]");
// Applied to a member
assertExprReturns(
"TupleToStr([Store].[USA].[OR])",
"[Store].[USA].[OR]");
// Applied to a member (extra set of parens)
assertExprReturns(
"TupleToStr(([Store].[USA].[OR]))",
"[Store].[USA].[OR]");
// Now, applied to a tuple
assertExprReturns(
"TupleToStr(([Marital Status], [Gender].[M]))",
"([Marital Status].[All Marital Status], [Gender].[M])");
// Applied to a tuple containing a null member
assertExprReturns(
"TupleToStr(([Marital Status], [Gender].Parent))",
"");
// Applied to a null member
assertExprReturns(
"TupleToStr([Marital Status].Parent)",
"");
}
/**
* Executes a scalar expression, and asserts that the result is as
* expected. For example, <code>assertExprReturns("1 + 2", "3")</code>
* should succeed.
*/
public void assertExprReturns(String expr, String expected) {
String actual = executeExpr(expr);
assertEquals(expected, actual);
}
/**
* Executes a scalar expression, and asserts that the result is within
* delta of the expected result.
*
* @param expr MDX scalar expression
* @param expected Expected value
* @param delta Maximum allowed deviation from expected value
*/
public void assertExprReturns(
String expr, double expected, double delta)
{
Object value = getTestContext().executeExprRaw(expr).getValue();
try {
double actual = ((Number) value).doubleValue();
if (Double.isNaN(expected) && Double.isNaN(actual)) {
return;
}
Assert.assertEquals(
null,
expected,
actual,
delta);
} catch (ClassCastException ex) {
String msg = "Actual value \"" + value + "\" is not a number.";
throw new ComparisonFailure(
msg, Double.toString(expected), String.valueOf(value));
}
}
/**
* Compiles a scalar expression, and asserts that the program looks as
* expected.
*/
public void assertExprCompilesTo(
String expr,
String expectedCalc)
{
final String actualCalc =
getTestContext().compileExpression(expr, true);
final int expDeps =
MondrianProperties.instance().TestExpDependencies.get();
if (expDeps > 0) {
// Don't bother checking the compiled output if we are also
// testing dependencies. The compiled code will have extra
// 'DependencyTestingCalc' instances embedded in it.
return;
}
TestContext.assertEqualsVerbose(expectedCalc, actualCalc);
}
/**
* Compiles a set expression, and asserts that the program looks as
* expected.
*/
public void assertAxisCompilesTo(
String expr,
String expectedCalc)
{
final String actualCalc =
getTestContext().compileExpression(expr, false);
final int expDeps =
MondrianProperties.instance().TestExpDependencies.get();
if (expDeps > 0) {
// Don't bother checking the compiled output if we are also
// testing dependencies. The compiled code will have extra
// 'DependencyTestingCalc' instances embedded in it.
return;
}
TestContext.assertEqualsVerbose(expectedCalc, actualCalc);
}
/**
* Tests the <code>Rank(member, set)</code> MDX function.
*/
public void testRank() {
// Member within set
assertExprReturns(
"Rank([Store].[USA].[CA], "
+ "{[Store].[USA].[OR],"
+ " [Store].[USA].[CA],"
+ " [Store].[USA]})", "2");
// Member not in set
assertExprReturns(
"Rank([Store].[USA].[WA], "
+ "{[Store].[USA].[OR],"
+ " [Store].[USA].[CA],"
+ " [Store].[USA]})", "0");
// Member not in empty set
assertExprReturns(
"Rank([Store].[USA].[WA], {})", "0");
// Null member not in set returns null.
assertExprReturns(
"Rank([Store].Parent, "
+ "{[Store].[USA].[OR],"
+ " [Store].[USA].[CA],"
+ " [Store].[USA]})", "");
// Null member in empty set. (MSAS returns an error "Formula error -
// dimension count is not valid - in the Rank function" but I think
// null is the correct behavior.)
assertExprReturns(
"Rank([Gender].Parent, {})", "");
// Member occurs twice in set -- pick first
assertExprReturns(
"Rank([Store].[USA].[WA], \n"
+ "{[Store].[USA].[WA],"
+ " [Store].[USA].[CA],"
+ " [Store].[USA],"
+ " [Store].[USA].[WA]})", "1");
// Tuple not in set
assertExprReturns(
"Rank(([Gender].[F], [Marital Status].[M]), \n"
+ "{([Gender].[F], [Marital Status].[S]),\n"
+ " ([Gender].[M], [Marital Status].[S]),\n"
+ " ([Gender].[M], [Marital Status].[M])})", "0");
// Tuple in set
assertExprReturns(
"Rank(([Gender].[F], [Marital Status].[M]), \n"
+ "{([Gender].[F], [Marital Status].[S]),\n"
+ " ([Gender].[M], [Marital Status].[S]),\n"
+ " ([Gender].[F], [Marital Status].[M])})", "3");
// Tuple not in empty set
assertExprReturns(
"Rank(([Gender].[F], [Marital Status].[M]), \n" + "{})", "0");
// Partially null tuple in set, returns null
assertExprReturns(
"Rank(([Gender].[F], [Marital Status].Parent), \n"
+ "{([Gender].[F], [Marital Status].[S]),\n"
+ " ([Gender].[M], [Marital Status].[S]),\n"
+ " ([Gender].[F], [Marital Status].[M])})", "");
}
public void testRankWithExpr() {
// Note that [Good] and [Top Measure] have the same [Unit Sales]
// value (5), but [Good] ranks 1 and [Top Measure] ranks 2. Even though
// they are sorted descending on unit sales, they remain in their
// natural order (member name) because MDX sorts are stable.
assertQueryReturns(
"with member [Measures].[Sibling Rank] as ' Rank([Product].CurrentMember, [Product].CurrentMember.Siblings) '\n"
+ " member [Measures].[Sales Rank] as ' Rank([Product].CurrentMember, Order([Product].Parent.Children, [Measures].[Unit Sales], DESC)) '\n"
+ " member [Measures].[Sales Rank2] as ' Rank([Product].CurrentMember, [Product].Parent.Children, [Measures].[Unit Sales]) '\n"
+ "select {[Measures].[Unit Sales], [Measures].[Sales Rank], [Measures].[Sales Rank2]} on columns,\n"
+ " {[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].children} on rows\n"
+ "from [Sales]\n"
+ "WHERE ([Store].[USA].[OR].[Portland].[Store 11], [Time].[1997].[Q2].[6])",
"Axis #0:\n"
+ "{[Store].[USA].[OR].[Portland].[Store 11], [Time].[1997].[Q2].[6]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Sales Rank]}\n"
+ "{[Measures].[Sales Rank2]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Pearl]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Top Measure]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Walrus]}\n"
+ "Row #0: 5\n"
+ "Row #0: 1\n"
+ "Row #0: 1\n"
+ "Row #1: \n"
+ "Row #1: 5\n"
+ "Row #1: 5\n"
+ "Row #2: 3\n"
+ "Row #2: 3\n"
+ "Row #2: 3\n"
+ "Row #3: 5\n"
+ "Row #3: 2\n"
+ "Row #3: 1\n"
+ "Row #4: 3\n"
+ "Row #4: 4\n"
+ "Row #4: 3\n");
}
public void testRankMembersWithTiedExpr() {
assertQueryReturns(
"with "
+ " Set [Beers] as {[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].children} "
+ " member [Measures].[Sales Rank] as ' Rank([Product].CurrentMember, [Beers], [Measures].[Unit Sales]) '\n"
+ "select {[Measures].[Unit Sales], [Measures].[Sales Rank]} on columns,\n"
+ " Generate([Beers], {[Product].CurrentMember}) on rows\n"
+ "from [Sales]\n"
+ "WHERE ([Store].[USA].[OR].[Portland].[Store 11], [Time].[1997].[Q2].[6])",
"Axis #0:\n"
+ "{[Store].[USA].[OR].[Portland].[Store 11], [Time].[1997].[Q2].[6]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Sales Rank]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Pearl]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Top Measure]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Walrus]}\n"
+ "Row #0: 5\n"
+ "Row #0: 1\n"
+ "Row #1: \n"
+ "Row #1: 5\n"
+ "Row #2: 3\n"
+ "Row #2: 3\n"
+ "Row #3: 5\n"
+ "Row #3: 1\n"
+ "Row #4: 3\n"
+ "Row #4: 3\n");
}
public void testRankTuplesWithTiedExpr() {
assertQueryReturns(
"with "
+ " Set [Beers for Store] as 'NonEmptyCrossJoin("
+ "[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].children, "
+ "{[Store].[USA].[OR].[Portland].[Store 11]})' "
+ " member [Measures].[Sales Rank] as ' Rank(([Product].CurrentMember,[Store].CurrentMember), [Beers for Store], [Measures].[Unit Sales]) '\n"
+ "select {[Measures].[Unit Sales], [Measures].[Sales Rank]} on columns,\n"
+ " Generate([Beers for Store], {([Product].CurrentMember, [Store].CurrentMember)}) on rows\n"
+ "from [Sales]\n"
+ "WHERE ([Time].[1997].[Q2].[6])",
"Axis #0:\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Sales Rank]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Good], [Store].[USA].[OR].[Portland].[Store 11]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth], [Store].[USA].[OR].[Portland].[Store 11]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Top Measure], [Store].[USA].[OR].[Portland].[Store 11]}\n"
+ "{[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Walrus], [Store].[USA].[OR].[Portland].[Store 11]}\n"
+ "Row #0: 5\n"
+ "Row #0: 1\n"
+ "Row #1: 3\n"
+ "Row #1: 3\n"
+ "Row #2: 5\n"
+ "Row #2: 1\n"
+ "Row #3: 3\n"
+ "Row #3: 3\n");
}
public void testRankWithExpr2() {
// Data: Unit Sales
// All gender 266,733
// F 131,558
// M 135,215
assertExprReturns(
"Rank([Gender].[All Gender],"
+ " {[Gender].Members},"
+ " [Measures].[Unit Sales])", "1");
assertExprReturns(
"Rank([Gender].[F],"
+ " {[Gender].Members},"
+ " [Measures].[Unit Sales])", "3");
assertExprReturns(
"Rank([Gender].[M],"
+ " {[Gender].Members},"
+ " [Measures].[Unit Sales])", "2");
// Null member. Expression evaluates to null, therefore value does
// not appear in the list of values, therefore the rank is null.
assertExprReturns(
"Rank([Gender].[All Gender].Parent,"
+ " {[Gender].Members},"
+ " [Measures].[Unit Sales])", "");
// Empty set. Value would appear after all elements in the empty set,
// therefore rank is 1.
// Note that SSAS gives error 'The first argument to the Rank function,
// a tuple expression, should reference the same hierachies as the
// second argument, a set expression'. I think that's because it can't
// deduce a type for '{}'. SSAS's problem, not Mondrian's. :)
assertExprReturns(
"Rank([Gender].[M],"
+ " {},"
+ " [Measures].[Unit Sales])",
"1");
// As above, but SSAS can type-check this.
assertExprReturns(
"Rank([Gender].[M],"
+ " Filter(Gender.Members, 1 = 0),"
+ " [Measures].[Unit Sales])",
"1");
// Member is not in set
assertExprReturns(
"Rank([Gender].[M]," + " {[Gender].[All Gender], [Gender].[F]})",
"0");
// Even though M is not in the set, its value lies between [All Gender]
// and [F].
assertExprReturns(
"Rank([Gender].[M],"
+ " {[Gender].[All Gender], [Gender].[F]},"
+ " [Measures].[Unit Sales])", "2");
// Expr evaluates to null for some values of set.
assertExprReturns(
"Rank([Product].[Non-Consumable].[Household],"
+ " {[Product].[Food], [Product].[All Products], [Product].[Drink].[Dairy]},"
+ " [Product].CurrentMember.Parent)", "2");
// Expr evaluates to null for all values in the set.
assertExprReturns(
"Rank([Gender].[M],"
+ " {[Gender].[All Gender], [Gender].[F]},"
+ " [Marital Status].[All Marital Status].Parent)", "1");
}
/**
* Tests the 3-arg version of the RANK function with a value
* which returns null within a set of nulls.
*/
public void testRankWithNulls() {
assertQueryReturns(
"with member [Measures].[X] as "
+ "'iif([Measures].[Store Sales]=777,"
+ "[Measures].[Store Sales],Null)'\n"
+ "member [Measures].[Y] as 'Rank([Gender].[M],"
+ "{[Measures].[X],[Measures].[X],[Measures].[X]},"
+ " [Marital Status].[All Marital Status].Parent)'"
+ "select {[Measures].[Y]} on columns from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Y]}\n"
+ "Row #0: 1\n");
}
/**
* Tests a RANK function which is so large that we need to use caching
* in order to execute it efficiently.
*/
public void testRankHuge() {
// If caching is disabled, don't even try -- it will take too long.
if (!MondrianProperties.instance().EnableExpCache.get()) {
return;
}
checkRankHuge(
"WITH \n"
+ " MEMBER [Measures].[Rank among products] \n"
+ " AS ' Rank([Product].CurrentMember, "
+ " Order([Product].members, "
+ " [Measures].[Unit Sales], BDESC)) '\n"
+ "SELECT CrossJoin(\n"
+ " [Gender].members,\n"
+ " {[Measures].[Unit Sales],\n"
+ " [Measures].[Rank among products]}) ON COLUMNS,\n"
// + " {[Product], [Product].[All Products].[Non-Consumable].
// [Periodicals].[Magazines].[Sports Magazines].[Robust].
// [Robust Monthly Sports Magazine]} ON ROWS\n"
+ " {[Product].members} ON ROWS\n"
+ "FROM [Sales]",
false);
}
/**
* As {@link #testRankHuge()}, but for the 3-argument form of the
* <code>RANK</code> function.
*
* <p>Disabled by jhyde, 2006/2/14. Bug 1431316 logged.
*/
public void _testRank3Huge() {
// If caching is disabled, don't even try -- it will take too long.
if (!MondrianProperties.instance().EnableExpCache.get()) {
return;
}
checkRankHuge(
"WITH \n"
+ " MEMBER [Measures].[Rank among products] \n"
+ " AS ' Rank([Product].CurrentMember, [Product].members, [Measures].[Unit Sales]) '\n"
+ "SELECT CrossJoin(\n"
+ " [Gender].members,\n"
+ " {[Measures].[Unit Sales],\n"
+ " [Measures].[Rank among products]}) ON COLUMNS,\n"
+ " {[Product],"
+ " [Product].[All Products].[Non-Consumable].[Periodicals]"
+ ".[Magazines].[Sports Magazines].[Robust]"
+ ".[Robust Monthly Sports Magazine]} ON ROWS\n"
// + " {[Product].members} ON ROWS\n"
+ "FROM [Sales]",
true);
}
private void checkRankHuge(String query, boolean rank3) {
final Result result = getTestContext().executeQuery(query);
final Axis[] axes = result.getAxes();
final Axis rowsAxis = axes[1];
final int rowCount = rowsAxis.getPositions().size();
assertEquals(2256, rowCount);
// [All Products], [All Gender], [Rank]
Cell cell = result.getCell(new int[] {1, 0});
assertEquals("1", cell.getFormattedValue());
// [Robust Monthly Sports Magazine]
Member member = rowsAxis.getPositions().get(rowCount - 1).get(0);
assertEquals("Robust Monthly Sports Magazine", member.getName());
// [Robust Monthly Sports Magazine], [All Gender], [Rank]
cell = result.getCell(new int[] {0, rowCount - 1});
assertEquals("152", cell.getFormattedValue());
cell = result.getCell(new int[] {1, rowCount - 1});
assertEquals(rank3 ? "1,854" : "1,871", cell.getFormattedValue());
// [Robust Monthly Sports Magazine], [Gender].[F], [Rank]
cell = result.getCell(new int[] {2, rowCount - 1});
assertEquals("90", cell.getFormattedValue());
cell = result.getCell(new int[] {3, rowCount - 1});
assertEquals(rank3 ? "1,119" : "1,150", cell.getFormattedValue());
// [Robust Monthly Sports Magazine], [Gender].[M], [Rank]
cell = result.getCell(new int[] {4, rowCount - 1});
assertEquals("62", cell.getFormattedValue());
cell = result.getCell(new int[] {5, rowCount - 1});
assertEquals(rank3 ? "2,131" : "2,147", cell.getFormattedValue());
}
public void testLinRegPointQuarter() {
assertQueryReturns(
"WITH MEMBER [Measures].[Test] as \n"
+ " 'LinRegPoint(\n"
+ " Rank(Time.[Time].CurrentMember, Time.[Time].CurrentMember.Level.Members),\n"
+ " Descendants([Time].[1997], [Time].[Quarter]), \n"
+ "[Measures].[Store Sales], \n"
+ " Rank(Time.[Time].CurrentMember, Time.[Time].CurrentMember.Level.Members))' \n"
+ "SELECT \n"
+ "{[Measures].[Test],[Measures].[Store Sales]} ON ROWS, \n"
+ "{[Time].[1997].Children} ON COLUMNS \n"
+ "FROM Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q3]}\n"
+ "{[Time].[1997].[Q4]}\n"
+ "Axis #2:\n"
+ "{[Measures].[Test]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Row #0: 134,299.22\n"
+ "Row #0: 138,972.76\n"
+ "Row #0: 143,646.30\n"
+ "Row #0: 148,319.85\n"
+ "Row #1: 139,628.35\n"
+ "Row #1: 132,666.27\n"
+ "Row #1: 140,271.89\n"
+ "Row #1: 152,671.62\n");
}
/**
* Tests all of the linear regression functions, as suggested by
* <a href="http://support.microsoft.com/kb/q307276/">a Microsoft knowledge
* base article</a>.
*/
public void _testLinRegAll() {
// We have not implemented the LastPeriods function, so we use
// [Time].CurrentMember.Lag(9) : [Time].CurrentMember
// is equivalent to
// LastPeriods(10)
assertQueryReturns(
"WITH MEMBER \n"
+ "[Measures].[Intercept] AS \n"
+ " 'LinRegIntercept([Time].CurrentMember.Lag(10) : [Time].CurrentMember, [Measures].[Unit Sales], [Measures].[Store Sales])' \n"
+ "MEMBER [Measures].[Regression Slope] AS\n"
+ " 'LinRegSlope([Time].CurrentMember.Lag(9) : [Time].CurrentMember,[Measures].[Unit Sales],[Measures].[Store Sales]) '\n"
+ "MEMBER [Measures].[Predict] AS\n"
+ " 'LinRegPoint([Measures].[Unit Sales],[Time].CurrentMember.Lag(9) : [Time].CurrentMember,[Measures].[Unit Sales],[Measures].[Store Sales])',\n"
+ " FORMAT_STRING = 'Standard' \n"
+ "MEMBER [Measures].[Predict Formula] AS\n"
+ " '([Measures].[Regression Slope] * [Measures].[Unit Sales]) + [Measures].[Intercept]',\n"
+ " FORMAT_STRING='Standard'\n"
+ "MEMBER [Measures].[Good Fit] AS\n"
+ " 'LinRegR2([Time].CurrentMember.Lag(9) : [Time].CurrentMember, [Measures].[Unit Sales],[Measures].[Store Sales])',\n"
+ " FORMAT_STRING='#,#.00'\n"
+ "MEMBER [Measures].[Variance] AS\n"
+ " 'LinRegVariance([Time].CurrentMember.Lag(9) : [Time].CurrentMember,[Measures].[Unit Sales],[Measures].[Store Sales])'\n"
+ "SELECT \n"
+ " {[Measures].[Store Sales], \n"
+ " [Measures].[Intercept], \n"
+ " [Measures].[Regression Slope], \n"
+ " [Measures].[Predict], \n"
+ " [Measures].[Predict Formula], \n"
+ " [Measures].[Good Fit], \n"
+ " [Measures].[Variance] } ON COLUMNS, \n"
+ " Descendants([Time].[1997], [Time].[Month]) ON ROWS\n"
+ "FROM Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Store Sales]}\n"
+ "{[Measures].[Intercept]}\n"
+ "{[Measures].[Regression Slope]}\n"
+ "{[Measures].[Predict]}\n"
+ "{[Measures].[Predict Formula]}\n"
+ "{[Measures].[Good Fit]}\n"
+ "{[Measures].[Variance]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q1].[2]}\n"
+ "{[Time].[1997].[Q1].[3]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q3].[7]}\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "{[Time].[1997].[Q3].[9]}\n"
+ "{[Time].[1997].[Q4].[10]}\n"
+ "{[Time].[1997].[Q4].[11]}\n"
+ "{[Time].[1997].[Q4].[12]}\n"
+ "Row #0: 45,539.69\n"
+ "Row #0: 68711.40\n"
+ "Row #0: -1.033\n"
+ "Row #0: 46,350.26\n"
+ "Row #0: 46.350.26\n"
+ "Row #0: -1.#INF\n"
+ "Row #0: 5.17E-08\n"
+ "...\n"
+ "Row #11: 15343.67\n");
}
public void testLinRegPointMonth() {
assertQueryReturns(
"WITH MEMBER \n"
+ "[Measures].[Test] as \n"
+ " 'LinRegPoint(\n"
+ " Rank(Time.[Time].CurrentMember, Time.[Time].CurrentMember.Level.Members),\n"
+ " Descendants([Time].[1997], [Time].[Month]), \n"
+ " [Measures].[Store Sales], \n"
+ " Rank(Time.[Time].CurrentMember, Time.[Time].CurrentMember.Level.Members)\n"
+ " )' \n"
+ "SELECT \n"
+ " {[Measures].[Test],[Measures].[Store Sales]} ON ROWS, \n"
+ " Descendants([Time].[1997], [Time].[Month]) ON COLUMNS \n"
+ "FROM Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997].[Q1].[1]}\n"
+ "{[Time].[1997].[Q1].[2]}\n"
+ "{[Time].[1997].[Q1].[3]}\n"
+ "{[Time].[1997].[Q2].[4]}\n"
+ "{[Time].[1997].[Q2].[5]}\n"
+ "{[Time].[1997].[Q2].[6]}\n"
+ "{[Time].[1997].[Q3].[7]}\n"
+ "{[Time].[1997].[Q3].[8]}\n"
+ "{[Time].[1997].[Q3].[9]}\n"
+ "{[Time].[1997].[Q4].[10]}\n"
+ "{[Time].[1997].[Q4].[11]}\n"
+ "{[Time].[1997].[Q4].[12]}\n"
+ "Axis #2:\n"
+ "{[Measures].[Test]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Row #0: 43,824.36\n"
+ "Row #0: 44,420.51\n"
+ "Row #0: 45,016.66\n"
+ "Row #0: 45,612.81\n"
+ "Row #0: 46,208.95\n"
+ "Row #0: 46,805.10\n"
+ "Row #0: 47,401.25\n"
+ "Row #0: 47,997.40\n"
+ "Row #0: 48,593.55\n"
+ "Row #0: 49,189.70\n"
+ "Row #0: 49,785.85\n"
+ "Row #0: 50,382.00\n"
+ "Row #1: 45,539.69\n"
+ "Row #1: 44,058.79\n"
+ "Row #1: 50,029.87\n"
+ "Row #1: 42,878.25\n"
+ "Row #1: 44,456.29\n"
+ "Row #1: 45,331.73\n"
+ "Row #1: 50,246.88\n"
+ "Row #1: 46,199.04\n"
+ "Row #1: 43,825.97\n"
+ "Row #1: 42,342.27\n"
+ "Row #1: 53,363.71\n"
+ "Row #1: 56,965.64\n");
}
public void testLinRegIntercept() {
assertExprReturns(
"LinRegIntercept([Time].[Month].members,"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
-126.65,
0.50);
/*
-1#IND missing data
*/
/*
1#INF division by zero
*/
/*
The following table shows query return values from using different
FORMAT_STRING's in an expression involving 'division by zero' (tested on
Intel platforms):
+===========================+=====================+
| Format Strings | Query Return Values |
+===========================+=====================+
| FORMAT_STRING=" | 1.#INF |
+===========================+=====================+
| FORMAT_STRING='Standard' | 1.#J |
+===========================+=====================+
| FORMAT_STRING='Fixed' | 1.#J |
+===========================+=====================+
| FORMAT_STRING='Percent' | 1#I.NF% |
+===========================+=====================+
| FORMAT_STRING='Scientific'| 1.JE+00 |
+===========================+=====================+
*/
// Mondrian can not return "missing data" value -1.#IND
// empty set
if (false) {
assertExprReturns(
"LinRegIntercept({[Time].Parent},"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
// first expr constant
if (false) {
assertExprReturns(
"LinRegIntercept([Time].[Month].members,"
+ " 7, [Measures].[Store Sales])",
"$7.00");
}
// format does not add '$'
assertExprReturns(
"LinRegIntercept([Time].[Month].members,"
+ " 7, [Measures].[Store Sales])",
7.00,
0.01);
// Mondrian can not return "missing data" value -1.#IND
// second expr constant
if (false) {
assertExprReturns(
"LinRegIntercept([Time].[Month].members,"
+ " [Measures].[Unit Sales], 4)",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
}
public void testLinRegSlope() {
assertExprReturns(
"LinRegSlope([Time].[Month].members,"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
0.4746,
0.50);
// Mondrian can not return "missing data" value -1.#IND
// empty set
if (false) {
assertExprReturns(
"LinRegSlope({[Time].Parent},"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
// first expr constant
if (false) {
assertExprReturns(
"LinRegSlope([Time].[Month].members,"
+ " 7, [Measures].[Store Sales])",
"$7.00");
}
// ^^^^
// copy and paste error
assertExprReturns(
"LinRegSlope([Time].[Month].members,"
+ " 7, [Measures].[Store Sales])",
0.00,
0.01);
// Mondrian can not return "missing data" value -1.#IND
// second expr constant
if (false) {
assertExprReturns(
"LinRegSlope([Time].[Month].members,"
+ " [Measures].[Unit Sales], 4)",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
}
public void testLinRegPoint() {
// NOTE: mdx does not parse
if (false) {
assertExprReturns(
"LinRegPoint([Measures].[Unit Sales],"
+ " [Time].CurrentMember[Time].[Month].members,"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
"0.4746");
}
// Mondrian can not return "missing data" value -1.#IND
// empty set
if (false) {
assertExprReturns(
"LinRegPoint([Measures].[Unit Sales],"
+ " {[Time].Parent},"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
// Expected value is wrong
// zeroth expr constant
if (false) {
assertExprReturns(
"LinRegPoint(-1,"
+ " [Time].[Month].members,"
+ " 7, [Measures].[Store Sales])", "-127.124");
}
// first expr constant
if (false) {
assertExprReturns(
"LinRegPoint([Measures].[Unit Sales],"
+ " [Time].[Month].members,"
+ " 7, [Measures].[Store Sales])", "$7.00");
}
// format does not add '$'
assertExprReturns(
"LinRegPoint([Measures].[Unit Sales],"
+ " [Time].[Month].members,"
+ " 7, [Measures].[Store Sales])",
7.00,
0.01);
// Mondrian can not return "missing data" value -1.#IND
// second expr constant
if (false) {
assertExprReturns(
"LinRegPoint([Measures].[Unit Sales],"
+ " [Time].[Month].members,"
+ " [Measures].[Unit Sales], 4)",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
}
public void _testLinRegR2() {
// Why would R2 equal the slope
if (false) {
assertExprReturns(
"LinRegR2([Time].[Month].members,"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
"0.4746");
}
// Mondrian can not return "missing data" value -1.#IND
// empty set
if (false) {
assertExprReturns(
"LinRegR2({[Time].Parent},"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
// first expr constant
assertExprReturns(
"LinRegR2([Time].[Month].members,"
+ " 7, [Measures].[Store Sales])",
"$7.00");
// Mondrian can not return "missing data" value -1.#IND
// second expr constant
if (false) {
assertExprReturns(
"LinRegR2([Time].[Month].members,"
+ " [Measures].[Unit Sales], 4)",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
}
public void _testLinRegVariance() {
assertExprReturns(
"LinRegVariance([Time].[Month].members,"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
"0.4746");
// empty set
assertExprReturns(
"LinRegVariance({[Time].Parent},"
+ " [Measures].[Unit Sales], [Measures].[Store Sales])",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
// first expr constant
assertExprReturns(
"LinRegVariance([Time].[Month].members,"
+ " 7, [Measures].[Store Sales])",
"$7.00");
// second expr constant
assertExprReturns(
"LinRegVariance([Time].[Month].members,"
+ " [Measures].[Unit Sales], 4)",
"-1.#IND"); // MSAS returns -1.#IND (whatever that means)
}
public void testVisualTotalsBasic() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns, "
+ "{VisualTotals("
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},"
+ " \"**Subtotal - *\")} on rows "
+ "from [Sales]",
// note that Subtotal - Bread only includes 2 displayed children
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Food].[Baked Goods].[*Subtotal - Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Bagels]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 4,312\n"
+ "Row #1: 815\n"
+ "Row #2: 3,497\n");
}
public void testVisualTotalsConsecutively() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns, "
+ "{VisualTotals("
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels].[Colony],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},"
+ " \"**Subtotal - *\")} on rows "
+ "from [Sales]",
// Note that [Bagels] occurs 3 times, but only once does it
// become a subtotal. Note that the subtotal does not include
// the following [Bagels] member.
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Food].[Baked Goods].[*Subtotal - Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Bagels]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[*Subtotal - Bagels]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Bagels].[Colony]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Bagels]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 5,290\n"
+ "Row #1: 815\n"
+ "Row #2: 163\n"
+ "Row #3: 163\n"
+ "Row #4: 815\n"
+ "Row #5: 3,497\n");
}
public void testVisualTotalsNoPattern() {
assertAxisReturns(
"VisualTotals("
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]})",
// Note that the [Bread] visual member is just called [Bread].
"[Product].[Food].[Baked Goods].[Bread]\n"
+ "[Product].[Food].[Baked Goods].[Bread].[Bagels]\n"
+ "[Product].[Food].[Baked Goods].[Bread].[Muffins]");
}
public void testVisualTotalsWithFilter() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns, "
+ "{Filter("
+ " VisualTotals("
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},"
+ " \"**Subtotal - *\"),"
+ "[Measures].[Unit Sales] > 3400)} on rows "
+ "from [Sales]",
// Note that [*Subtotal - Bread] still contains the
// contribution of [Bagels] 815, which was filtered out.
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Food].[Baked Goods].[*Subtotal - Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 4,312\n"
+ "Row #1: 3,497\n");
}
public void testVisualTotalsNested() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns, "
+ "{VisualTotals("
+ " Filter("
+ " VisualTotals("
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},"
+ " \"**Subtotal - *\"),"
+ " [Measures].[Unit Sales] > 3400),"
+ " \"Second total - *\")} on rows "
+ "from [Sales]",
// Yields the same -- no extra total.
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Food].[Baked Goods].[*Subtotal - Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 4,312\n"
+ "Row #1: 3,497\n");
}
public void testVisualTotalsFilterInside() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns, "
+ "{VisualTotals("
+ " Filter("
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},"
+ " [Measures].[Unit Sales] > 3400),"
+ " \"**Subtotal - *\")} on rows "
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Food].[Baked Goods].[*Subtotal - Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 3,497\n"
+ "Row #1: 3,497\n");
}
public void testVisualTotalsOutOfOrder() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns, "
+ "{VisualTotals("
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},"
+ " \"**Subtotal - *\")} on rows "
+ "from [Sales]",
// Note that [*Subtotal - Bread] 3497 does not include 815 for
// bagels.
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Bagels]}\n"
+ "{[Product].[Food].[Baked Goods].[*Subtotal - Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 815\n"
+ "Row #1: 3,497\n"
+ "Row #2: 3,497\n");
}
public void testVisualTotalsGrandparentsAndOutOfOrder() {
assertQueryReturns(
"select {[Measures].[Unit Sales]} on columns, "
+ "{VisualTotals("
+ " {[Product].[All Products].[Food],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],"
+ " [Product].[All Products].[Food].[Frozen Foods].[Breakfast Foods],"
+ " [Product].[All Products].[Food].[Frozen Foods].[Breakfast Foods].[Pancake Mix].[Golden],"
+ " [Product].[All Products].[Food].[Frozen Foods].[Breakfast Foods].[Pancake Mix].[Big Time],"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},"
+ " \"**Subtotal - *\")} on rows "
+ "from [Sales]",
// Note:
// [*Subtotal - Food] = 4513 = 815 + 311 + 3497
// [*Subtotal - Bread] = 815, does not include muffins
// [*Subtotal - Breakfast Foods] = 311 = 110 + 201, includes
// grandchildren
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Product].[*Subtotal - Food]}\n"
+ "{[Product].[Food].[Baked Goods].[*Subtotal - Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Bagels]}\n"
+ "{[Product].[Food].[Frozen Foods].[*Subtotal - Breakfast Foods]}\n"
+ "{[Product].[Food].[Frozen Foods].[Breakfast Foods].[Pancake Mix].[Golden]}\n"
+ "{[Product].[Food].[Frozen Foods].[Breakfast Foods].[Pancake Mix].[Big Time]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 4,623\n"
+ "Row #1: 815\n"
+ "Row #2: 815\n"
+ "Row #3: 311\n"
+ "Row #4: 110\n"
+ "Row #5: 201\n"
+ "Row #6: 3,497\n");
}
public void testVisualTotalsCrossjoin() {
assertAxisThrows(
"VisualTotals(Crossjoin([Gender].Members, [Store].children))",
"Argument to 'VisualTotals' function must be a set of members; got set of tuples.");
}
/**
* Test case for bug
* <a href="http://jira.pentaho.com/browse/MONDRIAN-615">MONDRIAN-615</a>,
* "VisualTotals doesn't work for the all member".
*/
public void testVisualTotalsAll() {
final String query =
"SELECT \n"
+ " {[Measures].[Unit Sales]} ON 0, \n"
+ " VisualTotals(\n"
+ " {[Customers].[All Customers],\n"
+ " [Customers].[USA],\n"
+ " [Customers].[USA].[CA],\n"
+ " [Customers].[USA].[OR]}) ON 1\n"
+ "FROM [Sales]";
assertQueryReturns(
query,
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[USA].[CA]}\n"
+ "{[Customers].[USA].[OR]}\n"
+ "Row #0: 142,407\n"
+ "Row #1: 142,407\n"
+ "Row #2: 74,748\n"
+ "Row #3: 67,659\n");
// Check captions
final Result result = getTestContext().executeQuery(query);
final List<Position> positionList = result.getAxes()[1].getPositions();
assertEquals("All Customers", positionList.get(0).get(0).getCaption());
assertEquals("USA", positionList.get(1).get(0).getCaption());
assertEquals("CA", positionList.get(2).get(0).getCaption());
}
/**
* Test case involving a named set and query pivoted. Suggested in
* <a href="http://jira.pentaho.com/browse/MONDRIAN-615">MONDRIAN-615</a>,
* "VisualTotals doesn't work for the all member".
*/
public void testVisualTotalsWithNamedSetAndPivot() {
assertQueryReturns(
"WITH SET [CA_OR] AS\n"
+ " VisualTotals(\n"
+ " {[Customers].[All Customers],\n"
+ " [Customers].[USA],\n"
+ " [Customers].[USA].[CA],\n"
+ " [Customers].[USA].[OR]})\n"
+ "SELECT \n"
+ " Drilldownlevel({[Time].[1997]}) ON 0, \n"
+ " [CA_OR] ON 1 \n"
+ "FROM [Sales] ",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997]}\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q3]}\n"
+ "{[Time].[1997].[Q4]}\n"
+ "Axis #2:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[USA].[CA]}\n"
+ "{[Customers].[USA].[OR]}\n"
+ "Row #0: 142,407\n"
+ "Row #0: 36,177\n"
+ "Row #0: 33,131\n"
+ "Row #0: 35,310\n"
+ "Row #0: 37,789\n"
+ "Row #1: 142,407\n"
+ "Row #1: 36,177\n"
+ "Row #1: 33,131\n"
+ "Row #1: 35,310\n"
+ "Row #1: 37,789\n"
+ "Row #2: 74,748\n"
+ "Row #2: 16,890\n"
+ "Row #2: 18,052\n"
+ "Row #2: 18,370\n"
+ "Row #2: 21,436\n"
+ "Row #3: 67,659\n"
+ "Row #3: 19,287\n"
+ "Row #3: 15,079\n"
+ "Row #3: 16,940\n"
+ "Row #3: 16,353\n");
// same query, swap axes
assertQueryReturns(
"WITH SET [CA_OR] AS\n"
+ " VisualTotals(\n"
+ " {[Customers].[All Customers],\n"
+ " [Customers].[USA],\n"
+ " [Customers].[USA].[CA],\n"
+ " [Customers].[USA].[OR]})\n"
+ "SELECT \n"
+ " [CA_OR] ON 0,\n"
+ " Drilldownlevel({[Time].[1997]}) ON 1\n"
+ "FROM [Sales] ",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[USA].[CA]}\n"
+ "{[Customers].[USA].[OR]}\n"
+ "Axis #2:\n"
+ "{[Time].[1997]}\n"
+ "{[Time].[1997].[Q1]}\n"
+ "{[Time].[1997].[Q2]}\n"
+ "{[Time].[1997].[Q3]}\n"
+ "{[Time].[1997].[Q4]}\n"
+ "Row #0: 142,407\n"
+ "Row #0: 142,407\n"
+ "Row #0: 74,748\n"
+ "Row #0: 67,659\n"
+ "Row #1: 36,177\n"
+ "Row #1: 36,177\n"
+ "Row #1: 16,890\n"
+ "Row #1: 19,287\n"
+ "Row #2: 33,131\n"
+ "Row #2: 33,131\n"
+ "Row #2: 18,052\n"
+ "Row #2: 15,079\n"
+ "Row #3: 35,310\n"
+ "Row #3: 35,310\n"
+ "Row #3: 18,370\n"
+ "Row #3: 16,940\n"
+ "Row #4: 37,789\n"
+ "Row #4: 37,789\n"
+ "Row #4: 21,436\n"
+ "Row #4: 16,353\n");
}
/**
* Tests that members generated by VisualTotals have correct identity.
*
* <p>Testcase for <a href="http://jira.pentaho.com/browse/MONDRIAN-295">
* bug MONDRIAN-295, "Query generated by Excel 2007 gives incorrect
* results"</a>.
*/
public void testVisualTotalsIntersect() {
assertQueryReturns(
"WITH\n"
+ "SET [XL_Row_Dim_0] AS 'VisualTotals(Distinct(Hierarchize({Ascendants([Customers].[All Customers].[USA]), Descendants([Customers].[All Customers].[USA])})))' \n"
+ "SELECT \n"
+ "NON EMPTY Hierarchize({[Time].[Year].members}) ON COLUMNS , \n"
+ "NON EMPTY Hierarchize(Intersect({DrilldownLevel({[Customers].[All Customers]})}, [XL_Row_Dim_0])) ON ROWS \n"
+ "FROM [Sales] \n"
+ "WHERE ([Measures].[Store Sales])",
"Axis #0:\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #1:\n"
+ "{[Time].[1997]}\n"
+ "Axis #2:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[USA]}\n"
+ "Row #0: 565,238.13\n"
+ "Row #1: 565,238.13\n");
}
/**
* <p>Testcase for <a href="http://jira.pentaho.com/browse/MONDRIAN-668">
* bug MONDRIAN-668, "Intersect should return any VisualTotals members in
* right-hand set"</a>.
*/
public void testVisualTotalsWithNamedSetAndPivotSameAxis() {
assertQueryReturns(
"WITH SET [XL_Row_Dim_0] AS\n"
+ " VisualTotals(\n"
+ " Distinct(\n"
+ " Hierarchize(\n"
+ " {Ascendants([Store].[USA].[CA]),\n"
+ " Descendants([Store].[USA].[CA])})))\n"
+ "select NON EMPTY \n"
+ " Hierarchize(\n"
+ " Intersect(\n"
+ " {DrilldownLevel({[Store].[USA]})},\n"
+ " [XL_Row_Dim_0])) ON COLUMNS\n"
+ "from [Sales] "
+ "where [Measures].[Sales count]\n",
"Axis #0:\n"
+ "{[Measures].[Sales Count]}\n"
+ "Axis #1:\n"
+ "{[Store].[USA]}\n"
+ "{[Store].[USA].[CA]}\n"
+ "Row #0: 24,442\n"
+ "Row #0: 24,442\n");
// now with tuples
assertQueryReturns(
"WITH SET [XL_Row_Dim_0] AS\n"
+ " VisualTotals(\n"
+ " Distinct(\n"
+ " Hierarchize(\n"
+ " {Ascendants([Store].[USA].[CA]),\n"
+ " Descendants([Store].[USA].[CA])})))\n"
+ "select NON EMPTY \n"
+ " Hierarchize(\n"
+ " Intersect(\n"
+ " [Marital Status].[M]\n"
+ " * {DrilldownLevel({[Store].[USA]})}\n"
+ " * [Gender].[F],\n"
+ " [Marital Status].[M]\n"
+ " * [XL_Row_Dim_0]\n"
+ " * [Gender].[F])) ON COLUMNS\n"
+ "from [Sales] "
+ "where [Measures].[Sales count]\n",
"Axis #0:\n"
+ "{[Measures].[Sales Count]}\n"
+ "Axis #1:\n"
+ "{[Marital Status].[M], [Store].[USA], [Gender].[F]}\n"
+ "{[Marital Status].[M], [Store].[USA].[CA], [Gender].[F]}\n"
+ "Row #0: 6,054\n"
+ "Row #0: 6,054\n");
}
/**
* <p>Testcase for <a href="http://jira.pentaho.com/browse/MONDRIAN-682">
* bug MONDRIAN-682, "VisualTotals + Distinct-count measure gives wrong
* results"</a>.
*/
public void testVisualTotalsDistinctCountMeasure() {
// distinct measure
assertQueryReturns(
"WITH SET [XL_Row_Dim_0] AS\n"
+ " VisualTotals(\n"
+ " Distinct(\n"
+ " Hierarchize(\n"
+ " {Ascendants([Store].[USA].[CA]),\n"
+ " Descendants([Store].[USA].[CA])})))\n"
+ "select NON EMPTY \n"
+ " Hierarchize(\n"
+ " Intersect(\n"
+ " {DrilldownLevel({[Store].[All Stores]})},\n"
+ " [XL_Row_Dim_0])) ON COLUMNS\n"
+ "from [HR] "
+ "where [Measures].[Number of Employees]\n",
"Axis #0:\n"
+ "{[Measures].[Number of Employees]}\n"
+ "Axis #1:\n"
+ "{[Store].[All Stores]}\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 193\n"
+ "Row #0: 193\n");
// distinct measure
assertQueryReturns(
"WITH SET [XL_Row_Dim_0] AS\n"
+ " VisualTotals(\n"
+ " Distinct(\n"
+ " Hierarchize(\n"
+ " {Ascendants([Store].[USA].[CA].[Beverly Hills]),\n"
+ " Descendants([Store].[USA].[CA].[Beverly Hills]),\n"
+ " Ascendants([Store].[USA].[CA].[Los Angeles]),\n"
+ " Descendants([Store].[USA].[CA].[Los Angeles])})))"
+ "select NON EMPTY \n"
+ " Hierarchize(\n"
+ " Intersect(\n"
+ " {DrilldownLevel({[Store].[All Stores]})},\n"
+ " [XL_Row_Dim_0])) ON COLUMNS\n"
+ "from [HR] "
+ "where [Measures].[Number of Employees]\n",
"Axis #0:\n"
+ "{[Measures].[Number of Employees]}\n"
+ "Axis #1:\n"
+ "{[Store].[All Stores]}\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 110\n"
+ "Row #0: 110\n");
// distinct measure on columns
assertQueryReturns(
"WITH SET [XL_Row_Dim_0] AS\n"
+ " VisualTotals(\n"
+ " Distinct(\n"
+ " Hierarchize(\n"
+ " {Ascendants([Store].[USA].[CA]),\n"
+ " Descendants([Store].[USA].[CA])})))\n"
+ "select {[Measures].[Count], [Measures].[Number of Employees]} on COLUMNS,"
+ " NON EMPTY \n"
+ " Hierarchize(\n"
+ " Intersect(\n"
+ " {DrilldownLevel({[Store].[All Stores]})},\n"
+ " [XL_Row_Dim_0])) ON ROWS\n"
+ "from [HR] ",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Count]}\n"
+ "{[Measures].[Number of Employees]}\n"
+ "Axis #2:\n"
+ "{[Store].[All Stores]}\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 2,316\n"
+ "Row #0: 193\n"
+ "Row #1: 2,316\n"
+ "Row #1: 193\n");
// distinct measure with tuples
assertQueryReturns(
"WITH SET [XL_Row_Dim_0] AS\n"
+ " VisualTotals(\n"
+ " Distinct(\n"
+ " Hierarchize(\n"
+ " {Ascendants([Store].[USA].[CA]),\n"
+ " Descendants([Store].[USA].[CA])})))\n"
+ "select NON EMPTY \n"
+ " Hierarchize(\n"
+ " Intersect(\n"
+ " [Marital Status].[M]\n"
+ " * {DrilldownLevel({[Store].[USA]})}\n"
+ " * [Gender].[F],\n"
+ " [Marital Status].[M]\n"
+ " * [XL_Row_Dim_0]\n"
+ " * [Gender].[F])) ON COLUMNS\n"
+ "from [Sales] "
+ "where [Measures].[Customer count]\n",
"Axis #0:\n"
+ "{[Measures].[Customer Count]}\n"
+ "Axis #1:\n"
+ "{[Marital Status].[M], [Store].[USA], [Gender].[F]}\n"
+ "{[Marital Status].[M], [Store].[USA].[CA], [Gender].[F]}\n"
+ "Row #0: 654\n"
+ "Row #0: 654\n");
}
/**
* <p>Testcase for <a href="http://jira.pentaho.com/browse/MONDRIAN-761">
* bug MONDRIAN-761, "VisualTotalMember cannot be cast to
* RolapCubeMember"</a>.
*/
public void testVisualTotalsClassCast() {
assertQueryReturns(
"WITH SET [XL_Row_Dim_0] AS\n"
+ " VisualTotals(\n"
+ " Distinct(\n"
+ " Hierarchize(\n"
+ " {Ascendants([Store].[USA].[WA].[Yakima]), \n"
+ " Descendants([Store].[USA].[WA].[Yakima]), \n"
+ " Ascendants([Store].[USA].[WA].[Walla Walla]), \n"
+ " Descendants([Store].[USA].[WA].[Walla Walla]), \n"
+ " Ascendants([Store].[USA].[WA].[Tacoma]), \n"
+ " Descendants([Store].[USA].[WA].[Tacoma]), \n"
+ " Ascendants([Store].[USA].[WA].[Spokane]), \n"
+ " Descendants([Store].[USA].[WA].[Spokane]), \n"
+ " Ascendants([Store].[USA].[WA].[Seattle]), \n"
+ " Descendants([Store].[USA].[WA].[Seattle]), \n"
+ " Ascendants([Store].[USA].[WA].[Bremerton]), \n"
+ " Descendants([Store].[USA].[WA].[Bremerton]), \n"
+ " Ascendants([Store].[USA].[OR]), \n"
+ " Descendants([Store].[USA].[OR])}))) \n"
+ " SELECT NON EMPTY \n"
+ " Hierarchize(\n"
+ " Intersect(\n"
+ " DrilldownMember(\n"
+ " {{DrilldownMember(\n"
+ " {{DrilldownMember(\n"
+ " {{DrilldownLevel(\n"
+ " {[Store].[All Stores]})}},\n"
+ " {[Store].[USA]})}},\n"
+ " {[Store].[USA].[WA]})}},\n"
+ " {[Store].[USA].[WA].[Bremerton]}),\n"
+ " [XL_Row_Dim_0]))\n"
+ "DIMENSION PROPERTIES \n"
+ " PARENT_UNIQUE_NAME, \n"
+ " [Store].[Store Name].[Store Type],\n"
+ " [Store].[Store Name].[Store Manager],\n"
+ " [Store].[Store Name].[Store Sqft],\n"
+ " [Store].[Store Name].[Grocery Sqft],\n"
+ " [Store].[Store Name].[Frozen Sqft],\n"
+ " [Store].[Store Name].[Meat Sqft],\n"
+ " [Store].[Store Name].[Has coffee bar],\n"
+ " [Store].[Store Name].[Street address] ON COLUMNS \n"
+ "FROM [HR]\n"
+ "WHERE \n"
+ " ([Measures].[Number of Employees])\n"
+ "CELL PROPERTIES\n"
+ " VALUE,\n"
+ " FORMAT_STRING,\n"
+ " LANGUAGE,\n"
+ " BACK_COLOR,\n"
+ " FORE_COLOR,\n"
+ " FONT_FLAGS",
"Axis #0:\n"
+ "{[Measures].[Number of Employees]}\n"
+ "Axis #1:\n"
+ "{[Store].[All Stores]}\n"
+ "{[Store].[USA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "{[Store].[USA].[WA]}\n"
+ "{[Store].[USA].[WA].[Bremerton]}\n"
+ "{[Store].[USA].[WA].[Bremerton].[Store 3]}\n"
+ "{[Store].[USA].[WA].[Seattle]}\n"
+ "{[Store].[USA].[WA].[Spokane]}\n"
+ "{[Store].[USA].[WA].[Tacoma]}\n"
+ "{[Store].[USA].[WA].[Walla Walla]}\n"
+ "{[Store].[USA].[WA].[Yakima]}\n"
+ "Row #0: 419\n"
+ "Row #0: 419\n"
+ "Row #0: 136\n"
+ "Row #0: 283\n"
+ "Row #0: 62\n"
+ "Row #0: 62\n"
+ "Row #0: 62\n"
+ "Row #0: 62\n"
+ "Row #0: 74\n"
+ "Row #0: 4\n"
+ "Row #0: 19\n");
}
/**
* <p>Testcase for <a href="http://jira.pentaho.com/browse/MONDRIAN-678">
* bug MONDRIAN-678, "VisualTotals gives UnsupportedOperationException
* calling getOrdinal"</a>. Key difference from previous test is that there
* are multiple hierarchies in Named set.
*/
public void testVisualTotalsWithNamedSetOfTuples() {
assertQueryReturns(
"WITH SET [XL_Row_Dim_0] AS\n"
+ " VisualTotals(\n"
+ " Distinct(\n"
+ " Hierarchize(\n"
+ " {Ascendants([Customers].[All Customers].[USA].[CA].[Beverly Hills].[Ari Tweten]),\n"
+ " Descendants([Customers].[All Customers].[USA].[CA].[Beverly Hills].[Ari Tweten]),\n"
+ " Ascendants([Customers].[All Customers].[Mexico]),\n"
+ " Descendants([Customers].[All Customers].[Mexico])})))\n"
+ "select NON EMPTY \n"
+ " Hierarchize(\n"
+ " Intersect(\n"
+ " (DrilldownMember(\n"
+ " {{DrilldownMember(\n"
+ " {{DrilldownLevel(\n"
+ " {[Customers].[All Customers]})}},\n"
+ " {[Customers].[All Customers].[USA]})}},\n"
+ " {[Customers].[All Customers].[USA].[CA]})),\n"
+ " [XL_Row_Dim_0])) ON COLUMNS\n"
+ "from [Sales]\n"
+ "where [Measures].[Sales count]\n",
"Axis #0:\n"
+ "{[Measures].[Sales Count]}\n"
+ "Axis #1:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[USA].[CA]}\n"
+ "{[Customers].[USA].[CA].[Beverly Hills]}\n"
+ "Row #0: 4\n"
+ "Row #0: 4\n"
+ "Row #0: 4\n"
+ "Row #0: 4\n");
}
public void testVisualTotalsLevel() {
Result result = getTestContext().executeQuery(
"select {[Measures].[Unit Sales]} on columns,\n"
+ "{[Product].[All Products],\n"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread],\n"
+ " VisualTotals(\n"
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread],\n"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],\n"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},\n"
+ " \"**Subtotal - *\")} on rows\n"
+ "from [Sales]");
final List<Position> rowPos = result.getAxes()[1].getPositions();
final Member member0 = rowPos.get(0).get(0);
assertEquals("All Products", member0.getName());
assertEquals("(All)", member0.getLevel().getName());
final Member member1 = rowPos.get(1).get(0);
assertEquals("Bread", member1.getName());
assertEquals("Product Category", member1.getLevel().getName());
final Member member2 = rowPos.get(2).get(0);
assertEquals("*Subtotal - Bread", member2.getName());
assertEquals("Product Category", member2.getLevel().getName());
final Member member3 = rowPos.get(3).get(0);
assertEquals("Bagels", member3.getName());
assertEquals("Product Subcategory", member3.getLevel().getName());
final Member member4 = rowPos.get(4).get(0);
assertEquals("Muffins", member4.getName());
assertEquals("Product Subcategory", member4.getLevel().getName());
}
/**
* Testcase for bug <a href="http://jira.pentaho.com/browse/MONDRIAN-749">
* MONDRIAN-749, "Cannot use visual totals members in calculations"</a>.
*
* <p>The bug is not currently fixed, so it is a negative test case. Row #2
* cell #1 contains an exception, but should be "**Subtotal - Bread :
* Product Subcategory".
*/
public void testVisualTotalsMemberInCalculation() {
getTestContext().assertQueryReturns(
"with member [Measures].[Foo] as\n"
+ " [Product].CurrentMember.Name || ' : ' || [Product].Level.Name\n"
+ "select {[Measures].[Unit Sales], [Measures].[Foo]} on columns,\n"
+ "{[Product].[All Products],\n"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread],\n"
+ " VisualTotals(\n"
+ " {[Product].[All Products].[Food].[Baked Goods].[Bread],\n"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Bagels],\n"
+ " [Product].[All Products].[Food].[Baked Goods].[Bread].[Muffins]},\n"
+ " \"**Subtotal - *\")} on rows\n"
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Foo]}\n"
+ "Axis #2:\n"
+ "{[Product].[All Products]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[*Subtotal - Bread]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Bagels]}\n"
+ "{[Product].[Food].[Baked Goods].[Bread].[Muffins]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: All Products : (All)\n"
+ "Row #1: 7,870\n"
+ "Row #1: Bread : Product Category\n"
+ "Row #2: 4,312\n"
+ "Row #2: #ERR: mondrian.olap.fun.MondrianEvaluationException: Could not find an aggregator in the current evaluation context\n"
+ "Row #3: 815\n"
+ "Row #3: Bagels : Product Subcategory\n"
+ "Row #4: 3,497\n"
+ "Row #4: Muffins : Product Subcategory\n");
}
public void testCalculatedChild() {
// Construct calculated children with the same name for both [Drink] and
// [Non-Consumable]. Then, create a metric to select the calculated
// child based on current product member.
assertQueryReturns(
"with\n"
+ " member [Product].[All Products].[Drink].[Calculated Child] as '[Product].[All Products].[Drink].[Alcoholic Beverages]'\n"
+ " member [Product].[All Products].[Non-Consumable].[Calculated Child] as '[Product].[All Products].[Non-Consumable].[Carousel]'\n"
+ " member [Measures].[Unit Sales CC] as '([Measures].[Unit Sales],[Product].currentmember.CalculatedChild(\"Calculated Child\"))'\n"
+ " select non empty {[Measures].[Unit Sales CC]} on columns,\n"
+ " non empty {[Product].[Drink], [Product].[Non-Consumable]} on rows\n"
+ " from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales CC]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: 6,838\n" // Calculated child for [Drink]
+ "Row #1: 841\n"); // Calculated child for [Non-Consumable]
Member member = executeSingletonAxis(
"[Product].[All Products].CalculatedChild(\"foobar\")");
Assert.assertEquals(member, null);
}
public void testCalculatedChildUsingItem() {
// Construct calculated children with the same name for both [Drink] and
// [Non-Consumable]. Then, create a metric to select the first
// calculated child.
assertQueryReturns(
"with\n"
+ " member [Product].[All Products].[Drink].[Calculated Child] as '[Product].[All Products].[Drink].[Alcoholic Beverages]'\n"
+ " member [Product].[All Products].[Non-Consumable].[Calculated Child] as '[Product].[All Products].[Non-Consumable].[Carousel]'\n"
+ " member [Measures].[Unit Sales CC] as '([Measures].[Unit Sales],AddCalculatedMembers([Product].currentmember.children).Item(\"Calculated Child\"))'\n"
+ " select non empty {[Measures].[Unit Sales CC]} on columns,\n"
+ " non empty {[Product].[Drink], [Product].[Non-Consumable]} on rows\n"
+ " from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales CC]}\n"
+ "Axis #2:\n"
+ "{[Product].[Drink]}\n"
+ "{[Product].[Non-Consumable]}\n"
+ "Row #0: 6,838\n"
// Note: For [Non-Consumable], the calculated child for [Drink] was
// selected!
+ "Row #1: 6,838\n");
Member member = executeSingletonAxis(
"[Product].[All Products].CalculatedChild(\"foobar\")");
Assert.assertEquals(member, null);
}
public void testCalculatedChildOnMemberWithNoChildren() {
Member member =
executeSingletonAxis(
"[Measures].[Store Sales].CalculatedChild(\"foobar\")");
Assert.assertEquals(member, null);
}
public void testCalculatedChildOnNullMember() {
Member member =
executeSingletonAxis(
"[Measures].[Store Sales].parent.CalculatedChild(\"foobar\")");
Assert.assertEquals(member, null);
}
public void testCast() {
// NOTE: Some of these tests fail with 'cannot convert ...', and they
// probably shouldn't. Feel free to fix the conversion.
// -- jhyde, 2006/9/3
// From double to integer. MONDRIAN-1631
Cell cell = getTestContext().executeExprRaw("Cast(1.4 As Integer)");
assertEquals(
"Cast to Integer resulted in wrong datatype\n"
+ cell.getValue().getClass().toString(),
Integer.class, cell.getValue().getClass());
assertEquals(cell.getValue(), 1);
// From integer
// To integer (trivial)
assertExprReturns("0 + Cast(1 + 2 AS Integer)", "3");
// To String
assertExprReturns("'' || Cast(1 + 2 AS String)", "3.0");
// To Boolean
assertExprReturns("1=1 AND Cast(1 + 2 AS Boolean)", "true");
assertExprReturns("1=1 AND Cast(1 - 1 AS Boolean)", "false");
// From boolean
// To String
assertExprReturns("'' || Cast((1 = 1 AND 1 = 2) AS String)", "false");
// This case demonstrates the relative precedence of 'AS' in 'CAST'
// and 'AS' for creating inline named sets. See also bug MONDRIAN-648.
Util.discard(Bug.BugMondrian648Fixed);
assertExprReturns(
"'xxx' || Cast(1 = 1 AND 1 = 2 AS String)",
"xxxfalse");
// To boolean (trivial)
assertExprReturns(
"1=1 AND Cast((1 = 1 AND 1 = 2) AS Boolean)",
"false");
assertExprReturns(
"1=1 OR Cast(1 = 1 AND 1 = 2 AS Boolean)",
"true");
// From null : should not throw exceptions since RolapResult.executeBody
// can receive NULL values when the cell value is not loaded yet, so
// should return null instead.
// To Integer : Expect to return NULL
// Expect to return NULL
assertExprReturns("0 * Cast(NULL AS Integer)", "");
// To Numeric : Expect to return NULL
// Expect to return NULL
assertExprReturns("0 * Cast(NULL AS Numeric)", "");
// To String : Expect to return "null"
assertExprReturns("'' || Cast(NULL AS String)", "null");
// To Boolean : Expect to return NULL, but since FunUtil.BooleanNull
// does not implement three-valued boolean logic yet, this will return
// false
assertExprReturns("1=1 AND Cast(NULL AS Boolean)", "false");
// Double is not allowed as a type
assertExprThrows(
"Cast(1 AS Double)",
"Unknown type 'Double'; values are NUMERIC, STRING, BOOLEAN");
// An integer constant is not allowed as a type
assertExprThrows(
"Cast(1 AS 5)",
"Syntax error at line 1, column 11, token '5'");
assertExprReturns("Cast('tr' || 'ue' AS boolean)", "true");
}
/**
* Testcase for bug <a href="http://jira.pentaho.com/browse/MONDRIAN-524">
* MONDRIAN-524, "VB functions: expected primitive type, got
* java.lang.Object"</a>.
*/
public void testCastBug524() {
assertExprReturns(
"Cast(Int([Measures].[Store Sales] / 3600) as String)",
"157");
}
/**
* Tests {@link mondrian.olap.FunTable#getFunInfoList()}, but more
* importantly, generates an HTML table of all implemented functions into
* a file called "functions.html". You can manually include that table
* in the <a href="{@docRoot}/../mdx.html">MDX
* specification</a>.
*/
public void testDumpFunctions() throws IOException {
final List<FunInfo> funInfoList = new ArrayList<FunInfo>();
funInfoList.addAll(BuiltinFunTable.instance().getFunInfoList());
// Add some UDFs.
funInfoList.add(
new FunInfo(
new UdfResolver(
new UdfResolver.ClassUdfFactory(
CurrentDateMemberExactUdf.class,
null))));
funInfoList.add(
new FunInfo(
new UdfResolver(
new UdfResolver.ClassUdfFactory(
CurrentDateMemberUdf.class,
null))));
funInfoList.add(
new FunInfo(
new UdfResolver(
new UdfResolver.ClassUdfFactory(
CurrentDateStringUdf.class,
null))));
Collections.sort(funInfoList);
final File file = new File("functions.html");
final FileOutputStream os = new FileOutputStream(file);
final PrintWriter pw = new PrintWriter(os);
pw.println("<table border='1'>");
pw.println("<tr>");
pw.println("<td><b>Name</b></td>");
pw.println("<td><b>Description</b></td>");
pw.println("</tr>");
for (FunInfo funInfo : funInfoList) {
pw.println("<tr>");
pw.print(" <td valign=top><code>");
printHtml(pw, funInfo.getName());
pw.println("</code></td>");
pw.print(" <td>");
if (funInfo.getDescription() != null) {
printHtml(pw, funInfo.getDescription());
}
pw.println();
final String[] signatures = funInfo.getSignatures();
if (signatures != null) {
pw.println(" <h1>Syntax</h1>");
for (int j = 0; j < signatures.length; j++) {
if (j > 0) {
pw.println("<br/>");
}
String signature = signatures[j];
pw.print(" ");
printHtml(pw, signature);
}
pw.println();
}
pw.println(" </td>");
pw.println("</tr>");
}
pw.println("</table>");
pw.close();
}
public void testComplexOrExpr()
{
switch (TestContext.instance().getDialect().getDatabaseProduct()) {
case INFOBRIGHT:
// Skip this test on Infobright, because [Promotion Sales] is
// defined wrong.
return;
}
// make sure all aggregates referenced in the OR expression are
// processed in a single load request by setting the eval depth to
// a value smaller than the number of measures
int origDepth = MondrianProperties.instance().MaxEvalDepth.get();
MondrianProperties.instance().MaxEvalDepth.set(3);
assertQueryReturns(
"with set [*NATIVE_CJ_SET] as '[Store].[Store Country].members' "
+ "set [*GENERATED_MEMBERS_Measures] as "
+ " '{[Measures].[Unit Sales], [Measures].[Store Cost], "
+ " [Measures].[Sales Count], [Measures].[Customer Count], "
+ " [Measures].[Promotion Sales]}' "
+ "set [*GENERATED_MEMBERS] as "
+ " 'Generate([*NATIVE_CJ_SET], {[Store].CurrentMember})' "
+ "member [Store].[*SUBTOTAL_MEMBER_SEL~SUM] as 'Sum([*GENERATED_MEMBERS])' "
+ "select [*GENERATED_MEMBERS_Measures] ON COLUMNS, "
+ "NON EMPTY "
+ " Filter("
+ " Generate("
+ " [*NATIVE_CJ_SET], "
+ " {[Store].CurrentMember}), "
+ " (((((NOT IsEmpty([Measures].[Unit Sales])) OR "
+ " (NOT IsEmpty([Measures].[Store Cost]))) OR "
+ " (NOT IsEmpty([Measures].[Sales Count]))) OR "
+ " (NOT IsEmpty([Measures].[Customer Count]))) OR "
+ " (NOT IsEmpty([Measures].[Promotion Sales])))) "
+ "on rows "
+ "from [Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Sales Count]}\n"
+ "{[Measures].[Customer Count]}\n"
+ "{[Measures].[Promotion Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 225,627.23\n"
+ "Row #0: 86,837\n"
+ "Row #0: 5,581\n"
+ "Row #0: 151,211.21\n");
MondrianProperties.instance().MaxEvalDepth.set(origDepth);
}
public void testLeftFunctionWithValidArguments() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "Left([Store].CURRENTMEMBER.Name, 4)=\"Bell\") on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testLeftFunctionWithLengthValueZero() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "Left([Store].CURRENTMEMBER.Name, 0)=\"\" And "
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\") on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testLeftFunctionWithLengthValueEqualToStringLength() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "Left([Store].CURRENTMEMBER.Name, 10)=\"Bellingham\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testLeftFunctionWithLengthMoreThanStringLength() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "Left([Store].CURRENTMEMBER.Name, 20)=\"Bellingham\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testLeftFunctionWithZeroLengthString() {
assertQueryReturns(
"select filter([Store].MEMBERS,Left(\"\", 20)=\"\" "
+ "And [Store].CURRENTMEMBER.Name = \"Bellingham\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testLeftFunctionWithNegativeLength() {
assertQueryThrows(
"select filter([Store].MEMBERS,"
+ "Left([Store].CURRENTMEMBER.Name, -20)=\"Bellingham\") "
+ "on 0 from sales",
Util.IBM_JVM
? "StringIndexOutOfBoundsException: null"
: "StringIndexOutOfBoundsException: String index out of range: "
+ "-20");
}
public void testMidFunctionWithValidArguments() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", 4, 6) = \"lingha\")"
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testMidFunctionWithZeroLengthStringArgument() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"\", 4, 6) = \"\")"
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testMidFunctionWithLengthArgumentLargerThanStringLength() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", 4, 20) = \"lingham\")"
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testMidFunctionWithStartIndexGreaterThanStringLength() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", 20, 2) = \"\")"
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testMidFunctionWithStartIndexZeroFails() {
// Note: SSAS 2005 treats start<=0 as 1, therefore gives different
// result for this query. We favor the VBA spec over SSAS 2005.
if (Bug.Ssas2005Compatible) {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", 0, 2) = \"Be\")"
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
} else {
assertQueryThrows(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", 0, 2) = \"Be\")"
+ "on 0 from sales",
"Invalid parameter. Start parameter of Mid function must be "
+ "positive");
}
}
public void testMidFunctionWithStartIndexOne() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", 1, 2) = \"Be\")"
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testMidFunctionWithNegativeStartIndex() {
assertQueryThrows(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", -20, 2) = \"\")"
+ "on 0 from sales",
"Invalid parameter. "
+ "Start parameter of Mid function must be positive");
}
public void testMidFunctionWithNegativeLength() {
assertQueryThrows(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", 2, -2) = \"\")"
+ "on 0 from sales",
"Invalid parameter. "
+ "Length parameter of Mid function must be non-negative");
}
public void testMidFunctionWithoutLength() {
assertQueryReturns(
"select filter([Store].MEMBERS,"
+ "[Store].CURRENTMEMBER.Name = \"Bellingham\""
+ "And Mid(\"Bellingham\", 2) = \"ellingham\")"
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testLenFunctionWithNonEmptyString() {
assertQueryReturns(
"select filter([Store].MEMBERS, "
+ "Len([Store].CURRENTMEMBER.Name) = 3) on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 266,773\n");
}
public void testLenFunctionWithAnEmptyString() {
assertQueryReturns(
"select filter([Store].MEMBERS,Len(\"\")=0 "
+ "And [Store].CURRENTMEMBER.Name = \"Bellingham\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testLenFunctionWithNullString() {
// SSAS2005 returns 0
assertQueryReturns(
"with member [Measures].[Foo] as ' NULL '\n"
+ " member [Measures].[Bar] as ' len([Measures].[Foo]) '\n"
+ "select [Measures].[Bar] on 0\n"
+ "from [Warehouse and Sales]",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Bar]}\n"
+ "Row #0: 0\n");
// same, but inline
assertExprReturns("len(null)", 0, 0);
}
public void testUCaseWithNonEmptyString() {
assertQueryReturns(
"select filter([Store].MEMBERS, "
+ " UCase([Store].CURRENTMEMBER.Name) = \"BELLINGHAM\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testUCaseWithEmptyString() {
assertQueryReturns(
"select filter([Store].MEMBERS, "
+ " UCase(\"\") = \"\" "
+ "And [Store].CURRENTMEMBER.Name = \"Bellingham\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testInStrFunctionWithValidArguments() {
assertQueryReturns(
"select filter([Store].MEMBERS,InStr(\"Bellingham\", \"ingha\")=5 "
+ "And [Store].CURRENTMEMBER.Name = \"Bellingham\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void
testIifFWithBooleanBooleanAndNumericParameterForReturningTruePart()
{
assertQueryReturns(
"SELECT Filter(Store.allmembers, "
+ "iif(measures.profit < 400000,"
+ "[store].currentMember.NAME = \"USA\", 0)) on 0 FROM SALES",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 266,773\n");
}
public void
testIifWithBooleanBooleanAndNumericParameterForReturningFalsePart()
{
assertQueryReturns(
"SELECT Filter([Store].[USA].[CA].[Beverly Hills].children, "
+ "iif(measures.profit > 400000,"
+ "[store].currentMember.NAME = \"USA\", 1)) on 0 FROM SALES",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[CA].[Beverly Hills].[Store 6]}\n"
+ "Row #0: 21,333\n");
}
public void testIIFWithBooleanBooleanAndNumericParameterForReturningZero() {
assertQueryReturns(
"SELECT Filter(Store.allmembers, "
+ "iif(measures.profit > 400000,"
+ "[store].currentMember.NAME = \"USA\", 0)) on 0 FROM SALES",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n");
}
public void testInStrFunctionWithEmptyString1() {
assertQueryReturns(
"select filter([Store].MEMBERS,InStr(\"\", \"ingha\")=0 "
+ "And [Store].CURRENTMEMBER.Name = \"Bellingham\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testInStrFunctionWithEmptyString2() {
assertQueryReturns(
"select filter([Store].MEMBERS,InStr(\"Bellingham\", \"\")=1 "
+ "And [Store].CURRENTMEMBER.Name = \"Bellingham\") "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA].[WA].[Bellingham]}\n"
+ "Row #0: 2,237\n");
}
public void testGetCaptionUsingMemberDotCaption() {
assertQueryReturns(
"SELECT Filter(Store.allmembers, "
+ "[store].currentMember.caption = \"USA\") on 0 FROM SALES",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Store].[USA]}\n"
+ "Row #0: 266,773\n");
}
private static void printHtml(PrintWriter pw, String s) {
final String escaped = StringEscaper.htmlEscaper.escapeString(s);
pw.print(escaped);
}
public void testCache() {
// test various data types: integer, string, member, set, tuple
assertExprReturns("Cache(1 + 2)", "3");
assertExprReturns("Cache('foo' || 'bar')", "foobar");
assertAxisReturns(
"[Gender].Children",
"[Gender].[F]\n"
+ "[Gender].[M]");
assertAxisReturns(
"([Gender].[M], [Marital Status].[S].PrevMember)",
"{[Gender].[M], [Marital Status].[M]}");
// inside another expression
assertAxisReturns(
"Order(Cache([Gender].Children), Cache(([Measures].[Unit Sales], [Time].[1997].[Q1])), BDESC)",
"[Gender].[M]\n"
+ "[Gender].[F]");
// doesn't work with multiple args
assertExprThrows(
"Cache(1, 2)",
"No function matches signature 'Cache(<Numeric Expression>, <Numeric Expression>)'");
}
// The following methods test VBA functions. They don't test all of them,
// because the raw methods are tested in VbaTest, but they test the core
// functionalities like error handling and operator overloading.
public void testVbaBasic() {
// Exp is a simple function: one arg.
assertExprReturns("exp(0)", "1");
assertExprReturns("exp(1)", Math.E, 0.00000001);
assertExprReturns("exp(-2)", 1d / (Math.E * Math.E), 0.00000001);
// If any arg is null, result is null.
assertExprReturns("exp(cast(null as numeric))", "");
}
// Test a VBA function with variable number of args.
public void testVbaOverloading() {
assertExprReturns("replace('xyzxyz', 'xy', 'a')", "azaz");
assertExprReturns("replace('xyzxyz', 'xy', 'a', 2)", "xyzaz");
assertExprReturns("replace('xyzxyz', 'xy', 'a', 1, 1)", "azxyz");
}
// Test VBA exception handling
public void testVbaExceptions() {
assertExprThrows(
"right(\"abc\", -4)",
Util.IBM_JVM
? "StringIndexOutOfBoundsException: null"
: "StringIndexOutOfBoundsException: "
+ "String index out of range: -4");
}
public void testVbaDateTime() {
// function which returns date
assertExprReturns(
"Format(DateSerial(2006, 4, 29), \"Long Date\")",
"Saturday, April 29, 2006");
// function with date parameter
assertExprReturns("Year(DateSerial(2006, 4, 29))", "2,006");
}
public void testExcelPi() {
// The PI function is defined in the Excel class.
assertExprReturns("Pi()", "3");
}
public void testExcelPower() {
assertExprReturns("Power(8, 0.333333)", 2.0, 0.01);
assertExprReturns("Power(-2, 0.5)", Double.NaN, 0.001);
}
// Comment from the bug: the reason for this is that in AbstractExpCompiler
// in the compileInteger method we are casting an IntegerCalc into a
// DoubleCalc and there is no check for IntegerCalc in the NumericType
// conditional path.
public void testBug1881739() {
assertExprReturns("LEFT(\"TEST\", LEN(\"TEST\"))", "TEST");
}
/**
* Testcase for bug <a href="http://jira.pentaho.com/browse/MONDRIAN-296">
* MONDRIAN-296, "Cube getTimeDimension use when Cube has no Time
* dimension"</a>.
*/
public void testCubeTimeDimensionFails() {
assertQueryThrows(
"select LastPeriods(1) on columns from [Store]",
"'LastPeriods', no time dimension");
assertQueryThrows(
"select OpeningPeriod() on columns from [Store]",
"'OpeningPeriod', no time dimension");
assertQueryThrows(
"select OpeningPeriod([Store Type]) on columns from [Store]",
"'OpeningPeriod', no time dimension");
assertQueryThrows(
"select ClosingPeriod() on columns from [Store]",
"'ClosingPeriod', no time dimension");
assertQueryThrows(
"select ClosingPeriod([Store Type]) on columns from [Store]",
"'ClosingPeriod', no time dimension");
assertQueryThrows(
"select ParallelPeriod() on columns from [Store]",
"'ParallelPeriod', no time dimension");
assertQueryThrows(
"select PeriodsToDate() on columns from [Store]",
"'PeriodsToDate', no time dimension");
assertQueryThrows(
"select Mtd() on columns from [Store]",
"'Mtd', no time dimension");
}
public void testFilterEmpty() {
// Unlike "Descendants(<set>, ...)", we do not need to know the precise
// type of the set, therefore it is OK if the set is empty.
assertAxisReturns(
"Filter({}, 1=0)",
"");
assertAxisReturns(
"Filter({[Time].[Time].Children}, 1=0)",
"");
}
public void testFilterCalcSlicer() {
assertQueryReturns(
"with member [Time].[Time].[Date Range] as \n"
+ "'Aggregate({[Time].[1997].[Q1]:[Time].[1997].[Q3]})'\n"
+ "select\n"
+ "{[Measures].[Unit Sales],[Measures].[Store Cost],\n"
+ "[Measures].[Store Sales]} ON columns,\n"
+ "NON EMPTY Filter ([Store].[Store State].members,\n"
+ "[Measures].[Store Cost] > 75000) ON rows\n"
+ "from [Sales] where [Time].[Date Range]",
"Axis #0:\n"
+ "{[Time].[Date Range]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[WA]}\n"
+ "Row #0: 90,131\n"
+ "Row #0: 76,151.59\n"
+ "Row #0: 190,776.88\n");
assertQueryReturns(
"with member [Time].[Time].[Date Range] as \n"
+ "'Aggregate({[Time].[1997].[Q1]:[Time].[1997].[Q3]})'\n"
+ "select\n"
+ "{[Measures].[Unit Sales],[Measures].[Store Cost],\n"
+ "[Measures].[Store Sales]} ON columns,\n"
+ "NON EMPTY Order (Filter ([Store].[Store State].members,\n"
+ "[Measures].[Store Cost] > 100),[Measures].[Store Cost], DESC) ON rows\n"
+ "from [Sales] where [Time].[Date Range]",
"Axis #0:\n"
+ "{[Time].[Date Range]}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Cost]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Store].[USA].[WA]}\n"
+ "{[Store].[USA].[CA]}\n"
+ "{[Store].[USA].[OR]}\n"
+ "Row #0: 90,131\n"
+ "Row #0: 76,151.59\n"
+ "Row #0: 190,776.88\n"
+ "Row #1: 53,312\n"
+ "Row #1: 45,435.93\n"
+ "Row #1: 113,966.00\n"
+ "Row #2: 51,306\n"
+ "Row #2: 43,033.82\n"
+ "Row #2: 107,823.63\n");
}
public void testExistsMembersAll() {
assertQueryReturns(
"select exists(\n"
+ " {[Customers].[All Customers],\n"
+ " [Customers].[Country].Members,\n"
+ " [Customers].[State Province].[CA],\n"
+ " [Customers].[Canada].[BC].[Richmond]},\n"
+ " {[Customers].[All Customers]})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[Canada]}\n"
+ "{[Customers].[Mexico]}\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[USA].[CA]}\n"
+ "{[Customers].[Canada].[BC].[Richmond]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: \n"
+ "Row #0: \n"
+ "Row #0: 266,773\n"
+ "Row #0: 74,748\n"
+ "Row #0: \n");
}
public void testExistsMembersLevel2() {
assertQueryReturns(
"select exists(\n"
+ " {[Customers].[All Customers],\n"
+ " [Customers].[Country].Members,\n"
+ " [Customers].[State Province].[CA],\n"
+ " [Customers].[Canada].[BC].[Richmond]},\n"
+ " {[Customers].[Country].[USA]})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[USA].[CA]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 266,773\n"
+ "Row #0: 74,748\n");
}
public void testExistsWithImplicitAllMember() {
// the tuple in the second arg in this case should implicitly
// contain [Customers].[All Customers], so the whole tuple list
// from the first arg should be returned.
assertQueryReturns(
"select non empty exists(\n"
+ " {[Customers].[All Customers],\n"
+ " [Customers].[All Customers].Children,\n"
+ " [Customers].[State Province].Members},\n"
+ " {[Product].Members})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[USA].[CA]}\n"
+ "{[Customers].[USA].[OR]}\n"
+ "{[Customers].[USA].[WA]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: 266,773\n"
+ "Row #0: 74,748\n"
+ "Row #0: 67,659\n"
+ "Row #0: 124,366\n");
assertQueryReturns(
"select exists( "
+ "[Customers].[USA].[CA], (Store.[USA], Gender.[F])) "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA]}\n"
+ "Row #0: 74,748\n");
}
public void testExistsWithMultipleHierarchies() {
// tests queries w/ a multi-hierarchy dim in either or both args.
assertQueryReturns(
"select exists( "
+ "crossjoin( time.[1997], {[Time.Weekly].[1997].[16]}), "
+ " { Gender.F } ) on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997], [Time].[Weekly].[1997].[16]}\n"
+ "Row #0: 3,839\n");
assertQueryReturns(
"select exists( "
+ "time.[1997].[Q1], {[Time.Weekly].[1997].[4]}) "
+ " on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1997].[Q1]}\n"
+ "Row #0: 66,291\n");
assertQueryReturns(
"select exists( "
+ "{ Gender.F }, "
+ "crossjoin( time.[1997], {[Time.Weekly].[1997].[16]}) ) "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Gender].[F]}\n"
+ "Row #0: 131,558\n");
assertQueryReturns(
"select exists( "
+ "{ time.[1998] }, "
+ "crossjoin( time.[1997], {[Time.Weekly].[1997].[16]}) ) "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n");
}
public void testExistsWithDefaultNonAllMember() {
// default mem for Time is 1997
// non-all default on right side.
assertQueryReturns(
"select exists( [Time].[1998].[Q1], Gender.[All Gender]) on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n");
// switching to an explicit member on the hierarchy chain should return
// 1998.Q1
assertQueryReturns(
"select exists( [Time].[1998].[Q1], ([Time].[1998], Gender.[All Gender])) on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1998].[Q1]}\n"
+ "Row #0: \n");
// non-all default on left side
assertQueryReturns(
"select exists( "
+ "Gender.[All Gender], (Gender.[F], [Time].[1998].[Q1])) "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n");
assertQueryReturns(
"select exists( "
+ "(Time.[1998].[Q1].[1], Gender.[All Gender]), (Gender.[F], [Time].[1998].[Q1])) "
+ "on 0 from sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Time].[1998].[Q1].[1], [Gender].[All Gender]}\n"
+ "Row #0: \n");
}
public void testExistsMembers2Hierarchies() {
assertQueryReturns(
"select exists(\n"
+ " {[Customers].[All Customers],\n"
+ " [Customers].[All Customers].Children,\n"
+ " [Customers].[State Province].Members,\n"
+ " [Customers].[Country].[Canada],\n"
+ " [Customers].[Country].[Mexico]},\n"
+ " {[Customers].[Country].[USA],\n"
+ " [Customers].[State Province].[Veracruz]})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[All Customers]}\n"
+ "{[Customers].[Mexico]}\n"
+ "{[Customers].[USA]}\n"
+ "{[Customers].[Mexico].[Veracruz]}\n"
+ "{[Customers].[USA].[CA]}\n"
+ "{[Customers].[USA].[OR]}\n"
+ "{[Customers].[USA].[WA]}\n"
+ "{[Customers].[Mexico]}\n"
+ "Row #0: 266,773\n"
+ "Row #0: \n"
+ "Row #0: 266,773\n"
+ "Row #0: \n"
+ "Row #0: 74,748\n"
+ "Row #0: 67,659\n"
+ "Row #0: 124,366\n"
+ "Row #0: \n");
}
public void testExistsTuplesAll() {
assertQueryReturns(
"select exists(\n"
+ " crossjoin({[Product].[All Products]},{[Customers].[All Customers]}),\n"
+ " {[Customers].[All Customers]})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Product].[All Products], [Customers].[All Customers]}\n"
+ "Row #0: 266,773\n");
}
public void testExistsTuplesLevel2() {
assertQueryReturns(
"select exists(\n"
+ " crossjoin({[Product].[All Products]},{[Customers].[All Customers].Children}),\n"
+ " {[Customers].[All Customers].[USA]})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Product].[All Products], [Customers].[USA]}\n"
+ "Row #0: 266,773\n");
}
public void testExistsTuplesLevel23() {
assertQueryReturns(
"select exists(\n"
+ " crossjoin({[Customers].[State Province].Members}, {[Product].[All Products]}),\n"
+ " {[Customers].[All Customers].[USA]})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA], [Product].[All Products]}\n"
+ "{[Customers].[USA].[OR], [Product].[All Products]}\n"
+ "{[Customers].[USA].[WA], [Product].[All Products]}\n"
+ "Row #0: 74,748\n"
+ "Row #0: 67,659\n"
+ "Row #0: 124,366\n");
}
public void testExistsTuples2Dim() {
assertQueryReturns(
"select exists(\n"
+ " crossjoin({[Customers].[State Province].Members}, {[Product].[Product Family].Members}),\n"
+ " {([Product].[Product Department].[Dairy],[Customers].[All Customers].[USA])})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA], [Product].[Drink]}\n"
+ "{[Customers].[USA].[OR], [Product].[Drink]}\n"
+ "{[Customers].[USA].[WA], [Product].[Drink]}\n"
+ "Row #0: 7,102\n"
+ "Row #0: 6,106\n"
+ "Row #0: 11,389\n");
}
public void testExistsTuplesDiffDim() {
assertQueryReturns(
"select exists(\n"
+ " crossjoin(\n"
+ " crossjoin({[Customers].[State Province].Members},\n"
+ " {[Time].[Year].[1997]}), \n"
+ " {[Product].[Product Family].Members}),\n"
+ " {([Product].[Product Department].[Dairy],\n"
+ " [Promotions].[All Promotions], \n"
+ " [Customers].[All Customers].[USA])})\n"
+ "on 0 from Sales",
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Customers].[USA].[CA], [Time].[1997], [Product].[Drink]}\n"
+ "{[Customers].[USA].[OR], [Time].[1997], [Product].[Drink]}\n"
+ "{[Customers].[USA].[WA], [Time].[1997], [Product].[Drink]}\n"
+ "Row #0: 7,102\n"
+ "Row #0: 6,106\n"
+ "Row #0: 11,389\n");
}
/**
* Executes a query that has a complex parse tree. Goal is to find
* algorithmic complexity bugs in the validator which would make the query
* run extremely slowly.
*/
public void testComplexQuery() {
final String expected =
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "Axis #2:\n"
+ "{[Gender].[All Gender]}\n"
+ "{[Gender].[F]}\n"
+ "{[Gender].[M]}\n"
+ "Row #0: 266,773\n"
+ "Row #1: 131,558\n"
+ "Row #2: 135,215\n";
// hand written case
assertQueryReturns(
"select\n"
+ " [Measures].[Unit Sales] on 0,\n"
+ " Distinct({\n"
+ " [Gender],\n"
+ " Tail(\n"
+ " Head({\n"
+ " [Gender],\n"
+ " [Gender].[F],\n"
+ " [Gender].[M]},\n"
+ " 2),\n"
+ " 1),\n"
+ " Tail(\n"
+ " Head({\n"
+ " [Gender],\n"
+ " [Gender].[F],\n"
+ " [Gender].[M]},\n"
+ " 2),\n"
+ " 1),\n"
+ " [Gender].[M]}) on 1\n"
+ "from [Sales]", expected);
// generated equivalent
StringBuilder buf = new StringBuilder();
buf.append(
"select\n"
+ " [Measures].[Unit Sales] on 0,\n");
generateComplex(buf, " ", 0, 7, 3);
buf.append(
" on 1\n"
+ "from [Sales]");
if (false) {
System.out.println(buf.toString().length() + ": " + buf.toString());
}
assertQueryReturns(buf.toString(), expected);
}
/**
* Recursive routine to generate a complex MDX expression.
*
* @param buf String builder
* @param indent Indent
* @param depth Current depth
* @param depthLimit Max recursion depth
* @param breadth Number of iterations at each depth
*/
private void generateComplex(
StringBuilder buf,
String indent,
int depth,
int depthLimit,
int breadth)
{
buf.append(indent + "Distinct({\n");
buf.append(indent + " [Gender],\n");
for (int i = 0; i < breadth; i++) {
if (depth < depthLimit) {
buf.append(indent + " Tail(\n");
buf.append(indent + " Head({\n");
generateComplex(
buf,
indent + " ",
depth + 1,
depthLimit,
breadth);
buf.append("},\n");
buf.append(indent + " 2),\n");
buf.append(indent + " 1),\n");
} else {
buf.append(indent + " [Gender].[F],\n");
}
}
buf.append(indent + " [Gender].[M]})");
}
/**
* Testcase for bug <a href="http://jira.pentaho.com/browse/MONDRIAN-1050">
* MONDRIAN-1050, "MDX Order function fails when using DateTime expression
* for ordering"</a>.
*/
public void testDateParameter() throws Exception {
executeQuery(
"SELECT {[Measures].[Unit Sales]} ON COLUMNS, Order([Gender].Members, Now(), ASC) ON ROWS FROM [Sales]");
}
/**
* Testcase for bug <a href="http://jira.pentaho.com/browse/MONDRIAN-1043">
* MONDRIAN-1043, "Hierarchize with Except sort set members differently than
* in Mondrian 3.2.1"</a>.
*
* <p>This test makes sure that
* Hierarchize and Except can be used within each other and that the
* sort order is maintained.</p>
*/
public void testHierarchizeExcept() throws Exception {
final String[] mdxA =
new String[] {
"SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS, Hierarchize(Except({[Customers].[USA].Children, [Customers].[USA].[CA].Children}, [Customers].[USA].[CA])) ON ROWS FROM [Sales]",
"SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS, Except(Hierarchize({[Customers].[USA].Children, [Customers].[USA].[CA].Children}), [Customers].[USA].[CA]) ON ROWS FROM [Sales] "
};
for (String mdx : mdxA) {
assertQueryReturns(
mdx,
"Axis #0:\n"
+ "{}\n"
+ "Axis #1:\n"
+ "{[Measures].[Unit Sales]}\n"
+ "{[Measures].[Store Sales]}\n"
+ "Axis #2:\n"
+ "{[Customers].[USA].[CA].[Altadena]}\n"
+ "{[Customers].[USA].[CA].[Arcadia]}\n"
+ "{[Customers].[USA].[CA].[Bellflower]}\n"
+ "{[Customers].[USA].[CA].[Berkeley]}\n"
+ "{[Customers].[USA].[CA].[Beverly Hills]}\n"
+ "{[Customers].[USA].[CA].[Burbank]}\n"
+ "{[Customers].[USA].[CA].[Burlingame]}\n"
+ "{[Customers].[USA].[CA].[Chula Vista]}\n"
+ "{[Customers].[USA].[CA].[Colma]}\n"
+ "{[Customers].[USA].[CA].[Concord]}\n"
+ "{[Customers].[USA].[CA].[Coronado]}\n"
+ "{[Customers].[USA].[CA].[Daly City]}\n"
+ "{[Customers].[USA].[CA].[Downey]}\n"
+ "{[Customers].[USA].[CA].[El Cajon]}\n"
+ "{[Customers].[USA].[CA].[Fremont]}\n"
+ "{[Customers].[USA].[CA].[Glendale]}\n"
+ "{[Customers].[USA].[CA].[Grossmont]}\n"
+ "{[Customers].[USA].[CA].[Imperial Beach]}\n"
+ "{[Customers].[USA].[CA].[La Jolla]}\n"
+ "{[Customers].[USA].[CA].[La Mesa]}\n"
+ "{[Customers].[USA].[CA].[Lakewood]}\n"
+ "{[Customers].[USA].[CA].[Lemon Grove]}\n"
+ "{[Customers].[USA].[CA].[Lincoln Acres]}\n"
+ "{[Customers].[USA].[CA].[Long Beach]}\n"
+ "{[Customers].[USA].[CA].[Los Angeles]}\n"
+ "{[Customers].[USA].[CA].[Mill Valley]}\n"
+ "{[Customers].[USA].[CA].[National City]}\n"
+ "{[Customers].[USA].[CA].[Newport Beach]}\n"
+ "{[Customers].[USA].[CA].[Novato]}\n"
+ "{[Customers].[USA].[CA].[Oakland]}\n"
+ "{[Customers].[USA].[CA].[Palo Alto]}\n"
+ "{[Customers].[USA].[CA].[Pomona]}\n"
+ "{[Customers].[USA].[CA].[Redwood City]}\n"
+ "{[Customers].[USA].[CA].[Richmond]}\n"
+ "{[Customers].[USA].[CA].[San Carlos]}\n"
+ "{[Customers].[USA].[CA].[San Diego]}\n"
+ "{[Customers].[USA].[CA].[San Francisco]}\n"
+ "{[Customers].[USA].[CA].[San Gabriel]}\n"
+ "{[Customers].[USA].[CA].[San Jose]}\n"
+ "{[Customers].[USA].[CA].[Santa Cruz]}\n"
+ "{[Customers].[USA].[CA].[Santa Monica]}\n"
+ "{[Customers].[USA].[CA].[Spring Valley]}\n"
+ "{[Customers].[USA].[CA].[Torrance]}\n"
+ "{[Customers].[USA].[CA].[West Covina]}\n"
+ "{[Customers].[USA].[CA].[Woodland Hills]}\n"
+ "{[Customers].[USA].[OR]}\n"
+ "{[Customers].[USA].[WA]}\n"
+ "Row #0: 2,574\n"
+ "Row #0: 5,585.59\n"
+ "Row #1: 2,440\n"
+ "Row #1: 5,136.59\n"
+ "Row #2: 3,106\n"
+ "Row #2: 6,633.97\n"
+ "Row #3: 136\n"
+ "Row #3: 320.17\n"
+ "Row #4: 2,907\n"
+ "Row #4: 6,194.37\n"
+ "Row #5: 3,086\n"
+ "Row #5: 6,577.33\n"
+ "Row #6: 198\n"
+ "Row #6: 407.38\n"
+ "Row #7: 2,999\n"
+ "Row #7: 6,284.30\n"
+ "Row #8: 129\n"
+ "Row #8: 287.78\n"
+ "Row #9: 105\n"
+ "Row #9: 219.77\n"
+ "Row #10: 2,391\n"
+ "Row #10: 5,051.15\n"
+ "Row #11: 129\n"
+ "Row #11: 271.60\n"
+ "Row #12: 3,440\n"
+ "Row #12: 7,367.06\n"
+ "Row #13: 2,543\n"
+ "Row #13: 5,460.42\n"
+ "Row #14: 163\n"
+ "Row #14: 350.22\n"
+ "Row #15: 3,284\n"
+ "Row #15: 7,082.91\n"
+ "Row #16: 2,131\n"
+ "Row #16: 4,458.60\n"
+ "Row #17: 1,616\n"
+ "Row #17: 3,409.34\n"
+ "Row #18: 1,938\n"
+ "Row #18: 4,081.37\n"
+ "Row #19: 1,834\n"
+ "Row #19: 3,908.26\n"
+ "Row #20: 2,487\n"
+ "Row #20: 5,174.12\n"
+ "Row #21: 2,651\n"
+ "Row #21: 5,636.82\n"
+ "Row #22: 2,176\n"
+ "Row #22: 4,691.94\n"
+ "Row #23: 2,973\n"
+ "Row #23: 6,422.37\n"
+ "Row #24: 2,009\n"
+ "Row #24: 4,312.99\n"
+ "Row #25: 58\n"
+ "Row #25: 109.36\n"
+ "Row #26: 2,031\n"
+ "Row #26: 4,237.46\n"
+ "Row #27: 3,098\n"
+ "Row #27: 6,696.06\n"
+ "Row #28: 163\n"
+ "Row #28: 335.98\n"
+ "Row #29: 70\n"
+ "Row #29: 145.90\n"
+ "Row #30: 133\n"
+ "Row #30: 272.08\n"
+ "Row #31: 2,712\n"
+ "Row #31: 5,595.62\n"
+ "Row #32: 144\n"
+ "Row #32: 312.43\n"
+ "Row #33: 110\n"
+ "Row #33: 212.45\n"
+ "Row #34: 145\n"
+ "Row #34: 289.80\n"
+ "Row #35: 1,535\n"
+ "Row #35: 3,348.69\n"
+ "Row #36: 88\n"
+ "Row #36: 195.28\n"
+ "Row #37: 2,631\n"
+ "Row #37: 5,663.60\n"
+ "Row #38: 161\n"
+ "Row #38: 343.20\n"
+ "Row #39: 185\n"
+ "Row #39: 367.78\n"
+ "Row #40: 2,660\n"
+ "Row #40: 5,739.63\n"
+ "Row #41: 1,790\n"
+ "Row #41: 3,862.79\n"
+ "Row #42: 2,570\n"
+ "Row #42: 5,405.02\n"
+ "Row #43: 2,503\n"
+ "Row #43: 5,302.08\n"
+ "Row #44: 2,516\n"
+ "Row #44: 5,406.21\n"
+ "Row #45: 67,659\n"
+ "Row #45: 142,277.07\n"
+ "Row #46: 124,366\n"
+ "Row #46: 263,793.22\n");
}
}
}
// End FunctionTest.java