Search in sources :

Example 1 with Column

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);
}
Also used : Column(mondrian.rolap.RolapStar.Column) Column(mondrian.rolap.RolapStar.Column) LiteralStarPredicate(mondrian.rolap.agg.LiteralStarPredicate)

Example 2 with Column

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);
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) CellRequest(mondrian.rolap.agg.CellRequest) Column(mondrian.rolap.RolapStar.Column) TupleList(mondrian.calc.TupleList) MondrianDef(mondrian.olap.MondrianDef) Column(mondrian.rolap.RolapStar.Column)

Example 3 with Column

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();
}
Also used : Table(mondrian.rolap.RolapStar.Table) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) LinkedHashMap(java.util.LinkedHashMap) AggStar(mondrian.rolap.aggmatcher.AggStar) List(java.util.List) FilteredIterableList(mondrian.util.FilteredIterableList) ArrayList(java.util.ArrayList) TupleList(mondrian.calc.TupleList) Column(mondrian.rolap.RolapStar.Column) Table(mondrian.rolap.RolapStar.Table)

Example 4 with Column

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;
}
Also used : Table(mondrian.rolap.RolapStar.Table) MondrianDef(mondrian.olap.MondrianDef) Dialect(mondrian.spi.Dialect) Column(mondrian.rolap.RolapStar.Column)

Example 5 with Column

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));
    }
}
Also used : MemberColumnPredicate(mondrian.rolap.agg.MemberColumnPredicate) ArrayList(java.util.ArrayList) Column(mondrian.rolap.RolapStar.Column)

Aggregations

Column (mondrian.rolap.RolapStar.Column)11 Table (mondrian.rolap.RolapStar.Table)5 AggStar (mondrian.rolap.aggmatcher.AggStar)4 MondrianDef (mondrian.olap.MondrianDef)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 TupleList (mondrian.calc.TupleList)2 Dialect (mondrian.spi.Dialect)2 HashSet (java.util.HashSet)1 LinkedHashSet (java.util.LinkedHashSet)1 List (java.util.List)1 Set (java.util.Set)1 CellRequest (mondrian.rolap.agg.CellRequest)1 ListColumnPredicate (mondrian.rolap.agg.ListColumnPredicate)1 LiteralStarPredicate (mondrian.rolap.agg.LiteralStarPredicate)1 MemberColumnPredicate (mondrian.rolap.agg.MemberColumnPredicate)1 SqlQuery (mondrian.rolap.sql.SqlQuery)1 FilteredIterableList (mondrian.util.FilteredIterableList)1