001    /*
002    // $Id: //open/mondrian/src/main/mondrian/rolap/agg/RangeColumnPredicate.java#4 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2006-2007 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package mondrian.rolap.agg;
011    
012    import mondrian.rolap.StarPredicate;
013    import mondrian.rolap.StarColumnPredicate;
014    import mondrian.rolap.RolapStar;
015    
016    import java.util.Collection;
017    
018    /**
019     * Predicate constraining a column to be greater than or less than a given
020     * bound, or between a pair of bounds.
021     *
022     * @author jhyde
023     * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/RangeColumnPredicate.java#4 $
024     * @since Nov 26, 2006
025     */
026    public class RangeColumnPredicate extends AbstractColumnPredicate {
027        private final boolean lowerInclusive;
028        private final ValueColumnPredicate lowerBound;
029        private final boolean upperInclusive;
030        private final ValueColumnPredicate upperBound;
031    
032        /**
033         * Creates a RangeColumnPredicate.
034         *
035         * @param column Constrained column
036         * @param lowerInclusive Whether range includes the lower bound;
037         *   must be false if not bounded below
038         * @param lowerBound Lower bound, or null if not bounded below
039         * @param upperInclusive Whether range includes the upper bound;
040         *   must be false if not bounded above
041         * @param upperBound Upper bound, or null if not bounded above
042         */
043        public RangeColumnPredicate(
044            RolapStar.Column column,
045            boolean lowerInclusive,
046            ValueColumnPredicate lowerBound,
047            boolean upperInclusive,
048            ValueColumnPredicate upperBound)
049        {
050            super(column);
051            assert lowerBound == null ||
052                lowerBound.getConstrainedColumn() == column;
053            assert !(lowerBound == null && lowerInclusive);
054            assert upperBound == null ||
055                upperBound.getConstrainedColumn() == column;
056            assert !(upperBound == null && upperInclusive);
057            this.lowerInclusive = lowerInclusive;
058            this.lowerBound = lowerBound;
059            this.upperInclusive = upperInclusive;
060            this.upperBound = upperBound;
061        }
062    
063        public int hashCode() {
064            int h = lowerInclusive ? 2 : 1;
065            h = 31 * h + lowerBound.hashCode();
066            h = 31 * h + (upperInclusive ? 2 : 1);
067            h = 31 * h + upperBound.hashCode();
068            return h;
069        }
070    
071        public boolean equals(Object obj) {
072            if (obj instanceof RangeColumnPredicate) {
073                RangeColumnPredicate that =
074                    (RangeColumnPredicate) obj;
075                return this.lowerInclusive == that.lowerInclusive &&
076                    this.lowerBound.equals(that.lowerBound) &&
077                    this.upperInclusive == that.upperInclusive &&
078                    this.upperBound.equals(that.upperBound);
079            } else {
080                return false;
081            }
082        }
083    
084        public void values(Collection<Object> collection) {
085            // Besides the end points, don't know what values may be in the range.
086            // FIXME: values() is only a half-useful method. Replace it?
087            throw new UnsupportedOperationException();
088        }
089    
090        public boolean evaluate(Object value) {
091            if (lowerBound != null) {
092                int c = ((Comparable<Object>) lowerBound.getValue()).compareTo(value);
093                if (lowerInclusive ? c > 0 : c >= 0) {
094                    return false;
095                }
096            }
097            if (upperBound != null) {
098                int c = ((Comparable<Object>) upperBound.getValue()).compareTo(value);
099                if (upperInclusive ? c < 0 : c <= 0) {
100                    return false;
101                }
102            }
103            return true;
104        }
105    
106        public void describe(StringBuilder buf) {
107            buf.append("Range(");
108            if (lowerBound == null) {
109                buf.append("unbounded");
110            } else {
111                lowerBound.describe(buf);
112                if (lowerInclusive) {
113                    buf.append(" inclusive");
114                }
115            }
116            buf.append(" to ");
117            if (upperBound == null) {
118                buf.append("unbounded");
119            } else {
120                upperBound.describe(buf);
121                if (upperInclusive) {
122                    buf.append(" inclusive");
123                }
124            }
125            buf.append(")");
126        }
127    
128        public Overlap intersect(StarColumnPredicate predicate) {
129            throw new UnsupportedOperationException();
130        }
131    
132        public boolean mightIntersect(StarPredicate other) {
133            if (other instanceof ValueColumnPredicate) {
134                return evaluate(((ValueColumnPredicate) other).getValue());
135            } else {
136                // It MIGHT intersect. (Might not.)
137                // todo: Handle case 'other instanceof RangeColumnPredicate'
138                return true;
139            }
140        }
141    
142        public StarColumnPredicate minus(StarPredicate predicate) {
143            assert predicate != null;
144            // todo: Implement some common cases, such as Range minus Range, and
145            // Range minus true/false
146            return new MinusStarPredicate(
147                this, (StarColumnPredicate) predicate);
148        }
149    
150        public StarColumnPredicate cloneWithColumn(RolapStar.Column column) {
151            return new RangeColumnPredicate(
152                column, lowerInclusive, lowerBound, upperInclusive, upperBound);
153        }
154    
155        public ValueColumnPredicate getLowerBound() {
156            return lowerBound;
157        }
158    
159        public boolean getLowerInclusive() {
160            return lowerInclusive;
161        }
162    
163        public ValueColumnPredicate getUpperBound() {
164            return upperBound;
165        }
166    
167        public boolean getUpperInclusive() {
168            return upperInclusive;
169        }
170    }
171    
172    // End RangeColumnPredicate.java