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