rolapresult.java
来自「数据仓库展示程序」· Java 代码 · 共 717 行 · 第 1/2 页
JAVA
717 行
/*
// $Id: //open/mondrian/src/main/mondrian/rolap/RolapResult.java#55 $
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// (C) Copyright 2001-2005 Kana Software, Inc. and others.
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
//
// jhyde, 10 August, 2001
*/
package mondrian.rolap;
import mondrian.olap.*;
import mondrian.olap.fun.MondrianEvaluationException;
import mondrian.rolap.agg.AggregationManager;
import mondrian.resource.MondrianResource;
import org.apache.log4j.Logger;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
/**
* A <code>RolapResult</code> is the result of running a query.
*
* @author jhyde
* @since 10 August, 2001
* @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapResult.java#55 $
*/
class RolapResult extends ResultBase {
private static final Logger LOGGER = Logger.getLogger(ResultBase.class);
private static final int MAX_AGGREGATION_PASS_COUNT = 5;
private final RolapEvaluator evaluator;
/**
* Evaluator containing context resulting from evaluating the slicer.
*/
private RolapEvaluator slicerEvaluator;
private final CellKey point;
private final Map cellValues;
private final FastBatchingCellReader batchingReader;
AggregatingCellReader aggregatingReader = new AggregatingCellReader();
private final int[] modulos;
private final Random random =
Util.createRandom(MondrianProperties.instance().TestSeed.get());
/**
* Maps expressions to the dimensions which they are independent of.
*/
private final Map expIndDims = new HashMap();
/**
* Maps the names of sets to their values. Populated on demand.
*/
private final Map namedSetValues = new HashMap();
RolapResult(Query query) {
super(query, new RolapAxis[query.axes.length]);
this.point = new CellKey(new int[query.axes.length]);
final int expDeps = MondrianProperties.instance().TestExpDependencies.get();
if (expDeps > 0) {
this.evaluator = new DependencyTestingEvaluator(this, expDeps);
} else {
final RolapEvaluator.RolapEvaluatorRoot root =
new RolapEvaluator.RolapEvaluatorRoot(this);
this.evaluator = new RolapEvaluator(root);
}
RolapCube rcube = (RolapCube) query.getCube();
this.batchingReader = new FastBatchingCellReader(rcube);
this.cellValues = new HashMap();
try {
for (int i = -1; i < axes.length; i++) {
QueryAxis axis;
if (i == -1) {
if (query.slicer != null) {
FunCall call = new FunCall(
"{}",
Syntax.Braces,
new Exp[] {
new FunCall(
"()",
Syntax.Parentheses,
new Exp[] {
query.slicer}
)});
Exp call2 = call.accept(query.createValidator());
axis = new QueryAxis(
false,
call2,
AxisOrdinal.Slicer,
QueryAxis.SubtotalVisibility.Undefined);
} else {
axis = null;
}
} else {
axis = query.axes[i];
}
int attempt = 0;
while (true) {
evaluator.setCellReader(batchingReader);
RolapAxis axisResult = executeAxis(evaluator.push(), axis);
Util.discard(axisResult);
evaluator.clearExpResultCache();
if (!batchingReader.loadAggregations()) {
break;
}
if (attempt++ > MAX_AGGREGATION_PASS_COUNT) {
throw Util.newInternal("Failed to load all aggregations after " +
MAX_AGGREGATION_PASS_COUNT +
"passes; there's probably a cycle");
}
}
evaluator.setCellReader(aggregatingReader);
RolapAxis axisResult = executeAxis(evaluator.push(), axis);
evaluator.clearExpResultCache();
if (i == -1) {
this.slicerAxis = axisResult;
// Use the context created by the slicer for the other
// axes. For example, "select filter([Customers], [Store
// Sales] > 100) on columns from Sales where
// ([Time].[1998])" should show customers whose 1998 (not
// total) purchases exceeded 100.
switch (this.slicerAxis.positions.length) {
case 0:
throw MondrianResource.instance().EmptySlicer.ex();
case 1:
break;
default:
throw MondrianResource.instance().CompoundSlicer.ex();
}
Position position = this.slicerAxis.positions[0];
for (int j = 0; j < position.members.length; j++) {
Member member = position.members[j];
if (member == null) {
throw MondrianResource.instance().EmptySlicer.ex();
}
evaluator.setContext(member);
}
slicerEvaluator = (RolapEvaluator) evaluator.push();
} else {
this.axes[i] = axisResult;
}
}
// Now that the axes are evaluated, make sure that the number of
// cells does not exceed the result limit.
int limit = MondrianProperties.instance().ResultLimit.get();
if (limit > 0) {
// result limit exceeded, throw an exception
long n = 1;
for (int i = 0; i < axes.length; i++) {
n = n * axes[i].positions.length;
}
if (n > limit) {
throw MondrianResource.instance().
LimitExceededDuringCrossjoin.ex(
new Long(n), new Long(limit));
}
}
// Suppose the result is 4 x 3 x 2, then modulo = {1, 4, 12, 24}.
//
// Then the ordinal of cell (3, 2, 1)
// = (modulo[0] * 3) + (modulo[1] * 2) + (modulo[2] * 1)
// = (1 * 3) + (4 * 2) + (12 * 1)
// = 23
//
// Reverse calculation:
// p[0] = (23 % modulo[1]) / modulo[0] = (23 % 4) / 1 = 3
// p[1] = (23 % modulo[2]) / modulo[1] = (23 % 12) / 4 = 2
// p[2] = (23 % modulo[3]) / modulo[2] = (23 % 24) / 12 = 1
this.modulos = new int[axes.length + 1];
int modulo = modulos[0] = 1;
for (int i = 0; i < axes.length; i++) {
modulo *= axes[i].positions.length;
modulos[i + 1] = modulo;
}
executeBody(query);
} finally {
evaluator.clearExpResultCache();
}
// RME : what is this doing???
query.getCube().getDimensions();
}
protected Logger getLogger() {
return LOGGER;
}
// implement Result
public Axis[] getAxes() {
return axes;
}
public Cell getCell(int[] pos) {
if (pos.length != point.ordinals.length) {
throw Util.newError(
"coordinates should have dimension " + point.ordinals.length);
}
Object value = cellValues.get(new CellKey(pos));
if (value == null) {
value = Util.nullValue;
}
return new RolapCell(this, getCellOrdinal(pos), value);
}
private RolapAxis executeAxis(Evaluator evaluator, QueryAxis axis) {
Position[] positions;
if (axis == null) {
// Create an axis containing one position with no members (not
// the same as an empty axis).
Member[] members = new Member[0];
RolapPosition position = new RolapPosition(members);
positions = new Position[] {position};
} else {
Exp exp = axis.set;
evaluator.setNonEmpty(axis.nonEmpty);
Object value = exp.evaluate(evaluator);
evaluator.setNonEmpty(false);
if (value == null) {
value = Collections.EMPTY_LIST;
}
Util.assertTrue(value instanceof List);
List list = (List) value;
positions = new Position[list.size()];
for (int i = 0; i < list.size(); i++) {
Member[] members = null;
Object o = list.get(i);
if (o instanceof Object[]) {
Object[] a = (Object[]) o;
members = new Member[a.length];
for (int j = 0; j < a.length; j++) {
members[j] = (Member) a[j];
}
} else {
members = new Member[] {(Member) o};
}
RolapPosition position = new RolapPosition(members);
positions[i] = position;
}
}
return new RolapAxis(positions);
}
private void executeBody(Query query) {
try {
// Compute the cells several times. The first time, use a dummy
// evaluator which collects requests.
int count = 0;
while (true) {
cellValues.clear();
evaluator.setCellReader(this.batchingReader);
executeStripe(query.axes.length - 1,
(RolapEvaluator) evaluator.push());
evaluator.clearExpResultCache();
// Retrieve the aggregations collected.
//
//
if (!batchingReader.loadAggregations()) {
// We got all of the cells we needed, so the result must be
// correct.
return;
}
if (count++ > MAX_AGGREGATION_PASS_COUNT) {
if (evaluator instanceof DependencyTestingEvaluator) {
// The dependency testing evaluator can trigger new
// requests every cycle. So let is run as normal for
// the first N times, then run it disabled.
((DependencyTestingEvalutorRoot) evaluator.root).disabled = true;
if (count > MAX_AGGREGATION_PASS_COUNT * 2) {
throw Util.newInternal("Query required more than "
+ count + " iterations");
}
} else {
throw Util.newInternal("Query required more than "
+ count + " iterations");
}
}
}
} finally {
RolapCube cube = (RolapCube) query.getCube();
cube.clearCache();
}
}
/**
* Evaluates a named set.
*
* <p>A given set is only evaluated once each time a query is executed; the
* result is added to the {@link #namedSetValues} cache on first execution
* and re-used.
*
* <p>Named sets are always evaluated in the context of the slicer.
*/
Object evaluateNamedSet(String name, Exp exp) {
Object value = namedSetValues.get(name);
if (value == null) {
value = evaluateExp(exp, (RolapEvaluator) slicerEvaluator.push());
namedSetValues.put(name, value);
}
return value;
}
private Object evaluateExp(Exp exp, RolapEvaluator evaluator) {
int attempt = 0;
boolean dirty = batchingReader.isDirty();
while (true) {
RolapEvaluator ev = (RolapEvaluator) evaluator.push();
ev.setCellReader(batchingReader);
Object preliminaryValue = exp.evaluate(ev);
Util.discard(preliminaryValue);
if (!batchingReader.loadAggregations()) {
break;
}
if (attempt++ > MAX_AGGREGATION_PASS_COUNT) {
throw Util.newInternal("Failed to load all aggregations after " +
MAX_AGGREGATION_PASS_COUNT +
"passes; there's probably a cycle");
}
}
// If there were pending reads when we entered, some of the other
// expressions may have been evaluated incorrectly. Set the reaader's
// 'dirty' flag so that the caller knows that it must re-evaluate them.
if (dirty) {
batchingReader.setDirty(true);
}
RolapEvaluator ev = (RolapEvaluator) evaluator.push();
ev.setCellReader(aggregatingReader);
Object value = exp.evaluate(ev);
return value;
}
/**
* An <code>AggregatingCellReader</code> reads cell values from the
* {@link RolapAggregationManager}.
**/
private static class AggregatingCellReader implements CellReader {
private final RolapAggregationManager aggMan =
AggregationManager.instance();
/**
* Overrides {@link CellReader#get}. Returns <code>null</code> if no
* aggregation contains the required cell.
**/
// implement CellReader
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?