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