use of mondrian.rolap.aggmatcher.AggStar in project mondrian by pentaho.
the class TestAggregationManager method testAggStarWithIgnoredColumnsAndCountDistinct.
public void testAggStarWithIgnoredColumnsAndCountDistinct() {
propSaver.set(propSaver.properties.ReadAggregates, true);
propSaver.set(propSaver.properties.UseAggregates, true);
propSaver.set(propSaver.properties.GenerateFormattedSql, true);
final TestContext context = TestContext.instance().withSchema("<Schema name=\"FoodMart\">" + " <Dimension name=\"Time\" type=\"TimeDimension\">\n" + " <Hierarchy hasAll=\"false\" primaryKey=\"time_id\">\n" + " <Table name=\"time_by_day\"/>\n" + " <Level name=\"Year\" column=\"the_year\" type=\"Numeric\" uniqueMembers=\"true\"\n" + " levelType=\"TimeYears\"/>\n" + " <Level name=\"Quarter\" column=\"quarter\" uniqueMembers=\"false\"\n" + " levelType=\"TimeQuarters\"/>\n" + " </Hierarchy>\n" + " </Dimension>\n" + "<Cube name=\"Sales\" defaultMeasure=\"Unit Sales\">\n" + " <Table name=\"sales_fact_1997\">\n" + " <AggExclude name=\"agg_c_special_sales_fact_1997\" />\n" + " <AggExclude name=\"agg_lc_100_sales_fact_1997\" />\n" + " <AggExclude name=\"agg_lc_10_sales_fact_1997\" />\n" + " <AggExclude name=\"agg_pc_10_sales_fact_1997\" />\n" + " <AggName name=\"agg_g_ms_pcat_sales_fact_1997\">\n" + " <AggFactCount column=\"FACT_COUNT\"/>\n" + " <AggIgnoreColumn column=\"Quarter\"/>\n" + " <AggIgnoreColumn column=\"MONTH_OF_YEAR\"/>\n" + " <AggMeasure name=\"[Measures].[Customer Count]\" column=\"customer_count\" />\n" + " <AggLevel name=\"[Time].[Year]\" column=\"the_year\" />\n" + " </AggName>\n" + " </Table>\n" + " <DimensionUsage name=\"Time\" source=\"Time\" foreignKey=\"time_id\"/>\n" + " <Measure name=\"Unit Sales\" column=\"unit_sales\" aggregator=\"sum\"\n" + " formatString=\"Standard\"/>\n" + " <Measure name=\"Customer Count\" column=\"customer_id\" aggregator=\"distinct-count\"\n" + " formatString=\"Standard\"/>\n" + "</Cube>\n" + "</Schema>");
RolapStar star = context.getConnection().getSchemaReader().getSchema().getStar("sales_fact_1997");
AggStar aggStarSpy = spy(getAggStar(star, "agg_g_ms_pcat_sales_fact_1997"));
// make sure the test AggStar will be prioritized first
when(aggStarSpy.getSize()).thenReturn(0l);
context.getConnection().getSchemaReader().getSchema().getStar("sales_fact_1997").addAggStar(aggStarSpy);
boolean[] rollup = { false };
AggStar returnedStar = AggregationManager.findAgg(star, aggStarSpy.getLevelBitKey(), aggStarSpy.getMeasureBitKey(), rollup);
assertNull("Should not find an agg star given that ignored or unused " + "columns are present, and loading distinct count measure", returnedStar);
String sqlOra = "select\n" + " \"time_by_day\".\"the_year\" as \"c0\",\n" + " count(distinct \"sales_fact_1997\".\"customer_id\") as \"m0\"\n" + "from\n" + " \"time_by_day\" \"time_by_day\",\n" + " \"sales_fact_1997\" \"sales_fact_1997\"\n" + "where\n" + " \"sales_fact_1997\".\"time_id\" = \"time_by_day\".\"time_id\"\n" + "and\n" + " \"time_by_day\".\"the_year\" = 1997\n" + "group by\n" + " \"time_by_day\".\"the_year\"";
String sqlMysql = "select\n" + " `time_by_day`.`the_year` as `c0`,\n" + " count(distinct `sales_fact_1997`.`customer_id`) as `m0`\n" + "from\n" + " `time_by_day` as `time_by_day`,\n" + " `sales_fact_1997` as `sales_fact_1997`\n" + "where\n" + " `sales_fact_1997`.`time_id` = `time_by_day`.`time_id`\n" + "and\n" + " `time_by_day`.`the_year` = 1997\n" + "group by\n" + " `time_by_day`.`the_year`";
assertQuerySqlOrNot(context, "select Time.[1997] on 0 from sales where " + "measures.[Customer Count]", new SqlPattern[] { new SqlPattern(Dialect.DatabaseProduct.MYSQL, sqlMysql, sqlMysql.length()), new SqlPattern(Dialect.DatabaseProduct.ORACLE, sqlOra, sqlOra.length()) }, false, false, true);
}
use of mondrian.rolap.aggmatcher.AggStar in project mondrian by pentaho.
the class RolapStar method addAggStar.
/**
* Adds an {@link AggStar} to this star.
*
* <p>Internally the AggStars are added in sort order, smallest row count
* to biggest, so that the most efficient AggStar is encountered first;
* ties do not matter.
*/
public void addAggStar(AggStar aggStar) {
// Add it before the first AggStar which is larger, if there is one.
long size = aggStar.getSize();
ListIterator<AggStar> lit = aggStars.listIterator();
while (lit.hasNext()) {
AggStar as = lit.next();
if (as.getSize() >= size) {
lit.previous();
lit.add(aggStar);
return;
}
}
// There is no larger star. Add at the end of the list.
aggStars.add(aggStar);
}
use of mondrian.rolap.aggmatcher.AggStar in project mondrian by pentaho.
the class SqlConstraintUtils method joinLevelTableToFactTable.
/**
* Ensures that the table of <code>level</code> is joined to the fact
* table
*
* @param sqlQuery sql query under construction
* @param aggStar The aggStar to use, if any.
* @param e evaluator corresponding to query
* @param level level to be added to query
*/
public static void joinLevelTableToFactTable(SqlQuery sqlQuery, RolapCube baseCube, AggStar aggStar, Evaluator e, RolapCubeLevel level) {
RolapStar.Column starColumn = level.getBaseStarKeyColumn(baseCube);
if (aggStar != null) {
int bitPos = starColumn.getBitPosition();
AggStar.Table.Column aggColumn = aggStar.lookupColumn(bitPos);
AggStar.Table table = aggColumn.getTable();
table.addToFrom(sqlQuery, false, true);
} else {
RolapStar.Table table = starColumn.getTable();
assert table != null;
table.addToFrom(sqlQuery, false, true);
}
}
use of mondrian.rolap.aggmatcher.AggStar in project mondrian by pentaho.
the class SqlConstraintUtils method generateSingleValueInExpr.
/**
* Generates a multi-value IN expression corresponding to a list of
* member expressions, and adds the expression to the WHERE clause
* of a query, provided the member values are all non-null
*
* @param sqlQuery query containing the where clause
* @param baseCube base cube if virtual
* @param aggStar aggregate star if available
* @param members list of constraining members
* @param fromLevel lowest parent level that is unique
* @param restrictMemberTypes defines the behavior when calculated members
* are present
* @param exclude whether to exclude the members. Default is false.
* @param includeParentLevels whether to include IN list constraint
* for parent levels.
* @return a non-empty String if IN list was generated for the members.
*/
private static String generateSingleValueInExpr(SqlQuery sqlQuery, RolapCube baseCube, AggStar aggStar, List<RolapMember> members, RolapLevel fromLevel, boolean restrictMemberTypes, boolean exclude, boolean includeParentLevels) {
int maxConstraints = MondrianProperties.instance().MaxConstraints.get();
Dialect dialect = sqlQuery.getDialect();
String condition = "";
boolean firstLevel = true;
for (Collection<RolapMember> c = members; !c.isEmpty(); c = getUniqueParentMembers(c)) {
RolapMember m = c.iterator().next();
if (m.isAll()) {
continue;
}
if (m.isNull()) {
return "1 = 0";
}
if (m.isCalculated() && !m.isParentChildLeaf()) {
if (restrictMemberTypes) {
throw Util.newInternal("addMemberConstraint: cannot " + "restrict SQL to calculated member :" + m);
}
continue;
}
boolean containsNullKey = false;
Iterator<RolapMember> it = c.iterator();
while (it.hasNext()) {
m = it.next();
if (m.getKey() == RolapUtil.sqlNullValue) {
containsNullKey = true;
}
}
RolapLevel level = m.getLevel();
RolapHierarchy hierarchy = level.getHierarchy();
// this method can be called within the context of shared members,
// outside of the normal rolap star, therefore we need to
// check the level to see if it is a shared or cube level.
RolapStar.Column column = null;
if (level instanceof RolapCubeLevel) {
column = ((RolapCubeLevel) level).getBaseStarKeyColumn(baseCube);
}
String q;
if (column != null) {
if (aggStar != null) {
int bitPos = column.getBitPosition();
AggStar.Table.Column aggColumn = aggStar.lookupColumn(bitPos);
if (aggColumn == null) {
throw Util.newInternal("AggStar " + aggStar + " has no column for " + column + " (bitPos " + bitPos + ")");
}
AggStar.Table table = aggColumn.getTable();
table.addToFrom(sqlQuery, false, true);
q = aggColumn.generateExprString(sqlQuery);
} else {
RolapStar.Table targetTable = column.getTable();
hierarchy.addToFrom(sqlQuery, targetTable);
q = column.generateExprString(sqlQuery);
}
} else {
assert (aggStar == null);
hierarchy.addToFrom(sqlQuery, level.getKeyExp());
q = level.getKeyExp().getExpression(sqlQuery);
}
StarColumnPredicate cc = getColumnPredicates(column, c);
if (!dialect.supportsUnlimitedValueList() && cc instanceof ListColumnPredicate && ((ListColumnPredicate) cc).getPredicates().size() > maxConstraints) {
// Simply get them all, do not create where-clause.
// Below are two alternative approaches (and code). They
// both have problems.
LOG.debug(MondrianResource.instance().NativeSqlInClauseTooLarge.str(level.getUniqueName(), maxConstraints + ""));
sqlQuery.setSupported(false);
} else {
String where = RolapStar.Column.createInExpr(q, cc, level.getDatatype(), sqlQuery);
if (!where.equals("true")) {
if (!firstLevel) {
if (exclude) {
condition += " or ";
} else {
condition += " and ";
}
} else {
firstLevel = false;
}
if (exclude) {
where = "not (" + where + ")";
if (!containsNullKey) {
// Null key fails all filters so should add it here
// if not already excluded. E.g., if the original
// exclusion filter is :
//
// not(year = '1997' and quarter in ('Q1','Q3'))
//
// then with IS NULL checks added, the filter
// becomes:
//
// (not(year = '1997') or year is null) or
// (not(quarter in ('Q1','Q3')) or quarter is null)
where = "(" + where + " or " + "(" + q + " is null))";
}
}
condition += where;
}
}
if (m.getLevel().isUnique() || m.getLevel() == fromLevel || !includeParentLevels) {
// no further qualification needed
break;
}
}
return condition;
}
use of mondrian.rolap.aggmatcher.AggStar in project mondrian by pentaho.
the class SqlConstraintUtils method getLevelColumn.
/**
* Gets the column, using AggStar if available, and ensures the table is in
* the query.
*/
private static RolapStar.Column getLevelColumn(RolapLevel level, RolapCube baseCube, AggStar aggStar, SqlQuery sqlQuery) {
final RolapStar.Column column = ((RolapCubeLevel) level).getBaseStarKeyColumn(baseCube);
if (aggStar != null) {
int bitPos = column.getBitPosition();
final AggStar.Table.Column aggColumn = aggStar.lookupColumn(bitPos);
AggStar.Table table = aggColumn.getTable();
table.addToFrom(sqlQuery, false, true);
// create a delegate to use the aggregated column's expression
return new Column(aggColumn.getDatatype()) {
public String generateExprString(SqlQuery query) {
// used by predicates for sql generation
return aggColumn.generateExprString(query);
}
public int getBitPosition() {
// this is the same as the one in RolapStar.Column
return aggColumn.getBitPosition();
}
public Table getTable() {
return column.getTable();
}
public RolapStar getStar() {
return column.getStar();
}
};
} else {
column.getTable().addToFrom(sqlQuery, false, true);
return column;
}
}
Aggregations