1 5 package org.h2.expression; 6 7 import java.sql.SQLException ; 8 9 import org.h2.engine.Constants; 10 import org.h2.engine.Database; 11 import org.h2.message.Message; 12 import org.h2.util.ObjectArray; 13 import org.h2.util.ValueHashMap; 14 import org.h2.value.Value; 15 import org.h2.value.ValueBoolean; 16 import org.h2.value.ValueDouble; 17 import org.h2.value.ValueInt; 18 import org.h2.value.ValueNull; 19 20 public class AggregateData { 21 private int aggregateType; 22 private int count; 23 private ValueHashMap distinctValues; 24 private Value value; 25 private double sum, vpn; 26 private ObjectArray list; 27 28 AggregateData(int aggregateType) { 29 this.aggregateType = aggregateType; 30 } 31 32 void add(Database database, boolean distinct, Value v) throws SQLException { 33 if(aggregateType == Aggregate.SELECTIVITY) { 34 count++; 35 if(distinctValues == null) { 36 distinctValues = new ValueHashMap(database); 37 } 38 int size = distinctValues.size(); 39 if(size > Constants.SELECTIVITY_DISTINCT_COUNT) { 40 distinctValues = new ValueHashMap(database); 41 sum += size; 42 } 43 distinctValues.put(v, this); 44 return; 45 } 46 if(aggregateType == Aggregate.COUNT_ALL) { 47 count++; 48 return; 49 } 50 if(v == ValueNull.INSTANCE) { 51 return; 52 } 53 count++; 54 if(distinct) { 55 if(distinctValues == null) { 56 distinctValues = new ValueHashMap(database); 57 } 58 distinctValues.put(v, this); 59 return; 60 } 61 switch(aggregateType) { 62 case Aggregate.COUNT: 63 return; 64 case Aggregate.SUM: 65 case Aggregate.AVG: 66 if(value == null) { 67 value = v; 68 } else { 69 value = value.add(v); 70 } 71 break; 72 case Aggregate.MIN: 73 if(value == null || database.compare(v, value) < 0) { 74 value = v; 75 } 76 break; 77 case Aggregate.MAX: 78 if(value == null || database.compare(v, value) > 0) { 79 value = v; 80 } 81 break; 82 case Aggregate.GROUP_CONCAT: { 83 if(list == null) { 84 list = new ObjectArray(); 85 } 86 list.add(v); 87 break; 88 } 89 case Aggregate.STDDEV_POP: 90 case Aggregate.STDDEV_SAMP: 91 case Aggregate.VAR_POP: 92 case Aggregate.VAR_SAMP: { 93 double x = v.getDouble(); 94 if(count == 1) { 95 sum = x; 96 vpn = 0; 97 } else { 98 double xs = sum - (x*(count-1)); 99 vpn += (xs*xs) / count / (count-1); 100 sum += x; 101 } 102 break; 103 } 104 case Aggregate.EVERY: 105 v = v.convertTo(Value.BOOLEAN); 106 if(value == null) { 107 value = v; 108 } else { 109 value = ValueBoolean.get(value.getBoolean().booleanValue() && v.getBoolean().booleanValue()); 110 } 111 break; 112 case Aggregate.SOME: 113 v = v.convertTo(Value.BOOLEAN); 114 if(value == null) { 115 value = v; 116 } else { 117 value = ValueBoolean.get(value.getBoolean().booleanValue() || v.getBoolean().booleanValue()); 118 } 119 break; 120 default: 121 throw Message.getInternalError("type="+aggregateType); 122 } 123 } 124 125 ObjectArray getList() { 126 return list; 127 } 128 129 Value getValue(Database database, boolean distinct) throws SQLException { 130 if(distinct) { 131 count = 0; 132 groupDistinct(database); 133 } 134 Value v = null; 135 switch(aggregateType) { 136 case Aggregate.SELECTIVITY: { 137 int s = 0; 138 if(count == 0) { 139 s = 0; 140 } else { 141 sum += distinctValues.size(); 142 sum = (100 * sum / count); 143 s = (int)sum; 144 s = s <= 0 ? 1 : s > 100 ? 100 : s; 145 } 146 v = ValueInt.get(s); 147 break; 148 } 149 case Aggregate.COUNT: 150 case Aggregate.COUNT_ALL: 151 v = ValueInt.get(count); 152 break; 153 case Aggregate.SUM: 154 case Aggregate.MIN: 155 case Aggregate.MAX: 156 case Aggregate.SOME: 157 case Aggregate.EVERY: 158 v = value; 159 break; 160 case Aggregate.AVG: 161 if(value != null) { 162 v = divide(value, count); 163 } 164 break; 165 case Aggregate.GROUP_CONCAT: 166 return null; 167 case Aggregate.STDDEV_POP: { 168 if(count < 1) { 169 return ValueNull.INSTANCE; 170 } 171 v = ValueDouble.get(Math.sqrt(vpn / count)); 172 break; 173 } 174 case Aggregate.STDDEV_SAMP: { 175 if(count < 2) { 176 return ValueNull.INSTANCE; 177 } 178 v = ValueDouble.get(Math.sqrt(vpn / (count-1))); 179 break; 180 } 181 case Aggregate.VAR_POP: { 182 if(count < 1) { 183 return ValueNull.INSTANCE; 184 } 185 v = ValueDouble.get(vpn / count); 186 break; 187 } 188 case Aggregate.VAR_SAMP: { 189 if(count < 2) { 190 return ValueNull.INSTANCE; 191 } 192 v = ValueDouble.get(vpn / (count-1)); 193 break; 194 } 195 default: 196 throw Message.getInternalError("type="+aggregateType); 197 } 198 return v == null ? ValueNull.INSTANCE : v; 199 } 200 201 private Value divide(Value a, int count) throws SQLException { 202 if(count == 0) { 203 return ValueNull.INSTANCE; 204 } 205 int type = Value.getHigherOrder(a.getType(), Value.INT); 206 Value b = ValueInt.get(count).convertTo(type); 207 a = a.convertTo(type).divide(b); 208 return a; 209 } 210 211 private void groupDistinct(Database database) throws SQLException { 212 if(distinctValues == null) { 213 return; 214 } 215 if(aggregateType == Aggregate.COUNT) { 216 count = distinctValues.size(); 217 } else { 218 count = 0; 219 ObjectArray l2 = distinctValues.keys(); 220 for(int i=0; i<l2.size(); i++) { 221 add(database, false, (Value)l2.get(i)); 222 } 223 } 224 } 225 226 } 227 | Popular Tags |