Skip to content

Commit

Permalink
MONDRIAN
Browse files Browse the repository at this point in the history
       Provide junit that demonstrates the issue that checkin 7634
       targeted. The changes ro RolapResult.java, RolapEvaluator.java
       and CrossJoinFunDef.java are there to enable the demonstration
       of the problem and debugging and should be removed
       after the issue is resolved.

[git-p4: depot-paths = "//open/mondrian/": change = 7905]
  • Loading branch information
Richard Emberson committed Oct 11, 2006
1 parent dd7c55f commit 0d4f6ab
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 3 deletions.
55 changes: 52 additions & 3 deletions src/main/mondrian/olap/fun/CrossJoinFunDef.java
Expand Up @@ -133,13 +133,30 @@ List crossJoin(List list1, List list2, Evaluator evaluator) {
// nonempty(crossjoin(nonempty(a),nonempty(b))
long size = (long)list1.size() * (long)list2.size();
int resultLimit = MondrianProperties.instance().ResultLimit.get();
if (size > 1000 && evaluator.isNonEmpty()) {

// NOTE: RME : These properties are used by the Checkin_7634
final String USE_PROP_NAME = "mondrian.test.7634.use";
final String SIZE_PROP_NAME = "mondrian.test.7634.size";
final String OLD_PROP_NAME = "mondrian.test.7634.old";
final int opSize = Integer.getInteger(SIZE_PROP_NAME, 1000).intValue();
//System.out.println("CrossJoinFunDef.crossjoin: size=" +size);
//System.out.println("CrossJoinFunDef.crossjoin: opSize=" +opSize);
boolean useOptimizer = (System.getProperty(USE_PROP_NAME) == null);
boolean doOld = (System.getProperty(OLD_PROP_NAME) != null);
if (useOptimizer && size > opSize && evaluator.isNonEmpty()) {
// instead of overflow exception try to further
// optimize nonempty(crossjoin(a,b)) ==
// nonempty(crossjoin(nonempty(a),nonempty(b))
final int missCount = evaluator.getMissCount();
list1 = nonEmptyList(evaluator, list1);
list2 = nonEmptyList(evaluator, list2);

//System.out.println("CrossJoinFunDef.crossjoin: oldprop=" +System.getProperty("mondrian.test.7634.old"));
if (doOld) {
list1 = nonEmptyListOld(evaluator, list1);
list2 = nonEmptyListOld(evaluator, list2);
} else {
list1 = nonEmptyList(evaluator, list1);
list2 = nonEmptyList(evaluator, list2);
}
size = (long)list1.size() * (long)list2.size();
// both list1 and list2 may be empty after nonEmpty optimization
if (size == 0) {
Expand Down Expand Up @@ -235,6 +252,37 @@ List crossJoin(List list1, List list2, Evaluator evaluator) {
return result;
}

protected static List nonEmptyListOld(Evaluator evaluator, List list) {
//System.out.println("CrossJoinFunDef.nonEmptyListOld");
if (list.isEmpty()) {
return list;
}
List result = new ArrayList();
evaluator = evaluator.push();
if (list.get(0) instanceof Member[]) {
for (Iterator it = list.iterator(); it.hasNext();) {
Member[] m = (Member[]) it.next();
evaluator.setContext(m);
Object value = evaluator.evaluateCurrent();
if (value != Util.nullValue && !(value instanceof Throwable)) {
result.add(m);
}
}
} else {
for (Iterator it = list.iterator(); it.hasNext();) {
Member m = (Member) it.next();
//System.out.println("CrossJoinFunDef.nonEmptyListOld: m=" +m.getUniqueName());
evaluator.setContext(m);
Object value = evaluator.evaluateCurrent();
//System.out.println("CrossJoinFunDef.nonEmptyListOld: value=" +value);
if (value != null && !(value instanceof Throwable)) {
result.add(m);
}
}
}
return result;
}


/**
* Visitor which builds a list of all measures referenced in a query.
Expand Down Expand Up @@ -285,6 +333,7 @@ public Object visit(mondrian.mdx.MemberExpr memberExpr) {
if (measureSet == null) {
measureSet = new HashSet();
}
//System.out.println("CrossJoinFunDef.MeasureVisitor.visit: measure=" +measure.getUniqueName());
measureSet.add(measure);
break;
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/mondrian/rolap/RolapEvaluator.java
Expand Up @@ -270,6 +270,22 @@ public boolean equals(Object obj) {
return Arrays.equals(this.currentMembers, that.currentMembers);
}

/**
* RME remove before checkin
* This is for debugging only
* For use in debugging Checkin_7634
*/
void printCurrentMemberNames() {
for (int i = 0; i < currentMembers.length; i++) {
Member m = currentMembers[i];
if (m == null) {
System.out.println("RolapEvaluator.printCurrentMemberNames: i="+i+", member NULL");
} else {
System.out.println("RolapEvaluator.printCurrentMemberNames: i="+i+", member="+m.getUniqueName());
}
}
}

/**
* Replace the current member of a given hierarchy with member parameter
* if the current member is the null, all, or default member.
Expand Down
2 changes: 2 additions & 0 deletions src/main/mondrian/rolap/RolapResult.java
Expand Up @@ -63,6 +63,8 @@ class RolapResult extends ResultBase {
return;
}

// for use in debugging Checkin_7634
// this.evaluator.printCurrentMemberNames();
try {
// An array of lists which will hold each axis' implicit members (does
// not include slicer axis).
Expand Down
75 changes: 75 additions & 0 deletions testsrc/main/mondrian/rolap/aggmatcher/Checkin_7634.csv
@@ -0,0 +1,75 @@
# Checkin_7634.csv
# Note that there is no data for prod_id=1,2,8,9,10,11,12
## TableName: table7634
## ColumnNames: cust_loc_id,prod_id,first,request_value,shipped_value
## ColumnTypes: INTEGER,INTEGER,DECIMAL(10,2):null,DECIMAL(10,2),DECIMAL(10,2)
## NosOfRows: 40
1,3,,11,11
1,4,,12,12
1,5,,13,13
1,6,,14,14
1,7,,15,15
2,3,,21,21
2,4,,22,22
2,5,,23,23
2,6,,24,24
2,7,,25,25
3,3,,31,31
3,4,,32,32
3,5,,33,33
3,6,,34,34
3,7,,35,35
4,3,,41,41
4,4,,42,42
4,5,,43,43
4,6,,44,44
4,7,,45,45
5,3,,51,51
5,4,,52,52
5,5,,53,53
5,6,,54,54
5,7,,55,55
6,3,,61,61
6,4,,62,62
6,5,,63,63
6,6,,64,64
6,7,,65,65
7,3,,71,71
7,4,,72,72
7,5,,73,73
7,6,,74,74
7,7,,75,75
8,3,,81,81
8,4,,82,82
8,5,,83,83
8,6,,84,84
8,7,,85,85
# geography dimension
## TableName: geography7631
## ColumnNames: cust_loc_id,state_cd,city_nm,zip_cd
## ColumnTypes: INTEGER,VARCHAR(20),VARCHAR(20),VARCHAR(20)
## NosOfRows: 8
1,New York,New York,1000
2,New York,New York,1001
3,New York,Albany,1010
4,New York,Albany,1011
5,California,San Fransisco,2000
6,California,San Fransisco,2001
7,California,San Diego,2010
8,California,San Diego,2011
# product dimension
## TableName: prod7631
## ColumnNames: prod_id,class,brand,item
## ColumnTypes: INTEGER,VARCHAR(30),VARCHAR(30),VARCHAR(30)
1,Class0,Brand01,Item011
2,Class0,Brand01,Item011
3,Class1,Brand11,Item111
4,Class1,Brand11,Item112
5,Class1,Brand12,Item121
6,Class1,Brand12,Item122
7,Class1,Brand12,Item123
8,Class2,Brand21,Item211
9,Class2,Brand21,Item212
10,Class2,Brand22,Item121
11,Class2,Brand22,Item122
12,Class2,Brand22,Item123
134 changes: 134 additions & 0 deletions testsrc/main/mondrian/rolap/aggmatcher/Checkin_7634.java
@@ -0,0 +1,134 @@

package mondrian.rolap.aggmatcher;

import mondrian.test.loader.CsvDBTestCase;
import mondrian.olap.Result;

/**
* Checkin 7634 attempted to correct a problem demonstrated by this
* junit. The CrossJoinFunDef class has an optimization that kicks in
* when the combined lists sizes are greater than 1000. I create a
* property here which, if set, can be used to change that size from
* 1000 to, in this case, 2. Also, there is a property that disables the
* use of the optimization altogether and another that permits the
* use of the old optimization, currently the nonEmptyListOld method in
* the CrossJoinFunDef class, and the new, checkin 7634, version of the
* method called nonEmptyList.
* The old optimization only looked at the default measure while the
* new version looks at all measures appearing in the query.
* The example Cube and data for the junit is such that there is no
* data for the default measure. Thus the old optimization fails
* to produce the correct result.
*
* @author <a>Richard M. Emberson</a>
* @version
*/
public class Checkin_7634 extends CsvDBTestCase {
private static final String DIRECTORY =
"testsrc/main/mondrian/rolap/aggmatcher";
private static final String CHECKIN_7634 = "Checkin_7634.csv";

public static final String USE_PROP_NAME = "mondrian.test.7634.use";
public static final String OLD_PROP_NAME = "mondrian.test.7634.old";
public static final String SIZE_PROP_NAME = "mondrian.test.7634.size";


public Checkin_7634() {
super();
}
public Checkin_7634(String name) {
super(name);
}
protected void setUp() throws Exception {
super.setUp();

System.getProperties().setProperty(SIZE_PROP_NAME, "2");
}
protected void tearDown() throws Exception {
System.getProperties().remove(SIZE_PROP_NAME);

super.tearDown();
}

public void _testCrossJoin() throws Exception {
// explicit use of [Product].[Class1]
String mdx =
"select {[Measures].[Requested Value]} ON COLUMNS,"+
" NON EMPTY Crossjoin("+
" {[Geography].[All Regions].Children},"+
" {[Product].[All Products].Children}"+
" ) ON ROWS"+
" from [Checkin_7634]";


// Execute query but do not used the CrossJoin nonEmptyList optimization
//System.out.println("NO OP");
System.getProperties().setProperty(USE_PROP_NAME, "not-null");
Result result1 = getCubeTestContext().executeQuery(mdx);
String resultString1 = getCubeTestContext().toString(result1);
//System.out.println(resultString1);
System.getProperties().remove(USE_PROP_NAME);

// Execute query using the new version of the CrossJoin
// nonEmptyList optimization
//System.out.println("OP NEW");
Result result2 = getCubeTestContext().executeQuery(mdx);
String resultString2 = getCubeTestContext().toString(result2);
//System.out.println(resultString2);

// This succeeds.
assertEquals(resultString1, resultString2);

//System.out.println("OP OLD");
// Execute query using the old version of the CrossJoin
// nonEmptyList optimization
System.getProperties().setProperty(OLD_PROP_NAME, "not-null");
Result result3 = getCubeTestContext().executeQuery(mdx);
String resultString3 = getCubeTestContext().toString(result3);
//System.out.println(resultString3);
System.getProperties().remove(OLD_PROP_NAME);

// This fails.
assertEquals(resultString1, resultString3);
}

protected String getDirectoryName() {
return DIRECTORY;
}
protected String getFileName() {
return CHECKIN_7634;
}

protected String getCubeDescription() {
// defines [Product].[Class2] as default (implicit) member
return "<Cube name='Checkin_7634'>\n" +
"<Table name='table7634'/>\n" +
"<Dimension name='Geography' foreignKey='cust_loc_id'>\n" +
"<Hierarchy hasAll='true' allMemberName='All Regions' defaultMember='' primaryKey='cust_loc_id'>\n" +
"<Table name='geography7631'/>\n" +
"<Level column='state_cd' name='State' type='String' uniqueMembers='true'/>\n" +
"<Level column='city_nm' name='City' type='String' uniqueMembers='true'/>\n" +
"<Level column='zip_cd' name='Zip Code' type='String' uniqueMembers='true'/>\n" +
"</Hierarchy>\n" +
"</Dimension>\n" +
"<Dimension name='Product' foreignKey='prod_id'>\n" +
"<Hierarchy hasAll='true' allMemberName='All Products' defaultMember='' primaryKey='prod_id'>\n" +
"<Table name='prod7631'/>\n" +
"<Level column='class' name='Class' type='String' uniqueMembers='true'/>\n" +
"<Level column='brand' name='Brand' type='String' uniqueMembers='true'/>\n" +
"<Level column='item' name='Item' type='String' uniqueMembers='true'/>\n" +
"</Hierarchy>\n" +
"</Dimension>\n" +
"<Measure name='First Measure' \n" +
" column='first' aggregator='sum'\n" +
" formatString='#,###'/>\n" +
"<Measure name='Requested Value' \n" +
" column='request_value' aggregator='sum'\n" +
" formatString='#,###'/>\n" +
"<Measure name='Shipped Value' \n" +
" column='shipped_value' aggregator='sum'\n" +
" formatString='#,###'/>\n" +
"</Cube>";

}
}

0 comments on commit 0d4f6ab

Please sign in to comment.