/* * 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) 2002-2013 Pentaho Corporation.. All rights reserved. */ package mondrian.test; import mondrian.olap.MondrianProperties; import mondrian.rolap.BatchTestCase; import mondrian.spi.Dialect; /** * Tests multiple hierarchies within the same dimension. * * @author jhyde * @since Dec 15, 2005 */ public class MultipleHierarchyTest extends BatchTestCase { private static final String timeWeekly = TestContext.hierarchyName("Time", "Weekly"); private static final String timeTime = TestContext.hierarchyName("Time", "Time"); public MultipleHierarchyTest(String name) { super(name); } public void testWeekly() { if (MondrianProperties.instance().SsasCompatibleNaming.get()) { // [Time.Weekly] has an 'all' member, but [Time] does not. assertAxisReturns( "{[Time].[Time].CurrentMember}", "[Time].[1997]"); assertAxisReturns( "{[Time].[Weekly].CurrentMember}", "[Time].[Weekly].[All Weeklys]"); } else { // [Time.Weekly] has an 'all' member, but [Time] does not. assertAxisReturns( "{[Time].CurrentMember}", "[Time].[1997]"); assertAxisReturns( "{[Time.Weekly].CurrentMember}", "[Time].[Weekly].[All Weeklys]"); } } public void testWeekly2() { // When the context is one hierarchy, // the current member of other hierarchy must be its default member. assertQueryReturns( "with\n" + " member [Measures].[Foo] as ' " + timeWeekly + ".CurrentMember.UniqueName '\n" + " member [Measures].[Foo2] as ' " + timeTime + ".CurrentMember.UniqueName '\n" + "select\n" + " {[Measures].[Unit Sales], [Measures].[Foo], [Measures].[Foo2]} on columns,\n" + " {" + timeTime + ".children} on rows\n" + "from [Sales]", "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Unit Sales]}\n" + "{[Measures].[Foo]}\n" + "{[Measures].[Foo2]}\n" + "Axis #2:\n" + "{[Time].[1997].[Q1]}\n" + "{[Time].[1997].[Q2]}\n" + "{[Time].[1997].[Q3]}\n" + "{[Time].[1997].[Q4]}\n" + "Row #0: 66,291\n" + "Row #0: [Time].[Weekly].[All Weeklys]\n" + "Row #0: [Time].[1997].[Q1]\n" + "Row #1: 62,610\n" + "Row #1: [Time].[Weekly].[All Weeklys]\n" + "Row #1: [Time].[1997].[Q2]\n" + "Row #2: 65,848\n" + "Row #2: [Time].[Weekly].[All Weeklys]\n" + "Row #2: [Time].[1997].[Q3]\n" + "Row #3: 72,024\n" + "Row #3: [Time].[Weekly].[All Weeklys]\n" + "Row #3: [Time].[1997].[Q4]\n"); } public void testMultipleMembersOfSameDimensionInSlicerFails() { assertQueryThrows( "select {[Measures].[Unit Sales]} on columns,\n" + " {[Store].children} on rows\n" + "from [Sales]\n" + "where ([Gender].[M], [Time].[1997], [Time].[1997].[Q1])", "Tuple contains more than one member of hierarchy '[Time]'."); } public void testMembersOfHierarchiesInSameDimensionInSlicer() { assertQueryReturns( "select {[Measures].[Unit Sales]} on columns,\n" + " {[Store].children} on rows\n" + "from [Sales]\n" + "where ([Gender].[M], " + TestContext.hierarchyName("Time", "Weekly") + ".[1997], [Time].[1997].[Q1])", "Axis #0:\n" + "{[Gender].[M], [Time].[Weekly].[1997], [Time].[1997].[Q1]}\n" + "Axis #1:\n" + "{[Measures].[Unit Sales]}\n" + "Axis #2:\n" + "{[Store].[Canada]}\n" + "{[Store].[Mexico]}\n" + "{[Store].[USA]}\n" + "Row #0: \n" + "Row #1: \n" + "Row #2: 33,381\n"); } public void testCalcMember() { assertQueryReturns( "with member [Measures].[Sales to Date] as \n" + " ' Sum(PeriodsToDate([Time].[Year], [Time].[Time].CurrentMember), [Measures].[Unit Sales])'\n" + "select {[Measures].[Sales to Date]} on columns,\n" + " {[Time].[1997].[Q2].[4]," + " [Time].[1997].[Q2].[5]} on rows\n" + "from [Sales]", // msas give 86740, 107551 "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Sales to Date]}\n" + "Axis #2:\n" + "{[Time].[1997].[Q2].[4]}\n" + "{[Time].[1997].[Q2].[5]}\n" + "Row #0: 86,470\n" + "Row #1: 107,551\n"); assertQueryReturns( "with member [Measures].[Sales to Date] as \n" + " ' Sum(PeriodsToDate(" + timeWeekly + ".[Year], " + timeWeekly + ".CurrentMember), [Measures].[Unit Sales])'\n" + "select {[Measures].[Sales to Date]} on columns,\n" + " {" + timeWeekly + ".[1997].[14] : " + timeWeekly + ".[1997].[16]} on rows\n" + "from [Sales]", "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Sales to Date]}\n" + "Axis #2:\n" + "{[Time].[Weekly].[1997].[14]}\n" + "{[Time].[Weekly].[1997].[15]}\n" + "{[Time].[Weekly].[1997].[16]}\n" + "Row #0: 81,670\n" + "Row #1: 86,300\n" + "Row #2: 90,139\n"); } /** * Tests <a href="http://jira.pentaho.com/browse/MONDRIAN-191"> * bug MONDRIAN-191, "Properties not working with multiple hierarchies"</a>. */ public void testProperty() { TestContext testContext = TestContext.instance().createSubstitutingCube( "Sales", "<Dimension name=\"NuStore\" foreignKey=\"store_id\">\n" + "<Hierarchy hasAll=\"true\" primaryKey=\"store_id\">\n" + " <Table name=\"store\"/>\n" + " <Level name=\"NuStore Country\" column=\"store_country\" uniqueMembers=\"true\"/>\n" + " <Level name=\"NuStore State\" column=\"store_state\" uniqueMembers=\"true\"/>\n" + " <Level name=\"NuStore City\" column=\"store_city\" uniqueMembers=\"false\"/>\n" + " <Level name=\"NuStore Name\" column=\"store_name\" uniqueMembers=\"true\">\n" + " <Property name=\"NuStore Type\" column=\"store_type\"/>\n" + " <Property name=\"NuStore Manager\" column=\"store_manager\"/>\n" + " <Property name=\"NuStore Sqft\" column=\"store_sqft\" type=\"Numeric\"/>\n" + " <Property name=\"Grocery Sqft\" column=\"grocery_sqft\" type=\"Numeric\"/>\n" + " <Property name=\"Frozen Sqft\" column=\"frozen_sqft\" type=\"Numeric\"/>\n" + " <Property name=\"Meat Sqft\" column=\"meat_sqft\" type=\"Numeric\"/>\n" + " <Property name=\"Has coffee bar\" column=\"coffee_bar\" type=\"Boolean\"/>\n" + " <Property name=\"Street address\" column=\"store_street_address\" type=\"String\"/>\n" + " </Level>\n" + "</Hierarchy>\n" + "<Hierarchy caption=\"NuStore2\" name=\"NuStore2\" allMemberName=\"All NuStore2s\" hasAll=\"true\" primaryKey=\"NuStore_id\">\n" + " <Table name=\"store\"/>\n" + " <Level name=\"NuStore City\" column=\"store_city\" uniqueMembers=\"false\"/>\n" + " <Level name=\"NuStore Name\" column=\"store_name\" uniqueMembers=\"true\">\n" + " <Property name=\"NuStore Type\" column=\"store_type\"/>\n" + " <Property name=\"NuStore Manager\" column=\"store_manager\"/>\n" + " <Property name=\"NuStore Sqft\" column=\"store_sqft\" type=\"Numeric\"/>\n" + " <Property name=\"Grocery Sqft\" column=\"grocery_sqft\" type=\"Numeric\"/>\n" + " <Property name=\"Frozen Sqft\" column=\"frozen_sqft\" type=\"Numeric\"/>\n" + " <Property name=\"Meat Sqft\" column=\"meat_sqft\" type=\"Numeric\"/>\n" + " <Property name=\"Has coffee bar\" column=\"coffee_bar\" type=\"Boolean\"/>\n" + " <Property name=\"Street address\" column=\"store_street_address\" type=\"String\"/>\n" + " </Level>\n" + "</Hierarchy>\n" + "</Dimension>"); final String nuStore = TestContext.hierarchyName("NuStore", "NuStore"); testContext.assertQueryReturns( "with member [Measures].[Store level] as '" + nuStore + ".CurrentMember.Level.Name'\n" + "member [Measures].[Store type] as 'IIf((" + nuStore + ".CurrentMember.Level.Name = \"NuStore Name\"), CAST(" + nuStore + ".CurrentMember.Properties(\"NuStore Type\") AS STRING), \"No type\")'\n" + "member [Measures].[Store Sqft] as 'IIf((" + nuStore + ".CurrentMember.Level.Name = \"NuStore Name\"), CAST(" + nuStore + ".CurrentMember.Properties(\"NuStore Sqft\") AS INTEGER), 0.0)'\n" + "select {" + "[Measures].[Unit Sales], " + "[Measures].[Store Cost], " + "[Measures].[Store Sales], " + "[Measures].[Store level], " + "[Measures].[Store type], " + "[Measures].[Store Sqft]" + "} ON COLUMNS,\n" + "{" + nuStore + ".[All NuStores], " + nuStore + ".[Canada], " + nuStore + ".[Canada].[BC], " + nuStore + ".[Canada].[BC].[Vancouver], " + nuStore + ".[Canada].[BC].[Vancouver].[Store 19], " + nuStore + ".[Canada].[BC].[Victoria], " + nuStore + ".[Mexico], " + nuStore + ".[USA]" + "} ON ROWS\n" + "from [Sales]\n" + "where [Time].[1997] ", "Axis #0:\n" + "{[Time].[1997]}\n" + "Axis #1:\n" + "{[Measures].[Unit Sales]}\n" + "{[Measures].[Store Cost]}\n" + "{[Measures].[Store Sales]}\n" + "{[Measures].[Store level]}\n" + "{[Measures].[Store type]}\n" + "{[Measures].[Store Sqft]}\n" + "Axis #2:\n" + "{[NuStore].[All NuStores]}\n" + "{[NuStore].[Canada]}\n" + "{[NuStore].[Canada].[BC]}\n" + "{[NuStore].[Canada].[BC].[Vancouver]}\n" + "{[NuStore].[Canada].[BC].[Vancouver].[Store 19]}\n" + "{[NuStore].[Canada].[BC].[Victoria]}\n" + "{[NuStore].[Mexico]}\n" + "{[NuStore].[USA]}\n" + "Row #0: 266,773\n" + "Row #0: 225,627.23\n" + "Row #0: 565,238.13\n" + "Row #0: (All)\n" + "Row #0: No type\n" + "Row #0: 0\n" + "Row #1: \n" + "Row #1: \n" + "Row #1: \n" + "Row #1: NuStore Country\n" + "Row #1: No type\n" + "Row #1: 0\n" + "Row #2: \n" + "Row #2: \n" + "Row #2: \n" + "Row #2: NuStore State\n" + "Row #2: No type\n" + "Row #2: 0\n" + "Row #3: \n" + "Row #3: \n" + "Row #3: \n" + "Row #3: NuStore City\n" + "Row #3: No type\n" + "Row #3: 0\n" + "Row #4: \n" + "Row #4: \n" + "Row #4: \n" + "Row #4: NuStore Name\n" + "Row #4: Deluxe Supermarket\n" + "Row #4: 23,112\n" + "Row #5: \n" + "Row #5: \n" + "Row #5: \n" + "Row #5: NuStore City\n" + "Row #5: No type\n" + "Row #5: 0\n" + "Row #6: \n" + "Row #6: \n" + "Row #6: \n" + "Row #6: NuStore Country\n" + "Row #6: No type\n" + "Row #6: 0\n" + "Row #7: 266,773\n" + "Row #7: 225,627.23\n" + "Row #7: 565,238.13\n" + "Row #7: NuStore Country\n" + "Row #7: No type\n" + "Row #7: 0\n"); } /** * Tests that mondrian detects an ambiguous hierarchy in a calculated member * at compile time. (SSAS detects at run time, and generates a cell error, * but this is better.) */ public void testAmbiguousHierarchyInCalcMember() { final String query = "with member [Measures].[Time Child Count] as\n" + " [Time].Children.Count\n" + "select [Measures].[Time Child Count] on 0\n" + "from [Sales]"; if (MondrianProperties.instance().SsasCompatibleNaming.get()) { assertQueryThrows( query, "The 'Time' dimension contains more than one hierarchy, " + "therefore the hierarchy must be explicitly specified."); } else { assertQueryReturns( query, "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[Time Child Count]}\n" + "Row #0: 4\n"); } } /** * Tests <a href="http://jira.pentaho.com/browse/MONDRIAN-750"> * bug MONDRIAN-750, "... multiple hierarchies beneath a single dimension * throws exception"</a>. */ public void testDefaultNamedHierarchy() { TestContext testContext = TestContext.instance().createSubstitutingCube( "Sales", "<Dimension name=\"NuStore\" foreignKey=\"store_id\">\n" + "<Hierarchy name=\"NuStore\" hasAll=\"true\" primaryKey=\"store_id\">\n" + " <Table name=\"store\"/>\n" + " <Level name=\"NuStore Country\" column=\"store_country\" uniqueMembers=\"true\"/>\n" + " <Level name=\"NuStore State\" column=\"store_state\" uniqueMembers=\"true\"/>\n" + " <Level name=\"NuStore City\" column=\"store_city\" uniqueMembers=\"false\"/>\n" + " <Level name=\"NuStore Name\" column=\"store_name\" uniqueMembers=\"true\"/>\n" + "</Hierarchy>\n" + "<Hierarchy caption=\"NuStore2\" name=\"NuStore2\" allMemberName=\"All NuStore2s\" hasAll=\"true\" primaryKey=\"NuStore_id\">\n" + " <Table name=\"store\"/>\n" + " <Level name=\"NuStore City\" column=\"store_city\" uniqueMembers=\"false\"/>\n" + " <Level name=\"NuStore Name\" column=\"store_name\" uniqueMembers=\"true\"/>\n" + "</Hierarchy>\n" + "</Dimension>"); final String nuStore = TestContext.hierarchyName("NuStore", "NuStore"); testContext.assertQueryReturns( "with set [*NATIVE_CJ_SET] as '[*BASE_MEMBERS_NuStore]' " + "set [*SORTED_ROW_AXIS] as 'Order([*CJ_ROW_AXIS], " + nuStore + ".CurrentMember.OrderKey, BASC)' " + "set [*BASE_MEMBERS_NuStore] as '" + nuStore + ".[NuStore Country].Members' " + "set [*BASE_MEMBERS_Measures] as '{[Measures].[*ZERO]}' " + "set [*CJ_ROW_AXIS] as 'Generate([*NATIVE_CJ_SET], {" + nuStore + ".CurrentMember})' " + "set [*CJ_COL_AXIS] as '[*NATIVE_CJ_SET]' " + "member [Measures].[*ZERO] as '0.0', SOLVE_ORDER = 0.0 " + "select [*BASE_MEMBERS_Measures] ON COLUMNS, " + "[*SORTED_ROW_AXIS] ON ROWS " + "from [Sales]", "Axis #0:\n" + "{}\n" + "Axis #1:\n" + "{[Measures].[*ZERO]}\n" + "Axis #2:\n" + "{[NuStore].[Canada]}\n" + "{[NuStore].[Mexico]}\n" + "{[NuStore].[USA]}\n" + "Row #0: 0\n" + "Row #1: 0\n" + "Row #2: 0\n"); } public void testCalcMemOnMultipleHierarchy() { // MONDRIAN-1485 // Mondrian generates multiple queries during getMemberChildren // that references the hierarchy as a value in the where clause. String forbiddenSql = "select `store`.`store_country` as `c0` from " + "`store` as `store` where UPPER(`store`.`store_country`) = " + "UPPER('Time.Weekly') group by `store`.`store_country` order by" + " ISNULL(`store`.`store_country`) ASC, " + "`store`.`store_country` ASC"; assertNoQuerySql( "with member [Time.Weekly].blah as '1' select from sales", new SqlPattern[]{ new SqlPattern( Dialect.DatabaseProduct.MYSQL, forbiddenSql, forbiddenSql) } ); } } // End MultipleHierarchyTest.java