rolapstar.java

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

JAVA
1,660
字号
/*
// $Id: //open/mondrian/src/main/mondrian/rolap/RolapStar.java#43 $
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// Copyright (C) 2001-2005 Kana Software, Inc. and others.
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
//
// jhyde, 12 August, 2001
*/

package mondrian.rolap;
import mondrian.olap.*;
import mondrian.rolap.agg.Aggregation;
import mondrian.rolap.agg.CellRequest;
import mondrian.rolap.agg.ColumnConstraint;
import mondrian.rolap.aggmatcher.AggStar;
import mondrian.rolap.sql.SqlQuery;
import mondrian.resource.MondrianResource;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.eigenbase.util.property.*;
import org.eigenbase.util.property.Property;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.DatabaseMetaData;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.HashMap;
import java.util.Collections;

/**
 * A <code>RolapStar</code> is a star schema. It is the means to read cell
 * values.
 *
 * <p>todo: put this in package which specicializes in relational aggregation,
 * doesn't know anything about hierarchies etc.
 *
 * @author jhyde
 * @since 12 August, 2001
 * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapStar.java#43 $
 **/
public class RolapStar {

    /**
      * This static variable controls the aggregate data cache for all
      * RolapStars. An administrator or tester might selectively enable or
      * disable in memory caching to allow direct measurement of database
      * performance.
      */
    private static boolean disableCaching =
             MondrianProperties.instance().DisableCaching.get();

    static {
        // Trigger is used to lookup and change the value of the
        // variable that controls aggregate data caching
        // Using a trigger means we don't have to look up the property eveytime.
        MondrianProperties.instance().DisableCaching.addTrigger(
                new TriggerBase(true) {
                    public void execute(Property property, String value) {
                        disableCaching = property.booleanValue();
                        // must flush all caches
                        if (disableCaching) {
                            RolapSchema.flushAllRolapStarCaches();
                        }
                    }
                }
        );
    }


    private final RolapSchema schema;

    // not final for test purposes
    private DataSource dataSource;

    private final Table factTable;
    /**
     * Maps {@link RolapCube} to a {@link HashMap} which maps
     * {@link RolapLevel} to {@link Column}. The double indirection is
     * necessary because in different cubes, a shared hierarchy might be joined
     * onto the fact table at different levels.
     */
    private final Map mapCubeToMapLevelToColumn;

    /** holds all aggregations of this star */
    private Map aggregations;

    /** how many columns (column and columnName) there are */
    private int columnCount;

    private final SqlQuery.Dialect sqlQueryDialect;

    /**
     * If true, then database aggregation information is cached, otherwise
     * it is flushed after each query.
     */
    private boolean cacheAggregations;

    /**
     * Partially ordered list of AggStars associated with this RolapStar's fact
     * table
     */
    private List aggStars;

    /**
     * Creates a RolapStar. Please use
     * {@link RolapSchema.RolapStarRegistry#getOrCreateStar} to create a
     * {@link RolapStar}.
     */
    RolapStar(final RolapSchema schema,
              final DataSource dataSource,
              final MondrianDef.Relation fact) {
        this.cacheAggregations = true;
        this.schema = schema;
        this.dataSource = dataSource;
        this.factTable = new RolapStar.Table(this, fact, null, null);

        this.mapCubeToMapLevelToColumn = new HashMap();
        this.aggregations = new HashMap();

        clearAggStarList();

        sqlQueryDialect = makeSqlQueryDialect();
    }

    /**
     * The the RolapStar's column count. After a star has been created with all
     * of its columns, this is the number of columns in the star.
     *
     * @return
     */
    public int getColumnCount() {
        return columnCount;
    }

    /**
     * This is used by the {@link Column} constructor to get a unique id (per
     * its parent {@link RolapStar}).
     *
     * @return
     */
    private int nextColumnCount() {
        return columnCount++;
    }

    /**
     * This is used to decrement the column counter and is used if a newly
     * created column is found to already exist.
     *
     * @return
     */
    private int decrementColumnCount() {
        return columnCount--;
    }

    /**
     * This is a place holder in case in the future we wish to be able to
     * reload aggregates. In that case, if aggregates had already been loaded,
     * i.e., this star has some aggstars, then those aggstars are cleared.
     */
    public void prepareToLoadAggregates() {
        aggStars = Collections.EMPTY_LIST;
    }

    /**
     * Internally the AggStars are added in sort order, smallest row count
     * to biggest where ties do not matter.
     *
     * @param aggStar
     */
    public void addAggStar(AggStar aggStar) {
        if (aggStars == Collections.EMPTY_LIST) {
            // if this is NOT a LinkedList, then the insertion time is longer.
            aggStars = new LinkedList();
            aggStars.add(aggStar);

        } else {
            // size
            int size = aggStar.getSize();
            ListIterator lit = aggStars.listIterator();
            while (lit.hasNext()) {
                AggStar as = (AggStar) lit.next();
                if (as.getSize() >= size) {
                    break;
                }
            }
            lit.previous();
            lit.add(aggStar);
        }
    }

    /**
     * Set the agg star list to empty.
     */
    void clearAggStarList() {
        aggStars = Collections.EMPTY_LIST;
    }

    /**
     * Reorder the list of aggregate stars. This should be called if the
     * algorithm used to order the AggStars has been changed.
     */
    public void reOrderAggStarList() {
        // the order of these two lines is important
        List l = aggStars;
        clearAggStarList();

        for (Iterator it = l.iterator(); it.hasNext(); ) {
            AggStar aggStar = (AggStar) it.next();
            addAggStar(aggStar);
        }
    }

    /**
     * Returns the AggStar with the lowest row count or volume whose bit key
     * is a super set of the bitKey parameter.
     *
     * @param bitKey Bit key to match
     * @param exact Whether an exact match is required; if not, AggStar can
     *   be a superset
     * @return An AggStar, or null if none matches
     */
    public AggStar select(BitKey bitKey, boolean exact) {
        for (Iterator it = getAggStars(); it.hasNext(); ){
            AggStar aggStar = (AggStar) it.next();
            if (aggStar.matches(bitKey, exact)) {
                return aggStar;
            }
        }
        return null;
    }

    /**
     * Get Iterator of this RolapStar's aggregate table AggStars.
     *
     * @return
     */
    public Iterator getAggStars() {
        return aggStars.iterator();
    }
    public Table getFactTable() {
        return factTable;
    }

    /**
     * Clone an existing SqlQuery to create a new one (this cloning creates one
     * with an empty sql query).
     *
     * @return
     */
    public SqlQuery getSqlQuery() {
        return new SqlQuery(getSqlQueryDialect());
    }

    /**
     * Get this RolapStar's RolapSchema's Sql Dialect.
     *
     * @return
     */
    public SqlQuery.Dialect getSqlQueryDialect() {
        return sqlQueryDialect;
    }

    /**
     * Make an SqlQuery from a jdbc connection.
     *
     * @return
     */
    private SqlQuery.Dialect makeSqlQueryDialect() {
        Connection conn = getJdbcConnection();
        try {
            return SqlQuery.Dialect.create(conn.getMetaData());
        } catch (SQLException e) {
            throw Util.newInternal(
                e, "Error while creating SqlQuery from connection");
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                //ignore
            }
        }
    }

    /**
     * This maps a cube to a Map of level to colunms. Now the only reason
     * the star needs to map via a cube is that more than one cube can
     * share the same star.
     *
     * @param cube
     * @return
     */
    Map getMapLevelToColumn(RolapCube cube) {
        Map mapLevelToColumn = (Map) this.mapCubeToMapLevelToColumn.get(cube);
        if (mapLevelToColumn == null) {
            mapLevelToColumn = new HashMap();
            this.mapCubeToMapLevelToColumn.put(cube, mapLevelToColumn);
        }
        return mapLevelToColumn;
    }


    /**
     * This is called only by the RolapCube and is only called if caching is to
     * be turned off. Note that the same RolapStar can be associated with more
     * than on RolapCube. If any one of those cubes has caching turned off, then
     * caching is turned off for all of them.
     *
     * @param b
     */
    void setCacheAggregations(boolean b) {
        // this can only change from true to false
        this.cacheAggregations = b;
        clearCache();
    }

    /**
     * Does the RolapStar cache aggregates.
     *
     * @return
     */
    boolean isCacheAggregations() {
        return this.cacheAggregations;
    }

    /**
     * Clear the aggregate cache. This only does something if this star has
     * caching set to off.
     */
    void clearCache() {
        if (! this.cacheAggregations || RolapStar.disableCaching) {
            aggregations.clear();
        }
    }

    /**
     * Looks up an aggregation or creates one if it does not exist in an
     * atomic (synchronized) operation
     *
     * @param bitKey
     * @return
     */
    public Aggregation lookupOrCreateAggregation(final BitKey bitKey) {
        synchronized(aggregations) {
            Aggregation aggregation = lookupAggregation(bitKey);
            if (aggregation == null) {
                aggregation = new Aggregation(this, bitKey);
                this.aggregations.put(bitKey, aggregation);
            }
            return aggregation;
        }
    }

    /**
     * Looks for an existing aggregation over a given set of columns, or
     * returns <code>null</code> if there is none.
     * <p>Must be called from synchronized context.
     *
     * @param bitKey
     * @return
     */
    public Aggregation lookupAggregation(BitKey bitKey) {
        synchronized(aggregations) {
            return (Aggregation) aggregations.get(bitKey);
        }
    }

    /**
     * Allocates a connection to the underlying RDBMS.
     *
     * <p>The client MUST close connection returned by this method; use the
     * <code>try ... finally</code> idiom to be sure of this.
     */
    public Connection getJdbcConnection() {
        Connection jdbcConnection;
        try {
            jdbcConnection = dataSource.getConnection();
        } catch (SQLException e) {
            throw Util.newInternal(
                e, "Error while creating connection from data source");
        }
        return jdbcConnection;
    }

    /** For testing purposes only.  **/
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * Retrieves the {@link RolapStar.Measure} in which a measure is stored.
     */
    public static Measure getStarMeasure(Member member) {
        return (Measure) ((RolapStoredMeasure) member).getStarMeasure();
    }

    /**
     * Retrieves a named column, returns null if not found.
     */

⌨️ 快捷键说明

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