rolapstar.java

来自「数据仓库展示程序」· Java 代码 · 共 1,660 行 · 第 1/4 页

JAVA
1,660
字号
    public Column[] lookupColumns(String tableAlias, String columnName) {
        final Table table = factTable.findDescendant(tableAlias);
        return (table == null) ? null : table.lookupColumns(columnName);
    }

    public Column[] lookupColumns(BitKey bitKey) {
        List list = new ArrayList();
        factTable.loadColumns(bitKey, list);
        return (Column[]) list.toArray(new Column[0]);
    }

    /**
     * This is used by TestAggregationManager only
     *
     * @param tableAlias
     * @param columnName
     * @return
     */
    public Column lookupColumn(String tableAlias, String columnName) {
        final Table table = factTable.findDescendant(tableAlias);
        return (table == null) ? null : table.lookupColumn(columnName);
    }

    /**
     * Returns a list of all aliases used in this star.
     */
    public List getAliasList() {
        List aliasList = new ArrayList();
        if (factTable != null) {
            collectAliases(aliasList, factTable);
        }
        return aliasList;
    }

    /**
     * Finds all of the table aliases in a table and its children.
     */
    private static void collectAliases(List aliasList, Table table) {
        aliasList.add(table.getAlias());
        for (int i = 0; i < table.children.size(); i++) {
            Table child = (Table) table.children.get(i);
            collectAliases(aliasList, child);
        }
    }


    /**
     * Reads a cell of <code>measure</code>, where <code>columns</code> are
     * constrained to <code>values</code>.  <code>values</code> must be the
     * same length as <code>columns</code>; null values are left unconstrained.
     **/
    Object getCell(CellRequest request) {
        Connection jdbcConnection = getJdbcConnection();
        try {
            return getCell(request, jdbcConnection);
        } finally {
            try {
                jdbcConnection.close();
            } catch (SQLException e) {
                //ignore
            }
        }
    }

    private Object getCell(CellRequest request, Connection jdbcConnection) {
        Measure measure = request.getMeasure();
        Column[] columns = request.getColumns();
        Object[] values = request.getSingleValues();
        Util.assertTrue(columns.length == values.length);
        SqlQuery sqlQuery = getSqlQuery();
        // add measure
        Util.assertTrue(measure.getTable() == factTable);
        factTable.addToFrom(sqlQuery, true, true);
        sqlQuery.addSelect(
            measure.aggregator.getExpression(measure.getExpression(sqlQuery)));
        // add constraining dimensions
        for (int i = 0; i < columns.length; i++) {
            Object value = values[i];
            if (value == null) {
                continue; // not constrained
            }
            Column column = columns[i];
            Table table = column.getTable();
            if (table.isFunky()) {
                // this is a funky dimension -- ignore for now
                continue;
            }
            table.addToFrom(sqlQuery, true, true);
        }
        String sql = sqlQuery.toString();
        ResultSet resultSet = null;
        try {
            resultSet = RolapUtil.executeQuery(
                    jdbcConnection, sql, "RolapStar.getCell");
            Object o = null;
            if (resultSet.next()) {
                o = resultSet.getObject(1);
            }
            if (o == null) {
                o = Util.nullValue; // convert to placeholder
            }
            return o;
        } catch (SQLException e) {
            throw Util.newInternal(e,
                    "while computing single cell; sql=[" + sql + "]");
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.getStatement().close();
                    resultSet.close();
                }
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    private boolean containsColumn(String tableName, String columnName) {
        final Connection jdbcConnection = getJdbcConnection();
        try {
            final DatabaseMetaData metaData = jdbcConnection.getMetaData();
            final ResultSet columns =
                metaData.getColumns(null, null, tableName, columnName);
            final boolean hasNext = columns.next();
            return hasNext;
        } catch (SQLException e) {
            throw Util.newInternal("Error while retrieving metadata for table '" +
                            tableName + "', column '" + columnName + "'");
        } finally {
            try {
                jdbcConnection.close();
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    public RolapSchema getSchema() {
        return schema;
    }

    public String toString() {
        StringWriter sw = new StringWriter(256);
        PrintWriter pw = new PrintWriter(sw);
        print(pw, "");
        pw.flush();
        return sw.toString();
    }

    public void print(PrintWriter pw, String prefix) {
        pw.print(prefix);
        pw.println("RolapStar:");
        String subprefix = prefix + "  ";
        factTable.print(pw, subprefix);

        for (Iterator it = getAggStars(); it.hasNext(); ) {
            AggStar aggStar = (AggStar) it.next();
            aggStar.print(pw, subprefix);
        }
    }

    /**
     * A column in a star schema.
     */
    public static class Column {
        private final Table table;
        private final MondrianDef.Expression expression;
        private final boolean isNumeric;
        private final String name;
        /**
         * When a Column is a column, and not a Measure, the parent column
         * is the coloumn associated with next highest Level.
         */
        private final Column parentColumn;

        /**
         * This is used during both aggregate table recognition and aggregate
         * table generation. For multiple dimension usages or multiple shared
         * dimension with the same column names, this is used to disambiguate
         * aggregate column names.
         */
        private final String usagePrefix;
        /**
         * This is only used in RolapAggregationManager and adds
         * non-constraining columns making the drill-through queries easier for
         * humans to understand.
         */
        private final Column nameColumn;
        private boolean isNameColumn;

        /** this has a unique value per star */
        private final int bitPosition;

        private int cardinality = -1;

        private Column(String name,
                       Table table,
                       MondrianDef.Expression expression,
                       boolean isNumeric) {
            this(name, table, expression, isNumeric, null, null, null);
        }
        private Column(String name,
                       Table table,
                       MondrianDef.Expression expression,
                       boolean isNumeric,
                       Column nameColumn,
                       Column parentColumn,
                       String usagePrefix
                       ) {
            this.name = name;
            this.table = table;
            this.expression = expression;
            this.isNumeric = isNumeric;
            this.bitPosition = table.star.nextColumnCount();
            this.nameColumn = nameColumn;
            this.parentColumn = parentColumn;
            this.usagePrefix = usagePrefix;
            if (nameColumn != null) {
                nameColumn.isNameColumn = true;
            }
        }

        public boolean equals(Object obj) {
            if (! (obj instanceof RolapStar.Column)) {
                return false;
            }
            RolapStar.Column other = (RolapStar.Column) obj;
            // Note: both columns have to be from the same table
            return (other.table == this.table) &&
                   other.expression.equals(this.expression) &&
                   (other.isNumeric == this.isNumeric) &&
                   other.name.equals(this.name);
        }

        public String getName() {
            return name;
        }
        public boolean isNumeric() {
            return isNumeric;
        }
        public int getBitPosition() {
            return bitPosition;
        }

        public RolapStar getStar() {
            return table.star;
        }

        public RolapStar.Table getTable() {
            return table;
        }
        public SqlQuery getSqlQuery() {
            return getTable().getStar().getSqlQuery();
        }
        public RolapStar.Column getNameColumn() {
            return nameColumn;
        }
        public RolapStar.Column getParentColumn() {
            return parentColumn;
        }
        public String getUsagePrefix() {
            return usagePrefix;
        }
        public boolean isNameColumn() {
            return isNameColumn;
        }

        public MondrianDef.Expression getExpression() {
            return expression;
        }

        public String getExpression(SqlQuery query) {
            return expression.getExpression(query);
        }

        private static void quoteValue(
                Object o,
                StringBuffer buf,
                boolean isNumeric) {
            String s = o.toString();
            if (isNumeric) {
                buf.append(s);
            } else {
                if (s == null) {
                    buf.append("NULL");
                } else {
                    Util.singleQuoteString(s, buf);
                }
            }
        }

        public int getCardinality() {
            if (cardinality == -1) {
                Connection jdbcConnection = getStar().getJdbcConnection();
                try {
                    cardinality = getCardinality(jdbcConnection);
                } finally {
                    try {
                        jdbcConnection.close();
                    } catch (SQLException e) {
                        //ignore
                    }
                }
            }
            return cardinality;
        }

        private int getCardinality(Connection jdbcConnection) {
            SqlQuery sqlQuery = getSqlQuery();
            if (sqlQuery.getDialect().allowsCountDistinct()) {
                // e.g. "select count(distinct product_id) from product"
                sqlQuery.addSelect("count(distinct "
                    + getExpression(sqlQuery) + ")");

                // no need to join fact table here
                table.addToFrom(sqlQuery, true, false);
            } else if (sqlQuery.getDialect().allowsFromQuery()) {
                // Some databases (e.g. Access) don't like 'count(distinct)',
                // so use, e.g., "select count(*) from (select distinct
                // product_id from product)"
                SqlQuery inner = sqlQuery.cloneEmpty();
                inner.setDistinct(true);
                inner.addSelect(getExpression(inner));
                boolean failIfExists = true,
                    joinToParent = false;
                table.addToFrom(inner, failIfExists, joinToParent);
                sqlQuery.addSelect("count(*)");
                sqlQuery.addFrom(inner, "init", failIfExists);
            } else {
                throw Util.newInternal("Cannot compute cardinality: this " +
                    "database neither supports COUNT DISTINCT nor SELECT in " +
                    "the FROM clause.");
            }
            String sql = sqlQuery.toString();
            ResultSet resultSet = null;
            try {
                resultSet = RolapUtil.executeQuery(
                        jdbcConnection, sql,
                        "RolapStar.Column.getCardinality");
                Util.assertTrue(resultSet.next());
                return resultSet.getInt(1);
            } catch (SQLException e) {
                throw Util.newInternal(e,
                        "while counting distinct values of column '" +
                        expression.getGenericExpression() +
                        "'; sql=[" + sql + "]");
            } finally {
                try {
                    if (resultSet != null) {
                        resultSet.getStatement().close();
                        resultSet.close();
                    }
                } catch (SQLException e) {
                    // ignore
                }
            }
        }

        /**
         * Generates a predicate that a column matches one of a list of values.
         *
         * <p>
         * Several possible outputs, depending upon whether the there are
         * nulls:<ul>
         *
         * <li>One not-null value: <code>foo.bar = 1</code>
         *
         * <li>All values not null: <code>foo.bar in (1, 2, 3)</code></li
         *
         * <li>Null and not null values:
         * <code>(foo.bar is null or foo.bar in (1, 2))</code></li>
         *
         * <li>Only null values:
         * <code>foo.bar is null</code></li>
         *
         * <li>String values: <code>foo.bar in ('a', 'b', 'c')</code></li></ul>
         */
        public static String createInExpr(
                String expr,
                ColumnConstraint[] constraints,
                boolean isNumeric) {
            if (constraints.length == 1) {
                final ColumnConstraint constraint = constraints[0];
                Object key = constraint.getValue();
                if (key != RolapUtil.sqlNullValue) {
                    StringBuffer buf = new StringBuffer(64);
                    buf.append(expr);
                    buf.append(" = ");
                    quoteValue(key, buf, isNumeric);
                    return buf.toString();
                }
            }
            int notNullCount = 0;
            StringBuffer sb = new StringBuffer(expr);
            sb.append(" in (");
            for (int i = 0; i < constraints.length; i++) {
                final ColumnConstraint constraint = constraints[i];
                Object key = constraint.getValue();
                if (key == RolapUtil.sqlNullValue) {
                    continue;
                }
                if (notNullCount > 0) {
                    sb.append(", ");
                }
                ++notNullCount;
                quoteValue(key, sb, isNumeric);
            }
            sb.append(')');
            if (notNullCount < constraints.length) {
                // There was at least one null.
                StringBuffer buf;
                switch (notNullCount) {
                case 0:
                    // Special case -- there were no values besides null.
                    // Return, for example, "x is null".

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?