Skip to content

Commit

Permalink
MONDRIAN - Fixed LER-2781. Added support for native sql processing of…
Browse files Browse the repository at this point in the history
… the

       nonempty MEMBERS function on virtual cubes.

[git-p4: depot-paths = "//open/mondrian/": change = 8146]
  • Loading branch information
Zelaine Fong committed Nov 14, 2006
1 parent c39a300 commit 61a4c87
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 100 deletions.
95 changes: 1 addition & 94 deletions src/main/mondrian/rolap/RolapNativeCrossJoin.java
Expand Up @@ -8,14 +8,11 @@
*/
package mondrian.rolap;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import mondrian.olap.*;
import mondrian.mdx.*;
import mondrian.rolap.sql.TupleConstraint;

/**
Expand Down Expand Up @@ -114,31 +111,7 @@ NativeEvaluator createEvaluator(RolapEvaluator evaluator, FunDef fun, Exp[] args
*/
private boolean validCrossJoinLevels(Query query, CrossJoinArg[] cargs)
{
// Gather the unique set of level-to-column maps corresponding
// to the underlying star/cube where the measure column
// originates from.
Set baseCubesLevelToColumnMaps = new HashSet();
Map measureMap = new HashMap();
Util.assertTrue(query.nativeCrossJoinVirtualCube());
for (Iterator it = query.getMeasuresMembers().iterator();
it.hasNext(); )
{
Member member = (Member) it.next();
if (member instanceof RolapStoredMeasure) {
addMeasure(
(RolapStoredMeasure) member,
baseCubesLevelToColumnMaps,
measureMap);
} else if (member instanceof RolapCalculatedMember) {
findMeasures(
((RolapCalculatedMember) member).getExpression(),
baseCubesLevelToColumnMaps,
measureMap);
}
}
if (measureMap.isEmpty()) {
return false;
}
Set baseCubesLevelToColumnMaps = query.getVirtualCubeBaseCubeMaps();

// we need to make sure all the levels join with each fact table;
// otherwise, it doesn't make sense to do the processing
Expand All @@ -154,72 +127,6 @@ private boolean validCrossJoinLevels(Query query, CrossJoinArg[] cargs)
}
}
}
query.setVirtualCubeBaseCubeMaps(baseCubesLevelToColumnMaps);
query.setLevelMapToMeasureMap(measureMap);
return true;
}

/**
* Adds information regarding a stored measure to maps
*
* @param measure the stored measure
* @param baseCubesLevelToColumnMaps level to column maps for the
* underlying cubes that make up the virtual cube referenced in a query
* @param measureMap maps a level-to-column map to a measure
*/
private void addMeasure(
RolapStoredMeasure measure,
Set baseCubesLevelToColumnMaps,
Map measureMap)
{
RolapStar.Measure starMeasure =
(RolapStar.Measure) measure.getStarMeasure();
RolapStar star = starMeasure.getStar();
RolapCube baseCube = measure.getCube();
Map levelToColumnMap =
star.getMapLevelToColumn(baseCube);
if (baseCubesLevelToColumnMaps.add(levelToColumnMap)) {
measureMap.put(levelToColumnMap, measure);
}
}

/**
* Extracts the stored measures referenced in an expression
*
* @param exp expression
* @param baseCubesLevelToColumnMaps
* @param baseCubesLevelToColumnMaps level to column maps for the
* underlying cubes that make up the virtual cube referenced in a query
* @param measureMap maps a level-to-column map to a measure
*/
private void findMeasures(
Exp exp,
Set baseCubesLevelToColumnMaps,
Map measureMap)
{
if (exp instanceof MemberExpr) {
MemberExpr memberExpr = (MemberExpr) exp;
Member member = memberExpr.getMember();
if (member instanceof RolapStoredMeasure) {
addMeasure(
(RolapStoredMeasure) member,
baseCubesLevelToColumnMaps,
measureMap);
} else if (member instanceof RolapCalculatedMember) {
findMeasures(
((RolapCalculatedMember) member).getExpression(),
baseCubesLevelToColumnMaps,
measureMap);
}
} else if (exp instanceof ResolvedFunCall) {
ResolvedFunCall funCall = (ResolvedFunCall) exp;
Exp [] args = funCall.getArgs();
for (int i = 0; i < args.length; i++) {
findMeasures(
args[i],
baseCubesLevelToColumnMaps,
measureMap);
}
}
}
}
2 changes: 1 addition & 1 deletion src/main/mondrian/rolap/SqlConstraintFactory.java
Expand Up @@ -42,7 +42,7 @@ public MemberChildrenConstraint getMemberChildrenConstraint(Evaluator context) {
}

public TupleConstraint getLevelMembersConstraint(Evaluator context) {
if (!enabled || !SqlContextConstraint.isValidContext(context))
if (!enabled || !SqlContextConstraint.isValidContext(context, false))
return DefaultTupleConstraint.instance();
return new SqlContextConstraint((RolapEvaluator) context, false);
}
Expand Down
128 changes: 123 additions & 5 deletions src/main/mondrian/rolap/SqlContextConstraint.java
Expand Up @@ -10,9 +10,9 @@

import java.util.*;

import mondrian.olap.Evaluator;
import mondrian.olap.Member;
import mondrian.olap.Util;
import mondrian.mdx.MemberExpr;
import mondrian.mdx.ResolvedFunCall;
import mondrian.olap.*;
import mondrian.rolap.sql.MemberChildrenConstraint;
import mondrian.rolap.sql.SqlQuery;
import mondrian.rolap.sql.TupleConstraint;
Expand Down Expand Up @@ -61,14 +61,132 @@ public static boolean isValidContext(
if (context == null) {
return false;
}
if (disallowVirtualCube) {
RolapCube cube = (RolapCube) context.getCube();
RolapCube cube = (RolapCube) context.getCube();
if (disallowVirtualCube) {
if (cube.isVirtual()) {
return false;
}
}
if (cube.isVirtual() &&
!findVirtualCubeJoinLevels(context.getQuery()))
{
return false;
}
return true;
}

/**
* Locates joins required with the underlying fact tables that make up a
* virtual cube by validating the measures referenced in the query.
*
* @param query query referencing the virtual cube
*
* @return true if valid measures exist
*/
private static boolean findVirtualCubeJoinLevels(Query query)
{
// Gather the unique set of level-to-column maps corresponding
// to the underlying star/cube where the measure column
// originates from.
Set baseCubesLevelToColumnMaps = new HashSet();
Map measureMap = new HashMap();
Set measureMembers = query.getMeasuresMembers();
// if no measures are explicitly referenced, just use the default
// measure
if (measureMembers.isEmpty()) {
Cube cube = query.getCube();
Dimension dimension = cube.getDimensions()[0];
query.addMeasuresMembers(
dimension.getHierarchy().getDefaultMember());
}
for (Iterator it = query.getMeasuresMembers().iterator();
it.hasNext(); )
{
Member member = (Member) it.next();
if (member instanceof RolapStoredMeasure) {
addMeasure(
(RolapStoredMeasure) member,
baseCubesLevelToColumnMaps,
measureMap);
} else if (member instanceof RolapCalculatedMember) {
findMeasures(
((RolapCalculatedMember) member).getExpression(),
baseCubesLevelToColumnMaps,
measureMap);
}
}
if (measureMap.isEmpty()) {
return false;
}

query.setVirtualCubeBaseCubeMaps(baseCubesLevelToColumnMaps);
query.setLevelMapToMeasureMap(measureMap);
return true;
}

/**
* Adds information regarding a stored measure to maps
*
* @param measure the stored measure
* @param baseCubesLevelToColumnMaps level to column maps for the
* underlying cubes that make up the virtual cube referenced in a query
* @param measureMap maps a level-to-column map to a measure
*/
private static void addMeasure(
RolapStoredMeasure measure,
Set baseCubesLevelToColumnMaps,
Map measureMap)
{
RolapStar.Measure starMeasure =
(RolapStar.Measure) measure.getStarMeasure();
RolapStar star = starMeasure.getStar();
RolapCube baseCube = measure.getCube();
Map levelToColumnMap =
star.getMapLevelToColumn(baseCube);
if (baseCubesLevelToColumnMaps.add(levelToColumnMap)) {
measureMap.put(levelToColumnMap, measure);
}
}

/**
* Extracts the stored measures referenced in an expression
*
* @param exp expression
* @param baseCubesLevelToColumnMaps
* @param baseCubesLevelToColumnMaps level to column maps for the
* underlying cubes that make up the virtual cube referenced in a query
* @param measureMap maps a level-to-column map to a measure
*/
private static void findMeasures(
Exp exp,
Set baseCubesLevelToColumnMaps,
Map measureMap)
{
if (exp instanceof MemberExpr) {
MemberExpr memberExpr = (MemberExpr) exp;
Member member = memberExpr.getMember();
if (member instanceof RolapStoredMeasure) {
addMeasure(
(RolapStoredMeasure) member,
baseCubesLevelToColumnMaps,
measureMap);
} else if (member instanceof RolapCalculatedMember) {
findMeasures(
((RolapCalculatedMember) member).getExpression(),
baseCubesLevelToColumnMaps,
measureMap);
}
} else if (exp instanceof ResolvedFunCall) {
ResolvedFunCall funCall = (ResolvedFunCall) exp;
Exp [] args = funCall.getArgs();
for (int i = 0; i < args.length; i++) {
findMeasures(
args[i],
baseCubesLevelToColumnMaps,
measureMap);
}
}
}

/**
* @param strict defines the behaviour if the evaluator context
Expand Down
9 changes: 9 additions & 0 deletions testsrc/main/mondrian/rolap/NonEmptyTest.java
Expand Up @@ -174,6 +174,15 @@ public void testVirtualCube() throws Exception {
"from [Warehouse and Sales]");
c.run();
}

public void testVirtualCubeMembers() throws Exception {
// ok to use native sql optimization for members on a virtual cube
TestCase c = new TestCase(6, 3,
"select NON EMPTY {[Measures].[Unit Sales], [Measures].[Warehouse Sales]} ON COLUMNS, " +
"NON EMPTY {[Product].[Product Family].Members} ON ROWS " +
"from [Warehouse and Sales]");
c.run();
}

public void testNativeFilter() {
if (!MondrianProperties.instance().EnableNativeFilter.get()) {
Expand Down

0 comments on commit 61a4c87

Please sign in to comment.