rolapcube.java
来自「数据仓库展示程序」· Java 代码 · 共 1,687 行 · 第 1/5 页
JAVA
1,687 行
}
}
// cube and dimension usage are in different tables
if (!relation.equals(table.getRelation())) {
// HierarchyUsage should have checked this.
if (hierarchyUsage.getForeignKey() == null) {
throw MondrianResource.instance()
.HierarchyMustHaveForeignKey.ex(
hierarchy.getName(), getName());
}
// jhyde: check is disabled until we handle <View> correctly
if (false &&
!star.getFactTable().containsColumn(hierarchyUsage.getForeignKey())) {
throw MondrianResource.instance()
.HierarchyInvalidForeignKey.ex(
hierarchyUsage.getForeignKey(),
hierarchy.getName(),
getName());
}
// parameters:
// fact table,
// fact table foreign key,
MondrianDef.Column column =
new MondrianDef.Column(table.getAlias(),
hierarchyUsage.getForeignKey());
// parameters:
// left column
// right column
RolapStar.Condition joinCondition =
new RolapStar.Condition(column,
hierarchyUsage.getJoinExp());
table = table.addJoin(relation, joinCondition);
}
// The parent Column is used so that non-shared dimensions
// which use the fact table (not a separate dimension table)
// can keep a record of what other columns are in the
// same set of levels.
RolapStar.Column parentColumn = null;
//RME
// If the level name is not null, then we need only register
// those columns for that level and above.
if (levelName != null) {
for (int l = 0; l < levels.length; l++) {
RolapLevel level = levels[l];
if (level.getKeyExp() != null) {
parentColumn = makeColumns(table,
level, parentColumn, usagePrefix);
}
if (levelName.equals(level.getName())) {
break;
}
}
} else {
// This is the normal case, no level attribute so register
// all columns.
for (int l = 0; l < levels.length; l++) {
RolapLevel level = levels[l];
if (level.getKeyExp() != null) {
parentColumn = makeColumns(table,
level, parentColumn, usagePrefix);
}
}
}
}
}
}
/**
* Adds a column to the appropriate table in the {@link RolapStar}.
* Note that if the RolapLevel has a table attribute, then the associated
* column needs to be associated with that table.
*
* @param table
* @param level
* @param parentColumn
* @param usagePrefix
* @return
*/
protected RolapStar.Column makeColumns(
RolapStar.Table table,
RolapLevel level,
RolapStar.Column parentColumn,
String usagePrefix) {
// If there is a table name, then first see if the table name is the
// table parameter's name or alias and, if so, simply add the column
// to that table. On the other hand, find the ancestor of the table
// parameter and if found, then associate the new column with
// that table.
// Lastly, if the ancestor can not be found, i.e., there is no table
// with the level's table name, what to do. Here we simply punt and
// associated the new column with the table parameter which might
// be an error. We do issue a warning in any case.
String tableName = level.getTableName();
if (tableName != null) {
if (table.getAlias().equals(tableName)) {
parentColumn = table.makeColumns(this, level,
parentColumn, usagePrefix);
} else if (table.equalsTableName(tableName)) {
parentColumn = table.makeColumns(this, level,
parentColumn, usagePrefix);
} else {
RolapStar.Table t = table.findAncestor(tableName);
if (t != null) {
parentColumn = t.makeColumns(this, level,
parentColumn, usagePrefix);
} else {
// Issue warning and keep going.
StringBuffer buf = new StringBuffer(64);
buf.append("RolapCube.makeColumns: for cube \"");
buf.append(getName());
buf.append("\" the Level \"");
buf.append(level.getName());
buf.append("\" has a table name attribute \"");
buf.append(tableName);
buf.append("\" but the associated RolapStar does not");
buf.append(" have a table with that name.");
getLogger().warn(buf.toString());
parentColumn = table.makeColumns(this, level,
parentColumn, usagePrefix);
}
}
} else {
// level's expr is not a MondrianDef.Column (this is used by tests)
// or there is no table name defined
parentColumn = table.makeColumns(this, level,
parentColumn, usagePrefix);
}
return parentColumn;
}
///////////////////////////////////////////////////////////////////////////
//
// The following code deals with handling the DimensionUsage level attribute
// and snowflake dimensions only.
//
/**
* Formats a {@link MondrianDef.Relation} indenting joins for
* readability.
*
* @param relation
* @return
*/
private static String format(MondrianDef.Relation relation) {
StringBuffer buf = new StringBuffer();
format(relation, buf, "");
return buf.toString();
}
private static void format(
MondrianDef.Relation relation,
StringBuffer buf, String indent) {
if (relation instanceof MondrianDef.Table) {
MondrianDef.Table table = (MondrianDef.Table) relation;
buf.append(indent);
buf.append(table.name);
if (table.alias != null) {
buf.append('(');
buf.append(table.alias);
buf.append(')');
}
buf.append(Util.nl);
} else {
MondrianDef.Join join = (MondrianDef.Join) relation;
String subindent = indent + " ";
buf.append(indent);
//buf.append(join.leftAlias);
buf.append(join.getLeftAlias());
buf.append('.');
buf.append(join.leftKey);
buf.append('=');
buf.append(join.getRightAlias());
//buf.append(join.rightAlias);
buf.append('.');
buf.append(join.rightKey);
buf.append(Util.nl);
format(join.left, buf, subindent);
format(join.right, buf, indent);
}
}
/**
* This class is used to associate a MondrianDef.Table with its associated
* level's depth. This is used to rank tables in a snowflake so that
* the table with the lowest rank, level depth, is furthest from
* the base fact table in the RolapStar.
*
*/
private static class RelNode {
/**
* Find a RelNode by table name or, if that fails, by table alias
* from a map of RelNodes.
*
* @param table
* @param map
* @return
*/
private static RelNode lookup(MondrianDef.Table table, Map map) {
RelNode relNode = (RelNode) map.get(table.name);
if ((relNode == null) && (table.alias != null)) {
relNode = (RelNode) map.get(table.alias);
}
return relNode;
}
private int depth;
private String alias;
private MondrianDef.Table table;
RelNode(String alias, int depth) {
this.alias = alias;
this.depth = depth;
}
}
/**
* Attempts to transform a {@link MondrianDef.Relation}
* into the "canonical" form.
*
* <p>What is the canonical form? It is only relevant
* when the relation is a snowflake (nested joins), not simply a table.
* The canonical form has lower levels to the left of higher levels (Day
* before Month before Quarter before Year) and the nested joins are always
* on the right side of the parent join.
*
* <p>The canonical form is (using a Time dimension example):
* <pre>
* |
* ----------------
* | |
* Day --------------
* | |
* Month ---------
* | |
* Quarter Year
* </pre>
* <p>
* When the relation looks like the above, then the fact table joins to the
* lowest level table (the Day table) which joins to the next level (the
* Month table) which joins to the next (the Quarter table) which joins to
* the top level table (the Year table).
* <p>
* This method supports the transformation of a subset of all possible
* join/table relation trees (and anyone who whats to generalize it is
* welcome to). It will take any of the following and convert them to
* the canonical.
* <pre>
* |
* ----------------
* | |
* Year --------------
* | |
* Quarter ---------
* | |
* Month Day
*
* |
* ----------------
* | |
* -------------- Year
* | |
* --------- Quarter
* | |
* Day Month
*
* |
* ----------------
* | |
* -------------- Day
* | |
* --------- Month
* | |
* Year Quarter
*
* |
* ----------------
* | |
* Day --------------
* | |
* Month ---------
* | |
* Quarter Year
*
* </pre>
* <p>
* In addition, at any join node, it can exchange the left and right
* child relations so that the lower level depth is to the left.
* For example, it can also transform the following:
* <pre>
* |
* ----------------
* | |
* -------------- Day
* | |
* Month ---------
* | |
* Year Quarter
* </pre>
* <p>
* What it can not handle are cases where on both the left and right side of
* a join there are child joins:
* <pre>
* |
* ----------------
* | |
* --------- ----------
* | | | |
* Month Day Year Quarter
*
* |
* ----------------
* | |
* --------- ----------
* | | | |
* Year Day Month Quarter
* </pre>
* <p>
* When does this method do nothing? 1) when there are less than 2 levels,
* 2) when any level does not have a table name, and 3) when for every table
* in the relation there is not a level. In these cases, this method simply
* return the original relation.
*
* @param relation
* @param levels
* @return
*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?