EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.expression]

COVERAGE SUMMARY FOR SOURCE FILE [AggregateDataDefault.java]

nameclass, %method, %block, %line, %
AggregateDataDefault.java100% (1/1)100% (5/5)93%  (391/422)95%  (89.6/94)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AggregateDataDefault100% (1/1)100% (5/5)93%  (391/422)95%  (89.6/94)
getValue (Database, int, boolean): Value 100% (1/1)91%  (106/117)96%  (26/27)
divide (Value, long): Value 100% (1/1)92%  (22/24)83%  (5/6)
add (Database, int, boolean, Value): void 100% (1/1)93%  (231/248)97%  (49.6/51)
groupDistinct (Database, int): void 100% (1/1)96%  (26/27)86%  (6/7)
AggregateDataDefault (int): void 100% (1/1)100% (6/6)100% (3/3)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.expression;
7 
8import org.h2.engine.Database;
9import org.h2.message.DbException;
10import org.h2.util.ValueHashMap;
11import org.h2.value.DataType;
12import org.h2.value.Value;
13import org.h2.value.ValueBoolean;
14import org.h2.value.ValueDouble;
15import org.h2.value.ValueLong;
16import org.h2.value.ValueNull;
17 
18/**
19 * Data stored while calculating an aggregate.
20 */
21class AggregateDataDefault extends AggregateData {
22    private final int aggregateType;
23    private long count;
24    private ValueHashMap<AggregateDataDefault> distinctValues;
25    private Value value;
26    private double m2, mean;
27 
28    /**
29     * @param aggregateType the type of the aggregate operation
30     */
31    AggregateDataDefault(int aggregateType) {
32        this.aggregateType = aggregateType;
33    }
34 
35    @Override
36    void add(Database database, int dataType, boolean distinct, Value v) {
37        if (v == ValueNull.INSTANCE) {
38            return;
39        }
40        count++;
41        if (distinct) {
42            if (distinctValues == null) {
43                distinctValues = ValueHashMap.newInstance();
44            }
45            distinctValues.put(v, this);
46            return;
47        }
48        switch (aggregateType) {
49        case Aggregate.SUM:
50            if (value == null) {
51                value = v.convertTo(dataType);
52            } else {
53                v = v.convertTo(value.getType());
54                value = value.add(v);
55            }
56            break;
57        case Aggregate.AVG:
58            if (value == null) {
59                value = v.convertTo(DataType.getAddProofType(dataType));
60            } else {
61                v = v.convertTo(value.getType());
62                value = value.add(v);
63            }
64            break;
65        case Aggregate.MIN:
66            if (value == null || database.compare(v, value) < 0) {
67                value = v;
68            }
69            break;
70        case Aggregate.MAX:
71            if (value == null || database.compare(v, value) > 0) {
72                value = v;
73            }
74            break;
75        case Aggregate.STDDEV_POP:
76        case Aggregate.STDDEV_SAMP:
77        case Aggregate.VAR_POP:
78        case Aggregate.VAR_SAMP: {
79            // Using Welford's method, see also
80            // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
81            // http://www.johndcook.com/standard_deviation.html
82            double x = v.getDouble();
83            if (count == 1) {
84                mean = x;
85                m2 = 0;
86            } else {
87                double delta = x - mean;
88                mean += delta / count;
89                m2 += delta * (x - mean);
90            }
91            break;
92        }
93        case Aggregate.BOOL_AND:
94            v = v.convertTo(Value.BOOLEAN);
95            if (value == null) {
96                value = v;
97            } else {
98                value = ValueBoolean.get(value.getBoolean().booleanValue() &&
99                        v.getBoolean().booleanValue());
100            }
101            break;
102        case Aggregate.BOOL_OR:
103            v = v.convertTo(Value.BOOLEAN);
104            if (value == null) {
105                value = v;
106            } else {
107                value = ValueBoolean.get(value.getBoolean().booleanValue() ||
108                        v.getBoolean().booleanValue());
109            }
110            break;
111        case Aggregate.BIT_AND:
112            if (value == null) {
113                value = v.convertTo(dataType);
114            } else {
115                value = ValueLong.get(value.getLong() & v.getLong()).convertTo(dataType);
116            }
117            break;
118        case Aggregate.BIT_OR:
119            if (value == null) {
120                value = v.convertTo(dataType);
121            } else {
122                value = ValueLong.get(value.getLong() | v.getLong()).convertTo(dataType);
123            }
124            break;
125        default:
126            DbException.throwInternalError("type=" + aggregateType);
127        }
128    }
129 
130    @Override
131    Value getValue(Database database, int dataType, boolean distinct) {
132        if (distinct) {
133            count = 0;
134            groupDistinct(database, dataType);
135        }
136        Value v = null;
137        switch (aggregateType) {
138        case Aggregate.SUM:
139        case Aggregate.MIN:
140        case Aggregate.MAX:
141        case Aggregate.BIT_OR:
142        case Aggregate.BIT_AND:
143        case Aggregate.BOOL_OR:
144        case Aggregate.BOOL_AND:
145            v = value;
146            break;
147        case Aggregate.AVG:
148            if (value != null) {
149                v = divide(value, count);
150            }
151            break;
152        case Aggregate.STDDEV_POP: {
153            if (count < 1) {
154                return ValueNull.INSTANCE;
155            }
156            v = ValueDouble.get(Math.sqrt(m2 / count));
157            break;
158        }
159        case Aggregate.STDDEV_SAMP: {
160            if (count < 2) {
161                return ValueNull.INSTANCE;
162            }
163            v = ValueDouble.get(Math.sqrt(m2 / (count - 1)));
164            break;
165        }
166        case Aggregate.VAR_POP: {
167            if (count < 1) {
168                return ValueNull.INSTANCE;
169            }
170            v = ValueDouble.get(m2 / count);
171            break;
172        }
173        case Aggregate.VAR_SAMP: {
174            if (count < 2) {
175                return ValueNull.INSTANCE;
176            }
177            v = ValueDouble.get(m2 / (count - 1));
178            break;
179        }
180        default:
181            DbException.throwInternalError("type=" + aggregateType);
182        }
183        return v == null ? ValueNull.INSTANCE : v.convertTo(dataType);
184    }
185 
186    private static Value divide(Value a, long by) {
187        if (by == 0) {
188            return ValueNull.INSTANCE;
189        }
190        int type = Value.getHigherOrder(a.getType(), Value.LONG);
191        Value b = ValueLong.get(by).convertTo(type);
192        a = a.convertTo(type).divide(b);
193        return a;
194    }
195 
196    private void groupDistinct(Database database, int dataType) {
197        if (distinctValues == null) {
198            return;
199        }
200        count = 0;
201        for (Value v : distinctValues.keys()) {
202            add(database, dataType, false, v);
203        }
204    }
205 
206}

[all classes][org.h2.expression]
EMMA 2.0.5312 (C) Vladimir Roubtsov