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) 2007-2011 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.rolap.agg; 011 012import mondrian.olap.Util; 013import mondrian.rolap.*; 014import mondrian.rolap.sql.SqlQuery; 015 016import java.util.*; 017 018/** 019 * Base class for {@link AndPredicate} and {@link OrPredicate}. 020 * 021 * @see mondrian.rolap.agg.ListColumnPredicate 022 * 023 * @author jhyde 024 */ 025public abstract class ListPredicate implements StarPredicate { 026 protected final List<StarPredicate> children = 027 new ArrayList<StarPredicate>(); 028 029 /** 030 * Hash map of children predicates, keyed off of the hash code of each 031 * child. Each entry in the map is a list of predicates matching that 032 * hash code. 033 */ 034 private HashMap<Integer, List<StarPredicate>> childrenHashMap; 035 036 /** 037 * Pre-computed hash code for this list column predicate 038 */ 039 private int hashValue; 040 041 protected final List<RolapStar.Column> columns; 042 043 private BitKey columnBitKey = null; 044 045 protected ListPredicate(List<StarPredicate> predicateList) { 046 childrenHashMap = null; 047 hashValue = 0; 048 // Ensure that columns are sorted by bit-key, for determinacy. 049 final SortedSet<RolapStar.Column> columnSet = 050 new TreeSet<RolapStar.Column>(RolapStar.Column.COMPARATOR); 051 for (StarPredicate predicate : predicateList) { 052 children.add(predicate); 053 columnSet.addAll(predicate.getConstrainedColumnList()); 054 } 055 columns = new ArrayList<RolapStar.Column>(columnSet); 056 } 057 058 public List<RolapStar.Column> getConstrainedColumnList() { 059 return columns; 060 } 061 062 public BitKey getConstrainedColumnBitKey() { 063 if (columnBitKey == null) { 064 for (StarPredicate predicate : children) { 065 if (columnBitKey == null) { 066 columnBitKey = 067 predicate.getConstrainedColumnBitKey().copy(); 068 } else { 069 columnBitKey = 070 columnBitKey.or(predicate.getConstrainedColumnBitKey()); 071 } 072 } 073 } 074 return columnBitKey; 075 } 076 077 public List<StarPredicate> getChildren() { 078 return children; 079 } 080 081 public int hashCode() { 082 // Don't use the default list hashcode because we want a hash code 083 // that's not order dependent 084 if (hashValue == 0) { 085 hashValue = 37; 086 for (StarPredicate child : children) { 087 int childHashCode = child.hashCode(); 088 if (childHashCode != 0) { 089 hashValue *= childHashCode; 090 } 091 } 092 hashValue ^= children.size(); 093 } 094 return hashValue; 095 } 096 097 public boolean equalConstraint(StarPredicate that) { 098 boolean isEqual = 099 that instanceof ListPredicate 100 && getConstrainedColumnBitKey().equals( 101 that.getConstrainedColumnBitKey()); 102 103 if (isEqual) { 104 ListPredicate thatPred = (ListPredicate) that; 105 if (getOp() != thatPred.getOp() 106 || getChildren().size() != thatPred.getChildren().size()) 107 { 108 isEqual = false; 109 } 110 111 if (isEqual) { 112 // Create a hash map of the children predicates, if not 113 // already done 114 if (childrenHashMap == null) { 115 childrenHashMap = 116 new HashMap<Integer, List<StarPredicate>>(); 117 for (StarPredicate thisChild : getChildren()) { 118 Integer key = new Integer(thisChild.hashCode()); 119 List<StarPredicate> predList = childrenHashMap.get(key); 120 if (predList == null) { 121 predList = new ArrayList<StarPredicate>(); 122 } 123 predList.add(thisChild); 124 childrenHashMap.put(key, predList); 125 } 126 } 127 128 // Loop through thatPred's children predicates. There needs 129 // to be a matching entry in the hash map for each child 130 // predicate. 131 for (StarPredicate thatChild : thatPred.getChildren()) { 132 List<StarPredicate> predList = 133 childrenHashMap.get(thatChild.hashCode()); 134 if (predList == null) { 135 isEqual = false; 136 break; 137 } 138 boolean foundMatch = false; 139 for (StarPredicate pred : predList) { 140 if (thatChild.equalConstraint(pred)) { 141 foundMatch = true; 142 break; 143 } 144 } 145 if (!foundMatch) { 146 isEqual = false; 147 break; 148 } 149 } 150 } 151 } 152 153 return isEqual; 154 } 155 156 public StarPredicate minus(StarPredicate predicate) { 157 throw Util.needToImplement(this); 158 } 159 160 public void toSql(SqlQuery sqlQuery, StringBuilder buf) { 161 if (children.size() == 1) { 162 children.get(0).toSql(sqlQuery, buf); 163 } else { 164 int k = 0; 165 buf.append("("); 166 for (StarPredicate child : children) { 167 if (k++ > 0) { 168 buf.append(" ").append(getOp()).append(" "); 169 } 170 child.toSql(sqlQuery, buf); 171 } 172 buf.append(")"); 173 } 174 } 175 176 protected abstract String getOp(); 177 178 public void describe(StringBuilder buf) { 179 buf.append(getOp()).append("("); 180 int k = 0; 181 for (StarPredicate child : children) { 182 if (k++ > 0) { 183 buf.append(", "); 184 } 185 buf.append(child); 186 } 187 buf.append(')'); 188 } 189 190 191 public String toString() { 192 final StringBuilder buf = new StringBuilder(); 193 describe(buf); 194 return buf.toString(); 195 } 196} 197 198// End ListPredicate.java