Skip to content

Commit

Permalink
MONDRIAN: Integrate some changes from main to 3.1:
Browse files Browse the repository at this point in the history
    @13267: Fix SqlQueryTest
    @13263: Fix MONDRIAN-668
    @13238: Fix MONDRIAN-295

[git-p4: depot-paths = "//open/mondrian-release/3.1/": change = 13269]
  • Loading branch information
julianhyde committed Dec 23, 2009
1 parent 99fc6d2 commit 79e203a
Show file tree
Hide file tree
Showing 8 changed files with 387 additions and 62 deletions.
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/DelegatingSchemaReader.java
Expand Up @@ -97,7 +97,7 @@ public Member getMemberByUniqueName(
uniqueNameParts, failIfNotFound, matchType);
}

public OlapElement lookupCompound(
public final OlapElement lookupCompound(
OlapElement parent, List<Id.Segment> names,
boolean failIfNotFound, int category)
{
Expand Down
24 changes: 8 additions & 16 deletions src/main/mondrian/olap/Query.java
Expand Up @@ -1497,29 +1497,21 @@ public OlapElement getElementChild(
return mdxElement;
}

public OlapElement lookupCompound(
OlapElement parent,
List<Id.Segment> names,
boolean failIfNotFound,
int category)
{
OlapElement oe = lookupCompound(
parent, names, failIfNotFound, category,
MatchType.EXACT_SCHEMA);
if (oe == null) {
oe = lookupCompound(
parent, names, failIfNotFound, category, MatchType.EXACT);
}
return oe;
}

public OlapElement lookupCompound(
OlapElement parent,
List<Id.Segment> names,
boolean failIfNotFound,
int category,
MatchType matchType)
{
if (matchType == MatchType.EXACT) {
OlapElement oe = lookupCompound(
parent, names, failIfNotFound, category,
MatchType.EXACT_SCHEMA);
if (oe != null) {
return oe;
}
}
// First look to ourselves.
switch (category) {
case Category.Unknown:
Expand Down
252 changes: 217 additions & 35 deletions src/main/mondrian/olap/fun/IntersectFunDef.java
Expand Up @@ -10,10 +10,11 @@
*/
package mondrian.olap.fun;

import mondrian.calc.impl.*;
import mondrian.olap.*;
import mondrian.calc.*;
import mondrian.calc.impl.AbstractListCalc;
import mondrian.mdx.ResolvedFunCall;
import mondrian.olap.type.SetType;

import java.util.*;

Expand Down Expand Up @@ -42,57 +43,238 @@ public IntersectFunDef(FunDef dummyFunDef)
}

public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
final ListCalc listCalc1 = compiler.compileList(call.getArg(0));
final ListCalc listCalc2 = compiler.compileList(call.getArg(1));
final String literalArg = getLiteralArg(call, 2, "", ReservedWords);
final boolean all = literalArg.equalsIgnoreCase("ALL");
final int arity = ((SetType) call.getType()).getArity();

// todo: optimize for member lists vs. tuple lists
return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}) {
public List evaluateList(Evaluator evaluator) {
List left = listCalc1.evaluateList(evaluator);
if (left == null || left.isEmpty()) {
return Collections.EMPTY_LIST;
if (arity == 1) {
final MemberListCalc listCalc1 =
(MemberListCalc) compiler.compileList(call.getArg(0));
final MemberListCalc listCalc2 =
(MemberListCalc) compiler.compileList(call.getArg(1));
return new AbstractMemberListCalc(
call, new Calc[] {listCalc1, listCalc2})
{
public List<Member> evaluateMemberList(Evaluator evaluator) {
List<Member> leftList =
listCalc1.evaluateMemberList(evaluator);
if (leftList.isEmpty()) {
return Collections.emptyList();
}
List<Member> rightList =
listCalc2.evaluateMemberList(evaluator);
if (rightList.isEmpty()) {
return Collections.emptyList();
}
// Set of members from the right side of the intersect.
// We use a RetrievableSet because distinct keys
// (regular members and visual totals members) compare
// identical using hashCode and equals, we want to retrieve
// the actual key, and java.util.Set only has containsKey.
final RetrievableSet<Member> rightSet =
new RetrievableHashSet<Member>();
for (Member member : rightList) {
rightSet.add(member);
}
final List<Member> result = new ArrayList<Member>();
final Set<Member> resultSet =
all ? null : new HashSet<Member>();
for (Member leftMember : leftList) {
final Member rightMember = rightSet.getKey(leftMember);
if (rightMember == null) {
continue;
}
if (resultSet != null && !resultSet.add(leftMember)) {
continue;
}
if (rightMember
instanceof VisualTotalsFunDef.VisualTotalMember)
{
result.add(rightMember);
} else {
result.add(leftMember);
}
}
return result;
}
Collection right = listCalc2.evaluateList(evaluator);
if (right == null || right.isEmpty()) {
return Collections.EMPTY_LIST;
};
} else {
final TupleListCalc listCalc1 =
(TupleListCalc) compiler.compileList(call.getArg(0));
final TupleListCalc listCalc2 =
(TupleListCalc) compiler.compileList(call.getArg(1));
return new AbstractTupleListCalc(
call, new Calc[] {listCalc1, listCalc2})
{
public List<Member[]> evaluateTupleList(Evaluator evaluator) {
List<Member[]> leftList =
listCalc1.evaluateTupleList(evaluator);
if (leftList.isEmpty()) {
return Collections.emptyList();
}
final List<Member[]> rightList =
listCalc2.evaluateTupleList(evaluator);
if (rightList.isEmpty()) {
return Collections.emptyList();
}
RetrievableSet<List<Member>> rightSet =
buildSearchableCollection(rightList);
final List<Member[]> result = new ArrayList<Member[]>();
final Set<List<Member>> resultSet =
all ? null : new HashSet<List<Member>>();
for (Member[] leftTuple : leftList) {
List<Member> leftKey = Arrays.asList(leftTuple);
List<Member> rightKey = rightSet.getKey(leftKey);
if (rightKey == null) {
continue;
}
if (resultSet != null && !resultSet.add(leftKey)) {
continue;
}
result.add(
copyTupleWithVisualTotalsMembersOverriding(
leftTuple, rightKey));
}
return result;
}
right = buildSearchableCollection(right);
List result = new ArrayList();

for (Object leftObject : left) {
Object resultObject = leftObject;

if (leftObject instanceof Object[]) {
leftObject = new ArrayHolder((Object[]) leftObject);
/**
* Constructs a tuple consisting of members from
* {@code leftTuple}, but overridden by any corresponding
* members from {@code rightKey} that happen to be visual totals
* members.
*
* <p>Returns the original tuple if there are no visual totals
* members on the RHS.
*
* @param leftTuple Original tuple
* @param rightKey Right tuple
* @return Copy of original tuple, with any VisualTotalMembers
* from right tuple overriding
*/
private Member[] copyTupleWithVisualTotalsMembersOverriding(
Member[] leftTuple,
List<Member> rightKey)
{
Member[] tuple = leftTuple;
for (int i = 0; i < rightKey.size(); i++) {
Member member = rightKey.get(i);
if (!(tuple[i]
instanceof VisualTotalsFunDef.VisualTotalMember)
&& member instanceof
VisualTotalsFunDef.VisualTotalMember)
{
if (tuple == leftTuple) {
// clone on first VisualTotalMember -- to avoid
// alloc/copy in the common case where there are
// no VisualTotalMembers
tuple = leftTuple.clone();
}
tuple[i] = member;
}
}
return tuple;
}

if (right.contains(leftObject)) {
if (all || !result.contains(leftObject)) {
result.add(resultObject);
}
private RetrievableSet<List<Member>> buildSearchableCollection(
List<Member[]> tuples)
{
RetrievableSet<List<Member>> result =
new RetrievableHashSet<List<Member>>(tuples.size());
for (Member[] tuple : tuples) {
result.add(Arrays.asList(tuple));
}
return result;
}
return result;
}
};
};
}
}

private static Collection buildSearchableCollection(Collection right) {
Iterator iter = right.iterator();
Set result = new HashSet(right.size(), 1);
while (iter.hasNext()) {
Object element = iter.next();
/**
* Interface similar to the Set interface that allows key values to be
* returned.
*
* <p>Useful if multiple objects can compare equal (using
* {@link Object#equals(Object)} and {@link Object#hashCode()}, per the
* set contract) and you wish to distinguish them after they have been added
* to the set.
*
* @param <E> element type
*/
private interface RetrievableSet<E> {
/**
* Returns the key in this set that compares equal to a given object,
* or null if there is no such key.
*
* @param e Key value
* @return Key in the set equal to given key value
*/
E getKey(E e);

if (element instanceof Object[]) {
element = new ArrayHolder((Object[])element);
/**
* Analogous to {@link Set#add(Object)}.
*/
boolean add(E e);
}

private static class RetrievableHashSet<E>
extends HashMap<E, E>
implements RetrievableSet<E>
{
public RetrievableHashSet(int initialCapacity) {
super(initialCapacity);
}

public RetrievableHashSet() {
super();
}

public E getKey(E e) {
return super.get(e);
}

/*
public boolean contains(Object o) {
return super.containsKey(o);
}
public Iterator<E> iterator() {
return super.keySet().iterator();
}
public Object[] toArray() {
return super.keySet().toArray();
}
public <T> T[] toArray(T[] a) {
return super.keySet().toArray(a);
}
*/

public boolean add(E e) {
return super.put(e, e) == null;
}

/*
public boolean containsAll(Collection<?> c) {
return super.keySet().containsAll(c);
}
public boolean addAll(Collection<? extends E> c) {
for (E e : c) {
put(e, e);
}
return c.size() > 0;
}
result.add(element);
public boolean retainAll(Collection<?> c) {
return super.keySet().retainAll(c);
}
return result;
public boolean removeAll(Collection<?> c) {
return super.keySet().removeAll(c);
}
*/
}
}

Expand Down
25 changes: 22 additions & 3 deletions src/main/mondrian/olap/fun/VisualTotalsFunDef.java
Expand Up @@ -14,8 +14,7 @@
import mondrian.mdx.*;
import mondrian.olap.*;
import mondrian.olap.type.*;
import mondrian.rolap.RolapLevel;
import mondrian.rolap.RolapMember;
import mondrian.rolap.*;
import mondrian.resource.MondrianResource;

import java.util.ArrayList;
Expand Down Expand Up @@ -197,7 +196,7 @@ private Exp makeExpr(final List childMemberList) {
* <li>its value is a calculation computed by aggregating all of the
* members which occur following it in the list</ul></p>
*/
private static class VisualTotalMember extends RolapMember {
public static class VisualTotalMember extends RolapMember {
private final Member member;
private final Exp exp;

Expand All @@ -214,6 +213,22 @@ private static class VisualTotalMember extends RolapMember {
this.exp = exp;
}

@Override
public boolean equals(Object o) {
// A visual total member must compare equal to the member it wraps
// (for purposes of the MDX Intersect function, for instance).
return o instanceof VisualTotalMember
&& this.member.equals(((VisualTotalMember) o).member)
&& this.exp.equals(((VisualTotalMember) o).exp)
|| o instanceof Member
&& this.member.equals(o);
}

@Override
public int hashCode() {
return member.hashCode();
}

protected boolean computeCalculated(final MemberType memberType) {
return true;
}
Expand Down Expand Up @@ -248,6 +263,10 @@ public OlapElement lookupChild(
public String getQualifiedName() {
throw new UnsupportedOperationException();
}

public Member getMember() {
return member;
}
}

/**
Expand Down

0 comments on commit 79e203a

Please sign in to comment.