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 + -
显示快捷键?