use of mondrian.rolap.RolapStar.Table in project mondrian by pentaho.
the class SqlConstraintUtils method getColumnExpr.
/**
* Get the column expression from the AggStar if provided or the regular
* table if not, and ensure table is in From
*/
public static String getColumnExpr(SqlQuery sqlQuery, AggStar aggStar, RolapStar.Column column) {
final String expr;
if (aggStar != null) {
int bitPos = column.getBitPosition();
AggStar.Table.Column aggColumn = aggStar.lookupColumn(bitPos);
AggStar.Table table = aggColumn.getTable();
table.addToFrom(sqlQuery, false, true);
expr = aggColumn.generateExprString(sqlQuery);
} else {
RolapStar.Table table = column.getTable();
table.addToFrom(sqlQuery, false, true);
expr = column.generateExprString(sqlQuery);
}
return expr;
}
use of mondrian.rolap.RolapStar.Table in project mondrian by pentaho.
the class SqlConstraintUtils method constrainMultiLevelMembers.
/**
* Adds to the where clause of a query expression matching a specified
* list of members
*
* @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.
*
* @return a non-empty String if SQL is generated for the multi-level
* member list.
*/
private static String constrainMultiLevelMembers(SqlQuery sqlQuery, RolapCube baseCube, AggStar aggStar, List<RolapMember> members, RolapLevel fromLevel, boolean restrictMemberTypes, boolean exclude) {
// Use LinkedHashMap so that keySet() is deterministic.
Map<RolapMember, List<RolapMember>> parentChildrenMap = new LinkedHashMap<RolapMember, List<RolapMember>>();
StringBuilder condition = new StringBuilder();
StringBuilder condition1 = new StringBuilder();
if (exclude) {
condition.append("not (");
}
// First try to generate IN list for all members
if (sqlQuery.getDialect().supportsMultiValueInExpr()) {
condition1.append(generateMultiValueInExpr(sqlQuery, baseCube, aggStar, members, fromLevel, restrictMemberTypes, parentChildrenMap));
//
if (parentChildrenMap.isEmpty()) {
condition.append(condition1.toString());
if (exclude) {
// If there are no NULL values in the member levels, then
// we're done except we need to also explicitly include
// members containing nulls across all levels.
condition.append(")");
condition.append(" or ");
condition.append(generateMultiValueIsNullExprs(sqlQuery, baseCube, members.get(0), fromLevel, aggStar));
}
return condition.toString();
}
} else {
//
for (RolapMember m : members) {
if (m.isCalculated()) {
if (restrictMemberTypes) {
throw Util.newInternal("addMemberConstraint: cannot " + "restrict SQL to calculated member :" + m);
}
continue;
}
RolapMember p = m.getParentMember();
List<RolapMember> childrenList = parentChildrenMap.get(p);
if (childrenList == null) {
childrenList = new ArrayList<RolapMember>();
parentChildrenMap.put(p, childrenList);
}
childrenList.add(m);
}
}
// Now we try to generate predicates for the remaining
// parent-children group.
// Note that NULLs are not used to enforce uniqueness
// so we ignore the fromLevel here.
boolean firstParent = true;
StringBuilder condition2 = new StringBuilder();
if (condition1.length() > 0) {
// Some members have already been translated into IN list.
firstParent = false;
condition.append(condition1.toString());
condition.append(" or ");
}
RolapLevel memberLevel = members.get(0).getLevel();
// should not contain null.
for (RolapMember p : parentChildrenMap.keySet()) {
assert p != null;
if (condition2.toString().length() > 0) {
condition2.append(" or ");
}
condition2.append("(");
// First generate ANDs for all members in the parent lineage of
// this parent-children group
int levelCount = 0;
for (RolapMember gp = p; gp != null; gp = gp.getParentMember()) {
if (gp.isAll()) {
// Get the next parent
continue;
}
RolapLevel level = gp.getLevel();
// first parent-children group we're generating sql for
if (firstParent) {
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);
}
if (column != null) {
if (aggStar != null) {
int bitPos = column.getBitPosition();
AggStar.Table.Column aggColumn = aggStar.lookupColumn(bitPos);
AggStar.Table table = aggColumn.getTable();
table.addToFrom(sqlQuery, false, true);
} else {
RolapStar.Table targetTable = column.getTable();
hierarchy.addToFrom(sqlQuery, targetTable);
}
} else {
assert (aggStar == null);
hierarchy.addToFrom(sqlQuery, level.getKeyExp());
}
}
if (levelCount > 0) {
condition2.append(" and ");
}
++levelCount;
condition2.append(constrainLevel(level, sqlQuery, baseCube, aggStar, getColumnValue(level.nameExp != null ? gp.getName() : gp.getKey(), sqlQuery.getDialect(), level.getDatatype()), false));
if (gp.getLevel() == fromLevel) {
// SQL is completely generated for this parent
break;
}
}
firstParent = false;
// Next, generate children for this parent-children group
List<RolapMember> children = parentChildrenMap.get(p);
// If no children to be generated for this parent then we are done
if (!children.isEmpty()) {
Map<RolapMember, List<RolapMember>> tmpParentChildrenMap = new HashMap<RolapMember, List<RolapMember>>();
if (levelCount > 0) {
condition2.append(" and ");
}
RolapLevel childrenLevel = (RolapLevel) (p.getLevel().getChildLevel());
if (sqlQuery.getDialect().supportsMultiValueInExpr() && childrenLevel != memberLevel) {
// Multi-level children and multi-value IN list supported
condition2.append(generateMultiValueInExpr(sqlQuery, baseCube, aggStar, children, childrenLevel, restrictMemberTypes, tmpParentChildrenMap));
assert tmpParentChildrenMap.isEmpty();
} else {
// needs to be generated for this case.
assert childrenLevel == memberLevel;
condition2.append(generateSingleValueInExpr(sqlQuery, baseCube, aggStar, children, childrenLevel, restrictMemberTypes, false, true));
}
}
// SQL is complete for this parent-children group.
condition2.append(")");
}
// In the case where multi-value IN expressions are not generated,
// condition2 contains the entire filter condition. In the
// case of excludes, we also need to explicitly include null values,
// minus the ones that are referenced in condition2. Therefore,
// we OR on a condition that corresponds to an OR'ing of IS NULL
// filters on each level PLUS an exclusion of condition2.
//
// Note that the expression generated is non-optimal in the case where
// multi-value IN's cannot be used because we end up excluding
// non-null values as well as the null ones. Ideally, we only need to
// exclude the expressions corresponding to nulls, which is possible
// in the multi-value IN case, since we have a map of the null values.
condition.append(condition2.toString());
if (exclude) {
condition.append(") or (");
condition.append(generateMultiValueIsNullExprs(sqlQuery, baseCube, members.get(0), fromLevel, aggStar));
condition.append(" and not(");
condition.append(condition2.toString());
condition.append("))");
}
return condition.toString();
}
use of mondrian.rolap.RolapStar.Table 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.RolapStar.Table 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.RolapStar.Table 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