Skip to content

Commit

Permalink
MONDRIAN: Implement member keys, for example [Store].&[1234]. Fixes bug
Browse files Browse the repository at this point in the history
    MONDRIAN-485, "Member key treated as member name in WHERE". Full
    functionality (in particular composite member keys, such as
    [Store].[City].&[San Francisco]&[CA]) is only available if
    SsasCompatibleNaming=true. If SsasCompatibleNaming=false, you can use simple
    member keys, and performance is poor (mondrian scans all members of a level)
    as before.

[git-p4: depot-paths = "//open/mondrian/": change = 15004]
  • Loading branch information
julianhyde committed Mar 15, 2012
1 parent b609443 commit 756d193
Show file tree
Hide file tree
Showing 69 changed files with 1,501 additions and 622 deletions.
8 changes: 5 additions & 3 deletions src/main/mondrian/olap/CellProperty.java
Expand Up @@ -5,11 +5,13 @@
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 1998-2005 Julian Hyde
// Copyright (C) 2005-2009 Pentaho and others
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap;

import java.util.List;

/**
* Represents Cell Property.
*
Expand All @@ -20,8 +22,8 @@
public class CellProperty extends QueryPart {
private String name;

public CellProperty(Object name) {
this.name = name.toString();
public CellProperty(List<Id.Segment> segments) {
this.name = Util.implode(segments);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/main/mondrian/olap/Cube.java
Expand Up @@ -5,7 +5,7 @@
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 1999-2005 Julian Hyde
// Copyright (C) 2005-2009 Pentaho and others
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap;
Expand All @@ -16,7 +16,7 @@
/**
* Cube.
*
* @author jhyde
* @author jhyde, 2 March, 1999
*/
public interface Cube extends OlapElement, Annotated {

Expand All @@ -38,7 +38,7 @@ public interface Cube extends OlapElement, Annotated {
* Finds a hierarchy whose name (or unique name, if <code>unique</code> is
* true) equals <code>s</code>.
*/
Hierarchy lookupHierarchy(Id.Segment s, boolean unique);
Hierarchy lookupHierarchy(Id.NameSegment s, boolean unique);

/**
* Returns Member[]. It builds Member[] by analyzing cellset, which
Expand Down
4 changes: 2 additions & 2 deletions src/main/mondrian/olap/CubeAccess.java
Expand Up @@ -5,7 +5,7 @@
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 1999-2005 Julian Hyde
// Copyright (C) 2005-2011 Pentaho and others
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap;
Expand Down Expand Up @@ -119,7 +119,7 @@ public void addGrantCubeSlicer(
boolean fail = false;
Hierarchy hierarchy =
mdxCube.lookupHierarchy(
new Id.Segment(sHierarchy, Id.Quoting.UNQUOTED),
new Id.NameSegment(sHierarchy),
fail);
if (hierarchy == null) {
throw MondrianResource.instance().MdxCubeSlicerHierarchyError
Expand Down
20 changes: 13 additions & 7 deletions src/main/mondrian/olap/CubeBase.java
Expand Up @@ -5,7 +5,7 @@
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2001-2005 Julian Hyde
// Copyright (C) 2005-2011 Pentaho and others
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap;
Expand Down Expand Up @@ -102,13 +102,13 @@ public Dimension[] getDimensions() {
return dimensions;
}

public Hierarchy lookupHierarchy(Id.Segment s, boolean unique) {
public Hierarchy lookupHierarchy(Id.NameSegment s, boolean unique) {
for (Dimension dimension : dimensions) {
Hierarchy[] hierarchies = dimension.getHierarchies();
for (Hierarchy hierarchy : hierarchies) {
String name = unique
? hierarchy.getUniqueName() : hierarchy.getName();
if (name.equals(s.name)) {
if (name.equals(s.getName())) {
return hierarchy;
}
}
Expand All @@ -130,18 +130,20 @@ public OlapElement lookupChild(

// Look for hierarchies named '[dimension.hierarchy]'.
if (MondrianProperties.instance().SsasCompatibleNaming.get()
&& s.name.contains("."))
&& s instanceof Id.NameSegment
&& ((Id.NameSegment) s).name.contains("."))
{
for (Dimension dimension : dimensions) {
if (!s.name.startsWith(dimension.getName())) {
if (!((Id.NameSegment) s).name.startsWith(dimension.getName()))
{
// Rough check to save time.
continue;
}
for (Hierarchy hierarchy
: schemaReader.getDimensionHierarchies(dimension))
{
if (Util.equalName(
s.name,
((Id.NameSegment) s).name,
dimension.getName()
+ "."
+ hierarchy.getName()))
Expand Down Expand Up @@ -179,8 +181,12 @@ public OlapElement lookupChild(
* @return Dimension, or null if not found
*/
public Dimension lookupDimension(Id.Segment s) {
if (!(s instanceof Id.NameSegment)) {
return null;
}
final Id.NameSegment nameSegment = (Id.NameSegment) s;
for (Dimension dimension : dimensions) {
if (Util.equalName(dimension.getName(), s.name)) {
if (Util.equalName(dimension.getName(), nameSegment.name)) {
return dimension;
}
}
Expand Down
11 changes: 7 additions & 4 deletions src/main/mondrian/olap/DimensionBase.java
Expand Up @@ -5,7 +5,7 @@
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2001-2005 Julian Hyde
// Copyright (C) 2005-2011 Pentaho and others
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap;
Expand Down Expand Up @@ -95,7 +95,10 @@ public boolean isMeasures() {
public OlapElement lookupChild(
SchemaReader schemaReader, Id.Segment s, MatchType matchType)
{
OlapElement oe = lookupHierarchy(s);
OlapElement oe = null;
if (s instanceof Id.NameSegment) {
oe = lookupHierarchy((Id.NameSegment) s);
}

// Original mondrian behavior:
// If the user is looking for [Marital Status].[Marital Status] we
Expand Down Expand Up @@ -134,9 +137,9 @@ public boolean isHighCardinality() {
return this.highCardinality;
}

private Hierarchy lookupHierarchy(Id.Segment s) {
private Hierarchy lookupHierarchy(Id.NameSegment s) {
for (Hierarchy hierarchy : hierarchies) {
if (Util.equalName(hierarchy.getName(), s.name)) {
if (Util.equalName(hierarchy.getName(), s.getName())) {
return hierarchy;
}
}
Expand Down
25 changes: 18 additions & 7 deletions src/main/mondrian/olap/Formula.java
Expand Up @@ -176,7 +176,12 @@ void createElement(Query q) {
OlapElement mdxElement = q.getCube();
final SchemaReader schemaReader = q.getSchemaReader(false);
for (int i = 0; i < segments.size(); i++) {
final Id.Segment segment = segments.get(i);
final Id.Segment segment0 = segments.get(i);
if (!(segment0 instanceof Id.NameSegment)) {
throw Util.newError(
"Calculated member name must not contain member keys");
}
final Id.NameSegment segment = (Id.NameSegment) segment0;
OlapElement parent = mdxElement;
mdxElement = null;
// The last segment of the id is the name of the calculated
Expand All @@ -201,7 +206,7 @@ void createElement(Query q) {
if (level == null) {
throw Util.newError(
"The '"
+ segment.name
+ segment
+ "' calculated member cannot be created "
+ "because its parent is at the lowest level "
+ "in the "
Expand Down Expand Up @@ -240,7 +245,7 @@ void createElement(Query q) {
}
Member mdxMember =
level.getHierarchy().createMember(
parentMember, level, segment.name, this);
parentMember, level, segment.getName(), this);
assert mdxMember != null;
mdxElement = mdxMember;
}
Expand All @@ -251,12 +256,17 @@ void createElement(Query q) {
Util.assertTrue(
segments.size() == 1,
"set names must not be compound");
final Id.Segment segment0 = segments.get(0);
if (!(segment0 instanceof Id.NameSegment)) {
throw Util.newError(
"Calculated member name must not contain member keys");
}
// Caption and description are initialized to null, and annotations
// to the empty map. If named set is defined in the schema, we will
// give these their true values later.
mdxSet =
new SetBase(
segments.get(0).name,
((Id.NameSegment) segment0).getName(),
null,
null,
exp,
Expand Down Expand Up @@ -340,11 +350,12 @@ void rename(String newName)
{
String oldName = getElement().getName();
final List<Id.Segment> segments = this.id.getSegments();
Util.assertTrue(
segments.get(segments.size() - 1).name.equalsIgnoreCase(oldName));
assert Util.last(segments) instanceof Id.NameSegment;
assert ((Id.NameSegment) Util.last(segments)).name
.equalsIgnoreCase(oldName);
segments.set(
segments.size() - 1,
new Id.Segment(newName, Id.Quoting.QUOTED));
new Id.NameSegment(newName));
if (isMember) {
mdxMember.setName(newName);
} else {
Expand Down
21 changes: 16 additions & 5 deletions src/main/mondrian/olap/HierarchyBase.java
Expand Up @@ -5,7 +5,7 @@
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2001-2005 Julian Hyde
// Copyright (C) 2005-2011 Pentaho and others
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap;
Expand Down Expand Up @@ -160,11 +160,22 @@ public OlapElement lookupChild(
Id.Segment s,
MatchType matchType)
{
OlapElement oe = Util.lookupHierarchyLevel(this, s.name);
if (oe == null) {
oe = Util.lookupHierarchyRootMember(
schemaReader, this, s, matchType);
OlapElement oe;
if (s instanceof Id.NameSegment) {
Id.NameSegment nameSegment = (Id.NameSegment) s;
oe = Util.lookupHierarchyLevel(this, nameSegment.getName());
if (oe == null) {
oe = Util.lookupHierarchyRootMember(
schemaReader, this, nameSegment, matchType);
}
} else {
// Key segment searches bottom level by default. For example,
// [Products].&[1] is shorthand for [Products].[Product Name].&[1].
final Id.KeySegment keySegment = (Id.KeySegment) s;
oe = levels[levels.length - 1]
.lookupChild(schemaReader, keySegment, matchType);
}

if (getLogger().isDebugEnabled()) {
StringBuilder buf = new StringBuilder(64);
buf.append("HierarchyBase.lookupChild: ");
Expand Down

0 comments on commit 756d193

Please sign in to comment.