Skip to content

Commit

Permalink
Calculated Measures to inherit format string from its closest ancesto…
Browse files Browse the repository at this point in the history
…r which has the format string.

[git-p4: depot-paths = "//open/mondrian/": change = 8977]
  • Loading branch information
thiyagu committed Mar 29, 2007
1 parent 3d5e4c8 commit dbf84c9
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 15 deletions.
86 changes: 72 additions & 14 deletions src/main/mondrian/olap/Formula.java
Expand Up @@ -17,10 +17,12 @@
import mondrian.mdx.MemberExpr;
import mondrian.mdx.MdxVisitor;
import mondrian.mdx.MdxVisitorImpl;
import mondrian.rolap.RolapCalculatedMember;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

/**
* A <code>Formula</code> is a clause in an MDX query which defines a Set or a
Expand Down Expand Up @@ -119,7 +121,7 @@ void accept(Validator validator) {
// Get the format expression from the property list, or derive it from
// the formula.
if (isMember) {
Exp formatExp = getFormatExp();
Exp formatExp = getFormatExp(validator);
if (formatExp != null) {
mdxMember.setProperty(Property.FORMAT_EXP.name, formatExp);
}
Expand Down Expand Up @@ -365,8 +367,9 @@ private static Number quickEval(Exp exp) {
* looks for properties called "format", "format_string", etc. Then it looks
* inside the expression, and returns the formatting expression for the
* first member it finds.
* @param validator
*/
private Exp getFormatExp() {
private Exp getFormatExp(Validator validator) {
// If they have specified a format string (which they can do under
// several names) return that.
for (String prop : Property.FORMAT_PROPERTIES) {
Expand Down Expand Up @@ -402,18 +405,7 @@ private Exp getFormatExp() {
// Burrow into the expression. If we find a member, use its format
// string.
try {
exp.accept(
new MdxVisitorImpl() {
public Object visit(MemberExpr memberExpr) {
Exp formatExp = (Exp) memberExpr.getMember().
getPropertyValue(Property.FORMAT_EXP.name);
if (formatExp != null) {
throw new FoundOne(formatExp);
}
return super.visit(memberExpr);
}
}
);
exp.accept(new FormatFinder(validator));
return null;
} catch (FoundOne foundOne) {
return foundOne.exp;
Expand Down Expand Up @@ -448,6 +440,72 @@ public FoundOne(Exp exp) {
this.exp = exp;
}
}

//A visitor for burrowing format information given a formula
private static class FormatFinder extends MdxVisitorImpl {
private final Validator validator;

public FormatFinder(Validator validator) {
this.validator = validator;
}

public Object visit(MemberExpr memberExpr) {
Member member = memberExpr.getMember();
returnFormula(member);
if (member.isCalculated() && member instanceof RolapCalculatedMember && !checkRecursion(memberExpr)){
RolapCalculatedMember rcm = (RolapCalculatedMember) member;
Formula formula = rcm.getFormula();
formula.accept(validator);
returnFormula(member);
}

return super.visit(memberExpr);
}

private boolean checkRecursion(Exp expr) {
List<MemberExpr> expList = new ArrayList<MemberExpr>();
return checkRecursion(expr,expList);
}

private boolean checkRecursion(Exp expr, List<MemberExpr> expList) {
if (expr instanceof MemberExpr) {
MemberExpr memberExpr = (MemberExpr) expr;
if(expList.contains(expr)){
return true;
}
expList.add(memberExpr);
Member member = memberExpr.getMember();
if (member instanceof RolapCalculatedMember) {
RolapCalculatedMember calculatedMember = (RolapCalculatedMember) member;
return checkRecursion(calculatedMember.getExpression().accept(validator),expList);
}
}
if (expr instanceof FunCall) {
FunCall funCall = (FunCall) expr;
Exp[] exps = funCall.getArgs();
for (int i = 0; i < exps.length; i++) {
if(checkRecursion(exps[i], cloneForEachBranch(expList))) return true;
}
}
return false;
}

private List<MemberExpr> cloneForEachBranch(List<MemberExpr> expList) {
ArrayList<MemberExpr> list = new ArrayList<MemberExpr>();
list.addAll(expList);
return list;
}

private void returnFormula(Member member) {
if (getFormula(member) != null) {
throw new FoundOne(getFormula(member));
}
}

private Exp getFormula(Member member) {
return (Exp) member.getPropertyValue(Property.FORMAT_EXP.name);
}
}
}

// End Formula.java
2 changes: 1 addition & 1 deletion src/main/mondrian/rolap/RolapCalculatedMember.java
Expand Up @@ -26,7 +26,7 @@
* @since 26 August, 2001
* @version $Id$
*/
class RolapCalculatedMember extends RolapMember {
public class RolapCalculatedMember extends RolapMember {
private final Formula formula;

RolapCalculatedMember(
Expand Down
21 changes: 21 additions & 0 deletions testsrc/main/mondrian/test/BasicQueryTest.java
Expand Up @@ -5376,6 +5376,27 @@ public void testQueryTimeout()
throwable, "Query timeout of 2 seconds reached");
}

public void testFormatInheritance() {
assertQueryReturns(
"with member measures.foo as 'measures.bar' member measures.bar as 'measures.profit' select {measures.foo} on 0 from sales",
fold("Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[foo]}\n" +
"Row #0: $339,610.90\n")
);
}

public void testFormatInheritanceWithIIF() {
assertQueryReturns(
"with member measures.foo as 'measures.bar' member measures.bar as 'iif(not isempty(measures.profit),measures.profit,null)' select from sales where measures.foo",
fold(
"Axis #0:\n" +
"{[Measures].[foo]}\n" +
"$339,610.90")
);
}

public void testQueryIterationLimit()
{
// Query will need to iterate 4*3 times to compute aggregates,
Expand Down

0 comments on commit dbf84c9

Please sign in to comment.