use of mondrian.olap.Formula in project mondrian by pentaho.
the class TestContext method assertExprDependsOn.
/**
* Asserts that an MDX expression depends upon a given list of dimensions.
*/
public void assertExprDependsOn(String expr, String hierList) {
// Construct a query, and mine it for a parsed expression.
// Use a fresh connection, because some tests define their own dims.
final Connection connection = getConnection();
final String queryString = "WITH MEMBER [Measures].[Foo] AS " + Util.singleQuoteString(expr) + " SELECT FROM [Sales]";
final Query query = connection.parseQuery(queryString);
query.resolve();
final Formula formula = query.getFormulas()[0];
final Exp expression = formula.getExpression();
// Build a list of the dimensions which the expression depends upon,
// and check that it is as expected.
checkDependsOn(query, expression, hierList, true);
}
use of mondrian.olap.Formula in project mondrian by pentaho.
the class CrossJoinFunDef method nonEmptyList.
/**
* This is the entry point to the crossjoin non-empty optimizer code.
*
* <p>
* What one wants to determine is for each individual Member of the input parameter list, a 'List-Member', whether
* across a slice there is any data.
*
* <p>
* But what data?
*
* <p>
* For Members other than those in the list, the 'non-List-Members', one wants to consider all data across the scope
* of these other Members. For instance, if Time is not a List-Member, then one wants to consider data across All
* Time. Or, if Customer is not a List-Member, then look at data across All Customers. The theory here, is if there is
* no data for a particular Member of the list where all other Members not part of the list are span their complete
* hierarchy, then there is certainly no data for Members of that Hierarchy at a more specific Level (more on this
* below).
*
* <p>
* When a Member that is a non-List-Member is part of a Hierarchy that has an All Member (hasAll="true"), then its
* very easy to make sure that the All Member is used during the optimization. If a non-List-Member is part of a
* Hierarchy that does not have an All Member, then one must, in fact, iterate over all top-level Members of the
* Hierarchy!!! - otherwise a List-Member might be excluded because the optimization code was not looking everywhere.
*
* <p>
* Concerning default Members for those Hierarchies for the non-List-Members, ignore them. What is wanted is either
* the All Member or one must iterate across all top-level Members, what happens to be the default Member of the
* Hierarchy is of no relevant.
*
* <p>
* The Measures Hierarchy has special considerations. First, there is no All Measure. But, certainly one need only
* involve Measures that are actually in the query... yes and no. For Calculated Measures one must also get all of the
* non-Calculated Measures that make up each Calculated Measure. Thus, one ends up iterating across all Calculated and
* non-Calculated Measures that are explicitly mentioned in the query as well as all Calculated and non-Calculated
* Measures that are used to define the Calculated Measures in the query. Why all of these? because this represents
* the total scope of possible Measures that might yield a non-null value for the List-Members and that is what we
* what to find. It might be a super set, but thats ok; we just do not want to miss anything.
*
* <p>
* For other Members, the default Member is used, but for Measures one should look for that data for all Measures
* associated with the query, not just one Measure. For a dense dataset this may not be a problem or even apparent,
* but for a sparse dataset, the first Measure may, in fact, have not data but other Measures associated with the
* query might. Hence, the solution here is to identify all Measures associated with the query and then for each
* Member of the list, determine if there is any data iterating across all Measures until non-null data is found or
* the end of the Measures is reached.
*
* <p>
* This is a non-optimistic implementation. This means that an element of the input parameter List is only not
* included in the returned result List if for no combination of Measures, non-All Members (for Hierarchies that have
* no All Members) and evaluator default Members did the element evaluate to non-null.
*
* @param evaluator
* Evaluator
* @param list
* List of members or tuples
* @param call
* Calling ResolvedFunCall used to determine what Measures to use
* @return List of elements from the input parameter list that have evaluated to non-null.
*/
protected TupleList nonEmptyList(Evaluator evaluator, TupleList list, ResolvedFunCall call) {
if (list.isEmpty()) {
return list;
}
TupleList result = TupleCollections.createList(list.getArity(), (list.size() + 2) >> 1);
// Get all of the Measures
final Query query = evaluator.getQuery();
final String measureSetKey = "MEASURE_SET-" + ctag;
Set<Member> measureSet = Util.cast((Set) query.getEvalCache(measureSetKey));
final String memberSetKey = "MEMBER_SET-" + ctag;
Set<Member> memberSet = Util.cast((Set) query.getEvalCache(memberSetKey));
// sense to create and cache it.
if (measureSet == null || memberSet == null) {
measureSet = new HashSet<Member>();
memberSet = new HashSet<Member>();
Set<Member> queryMeasureSet = query.getMeasuresMembers();
MeasureVisitor measureVisitor = new MeasureVisitor(measureSet, call);
// MemberExtractingVisitor will collect the dimension members
// referenced within the measures in the query.
// One or more measures may conflict with the members in the tuple,
// overriding the context of the tuple member when determining
// non-emptiness.
MemberExtractingVisitor memVisitor = new MemberExtractingVisitor(memberSet, call, false);
for (Member m : queryMeasureSet) {
if (m.isCalculated()) {
Exp exp = m.getExpression();
exp.accept(measureVisitor);
exp.accept(memVisitor);
} else {
measureSet.add(m);
}
}
Formula[] formula = query.getFormulas();
if (formula != null) {
for (Formula f : formula) {
if (SqlConstraintUtils.containsValidMeasure(f.getExpression())) {
// short circuit if VM is present.
return list;
}
f.accept(measureVisitor);
}
}
query.putEvalCache(measureSetKey, measureSet);
query.putEvalCache(memberSetKey, memberSet);
}
final String allMemberListKey = "ALL_MEMBER_LIST-" + ctag;
List<Member> allMemberList = Util.cast((List) query.getEvalCache(allMemberListKey));
final String nonAllMembersKey = "NON_ALL_MEMBERS-" + ctag;
Member[][] nonAllMembers = (Member[][]) query.getEvalCache(nonAllMembersKey);
if (nonAllMembers == null) {
//
// Get all of the All Members and those Hierarchies that
// do not have All Members.
//
Member[] evalMembers = evaluator.getMembers().clone();
List<Member> listMembers = list.get(0);
// Remove listMembers from evalMembers and independentSlicerMembers
for (Member lm : listMembers) {
Hierarchy h = lm.getHierarchy();
for (int i = 0; i < evalMembers.length; i++) {
Member em = evalMembers[i];
if ((em != null) && h.equals(em.getHierarchy())) {
evalMembers[i] = null;
}
}
}
Map<Hierarchy, Set<Member>> mapOfSlicerMembers = new HashMap<Hierarchy, Set<Member>>();
if (evaluator instanceof RolapEvaluator) {
RolapEvaluator rev = (RolapEvaluator) evaluator;
mapOfSlicerMembers = rev.getSlicerMembersByHierarchy();
}
// Now we have the non-List-Members, but some of them may not be
// All Members (default Member need not be the All Member) and
// for some Hierarchies there may not be an All Member.
// So we create an array of Objects some elements of which are
// All Members and others elements will be an array of all top-level
// Members when there is not an All Member.
SchemaReader schemaReader = evaluator.getSchemaReader();
allMemberList = new ArrayList<Member>();
List<Member[]> nonAllMemberList = new ArrayList<Member[]>();
Member em;
boolean isSlicerMember;
for (Member evalMember : evalMembers) {
em = evalMember;
if (em == null) {
// to null. These are the CrossJoin axes.
continue;
}
if (em.isMeasure()) {
continue;
}
isSlicerMember = false;
if (mapOfSlicerMembers != null) {
Set<Member> members = mapOfSlicerMembers.get(em.getHierarchy());
if (members != null) {
isSlicerMember = members.contains(em);
}
}
//
if ((isSlicerMember && !em.isCalculated()) || (!isSlicerMember && em.isCalculated())) {
// hierarchy, add them to nonAllMemberList
if (isSlicerMember) {
Set<Member> hierarchySlicerMembers = mapOfSlicerMembers.get(em.getHierarchy());
if (hierarchySlicerMembers.size() > 1) {
nonAllMemberList.add(hierarchySlicerMembers.toArray(new Member[hierarchySlicerMembers.size()]));
}
}
continue;
}
// replace with the "all" member.
if (isSlicerMember || !em.isAll()) {
Hierarchy h = em.getHierarchy();
final List<Member> rootMemberList = schemaReader.getHierarchyRootMembers(h);
if (h.hasAll()) {
// The Hierarchy has an All member
boolean found = false;
for (Member m : rootMemberList) {
if (m.isAll()) {
allMemberList.add(m);
found = true;
break;
}
}
if (!found) {
LOGGER.warn("CrossJoinFunDef.nonEmptyListNEW: ERROR");
}
} else {
// The Hierarchy does NOT have an All member
Member[] rootMembers = rootMemberList.toArray(new Member[rootMemberList.size()]);
nonAllMemberList.add(rootMembers);
}
}
}
nonAllMembers = nonAllMemberList.toArray(new Member[nonAllMemberList.size()][]);
query.putEvalCache(allMemberListKey, allMemberList);
query.putEvalCache(nonAllMembersKey, nonAllMembers);
}
//
// Determine if there is any data.
//
// Put all of the All Members into Evaluator
final int savepoint = evaluator.savepoint();
try {
evaluator.setContext(allMemberList);
// Iterate over elements of the input list. If for any
// combination of
// Measure and non-All Members evaluation is non-null, then
// add it to the result List.
final TupleCursor cursor = list.tupleCursor();
int currentIteration = 0;
Execution execution = query.getStatement().getCurrentExecution();
while (cursor.forward()) {
cursor.setContext(evaluator);
for (Member member : memberSet) {
// memberSet contains members referenced within measures.
// Make sure that we don't incorrectly assume a context
// that will be changed by the measure, so conservatively
// push context to [All] for each of the associated
// hierarchies.
evaluator.setContext(member.getHierarchy().getAllMember());
}
// Check if the MDX query was canceled.
// Throws an exception in case of timeout is exceeded
// see MONDRIAN-2425
CancellationChecker.checkCancelOrTimeout(currentIteration++, execution);
if (tupleContainsCalcs(cursor.current()) || checkData(nonAllMembers, nonAllMembers.length - 1, measureSet, evaluator)) {
result.addCurrent(cursor);
}
}
return result;
} finally {
evaluator.restore(savepoint);
}
}
Aggregations