Skip to content

Commit

Permalink
MONDRIAN: Allow default members to be specified using a name which do…
Browse files Browse the repository at this point in the history
…es not include the name of the all member, for example, [Gender].[F] and [Gender].[All gender].[F] both work. (Bug 1534593, "Non-All default member incompatible with All member".)

[git-p4: depot-paths = "//open/mondrian/": change = 7349]
  • Loading branch information
julianhyde committed Aug 7, 2006
1 parent 611b403 commit d8ce4a5
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 5 deletions.
27 changes: 22 additions & 5 deletions src/main/mondrian/rolap/RolapUtil.java
Expand Up @@ -27,12 +27,8 @@
import java.util.List;
import java.util.StringTokenizer;

import mondrian.olap.*;
import mondrian.resource.MondrianResource;
import mondrian.calc.ExpCompiler;

import org.apache.log4j.Logger;

/**
* Utility methods for classes in the <code>mondrian.rolap</code> package.
*
Expand Down Expand Up @@ -94,7 +90,28 @@ static RolapMember lookupMember(
MemberReader reader,
String[] uniqueNameParts,
boolean failIfNotFound) {
RolapMember member = null;
RolapMember member = xxx(uniqueNameParts, null, reader, failIfNotFound);
if (member != null) {
return member;
}

// If this hierarchy has an 'all' member, we can omit it.
// For example, '[Gender].[(All Gender)].[F]' can be abbreviated
// '[Gender].[F]'.
final List rootMembers = reader.getRootMembers();
if (rootMembers.size() == 1) {
final RolapMember rootMember = (RolapMember) rootMembers.get(0);
if (rootMember.isAll()) {
member = xxx(
uniqueNameParts, rootMember, reader, failIfNotFound);
}
}
return member;
}

private static RolapMember xxx(
String[] uniqueNameParts, RolapMember member,
MemberReader reader, boolean failIfNotFound) {
for (int i = 0; i < uniqueNameParts.length; i++) {
String name = uniqueNameParts[i];
List children;
Expand Down
1 change: 1 addition & 0 deletions testsrc/main/mondrian/test/Main.java
Expand Up @@ -177,6 +177,7 @@ public static Test suite() throws Exception {
suite.addTestSuite(I18nTest.class);
suite.addTestSuite(FormatTest.class);
suite.addTestSuite(ParallelTest.class);
suite.addTestSuite(SchemaTest.class);
suite.addTestSuite(CmdRunnerTest.class);

boolean testNonEmpty = isRunOnce();
Expand Down
88 changes: 88 additions & 0 deletions testsrc/main/mondrian/test/SchemaTest.java
@@ -0,0 +1,88 @@
/*
// $Id$
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// Copyright (C) 2006-2006 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.test;

/**
* Unit tests for various schema features.
*
* @author jhyde
* @since August 7, 2006
* @version $Id$
*/
public class SchemaTest extends FoodMartTestCase {

public SchemaTest(String name) {
super(name);
}

public void testHierarchyDefaultMember() {
final TestContext testContext = TestContext.createSubstitutingCube(
"Sales",
" <Dimension name=\"Gender with default\" foreignKey=\"customer_id\">\n" +
" <Hierarchy hasAll=\"true\" " +
"primaryKey=\"customer_id\" " +
// Define a default member's whose unique name includes the
// 'all' member.
"defaultMember=\"[Gender with default].[All Gender with defaults].[M]\" >\n" +
" <Table name=\"customer\"/>\n" +
" <Level name=\"Gender\" column=\"gender\" uniqueMembers=\"true\" />\n" +
" </Hierarchy>\n" +
" </Dimension>");
testContext.assertQueryReturns(
"select {[Gender with default]} on columns from [Sales]",
fold("Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Gender with default].[All Gender with defaults].[M]}\n" +
"Row #0: 135,215\n"));
}

public void testHierarchyAbbreviatedDefaultMember() {
final TestContext testContext = TestContext.createSubstitutingCube(
"Sales",
" <Dimension name=\"Gender with default\" foreignKey=\"customer_id\">\n" +
" <Hierarchy hasAll=\"true\" " +
"primaryKey=\"customer_id\" " +
// Default member unique name does not include 'All'.
"defaultMember=\"[Gender with default].[F]\" >\n" +
" <Table name=\"customer\"/>\n" +
" <Level name=\"Gender\" column=\"gender\" uniqueMembers=\"true\" />\n" +
" </Hierarchy>\n" +
" </Dimension>");
testContext.assertQueryReturns(
"select {[Gender with default]} on columns from [Sales]",
fold("Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
// Note that the 'all' member is named according to the rule
// '[<hierarchy>].[All <hierarchy>s]'.
"{[Gender with default].[All Gender with defaults].[F]}\n" +
"Row #0: 131,558\n"));
}

public void testHierarchyBadDefaultMember() {
final TestContext testContext = TestContext.createSubstitutingCube(
"Sales",
" <Dimension name=\"Gender with default\" foreignKey=\"customer_id\">\n" +
" <Hierarchy hasAll=\"true\" " +
"primaryKey=\"customer_id\" " +
// Default member unique name does not include 'All'.
"defaultMember=\"[Gender with default].[Non].[Existent]\" >\n" +
" <Table name=\"customer\"/>\n" +
" <Level name=\"Gender\" column=\"gender\" uniqueMembers=\"true\" />\n" +
" </Hierarchy>\n" +
" </Dimension>");
testContext.assertThrows(
"select {[Gender with default]} on columns from [Sales]",
"Can not find Default Member with name \"[Gender with default].[Non].[Existent]\" in Hierarchy \"Gender with default\"");
}
}

// End SchemaTest.java
49 changes: 49 additions & 0 deletions testsrc/main/mondrian/test/TestContext.java
Expand Up @@ -273,6 +273,38 @@ public String getFoodMartSchema(
return s;
}

/**
* Returns a the XML of the foodmart schema, adding dimension definitions
* to the definition of a given cube.
*/
public String getFoodMartSchemaSubstitutingCube(
String cubeName,
String dimensionDefs)
{
// First, get the unadulterated schema.
String s;
synchronized (SnoopingSchemaProcessor.class) {
getFoodMartConnection(SnoopingSchemaProcessor.class);
s = SnoopingSchemaProcessor.catalogContent;
}

// Search for the cube.
int h = s.indexOf("<Cube name=\"" + cubeName + "\"");
if (h < 0) {
throw new RuntimeException("cube '" + cubeName + "' not found");
}

// Add dimension definitions, if specified.
if (dimensionDefs != null) {
int i = s.indexOf("<Dimension ", h);
s = s.substring(0, i) +
dimensionDefs +
s.substring(i);
}

return s;
}

/**
* Executes a query.
*/
Expand Down Expand Up @@ -755,6 +787,23 @@ public synchronized Connection getFoodMartConnection(boolean fresh) {
};
}

/**
* Creates a TestContext, adding hierarchy definitions to a cube definition.
* @param cubeName Name of a cube in the schema (cube must exist)
* @param dimensionDefs String defining dimensions, or null
*/
public static TestContext createSubstitutingCube(
final String cubeName,
final String dimensionDefs) {
return new TestContext() {
public synchronized Connection getFoodMartConnection(boolean fresh) {
final String schema =
getFoodMartSchemaSubstitutingCube(cubeName, dimensionDefs);
return getFoodMartConnection(schema);
}
};
}

public static class SnoopingSchemaProcessor
extends DecoratingSchemaProcessor
{
Expand Down

0 comments on commit d8ce4a5

Please sign in to comment.