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