rolapcube.java
来自「数据仓库展示程序」· Java 代码 · 共 1,687 行 · 第 1/5 页
JAVA
1,687 行
private static MondrianDef.Relation reorder(
MondrianDef.Relation relation,
RolapLevel[] levels) {
// Need at least two levels, with only one level theres nothing to do.
if (levels.length < 2) {
return relation;
}
Map nodeMap = new HashMap();
// Create RelNode in top down order (year -> day)
for (int i = 0; i < levels.length; i++) {
RolapLevel level = levels[i];
if (level.isAll()) {
continue;
}
// this is the table alias
String tableName = level.getTableName();
if (tableName == null) {
// punt, no table name
return relation;
}
RelNode rnode = new RelNode(tableName, i);
nodeMap.put(tableName, rnode);
}
if (! validateNodes(relation, nodeMap)) {
return relation;
}
relation = copy(relation);
// Put lower levels to the left of upper levels
leftToRight(relation, nodeMap);
// Move joins to the right side
topToBottom(relation);
return relation;
}
/**
* The map has to be validated against the relation because there are
* certain cases where we do not want to (read: can not) do reordering, for
* instance, when closures are involved.
*
* @param relation
* @param map
* @return
*/
private static boolean validateNodes(MondrianDef.Relation relation, Map map) {
if (relation instanceof MondrianDef.Table) {
MondrianDef.Table table = (MondrianDef.Table) relation;
RelNode relNode = RelNode.lookup(table, map);
return (relNode != null);
} else if (relation instanceof MondrianDef.Join) {
MondrianDef.Join join = (MondrianDef.Join) relation;
return validateNodes(join.left, map) &&
validateNodes(join.right, map);
} else {
throw Util.newInternal("bad relation type " + relation);
}
}
/**
* Transforms the Relation moving the tables associated with
* lower levels (greater level depth, i.e., Day is lower than Month) to the
* left of tables with high levels.
*
* @param relation
* @param map
* @return
*/
private static int leftToRight(MondrianDef.Relation relation, Map map) {
if (relation instanceof MondrianDef.Table) {
MondrianDef.Table table = (MondrianDef.Table) relation;
RelNode relNode = RelNode.lookup(table, map);
// Associate the table with its RelNode!!!! This is where this
// happens.
relNode.table = table;
return relNode.depth;
} else if (relation instanceof MondrianDef.Join) {
MondrianDef.Join join = (MondrianDef.Join) relation;
int leftDepth = leftToRight(join.left, map);
int rightDepth = leftToRight(join.right, map);
// we want the right side to be less than the left
if (rightDepth > leftDepth) {
// switch
String leftAlias = join.leftAlias;
String leftKey = join.leftKey;
MondrianDef.Relation left = join.left;
join.leftAlias = join.rightAlias;
join.leftKey = join.rightKey;
join.left = join.right;
join.rightAlias = leftAlias;
join.rightKey = leftKey;
join.right = left;
}
// Does not currently matter which is returned because currently we
// only support structures where the left and right depth values
// form an inclusive subset of depth values, that is, any
// node with a depth value between the left or right values is
// a child of this current join.
return leftDepth;
} else {
throw Util.newInternal("bad relation type " + relation);
}
}
/**
* Transforms so that all joins have a table as their left child and either
* a table of child join on the right.
*
* @param relation
*/
private static void topToBottom(MondrianDef.Relation relation) {
if (relation instanceof MondrianDef.Table) {
MondrianDef.Table table = (MondrianDef.Table) relation;
// nothing
} else if (relation instanceof MondrianDef.Join) {
MondrianDef.Join join = (MondrianDef.Join) relation;
while (join.left instanceof MondrianDef.Join) {
MondrianDef.Join jleft = (MondrianDef.Join) join.left;
MondrianDef.Relation right = join.right;
join.right = new MondrianDef.Join(
join.leftAlias,
join.leftKey,
jleft.right,
join.rightAlias,
join.rightKey,
join.right);
join.left = jleft.left;
join.rightAlias = jleft.rightAlias;
join.rightKey = jleft.rightKey;
join.leftAlias = jleft.leftAlias;
join.leftKey = jleft.leftKey;
}
}
}
/**
* Copies a {@link MondrianDef.Relation}.
*
* @param relation
* @return
*/
private static MondrianDef.Relation copy(MondrianDef.Relation relation) {
if (relation instanceof MondrianDef.Table) {
MondrianDef.Table table = (MondrianDef.Table) relation;
return new MondrianDef.Table(table);
} else if (relation instanceof MondrianDef.Join) {
MondrianDef.Join join = (MondrianDef.Join) relation;
MondrianDef.Relation left = copy(join.left);
MondrianDef.Relation right = copy(join.right);
return new MondrianDef.Join(join.leftAlias, join.leftKey, left,
join.rightAlias, join.rightKey, right);
} else {
throw Util.newInternal("bad relation type " + relation);
}
}
/**
* Takes a relation in canonical form and snips off the
* the tables with the given tableName (or table alias). The matching table
* only appears once in the relation.
*
* @param relation
* @param tableName
* @return
*/
private static MondrianDef.Relation snip(MondrianDef.Relation relation,
String tableName) {
if (relation instanceof MondrianDef.Table) {
MondrianDef.Table table = (MondrianDef.Table) relation;
// Return null if the table's name or alias matches tableName
return ((table.alias != null) && table.alias.equals(tableName))
? null
: (table.name.equals(tableName) ? null : table);
} else if (relation instanceof MondrianDef.Join) {
MondrianDef.Join join = (MondrianDef.Join) relation;
// snip left
MondrianDef.Relation left = snip(join.left, tableName);
if (left == null) {
// left got snipped so return the right
// (the join is no longer a join).
return join.right;
} else {
// whatever happened on the left, save it
join.left = left;
// snip right
MondrianDef.Relation right = snip(join.right, tableName);
if (right == null) {
// right got snipped so return the left.
return join.left;
} else {
// save the right, join still has right and left children
// so return it.
join.right = right;
return join;
}
}
} else {
throw Util.newInternal("bad relation type " + relation);
}
}
//
///////////////////////////////////////////////////////////////////////////
public Member[] getMembersForQuery(String query, List calcMembers) {
throw new UnsupportedOperationException();
}
Member[] getMeasures() {
Level measuresLevel = dimensions[0].getHierarchies()[0].getLevels()[0];
return getSchemaReader().getLevelMembers(measuresLevel);
}
/**
* Returns this cube's fact table, null if the cube is virtual.
* @return
*/
MondrianDef.Relation getFact() {
return fact;
}
/**
* Returns whether this cube is virtual. We use the fact that virtual cubes
* do not have fact tables.
**/
public boolean isVirtual() {
return (fact == null);
}
RolapDimension createDimension(MondrianDef.CubeDimension xmlCubeDimension) {
MondrianDef.Dimension xmlDimension = null;
final RolapDimension dimension;
if (xmlCubeDimension instanceof MondrianDef.Dimension) {
xmlDimension = (MondrianDef.Dimension) xmlCubeDimension;
dimension = new RolapDimension(schema, this, xmlDimension,
xmlCubeDimension);
} else if (xmlCubeDimension instanceof MondrianDef.DimensionUsage) {
final MondrianDef.DimensionUsage usage =
(MondrianDef.DimensionUsage) xmlCubeDimension;
final RolapHierarchy sharedHierarchy =
((RolapSchema) schema).getSharedHierarchy(usage.source);
if (sharedHierarchy == null) {
throw Util.newInternal("todo: Shared hierarchy '" + usage.source +
"' not found");
}
final RolapDimension sharedDimension =
(RolapDimension) sharedHierarchy.getDimension();
dimension = sharedDimension.copy(this, usage.name,
xmlCubeDimension);
} else {
throw Util.newInternal("Unexpected subtype, " + xmlCubeDimension);
}
dimension.init(this, xmlCubeDimension);
// add to dimensions array
final int localOrdinal = dimensions.length;
this.dimensions = (DimensionBase[])
RolapUtil.addElement(dimensions, dimension);
RolapHierarchy hierarchy = (RolapHierarchy) dimension.getHierarchy();
createUsage(hierarchy, xmlCubeDimension);
// add to ordinals array
final int globalOrdinal = dimension.getGlobalOrdinal();
if (globalOrdinal >= localDimensionOrdinals.length) {
int[] newLocalDimensionOrdinals = new int[globalOrdinal + 1];
System.arraycopy(localDimensionOrdinals, 0,
newLocalDimensionOrdinals, 0, localDimensionOrdinals.length);
Arrays.fill(newLocalDimensionOrdinals,
localDimensionOrdinals.length,
newLocalDimensionOrdinals.length, -1);
this.localDimensionOrdinals = newLocalDimensionOrdinals;
}
Util.assertTrue(localDimensionOrdinals[globalOrdinal] == -1);
localDimensionOrdinals[globalOrdinal] = localOrdinal;
registerDimension(dimension);
return dimension;
}
public OlapElement lookupChild(SchemaReader schemaReader, String s) {
OlapElement oe = null;
String status = null;
if (s.equals("Measures")) {
// A Measure is never aliased, so just get it
// Note if one calls getUsageByName with "Measures" as the value
// it will return null so one must either do this or check for
// a null HierarchyUsage below and disambiguate.
oe = super.lookupChild(schemaReader, s);
} else {
// At this point everything ought to have a HierarchyUsage.
//
// If one does not exist (null), then odds are one is using
// the base/source hierarchy name in a calculated measure
// for a shared hierarchy - which is not legal.
// But there are cases where its OK here not to have a
// usage, i.e., the child is a measure, member or level
//
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?