Search in sources :

Example 1 with Formula

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);
}
Also used : Formula(mondrian.olap.Formula) Query(mondrian.olap.Query) OlapConnection(org.olap4j.OlapConnection) Connection(mondrian.olap.Connection) Exp(mondrian.olap.Exp)

Example 2 with Formula

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);
    }
}
Also used : SchemaReader(mondrian.olap.SchemaReader) Set(java.util.Set) HashSet(java.util.HashSet) Query(mondrian.olap.Query) HashMap(java.util.HashMap) TupleCursor(mondrian.calc.TupleCursor) AbstractTupleCursor(mondrian.calc.impl.AbstractTupleCursor) ArrayList(java.util.ArrayList) RolapEvaluator(mondrian.rolap.RolapEvaluator) Formula(mondrian.olap.Formula) Hierarchy(mondrian.olap.Hierarchy) Execution(mondrian.server.Execution) Member(mondrian.olap.Member) ListTupleList(mondrian.calc.impl.ListTupleList) DelegatingTupleList(mondrian.calc.impl.DelegatingTupleList) TupleList(mondrian.calc.TupleList) DummyExp(mondrian.calc.DummyExp) Exp(mondrian.olap.Exp)

Aggregations

Exp (mondrian.olap.Exp)2 Formula (mondrian.olap.Formula)2 Query (mondrian.olap.Query)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Set (java.util.Set)1 DummyExp (mondrian.calc.DummyExp)1 TupleCursor (mondrian.calc.TupleCursor)1 TupleList (mondrian.calc.TupleList)1 AbstractTupleCursor (mondrian.calc.impl.AbstractTupleCursor)1 DelegatingTupleList (mondrian.calc.impl.DelegatingTupleList)1 ListTupleList (mondrian.calc.impl.ListTupleList)1 Connection (mondrian.olap.Connection)1 Hierarchy (mondrian.olap.Hierarchy)1 Member (mondrian.olap.Member)1 SchemaReader (mondrian.olap.SchemaReader)1 RolapEvaluator (mondrian.rolap.RolapEvaluator)1 Execution (mondrian.server.Execution)1 OlapConnection (org.olap4j.OlapConnection)1