001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2004-2005 TONBELLER AG
008// Copyright (C) 2006-2012 Pentaho and others
009// All Rights Reserved.
010*/
011package mondrian.rolap;
012
013import mondrian.olap.*;
014import mondrian.rolap.sql.*;
015
016import java.util.List;
017import java.util.Set;
018
019/**
020 * Creates the right constraint for common tasks.
021 *
022 * @author av
023 * @since Nov 21, 2005
024 */
025public class SqlConstraintFactory {
026
027    static boolean enabled;
028
029    private static final SqlConstraintFactory instance =
030        new SqlConstraintFactory();
031
032    /**
033     * singleton
034     */
035    private SqlConstraintFactory() {
036    }
037
038    private boolean enabled(final Evaluator context) {
039        if (context != null) {
040            return enabled && context.nativeEnabled();
041        }
042        return enabled;
043    }
044
045    public static SqlConstraintFactory instance() {
046        setNativeNonEmptyValue();
047        return instance;
048    }
049
050    public static void setNativeNonEmptyValue() {
051        enabled = MondrianProperties.instance().EnableNativeNonEmpty.get();
052    }
053
054    public MemberChildrenConstraint getMemberChildrenConstraint(
055        Evaluator context)
056    {
057        if (!enabled(context)
058            || !SqlContextConstraint.isValidContext(context, false))
059        {
060            return DefaultMemberChildrenConstraint.instance();
061        }
062        return new SqlContextConstraint((RolapEvaluator) context, false);
063    }
064
065    public TupleConstraint getLevelMembersConstraint(Evaluator context) {
066        return getLevelMembersConstraint(context, null);
067    }
068
069    /**
070     * Returns a constraint that restricts the members of a level to those that
071     * are non-empty in the given context. If the constraint cannot be
072     * implemented (say if native constraints are disabled) returns null.
073     *
074     * @param context Context within which members must be non-empty
075     * @param levels  levels being referenced in the current context
076     * @return Constraint
077     */
078    public TupleConstraint getLevelMembersConstraint(
079        Evaluator context,
080        Level[] levels)
081    {
082        if (context == null) {
083            return DefaultTupleConstraint.instance();
084        }
085        if (!enabled(context)) {
086            return DefaultTupleConstraint.instance();
087        }
088        if (!SqlContextConstraint.isValidContext(
089                context, false, levels, false))
090        {
091            return DefaultTupleConstraint.instance();
092        }
093        if (context.isNonEmpty()) {
094            Set<CrossJoinArg> joinArgs =
095                new CrossJoinArgFactory(false).buildConstraintFromAllAxes(
096                    (RolapEvaluator) context);
097            if (joinArgs.size() > 0) {
098                return new RolapNativeCrossJoin.NonEmptyCrossJoinConstraint(
099                    joinArgs.toArray(
100                        new CrossJoinArg[joinArgs.size()]),
101                    (RolapEvaluator) context);
102            }
103        }
104        return new SqlContextConstraint((RolapEvaluator) context, false);
105    }
106
107    public MemberChildrenConstraint getChildByNameConstraint(
108        RolapMember parent,
109        Id.NameSegment childName)
110    {
111        // Ragged hierarchies span multiple levels, so SQL WHERE does not work
112        // there
113        if (!enabled || parent.getHierarchy().isRagged()) {
114            return DefaultMemberChildrenConstraint.instance();
115        }
116        return new ChildByNameConstraint(childName);
117    }
118
119    /**
120     * Returns a constraint that allows to read all children of multiple parents
121     * at once using a LevelMember query style. This does not work
122     * for parent/child hierarchies.
123     *
124     * @param parentMembers List of parents (all must belong to same level)
125     * @param mcc           The constraint that would return the children for
126     *                      each single parent
127     * @return constraint
128     */
129    public TupleConstraint getDescendantsConstraint(
130        List<RolapMember> parentMembers,
131        MemberChildrenConstraint mcc)
132    {
133        return new DescendantsConstraint(parentMembers, mcc);
134    }
135}
136
137// End SqlConstraintFactory.java