<commit_before>/*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2004-2005 TONBELLER AG
// Copyright (C) 2005-2005 <NAME>
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
 */
package mondrian.rolap;

import mondrian.olap.*;
import mondrian.olap.MondrianDef.RelationOrJoin;
import mondrian.rolap.agg.*;
import mondrian.rolap.aggmatcher.AggStar;
import mondrian.rolap.sql.SqlQuery;
import mondrian.spi.Dialect;
import mondrian.util.FilteredIterableList;

import java.util.*;

/**
 * Utility class used by implementations of {@link mondrian.rolap.sql.SqlConstraint},
 * used to generate constraints into {@link mondrian.rolap.sql.SqlQuery}.
 *
 * @author av
 * @since Nov 21, 2005
 */
public class SqlConstraintUtils {

    /** Utility class */
    private SqlConstraintUtils() {
    }

    /**
     * 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,
        boolean restrictMemberTypes)
    {
        // Add constraint using the current evaluator context
        Member[] members = evaluator.getNonAllMembers();
        RolapCube baseCube = null;
        if (evaluator instanceof RolapEvaluator) {
            baseCube = ((RolapEvaluator)evaluator).getCube();
        }

        Map<RelationOrJoin, Set<RolapMember>> mapOfSlicerMembers =
                new HashMap<RelationOrJoin, Set<RolapMember>>();
        Map<RelationOrJoin, Boolean> done =
                new HashMap<RelationOrJoin, Boolean>();
        if (restrictMemberTypes) {
            if (containsCalculatedMember(members)) {
                throw Util.newInternal(
                    "can not restrict SQL to calculated Members");
            }
            if (hasMultiPositionSlicer(evaluator)) {
                List<Member> slicerMembers =
                        ((RolapEvaluator)evaluator).getSlicerMembers();

                for (Member slicerMember : slicerMembers) {
                    RelationOrJoin rel =
                            ((RolapCubeHierarchy)slicerMember.getHierarchy())
                            .getRelation();
                    if (!mapOfSlicerMembers.containsKey(rel)) {
                        mapOfSlicerMembers.put(rel, new HashSet<RolapMember>());
                    }
                    mapOfSlicerMembers.get(rel).add((RolapMember)slicerMember);
                }
            }

        } else {
            members = removeCalculatedAndDefaultMembers(members);
            members = removeMultiPositionSlicerMembers(members, evaluator);
        }
        final CellRequest request =
            RolapAggregationManager.makeRequest(members);
        if (request == null) {
            if (restrictMemberTypes) {
                throw Util.newInternal("CellRequest is null - why?");
            }
            // One or more of the members was null or calculated, so the
            // request is impossible to satisfy.
            return;
        }
        RolapStar.Column[] columns = request.getConstrainedColumns();
        Object[] values = request.getSingleValues();
        int arity = columns.length;
        // following code is similar to
        // AbstractQuerySpec#nonDistinctGenerateSQL()
        for (int i = 0; i < arity; i++) {
            RolapStar.Column column = columns[i];

            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);
            }

            final String value = String.valueOf(values[i]);
            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);
                }

                RelationOrJoin keyForSlicerMap =
                        column.getTable().getRelation();
                if (mapOfSlicerMembers.containsKey(keyForSlicerMap)) {
                    if (!done.containsKey(keyForSlicerMap)) {
                        Set<RolapMember> slicerMembersArray =
                                mapOfSlicerMembers.get(keyForSlicerMap);
                        List<RolapMember> slicerMembers =
                                new ArrayList<RolapMember>(slicerMembersArray);

                        RolapMember allMember = null;
                        for (RolapMember slicerMember : slicerMembers) {
                            if (slicerMember.isAll()) {
                                allMember = slicerMember;
                                break;
                            }
                        }

                        if (allMember != null) {
                            slicerMembers.remove(allMember);
                        }

                        if (slicerMembers.size() > 0) {
                            RolapLevel levelForWhere =
                                    (RolapLevel) slicerMembers.get(0)
                                    .getHierarchy()
                                    .getLevels()[0];
                            final String where =
                                    generateMultiValueInExpr(
                                        sqlQuery, baseCube,
                                        aggStar, slicerMembers,
                                        levelForWhere,
                                        restrictMemberTypes, null);
                            sqlQuery.addWhere(where);
                        } else {
                            //No extra slicers.... just use the = method
                            final StringBuilder buf = new StringBuilder();
                            sqlQuery.getDialect().quote(
                                buf, value,
                                column.getDatatype());
                            sqlQuery.addWhere(
                                expr,
                                " = ",
                                buf.toString());
                        }
                        done.put(keyForSlicerMap, Boolean.TRUE);
                    }

                } else {
                    final StringBuilder buf = new StringBuilder();<commit_msg>Performance issue when using native top count with multiple levels - use unique level when possible instead of all the levels<commit_after>/*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2004-2005 TONBELLER AG
// Copyright (C) 2005-2005 <NAME>
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
 */
package mondrian.rolap;

import mondrian.olap.*;
import mondrian.olap.MondrianDef.RelationOrJoin;
import mondrian.rolap.agg.*;
import mondrian.rolap.aggmatcher.AggStar;
import mondrian.rolap.sql.SqlQuery;
import mondrian.spi.Dialect;
import mondrian.util.FilteredIterableList;

import java.util.*;

/**
 * Utility class used by implementations of {@link mondrian.rolap.sql.SqlConstraint},
 * used to generate constraints into {@link mondrian.rolap.sql.SqlQuery}.
 *
 * @author av
 * @since Nov 21, 2005
 */
public class SqlConstraintUtils {

    /** Utility class */
    private SqlConstraintUtils() {
    }

    /**
     * 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,
        boolean restrictMemberTypes)
    {
        // Add constraint using the current evaluator context
        Member[] members = evaluator.getNonAllMembers();
        RolapCube baseCube = null;
        if (evaluator instanceof RolapEvaluator) {
            baseCube = ((RolapEvaluator)evaluator).getCube();
        }

        Map<RelationOrJoin, Set<RolapMember>> mapOfSlicerMembers =
                new HashMap<RelationOrJoin, Set<RolapMember>>();
        Map<RelationOrJoin, Boolean> done =
                new HashMap<RelationOrJoin, Boolean>();
        if (restrictMemberTypes) {
            if (containsCalculatedMember(members)) {
                throw Util.newInternal(
                    "can not restrict SQL to calculated Members");
            }
            if (hasMultiPositionSlicer(evaluator)) {
                List<Member> slicerMembers =
                        ((RolapEvaluator)evaluator).getSlicerMembers();

                for (Member slicerMember : slicerMembers) {
                    RelationOrJoin rel =
                            ((RolapCubeHierarchy)slicerMember.getHierarchy())
                            .getRelation();
                    if (!mapOfSlicerMembers.containsKey(rel)) {
                        mapOfSlicerMembers.put(rel, new HashSet<RolapMember>());
                    }
                    mapOfSlicerMembers.get(rel).add((RolapMember)slicerMember);
                }
            }

        } else {
            members = removeCalculatedAndDefaultMembers(members);
            members = removeMultiPositionSlicerMembers(members, evaluator);
        }
        final CellRequest request =
            RolapAggregationManager.makeRequest(members);
        if (request == null) {
            if (restrictMemberTypes) {
                throw Util.newInternal("CellRequest is null - why?");
            }
            // One or more of the members was null or calculated, so the
            // request is impossible to satisfy.
            return;
        }
        RolapStar.Column[] columns = request.getConstrainedColumns();
        Object[] values = request.getSingleValues();
        int arity = columns.length;
        // following code is similar to
        // AbstractQuerySpec#nonDistinctGenerateSQL()
        for (int i = 0; i < arity; i++) {
            RolapStar.Column column = columns[i];

            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);
            }

            final String value = String.valueOf(values[i]);
            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);
                }

                RelationOrJoin keyForSlicerMap =
                        column.getTable().getRelation();
                if (mapOfSlicerMembers.containsKey(keyForSlicerMap)) {
                    if (!done.containsKey(keyForSlicerMap)) {
                        Set<RolapMember> slicerMembersArray =
                                mapOfSlicerMembers.get(keyForSlicerMap);
                        List<RolapMember> slicerMembers =
                                new ArrayList<RolapMember>(slicerMembersArray);

                        RolapMember allMember = null;
                        for (RolapMember slicerMember : slicerMembers) {
                            if (slicerMember.isAll()) {
                                allMember = slicerMember;
                                break;
                            }
                        }

                        if (allMember != null) {
                            slicerMembers.remove(allMember);
                        }

                        if (slicerMembers.size() > 0) {
                            int levelIndex = slicerMembers.get(0)
                                    .getHierarchy()
                                    .getLevels().length;
                            RolapLevel levelForWhere =
                                    (RolapLevel) slicerMembers.get(0)
                                    .getHierarchy()
                                    .getLevels()[levelIndex - 1];
                            final String where =
                                    generateMultiValueInExpr(
                                        sqlQuery, baseCube,
                                        aggStar, slicerMembers,
                                        levelForWhere,
                                        restrictMemberTypes, null);
                            sqlQuery.addWhere(where);
                        } else {
                            //No extra slicers.... just use the = method
                            final StringBuilder buf = new StringBuilder();
                            sqlQuery.getDialect().quote(
                                buf, value,
                                column.getDatatype());
                            sqlQuery.addWhere(
                                expr,
                                " = ",
                                buf.toString());
                        }
                        done.put(keyForSlicerMap, Boolean.TRUE);
                    }

                } else {
                    final StringBuilder buf = new StringBuilder();
{'fraction_non_alphanumeric': 0.08148827459714399, 'fraction_numerical': 0.0050438883794052146, 'mean_word_length': 1.398586017282011, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5555876', 'n_tokens_mistral': 3813, 'n_tokens_neox': 3565, 'n_words': 864}