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) 2006-2011 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.rolap.agg;
011
012import mondrian.rolap.*;
013import mondrian.rolap.sql.SqlQuery;
014
015import java.util.Collection;
016
017/**
018 * A constraint which requires a column to have a particular value.
019 *
020 * @author jhyde
021 * @since Nov 2, 2006
022 */
023public class ValueColumnPredicate
024    extends AbstractColumnPredicate
025    implements Comparable
026{
027    private final Object value;
028
029    /**
030     * Creates a column constraint.
031     *
032     * @param value Value to constraint the column to. (We require that it is
033     *   {@link Comparable} because we will sort the values in order to
034     *   generate deterministic SQL.)
035     */
036    public ValueColumnPredicate(
037        RolapStar.Column constrainedColumn,
038        Object value)
039    {
040        super(constrainedColumn);
041//        assert constrainedColumn != null;
042        assert value != null;
043        assert ! (value instanceof StarColumnPredicate);
044        this.value = value;
045    }
046
047    /**
048     * Returns the value which the column is compared to.
049     */
050    public Object getValue() {
051        return value;
052    }
053
054    public String toString() {
055        return String.valueOf(value);
056    }
057
058    public boolean equalConstraint(StarPredicate that) {
059        return that instanceof ValueColumnPredicate
060            && getConstrainedColumnBitKey().equals(
061                that.getConstrainedColumnBitKey())
062            && this.value.equals(((ValueColumnPredicate) that).value);
063    }
064
065    public int compareTo(Object o) {
066        ValueColumnPredicate that = (ValueColumnPredicate) o;
067        int columnBitKeyComp =
068            getConstrainedColumnBitKey().compareTo(
069                that.getConstrainedColumnBitKey());
070
071        // First compare the column bitkeys.
072        if (columnBitKeyComp != 0) {
073            return columnBitKeyComp;
074        }
075
076        if (this.value instanceof Comparable
077            && that.value instanceof Comparable
078            && this.value.getClass() == that.value.getClass())
079        {
080            return ((Comparable) this.value).compareTo(that.value);
081        } else {
082            String thisComp = String.valueOf(this.value);
083            String thatComp = String.valueOf(that.value);
084            return thisComp.compareTo(thatComp);
085        }
086    }
087
088    public boolean equals(Object other) {
089        if (!(other instanceof ValueColumnPredicate)) {
090            return false;
091        }
092        final ValueColumnPredicate that = (ValueColumnPredicate) other;
093
094        // First compare the column bitkeys.
095        if (!getConstrainedColumnBitKey().equals(
096                that.getConstrainedColumnBitKey()))
097        {
098            return false;
099        }
100
101        if (value != null) {
102            return value.equals(that.getValue());
103        } else {
104            return null == that.getValue();
105        }
106    }
107
108    public int hashCode() {
109        int hashCode = getConstrainedColumnBitKey().hashCode();
110
111        if (value != null) {
112            hashCode = hashCode ^ value.hashCode();
113        }
114
115        return hashCode;
116    }
117
118    public void values(Collection<Object> collection) {
119        collection.add(value);
120    }
121
122    public boolean evaluate(Object value) {
123        return this.value.equals(value);
124    }
125
126    public void describe(StringBuilder buf) {
127        buf.append(value);
128    }
129
130    public Overlap intersect(StarColumnPredicate predicate) {
131        throw new UnsupportedOperationException();
132    }
133
134    public boolean mightIntersect(StarPredicate other) {
135        return ((StarColumnPredicate) other).evaluate(value);
136    }
137
138    public StarColumnPredicate minus(StarPredicate predicate) {
139        assert predicate != null;
140        if (((StarColumnPredicate) predicate).evaluate(value)) {
141            return LiteralStarPredicate.FALSE;
142        } else {
143            return this;
144        }
145    }
146
147    public StarColumnPredicate cloneWithColumn(RolapStar.Column column) {
148        return new ValueColumnPredicate(column, value);
149    }
150
151    public void toSql(SqlQuery sqlQuery, StringBuilder buf) {
152        final RolapStar.Column column = getConstrainedColumn();
153        String expr = column.generateExprString(sqlQuery);
154        buf.append(expr);
155        Object key = getValue();
156        if (key == RolapUtil.sqlNullValue) {
157            buf.append(" is null");
158        } else {
159            buf.append(" = ");
160            sqlQuery.getDialect().quote(buf, key, column.getDatatype());
161        }
162    }
163
164    public BitKey checkInList(BitKey inListLHSBitKey) {
165        // ValueColumn predicate by itself is not using IN list; when it is
166        // one of the children to an OR predicate, then using IN list
167        // is helpful. The later is checked by passing in a bitmap that
168        // represent the LHS or the IN list, i.e. the column that is
169        // constrained by the OR.
170        BitKey inListRHSBitKey = inListLHSBitKey.copy();
171
172        if (!getConstrainedColumnBitKey().equals(inListLHSBitKey)
173            || value == RolapUtil.sqlNullValue)
174        {
175            inListRHSBitKey.clear();
176        }
177
178        return inListRHSBitKey;
179    }
180
181    public void toInListSql(SqlQuery sqlQuery, StringBuilder buf) {
182        sqlQuery.getDialect().quote(
183            buf, value, getConstrainedColumn().getDatatype());
184    }
185}
186
187// End ValueColumnPredicate.java