public Object execute(Evaluator evaluator, Argument[] arguments) { final Argument memberListExp = arguments[0]; final List memberList = (List) memberListExp.evaluate(evaluator); final Argument exp = arguments[1]; int nullCount = 0; int missCount = 0; for (int i = memberList.size() - 1; i >= 0; --i) { Member member = (Member) memberList.get(i); // Create an evaluator with the member as its context. Evaluator subEvaluator = evaluator.push(member); int missCountBefore = subEvaluator.getMissCount(); final Object o = exp.evaluateScalar(subEvaluator); int missCountAfter = subEvaluator.getMissCount(); if (Util.isNull(o)) { ++nullCount; continue; } if (missCountAfter > missCountBefore) { // There was a cache miss while evaluating the expression, so // the result is bogus. It would be a mistake to give up after // one cache miss, because then it would take us N // evaluate/fetch passes to move back through N members, which // is way too many. // // Carry on until we have seen as many misses as we have seen // null cells. The effect of this policy is that each pass // examines twice as many cells as the previous pass. Thus // we can move back through N members in log2(N) passes. ++missCount; if (missCount < 2 * nullCount + 1) { continue; } } if (o == RolapUtil.valueNotReadyException) { // Value is not in the cache yet, so we don't know whether // it will be empty. Carry on... continue; } if (o instanceof RuntimeException) { RuntimeException runtimeException = (RuntimeException) o; if (o == RolapUtil.valueNotReadyException) { // Value is not in the cache yet, so we don't know whether // it will be empty. Carry on... continue; } return runtimeException; } return member; } // Not found. Return the hierarchy's 'null member'. // It is possible that a MemberType has a Dimension but // no hierarchy, so we have to just get the type's Dimension's // default hierarchy and return it's null member. final Hierarchy hierarchy = memberListExp.getType().getHierarchy(); return (hierarchy == null) ? memberListExp.getType().getDimension().getHierarchies()[0].getNullMember() : hierarchy.getNullMember(); }
public Object evaluate(Evaluator evaluator) { final Member[] members = tupleCalc.evaluateTuple(evaluator); if (members == null) { return null; } final boolean needToReturnNull = evaluator.needToReturnNullForUnrelatedDimension(members); if (needToReturnNull) { return null; } Member[] savedMembers = new Member[members.length]; for (int i = 0; i < members.length; i++) { savedMembers[i] = evaluator.setContext(members[i]); } Object result = evaluator.evaluateCurrent(); evaluator.setContext(savedMembers); return result; }
public Object evaluate(Evaluator evaluator) { // Evaluate current member in the given scenario by expanding in // terms of the writeback cells. // First, evaluate in the null scenario. final Member defaultMember = scenario.member.getHierarchy().getDefaultMember(); final int savepoint = evaluator.savepoint(); try { evaluator.setContext(defaultMember); final Object o = evaluator.evaluateCurrent(); double d = o instanceof Number ? ((Number) o).doubleValue() : 0d; // Look for writeback cells which are equal to, ancestors of, // or descendants of, the current cell. Modify the value // accordingly. // // It is possible that the value is modified by several // writebacks. If so, order is important. int changeCount = 0; for (ScenarioImpl.WritebackCell writebackCell : scenario.writebackCells) { CellRelation relation = writebackCell.getRelationTo(evaluator.getMembers()); switch (relation) { case ABOVE: // This cell is below the writeback cell. Value is // determined by allocation policy. double atomicCellCount = evaluateAtomicCellCount((RolapEvaluator) evaluator); if (atomicCellCount == 0d) { // Sometimes the value comes back zero if the cache // is not ready. Switch to 1, which at least does // not give divide-by-zero. We will be invoked again // for the correct answer when the cache has been // populated. atomicCellCount = 1d; } switch (writebackCell.allocationPolicy) { case EQUAL_ALLOCATION: d = writebackCell.newValue * atomicCellCount / writebackCell.atomicCellCount; break; case EQUAL_INCREMENT: d += writebackCell.getOffset() * atomicCellCount / writebackCell.atomicCellCount; break; default: throw Util.unexpected(writebackCell.allocationPolicy); } ++changeCount; break; case EQUAL: // This cell is the writeback cell. Value is the value // written back. d = writebackCell.newValue; ++changeCount; break; case BELOW: // This cell is above the writeback cell. Value is the // current value plus the change in the writeback cell. d += writebackCell.getOffset(); ++changeCount; break; case NONE: // Writeback cell is unrelated. It has no effect on // cell's value. break; default: throw Util.unexpected(relation); } } // Don't create a new object if value has not changed. if (changeCount == 0) { return o; } else { return d; } } finally { evaluator.restore(savepoint); } }