📄 recognizer.java
字号:
if (avgAggUsage != null) {
makeMeasure(sumFactUsage, avgAggUsage);
}
if (sumAggUsage != null) {
makeMeasure(avgFactUsage, sumAggUsage);
}
}
}
}
}
/**
* Here we have the fact usage of either sum or avg and an aggregate usage
* of the opposite type. We wish to make a new aggregate usage based
* on the existing usage's column of the same type as the fact usage.
*
* @param factUsage fact usage
* @param aggSiblingUsage existing sibling usage
*/
protected void makeMeasure(final JdbcSchema.Table.Column.Usage factUsage,
final JdbcSchema.Table.Column.Usage aggSiblingUsage) {
JdbcSchema.Table.Column aggColumn = aggSiblingUsage.getColumn();
JdbcSchema.Table.Column.Usage aggUsage =
aggColumn.newUsage(JdbcSchema.MEASURE_COLUMN_USAGE);
aggUsage.setSymbolicName(factUsage.getSymbolicName());
convertAggregator(aggUsage,
factUsage.getAggregator(),
aggSiblingUsage.getAggregator());
aggUsage.rMeasure = factUsage.rMeasure;
}
/**
* This method creates an aggregate table column measure usage from a fact
* table column measure usage.
*
* @param factUsage
* @param aggColumn
*/
protected void makeMeasure(final JdbcSchema.Table.Column.Usage factUsage,
final JdbcSchema.Table.Column aggColumn) {
JdbcSchema.Table.Column.Usage aggUsage =
aggColumn.newUsage(JdbcSchema.MEASURE_COLUMN_USAGE);
aggUsage.setSymbolicName(factUsage.getSymbolicName());
convertAggregator(aggUsage, factUsage.getAggregator());
aggUsage.rMeasure = factUsage.rMeasure;
}
/**
* This method determine how may aggregate table column's match the fact
* table foreign key column return in the number matched. For each matching
* column a foreign key usage is created.
*
* @param factUsage
* @return
*/
protected abstract int matchForeignKey(JdbcSchema.Table.Column.Usage factUsage);
/**
* This method checks the foreign key columns.
* <p>
* For each foreign key column usage in the fact table, determine how many
* aggregate table columns match that column usage. If there is more than
* one match, then that is an error. If there were no matches, then the
* foreign key usage is added to the list of fact column foreign key that
* were not in the aggregate table. This list is returned by this method.
* <p>
* This matches foreign keys that were not "lost" or "collapsed".
*
* @return list on not seen foreign key column usages
*/
protected List checkForeignKeys() {
msgRecorder.pushContextName("Recognizer.checkForeignKeys");
try {
List notSeenForeignKeys = Collections.EMPTY_LIST;
for (Iterator it =
dbFactTable.getColumnUsages(JdbcSchema.FOREIGN_KEY_COLUMN_USAGE);
it.hasNext(); ) {
JdbcSchema.Table.Column.Usage factUsage =
(JdbcSchema.Table.Column.Usage) it.next();
int nosMatched = matchForeignKey(factUsage);
if (nosMatched > 1) {
String msg = mres.TooManyMatchingForeignKeyColumns.str(
aggTable.getName(),
dbFactTable.getName(),
new Integer(nosMatched),
factUsage.getColumn().getName()
);
msgRecorder.reportError(msg);
returnValue = false;
} else if (nosMatched == 0) {
if (notSeenForeignKeys == Collections.EMPTY_LIST) {
notSeenForeignKeys = new ArrayList();
}
notSeenForeignKeys.add(factUsage);
}
}
return notSeenForeignKeys;
} finally {
msgRecorder.popContextName();
}
}
/**
* This method identifies those columns in the aggregate table that match
* "collapsed" dimension columns. Remember that a collapsed dimension is one
* where the higher levels of some hierarchy are columns in the aggregate
* table (and all of the lower levels are missing - it has aggregated up to
* the first existing level).
* <p>
* Here, we do not start from the fact table, we iterator over each cube.
* For each of the cube's dimensions, the dimension's hirarchies are
* iterated over. In turn, each hierarchy's usage is iterated over.
* if the hierarchy's usage's foreign key is not in the list of not seen
* foreign keys (the notSeenForeignKeys parameter), then that hierarchy is
* not considered. If the hierarchy's usage's foreign key is in the not seen
* list, then starting with the hierarchy's top level, it is determined if
* the combination of hierarchy, hierarchy usage, and level matches an
* aggregated table column. If so, then a level usage is created for that
* column and the hierarchy's next level is considered and so on until a
* for a level an aggregate table column does not match. Then we continue
* iterating over the hierarchy usages.
* <p>
* This check is different. The others mine the fact table usages. This
* looks through the fact table's cubes' dimension, hierarchy,
* hiearchy usages, levels to match up symbolic names for levels. The other
* checks match on "physical" characteristics, the column name; this matches
* on "logical" characteristics.
* <p>
* Note: Levels should not be created for foreign keys that WERE seen.
* Currently, this is NOT checked explicitly. For the explicit rules any
* extra columns MUST ge declared ignored or one gets an error.
*
* @param notSeenForeignKeys
*/
protected void checkLevels(List notSeenForeignKeys) {
// These are the factTable that do not appear in the aggTable.
// 1) find all cubes with this given factTable
// 1) per cube, find all usages with the column as foreign key
// 2) for each usage, find dimension and its levels
// 3) determine if level columns are represented
// In generaly, there is only one cube.
for (Iterator it = findCubes(); it.hasNext(); ) {
RolapCube cube = (RolapCube) it.next();
Dimension[] dims = cube.getDimensions();
// start dimensions at 1 (0 is measures)
for (int j = 1; j < dims.length; j++) {
Dimension dim = dims[j];
// Ok, got dimension.
// See if any of the levels exist as columns in the
// aggTable. This requires applying a map from:
// hierarchyName
// levelName
// levelColumnName
// to each "unassigned" column in the aggTable.
// Remember that the rule is if a level does appear,
// then all of the higher levels must also appear.
String dimName = dim.getName();
Hierarchy[] hierarchies = dim.getHierarchies();
for (int k = 0; k < hierarchies.length; k++) {
Hierarchy hierarchy = hierarchies[k];
HierarchyUsage[] hierarchyUsages =
cube.getUsages(hierarchy);
for (int m = 0; m < hierarchyUsages.length; m++) {
HierarchyUsage hierarchyUsage = hierarchyUsages[m];
// Search through the notSeenForeignKeys list
// making sure that this HierarchyUsage's
// foreign key is not in the list.
String foreignKey = hierarchyUsage.getForeignKey();
boolean b = inNotSeenForeignKeys(foreignKey,
notSeenForeignKeys);
if (! b) {
// It was not in the not seen list, so ignore
continue;
}
RolapLevel[] levels =
(RolapLevel[]) hierarchy.getLevels();
// If the top level is seen, then one or more
// lower levels may appear but there can be no
// missing levels between the top level and
// lowest level seen.
// On the other hand, if the top level is not
// seen, then no other levels should be present.
mid_level:
for (int n = 0; n < levels.length; n++) {
RolapLevel level = levels[n];
if (level.isAll()) {
continue mid_level;
}
if (matchLevel(hierarchy, hierarchyUsage, level)) {
continue mid_level;
} else {
// There were no matches, break
// For now, do not check lower levels
break mid_level;
}
}
}
}
}
}
}
/**
* Return true if the foreignKey column name is in the list of not seen
* foreign keys.
*
* @param foreignKey
* @param notSeenForeignKeys
* @return
*/
boolean inNotSeenForeignKeys(String foreignKey, List notSeenForeignKeys) {
for (Iterator it = notSeenForeignKeys.iterator(); it.hasNext(); ) {
JdbcSchema.Table.Column.Usage usage =
(JdbcSchema.Table.Column.Usage) it.next();
if (usage.getColumn().getName().equals(foreignKey)) {
return true;
}
}
return false;
}
/**
* Debug method: Print out not seen foreign key list.
*
* @param notSeenForeignKeys
*/
private void printNotSeenForeignKeys(List notSeenForeignKeys) {
LOGGER.debug("Recognizer.printNotSeenForeignKeys: "
+ aggTable.getName());
for (Iterator it = notSeenForeignKeys.iterator(); it.hasNext(); ) {
JdbcSchema.Table.Column.Usage usage =
(JdbcSchema.Table.Column.Usage) it.next();
LOGGER.debug(" " + usage.getColumn().getName());
}
}
/**
* Here a measure ussage is created and the right join condition is
* explicitly supplied. This is needed is when the aggregate table's column
* names may not match those found in the RolapStar.
*
* @param factUsage
* @param aggColumn
* @param rightJoinConditionColumnName
*/
protected void makeForeignKey(final JdbcSchema.Table.Column.Usage factUsage,
final JdbcSchema.Table.Column aggColumn,
final String rightJoinConditionColumnName) {
JdbcSchema.Table.Column.Usage aggUsage =
aggColumn.newUsage(JdbcSchema.FOREIGN_KEY_COLUMN_USAGE);
aggUsage.setSymbolicName("FOREIGN_KEY");
// Extract from RolapStar enough stuff to build
// AggStar subtable except the column name of the right join
// condition might be different
aggUsage.rTable = factUsage.rTable;
aggUsage.rightJoinConditionColumnName = rightJoinConditionColumnName;
aggUsage.rColumn = factUsage.rColumn;
}
/**
* Match a aggregate table column given the hierarchy, hierarchy usage, and
* rolap level returning true if a match is found.
*
* @param hierarchy
* @param hierarchyUsage
* @param level
* @return
*/
protected abstract boolean matchLevel(final Hierarchy hierarchy,
final HierarchyUsage hierarchyUsage,
final RolapLevel level);
/**
* Make a level column usage.
* <p>
* Note there is a check in this code. If a given aggregate table column has
* already has a level usage, then that usage must all refer to the same
* hierarchy usage join table and column name as the one that calling this
* method was to create. If there is an existing level usage for the
* column and it matches something else, then it is an error.
*
* @param aggColumn
* @param hierarchy
* @param hierarchyUsage
* @param factColumnName
* @param levelColumnName
* @param symbolicName
*/
protected void makeLevel(final JdbcSchema.Table.Column aggColumn,
final Hierarchy hierarchy,
final HierarchyUsage hierarchyUsage,
final String factColumnName,
final String levelColumnName,
final String symbolicName) {
msgRecorder.pushContextName("Recognizer.makeLevel");
try {
if (aggColumn.hasUsage(JdbcSchema.LEVEL_COLUMN_USAGE)) {
// The column has at least one usage of level type
// make sure we are looking at the
// same table and column
for (Iterator uit =
aggColumn.getUsages(JdbcSchema.LEVEL_COLUMN_USAGE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -