use of mondrian.rolap.RolapStar.Column in project mondrian by pentaho.
the class SqlConstraintUtils method addContextConstraintTuples.
/**
* Same as {@link addConstraint} but uses tuples
*/
private static void addContextConstraintTuples(SqlQuery sqlQuery, AggStar aggStar, RolapEvaluator evaluator, RolapCube baseCube, boolean restrictMemberTypes, final CellRequest request, TupleList slicerTuples) {
assert slicerTuples != null;
assert slicerTuples.size() > 0;
StarPredicate tupleListPredicate = getSlicerTuplesPredicate(slicerTuples, baseCube, aggStar, sqlQuery, evaluator);
// get columns constrained by slicer
BitKey slicerBitKey = tupleListPredicate.getConstrainedColumnBitKey();
// constrain context members not in slicer tuples
RolapStar.Column[] columns = request.getConstrainedColumns();
Object[] values = request.getSingleValues();
for (int i = 0; i < columns.length; i++) {
final RolapStar.Column column = columns[i];
final String value = String.valueOf(values[i]);
if (!slicerBitKey.get(column.getBitPosition())) {
// column not constrained by tupleSlicer
String expr = getColumnExpr(sqlQuery, aggStar, column);
addSimpleColumnConstraint(sqlQuery, column, expr, value);
}
// ok to ignore otherwise, using optimizedSlicerTuples
// that shouldn't have overridden tuples
}
// add our slicer tuples
StringBuilder buffer = new StringBuilder();
tupleListPredicate.toSql(sqlQuery, buffer);
sqlQuery.addWhere(buffer.toString());
// force Role based Access filtering
addRoleAccessConstraints(sqlQuery, aggStar, restrictMemberTypes, baseCube, evaluator);
}
use of mondrian.rolap.RolapStar.Column in project mondrian by pentaho.
the class SqlConstraintUtils method addContextConstraint.
/**
* For every restricting member in the current context, generates
* a WHERE condition and a join to the fact table.
*
* @param sqlQuery the query to modify
* @param aggStar Aggregate table, or null if query is against fact table
* @param restrictMemberTypes defines the behavior if the current context
* contains calculated members. If true, thows an exception.
* @param evaluator Evaluator
*/
public static void addContextConstraint(SqlQuery sqlQuery, AggStar aggStar, Evaluator evaluator, RolapCube baseCube, boolean restrictMemberTypes) {
if (baseCube == null && evaluator instanceof RolapEvaluator) {
baseCube = ((RolapEvaluator) evaluator).getCube();
}
RolapEvaluator rEvaluator = (RolapEvaluator) evaluator;
// decide if we should use the tuple-based version instead
TupleList slicerTuples = rEvaluator.getOptimizedSlicerTuples(baseCube);
boolean disjointSlicerTuples = false;
if (slicerTuples != null && slicerTuples.size() > 0 && (SqlConstraintUtils.isDisjointTuple(slicerTuples) || rEvaluator.isMultiLevelSlicerTuple())) {
disjointSlicerTuples = true;
}
TupleConstraintStruct expandedSet = makeContextConstraintSet(rEvaluator, restrictMemberTypes, disjointSlicerTuples);
final CellRequest request = RolapAggregationManager.makeRequest(expandedSet.getMembersArray());
if (request == null) {
if (restrictMemberTypes) {
throw Util.newInternal("CellRequest is null - why?");
}
// request is impossible to satisfy.
return;
}
List<TupleList> slicerTupleList = expandedSet.getDisjoinedTupleLists();
if (disjointSlicerTuples) {
slicerTupleList.add(slicerTuples);
}
// add slicer tuples from the expanded members
if (slicerTupleList.size() > 0) {
LOG.warn("Using tuple-based native slicer.");
for (TupleList tuple : slicerTupleList) {
addContextConstraintTuples(sqlQuery, aggStar, rEvaluator, baseCube, restrictMemberTypes, request, tuple);
}
return;
}
RolapStar.Column[] columns = request.getConstrainedColumns();
Object[] values = request.getSingleValues();
Map<MondrianDef.Expression, Set<RolapMember>> mapOfSlicerMembers = null;
HashMap<MondrianDef.Expression, Boolean> done = new HashMap<MondrianDef.Expression, Boolean>();
for (int i = 0; i < columns.length; i++) {
final RolapStar.Column column = columns[i];
final String value = String.valueOf(values[i]);
// choose from agg or regular star
String expr = getColumnExpr(sqlQuery, aggStar, column);
if ((RolapUtil.mdxNullLiteral().equalsIgnoreCase(value)) || (value.equalsIgnoreCase(RolapUtil.sqlNullValue.toString()))) {
sqlQuery.addWhere(expr, " is ", RolapUtil.sqlNullLiteral);
} else {
if (column.getDatatype().isNumeric()) {
// make sure it can be parsed
Double.valueOf(value);
}
if (mapOfSlicerMembers == null) {
mapOfSlicerMembers = getSlicerMemberMap(evaluator);
}
final MondrianDef.Expression keyForSlicerMap = column.getExpression();
if (mapOfSlicerMembers.containsKey(keyForSlicerMap)) {
if (!done.containsKey(keyForSlicerMap)) {
Set<RolapMember> slicerMembersSet = mapOfSlicerMembers.get(keyForSlicerMap);
// get only constraining members
// TODO: can we do this right at getSlicerMemberMap?
List<RolapMember> slicerMembers = getNonAllMembers(slicerMembersSet);
if (slicerMembers.size() > 0) {
// get level
final int levelIndex = slicerMembers.get(0).getHierarchy().getLevels().length - 1;
RolapLevel levelForWhere = (RolapLevel) slicerMembers.get(0).getHierarchy().getLevels()[levelIndex];
// build where constraint
final String where = generateSingleValueInExpr(sqlQuery, baseCube, aggStar, slicerMembers, levelForWhere, restrictMemberTypes, false, false);
if (!where.equals("")) {
// The where clause might be null because if the
// list of members is greater than the limit
// permitted, we won't constraint.
sqlQuery.addWhere(where);
}
} else {
addSimpleColumnConstraint(sqlQuery, column, expr, value);
}
done.put(keyForSlicerMap, Boolean.TRUE);
}
// if done, no op
} else {
// column not constrained by slicer
addSimpleColumnConstraint(sqlQuery, column, expr, value);
}
}
}
// force Role based Access filtering
addRoleAccessConstraints(sqlQuery, aggStar, restrictMemberTypes, baseCube, evaluator);
}
use of mondrian.rolap.RolapStar.Column 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.Column in project mondrian by pentaho.
the class SqlConstraintUtils method constrainLevel.
/**
* Generates a sql expression constraining a level by some value
*
* @param level the level
* @param query the query that the sql expression will be added to
* @param baseCube base cube for virtual levels
* @param aggStar aggregate star if available
* @param columnValue value constraining the level
* @param caseSensitive if true, need to handle case sensitivity of the
* member value
*
* @return generated string corresponding to the expression
*/
public static String constrainLevel(RolapLevel level, SqlQuery query, RolapCube baseCube, AggStar aggStar, String[] columnValue, boolean caseSensitive) {
// 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 columnString;
Dialect.Datatype datatype;
if (column != null) {
if (column.getNameColumn() == null) {
datatype = level.getDatatype();
} else {
column = column.getNameColumn();
// The schema doesn't specify the datatype of the name column,
// but we presume that it is a string.
datatype = Dialect.Datatype.String;
}
if (aggStar != null) {
// this makes the assumption that the name column is the same
// as the key column
int bitPos = column.getBitPosition();
AggStar.Table.Column aggColumn = aggStar.lookupColumn(bitPos);
columnString = aggColumn.generateExprString(query);
} else {
columnString = column.generateExprString(query);
}
} else {
assert (aggStar == null);
MondrianDef.Expression exp = level.getNameExp();
if (exp == null) {
exp = level.getKeyExp();
datatype = level.getDatatype();
} else {
// The schema doesn't specify the datatype of the name column,
// but we presume that it is a string.
datatype = Dialect.Datatype.String;
}
columnString = exp.getExpression(query);
}
String constraint;
constraint = getColumnValueConstraint(query, columnValue, caseSensitive, columnString, datatype);
return constraint;
}
use of mondrian.rolap.RolapStar.Column in project mondrian by pentaho.
the class SqlConstraintUtils method addMember.
/**
* add single member constraint to predicate list
*/
private static void addMember(RolapMember member, List<StarPredicate> predicateList, RolapCube baseCube, AggStar aggStar, SqlQuery sqlQuery) {
ArrayList<MemberColumnPredicate> memberList = new ArrayList<MemberColumnPredicate>();
// add parents until a unique level is reached
for (RolapMember currMember = member; currMember != null; currMember = currMember.getParentMember()) {
if (currMember.isAll()) {
continue;
}
RolapLevel level = currMember.getLevel();
RolapStar.Column column = getLevelColumn(level, baseCube, aggStar, sqlQuery);
((RolapCubeLevel) level).getBaseStarKeyColumn(baseCube);
memberList.add(new MemberColumnPredicate(column, currMember));
if (level.isUnique()) {
break;
}
}
for (int i = memberList.size() - 1; i >= 0; i--) {
predicateList.add(memberList.get(i));
}
}
Aggregations