Skip to content

Commit

Permalink
MONDRIAN: made NON EMPTY Optimization optional (to be configured in M…
Browse files Browse the repository at this point in the history
…ondrianProperties). Native TopCount works but is disabled because MS Access cant do it.

[git-p4: depot-paths = "//open/mondrian/": change = 4455]
  • Loading branch information
Andreas Voss committed Nov 22, 2005
1 parent 298bf04 commit c3df895
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 74 deletions.
4 changes: 2 additions & 2 deletions src/main/mondrian/olap/MondrianProperties.java
Expand Up @@ -539,10 +539,10 @@ private void load(final URL url) {
* if enabled some TopCount will be computed in SQL
*/
public final BooleanProperty EnableNativeTopCount = new BooleanProperty(
this, "mondrian.native.crossjoin.enable", false);
this, "mondrian.native.topcount.enable", false);

/**
* some NON EMPTY set operations member.children, level.members and
* some NON EMPTY set operations like member.children, level.members and
* member descendants will be computed in SQL
*/
public final BooleanProperty EnableNativeNonEmpty = new BooleanProperty(
Expand Down
1 change: 1 addition & 0 deletions src/main/mondrian/rolap/RolapNativeRegistry.java
Expand Up @@ -25,6 +25,7 @@ public class RolapNativeRegistry extends RolapNative {
private List natives = new ArrayList();

public RolapNativeRegistry() {
super.setEnabled(true);
register(new RolapNativeCrossJoin());
register(new RolapNativeTopCount());
}
Expand Down
13 changes: 4 additions & 9 deletions src/main/mondrian/rolap/RolapNativeSet.java
Expand Up @@ -10,6 +10,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import mondrian.olap.Exp;
Expand Down Expand Up @@ -137,10 +138,12 @@ public Object execute() {
listener.excutingSql(e);
}
result = tr.readTuples(schemaReader.getDataSource());
result = Collections.unmodifiableList(result);
cache.put(key, result);
return result;
}


private void addLevel(TupleReader tr, CrossJoinArg arg) {
RolapLevel level = arg.getLevel();
Hierarchy hierarchy = level.getHierarchy();
Expand Down Expand Up @@ -471,15 +474,7 @@ protected boolean isPreferInterpreter(CrossJoinArg[] args) {
return true;
}

protected SmartCache getCache() {
return cache;
}

/** for testing */
void setCache(SmartCache cache) {
this.cache = cache;
}

/** disable garbage collection for test */
void useHardCache(boolean hard) {
if (hard)
cache = new HardSmartCache();
Expand Down
2 changes: 2 additions & 0 deletions src/main/mondrian/rolap/RolapNativeSql.java
Expand Up @@ -41,6 +41,8 @@ public String generateTopCountOrderBy(Exp exp) {
RolapStoredMeasure measure = checkMeasure(exp);
if (measure == null)
return null;
if (measure.isCalculated())
return null;
String exprInner = measure.getMondrianDefExpression().getExpression(sqlQuery);
return measure.getAggregator().getExpression(exprInner);
}
Expand Down
31 changes: 18 additions & 13 deletions src/main/mondrian/rolap/RolapNativeTopCount.java
Expand Up @@ -38,11 +38,11 @@ public RolapNativeTopCount() {
}

class TopCountConstraint extends SetConstraint {
String selectExpr;
String orderByExpr;

public TopCountConstraint(CrossJoinArg[] args, RolapEvaluator evaluator, String selectExpr) {
public TopCountConstraint(CrossJoinArg[] args, RolapEvaluator evaluator, String orderByExpr) {
super(args, evaluator, true);
this.selectExpr = selectExpr;
this.orderByExpr = orderByExpr;
}

/**
Expand All @@ -54,16 +54,18 @@ protected boolean isJoinRequired() {
}

public void addConstraint(SqlQuery sqlQuery) {
if (orderByExpr != null) {
String alias = sqlQuery.nextColumnAlias();
sqlQuery.addSelect(orderByExpr, alias);
sqlQuery.addOrderBy(alias, ascending, true);
}
super.addConstraint(sqlQuery);
String alias = sqlQuery.nextColumnAlias();
sqlQuery.addSelect(selectExpr, alias);
sqlQuery.addOrderBy(alias, ascending);
}

public Object getCacheKey() {
List key = new ArrayList();
key.add(super.getCacheKey());
key.add(selectExpr);
key.add(orderByExpr);
return key;
}
}
Expand Down Expand Up @@ -103,16 +105,19 @@ else if ("BottomCount".equalsIgnoreCase(funName))
RolapSchemaReader schemaReader = (RolapSchemaReader) evaluator.getSchemaReader();
DataSource ds = schemaReader.getDataSource();
try {

// generate the ORDER BY Clause
RolapNativeSql sql = new RolapNativeSql(SqlTupleReader.newQuery(ds.getConnection(),
"NativeTopCount"));
Exp exp;
if (args.length == 3)
exp = args[2];
else
exp = evaluator.getMembers()[0];
String orderByExpr = sql.generateTopCountOrderBy(exp);
String orderByExpr = null;
if (args.length == 3) {
orderByExpr = sql.generateTopCountOrderBy(args[2]);
if (orderByExpr == null)
return null;
}

LOGGER.info("using native topcount");
System.out.println("** NATIVE TOPCOUNT **");

TupleConstraint constraint = new TopCountConstraint(cargs, evaluator, orderByExpr);
SetEvaluator sev = new SetEvaluator(cargs, schemaReader, constraint);
Expand Down
11 changes: 7 additions & 4 deletions src/main/mondrian/rolap/SqlConstraintFactory.java
Expand Up @@ -11,8 +11,9 @@
import java.util.List;

import mondrian.olap.Evaluator;
import mondrian.rolap.sql.TupleConstraint;
import mondrian.olap.MondrianProperties;
import mondrian.rolap.sql.MemberChildrenConstraint;
import mondrian.rolap.sql.TupleConstraint;

/**
* creates the right constraint for common tasks.
Expand All @@ -22,6 +23,8 @@
*/
public class SqlConstraintFactory {

boolean enabled = MondrianProperties.instance().EnableNativeNonEmpty.get();

private static final SqlConstraintFactory instance = new SqlConstraintFactory();

/** singleton */
Expand All @@ -33,21 +36,21 @@ public static final SqlConstraintFactory instance() {
}

public MemberChildrenConstraint getMemberChildrenConstraint(Evaluator context) {
if (context == null)
if (!enabled || context == null)
return DefaultMemberChildrenConstraint.instance();
return new SqlContextConstraint((RolapEvaluator) context, false);
}

public TupleConstraint getLevelMembersConstraint(Evaluator context) {
if (context == null)
if (!enabled || context == null)
return DefaultTupleConstraint.instance();
return new SqlContextConstraint((RolapEvaluator) context, false);
}

public MemberChildrenConstraint getChildByNameConstraint(RolapMember parent,
String childName) {
// ragged hierarchies span multiple levels, so SQL WHERE does not work there
if (parent.getRolapHierarchy().isRagged())
if (!enabled || parent.getRolapHierarchy().isRagged())
return DefaultMemberChildrenConstraint.instance();
return new ChildByNameConstraint(childName);
}
Expand Down
16 changes: 13 additions & 3 deletions src/main/mondrian/rolap/sql/SqlQuery.java
Expand Up @@ -403,12 +403,22 @@ public void addOrderBy(final String expression)
}
}

public void addOrderBy(String alias, boolean ascending) {
/**
* creates an ORDER BY
* @param alias the alias name to order by. This must appear somewhere on the select list
* @param ascending sort direction
* @param prepend true = prepend to the current list of order by elements.
*/
public void addOrderBy(String alias, boolean ascending, boolean prepend) {
alias = dialect.quoteIdentifier(alias);
if (ascending)
orderBy.add(alias + " ASC");
alias = alias + " ASC";
else
alias = alias + " DESC";
if (prepend)
orderBy.add(0, alias);
else
orderBy.add(alias + " DESC");
orderBy.add(alias);
}

public String toString()
Expand Down
111 changes: 68 additions & 43 deletions testsrc/main/mondrian/rolap/NonEmptyTest.java
Expand Up @@ -46,6 +46,19 @@ public class NonEmptyTest extends FoodMartTestCase {
private static Logger logger = Logger.getLogger(NonEmptyTest.class);
SqlConstraintFactory scf = SqlConstraintFactory.instance();

/** check that top count is executed native unless disabled */
public void testNativeTopCount() {
if (!MondrianProperties.instance().EnableNativeTopCount.get())
return;
checkNative(3, 3, "select {[Measures].[Store Sales]} on columns,"
+ " NON EMPTY TopCount("
+ " CrossJoin([Customers].[All Customers].[USA].children, [Promotions].[Promotion Name].Members), "
+ " 10, [Measures].[Store Sales]) ON ROWS"
+ " from [Sales] where ("
+ " [Store].[All Stores].[USA].[CA].[San Francisco].[Store 14],"
+ " [Time].[1997].[Q1].[1])");
}

public void testMeasureAndAggregateInSlicer() {
String result = "Axis #0:"
+ nl
Expand Down Expand Up @@ -119,7 +132,7 @@ public void testCjMembersMembersMembers() {
+ " [Store].[All Stores].[USA].[CA].[San Francisco].[Store 14],"
+ " [Time].[1997].[Q1].[1])");
}

/** SQL does not make sense because alle members are known */
public void testCjEnumEnum() {
checkNotNative(
Expand Down Expand Up @@ -600,48 +613,6 @@ RolapNativeRegistry getRegistry(Connection connection) {
return schemaReader.getSchema().getNativeRegistry();
}

class TestListener implements Listener {
boolean foundEvaluator;
boolean foundInCache;
boolean excecuteSql;

boolean isExcecuteSql() {
return excecuteSql;
}

void setExcecuteSql(boolean excecuteSql) {
this.excecuteSql = excecuteSql;
}

boolean isFoundEvaluator() {
return foundEvaluator;
}

void setFoundEvaluator(boolean foundEvaluator) {
this.foundEvaluator = foundEvaluator;
}

boolean isFoundInCache() {
return foundInCache;
}

void setFoundInCache(boolean foundInCache) {
this.foundInCache = foundInCache;
}

public void foundEvaluator(NativeEvent e) {
this.foundEvaluator = true;
}

public void foundInCache(TupleEvent e) {
this.foundInCache = true;
}

public void excutingSql(TupleEvent e) {
this.excecuteSql = true;
}

}

/**
* runs a query twice, with native crossjoin optimization enabled and
Expand Down Expand Up @@ -682,6 +653,7 @@ private Result checkNative(int resultLimit, int rowCount, String mdx) {
reg = getRegistry(con);
listener.setFoundEvaluator(false);
reg.setListener(listener);
// disable RolapNativeSet
reg.setEnabled(false);
Result r2 = executeQuery(mdx, con);
String s2 = toString(r2);
Expand Down Expand Up @@ -740,4 +712,57 @@ RolapEvaluator getEvaluator(Result res, int[] pos) {
res = ((NonEmptyResult) res).underlying;
return (RolapEvaluator) ((RolapResult) res).getEvaluator(pos);
}

/**
* gets notified
* <ul>
* <li>when a matching native evaluator was found
* <li>when SQL is executed
* <li>when result is found in the cache
* </ul>
* @author av
* @since Nov 22, 2005
*/
class TestListener implements Listener {
boolean foundEvaluator;
boolean foundInCache;
boolean excecuteSql;

boolean isExcecuteSql() {
return excecuteSql;
}

void setExcecuteSql(boolean excecuteSql) {
this.excecuteSql = excecuteSql;
}

boolean isFoundEvaluator() {
return foundEvaluator;
}

void setFoundEvaluator(boolean foundEvaluator) {
this.foundEvaluator = foundEvaluator;
}

boolean isFoundInCache() {
return foundInCache;
}

void setFoundInCache(boolean foundInCache) {
this.foundInCache = foundInCache;
}

public void foundEvaluator(NativeEvent e) {
this.foundEvaluator = true;
}

public void foundInCache(TupleEvent e) {
this.foundInCache = true;
}

public void excutingSql(TupleEvent e) {
this.excecuteSql = true;
}

}
}

0 comments on commit c3df895

Please sign in to comment.