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