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) 2005-2005 Julian Hyde 008// Copyright (C) 2005-2012 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.rolap.agg; 012 013import mondrian.olap.Util; 014import mondrian.rolap.*; 015import mondrian.rolap.sql.SqlQuery; 016 017import java.util.*; 018 019/** 020 * Column context that an Aggregation is computed for. 021 * 022 * <p>Column context has two components:</p> 023 * <ul> 024 * <li>The column constraints which define the dimentionality of an 025 * Aggregation</li> 026 * <li>An orthogonal context for which the measures are defined. This context 027 * is sometimes referred to as the compound member predicates, and usually of 028 * the shape: 029 * <blockquote>OR(AND(column predicates))</blockquote></li> 030 * </ul> 031 * 032 * <p>Any column is only used in either column context or compound context, not 033 * both.</p> 034 * 035 * @author Rushan Chen 036 */ 037public class AggregationKey 038{ 039 /** 040 * This is needed because for a Virtual Cube: two CellRequests 041 * could have the same BitKey but have different underlying 042 * base cubes. Without this, one get the result in the 043 * SegmentArrayQuerySpec addMeasure Util.assertTrue being 044 * triggered (which is what happened). 045 */ 046 private final RolapStar star; 047 048 private final BitKey constrainedColumnsBitKey; 049 050 /** 051 * List of StarPredicate (representing the predicate 052 * defining the compound member). 053 * 054 * <p>In sorted order of BitKey. This ensures that the map is deternimistic 055 * (otherwise different runs generate SQL statements in different orders), 056 * and speeds up comparison. 057 */ 058 final List<StarPredicate> compoundPredicateList; 059 060 private int hashCode; 061 062 /** 063 * Creates an AggregationKey. 064 * 065 * @param request Cell request 066 */ 067 public AggregationKey(CellRequest request) { 068 this.constrainedColumnsBitKey = request.getConstrainedColumnsBitKey(); 069 this.star = request.getMeasure().getStar(); 070 Map<BitKey, StarPredicate> compoundPredicateMap = 071 request.getCompoundPredicateMap(); 072 this.compoundPredicateList = 073 compoundPredicateMap == null 074 ? Collections.<StarPredicate>emptyList() 075 : new ArrayList<StarPredicate>(compoundPredicateMap.values()); 076 } 077 078 public final int computeHashCode() { 079 return computeHashCode( 080 constrainedColumnsBitKey, 081 star, 082 compoundPredicateList == null 083 ? null 084 : new AbstractList<BitKey>() { 085 public BitKey get(int index) { 086 return compoundPredicateList.get(index) 087 .getConstrainedColumnBitKey(); 088 } 089 090 public int size() { 091 return compoundPredicateList.size(); 092 } 093 }); 094 } 095 096 public static int computeHashCode( 097 BitKey constrainedColumnsBitKey, 098 RolapStar star, 099 Collection<BitKey> compoundPredicateBitKeys) 100 { 101 int retCode = constrainedColumnsBitKey.hashCode(); 102 retCode = Util.hash(retCode, star); 103 return Util.hash(retCode, compoundPredicateBitKeys); 104 } 105 106 public int hashCode() { 107 if (hashCode == 0) { 108 // Compute hash code on first use. It is expensive to compute, and 109 // not always required. 110 hashCode = computeHashCode(); 111 } 112 return hashCode; 113 } 114 115 public boolean equals(Object other) { 116 if (!(other instanceof AggregationKey)) { 117 return false; 118 } 119 final AggregationKey that = (AggregationKey) other; 120 return constrainedColumnsBitKey.equals(that.constrainedColumnsBitKey) 121 && star.equals(that.star) 122 && equal(compoundPredicateList, that.compoundPredicateList); 123 } 124 125 /** 126 * Returns whether two lists of compound predicates are equal. 127 * 128 * @param list1 First compound predicate map 129 * @param list2 Second compound predicate map 130 * @return Whether compound predicate maps are equal 131 */ 132 static boolean equal( 133 final List<StarPredicate> list1, 134 final List<StarPredicate> list2) 135 { 136 if (list1 == null) { 137 return list2 == null; 138 } 139 if (list2 == null) { 140 return false; 141 } 142 final int size = list1.size(); 143 if (size != list2.size()) { 144 return false; 145 } 146 for (int i = 0; i < size; i++) { 147 StarPredicate pred1 = list1.get(i); 148 StarPredicate pred2 = list2.get(i); 149 if (!pred1.equalConstraint(pred2)) { 150 return false; 151 } 152 } 153 return true; 154 } 155 156 public String toString() { 157 return 158 star.getFactTable().getTableName() 159 + " " + constrainedColumnsBitKey.toString() 160 + "\n" 161 + (compoundPredicateList == null 162 ? "{}" 163 : compoundPredicateList.toString()); 164 } 165 166 /** 167 * Returns the bitkey of columns that constrain this aggregation. 168 * 169 * @return Bitkey of contraining columns 170 */ 171 public final BitKey getConstrainedColumnsBitKey() { 172 return constrainedColumnsBitKey; 173 } 174 175 /** 176 * Returns the star. 177 * 178 * @return Star 179 */ 180 public final RolapStar getStar() { 181 return star; 182 } 183 184 /** 185 * Returns the list of compound predicates. 186 * 187 * @return list of predicates 188 */ 189 public List<StarPredicate> getCompoundPredicateList() { 190 return compoundPredicateList; 191 } 192 193 /** 194 * Returns a list of compound predicates, expressed as SQL strings. 195 * 196 * @param star Star 197 * @param compoundPredicateList Predicate list 198 * @return list of predicate strings 199 */ 200 public static List<String> getCompoundPredicateStringList( 201 RolapStar star, 202 List<StarPredicate> compoundPredicateList) 203 { 204 if (compoundPredicateList.isEmpty()) { 205 return Collections.emptyList(); 206 } 207 final List<String> cp = new ArrayList<String>(); 208 final StringBuilder buf = new StringBuilder(); 209 for (StarPredicate compoundPredicate : compoundPredicateList) { 210 buf.setLength(0); 211 SqlQuery query = 212 new SqlQuery( 213 star.getSqlQueryDialect()); 214 compoundPredicate.toSql(query, buf); 215 cp.add(buf.toString()); 216 } 217 return cp; 218 } 219} 220 221// End AggregationKey.java