Search in sources :

Example 1 with Table

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;
}
Also used : Table(mondrian.rolap.RolapStar.Table) AggStar(mondrian.rolap.aggmatcher.AggStar) Table(mondrian.rolap.RolapStar.Table)

Example 2 with Table

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();
}
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 3 with Table

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

Example 4 with Table

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;
}
Also used : Table(mondrian.rolap.RolapStar.Table) ListColumnPredicate(mondrian.rolap.agg.ListColumnPredicate) Dialect(mondrian.spi.Dialect) AggStar(mondrian.rolap.aggmatcher.AggStar) Column(mondrian.rolap.RolapStar.Column) Table(mondrian.rolap.RolapStar.Table)

Example 5 with Table

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;
    }
}
Also used : Table(mondrian.rolap.RolapStar.Table) SqlQuery(mondrian.rolap.sql.SqlQuery) Column(mondrian.rolap.RolapStar.Column) AggStar(mondrian.rolap.aggmatcher.AggStar) Column(mondrian.rolap.RolapStar.Column)

Aggregations

Table (mondrian.rolap.RolapStar.Table)6 AggStar (mondrian.rolap.aggmatcher.AggStar)6 Column (mondrian.rolap.RolapStar.Column)5 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 List (java.util.List)1 TupleList (mondrian.calc.TupleList)1 MondrianDef (mondrian.olap.MondrianDef)1 ListColumnPredicate (mondrian.rolap.agg.ListColumnPredicate)1 SqlQuery (mondrian.rolap.sql.SqlQuery)1 Dialect (mondrian.spi.Dialect)1 FilteredIterableList (mondrian.util.FilteredIterableList)1