001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/agg/MinusStarPredicate.java#3 $ 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.*; 017 018 /** 019 * A <code>StarPredicate</code> which evaluates to true if its 020 * first child evaluates to true and its second child evaluates to false. 021 * 022 * @author jhyde 023 * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/MinusStarPredicate.java#3 $ 024 * @since Nov 6, 2006 025 */ 026 public class MinusStarPredicate extends AbstractColumnPredicate { 027 private final StarColumnPredicate plus; 028 private final StarColumnPredicate minus; 029 030 /** 031 * Creates a MinusStarPredicate. 032 * 033 * @param plus Positive predicate 034 * @param minus Negative predicate 035 * @pre plus != null 036 * @pre minus != null 037 */ 038 public MinusStarPredicate( 039 StarColumnPredicate plus, 040 StarColumnPredicate minus) 041 { 042 super(plus.getConstrainedColumn()); 043 assert minus != null; 044 this.plus = plus; 045 this.minus = minus; 046 } 047 048 049 public boolean equals(Object obj) { 050 if (obj instanceof MinusStarPredicate) { 051 MinusStarPredicate that = (MinusStarPredicate) obj; 052 return this.plus.equals(that.plus) && 053 this.minus.equals(that.minus); 054 } else { 055 return false; 056 } 057 } 058 059 public int hashCode() { 060 return plus.hashCode() * 31 + 061 minus.hashCode(); 062 } 063 064 public RolapStar.Column getConstrainedColumn() { 065 return plus.getConstrainedColumn(); 066 } 067 068 public void values(Collection<Object> collection) { 069 Set<Object> plusValues = new HashSet<Object>(); 070 plus.values(plusValues); 071 List<Object> minusValues = new ArrayList<Object>(); 072 minus.values(minusValues); 073 plusValues.removeAll(minusValues); 074 collection.addAll(plusValues); 075 } 076 077 public boolean evaluate(Object value) { 078 return plus.evaluate(value) && 079 !minus.evaluate(value); 080 } 081 082 public void describe(StringBuilder buf) { 083 buf.append("(").append(plus).append(" - ").append(minus).append(")"); 084 } 085 086 public Overlap intersect(StarColumnPredicate predicate) { 087 throw new UnsupportedOperationException(); 088 } 089 090 public boolean mightIntersect(StarPredicate other) { 091 // Approximately, this constraint might intersect if it intersects 092 // with the 'plus' side. It's possible that the 'minus' side might 093 // wipe out all of those intersections, but we don't consider that. 094 return plus.mightIntersect(other); 095 } 096 097 public StarColumnPredicate minus(StarPredicate predicate) { 098 assert predicate != null; 099 if (predicate instanceof ValueColumnPredicate) { 100 ValueColumnPredicate valuePredicate = 101 (ValueColumnPredicate) predicate; 102 if (!evaluate(valuePredicate.getValue())) { 103 // Case 3: 'minus' is a list, 'constraint' is a value 104 // which is not matched by this 105 return this; 106 } 107 } 108 if (minus instanceof ListColumnPredicate) { 109 ListColumnPredicate minusList = (ListColumnPredicate) minus; 110 RolapStar.Column column = plus.getConstrainedColumn(); 111 if (predicate instanceof ListColumnPredicate) { 112 // Case 1: 'minus' and 'constraint' are both lists. 113 ListColumnPredicate list = 114 (ListColumnPredicate) predicate; 115 List<StarColumnPredicate> unionList = 116 new ArrayList<StarColumnPredicate>(); 117 unionList.addAll(minusList.getPredicates()); 118 unionList.addAll(list.getPredicates()); 119 return new MinusStarPredicate( 120 plus, 121 new ListColumnPredicate( 122 column, 123 unionList)); 124 } 125 if (predicate instanceof ValueColumnPredicate) { 126 ValueColumnPredicate valuePredicate = 127 (ValueColumnPredicate) predicate; 128 if (!evaluate(valuePredicate.getValue())) { 129 // Case 3: 'minus' is a list, 'constraint' is a value 130 // which is not matched by this 131 return this; 132 } 133 // Case 2: 'minus' is a list, 'constraint' is a value. 134 List<StarColumnPredicate> unionList = 135 new ArrayList<StarColumnPredicate>(); 136 unionList.addAll(minusList.getPredicates()); 137 unionList.add( 138 new ValueColumnPredicate(column, valuePredicate.getValue())); 139 return new MinusStarPredicate( 140 plus, 141 new ListColumnPredicate(column, unionList)); 142 } 143 } 144 return new MinusStarPredicate( 145 this, 146 (StarColumnPredicate) predicate); 147 } 148 149 public StarColumnPredicate cloneWithColumn(RolapStar.Column column) { 150 return new MinusStarPredicate( 151 plus.cloneWithColumn(column), 152 minus.cloneWithColumn(column)); 153 } 154 } 155 156 // End MinusStarPredicate.java