KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > SetFunction


1 /* Copyright (c) 2001-2005, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31
32 package org.hsqldb;
33
34 import java.lang.Math JavaDoc;
35 import java.math.BigDecimal JavaDoc;
36 import java.math.BigInteger JavaDoc;
37
38 import org.hsqldb.lib.HashSet;
39 import org.hsqldb.store.ValuePool;
40
41 /**
42  * Implementation of SQL set functions (currently only aggregate functions).
43  * This reduces temporary Object creation by SUM and AVG functions for
44  * INTEGER and narrower types.
45  *
46  * @author fredt@users
47  * @author boucherb@users
48  * @version 1.7.3
49  * @since 1.7.2
50  *
51  */

52 public class SetFunction {
53
54     private HashSet distinctValues;
55     private boolean isDistinct;
56
57     //
58
private int setType;
59     private int type;
60
61     //
62
private int count;
63
64     //
65
private boolean hasNull;
66     private boolean every = true;
67     private boolean some = false;
68     private long currentLong;
69     private double currentDouble;
70     private BigDecimal JavaDoc currentBigDecimal;
71     private Object JavaDoc currentValue;
72
73     SetFunction(int setType, int type, boolean isDistinct) {
74
75         this.setType = setType;
76         this.type = type;
77
78         if (isDistinct) {
79             this.isDistinct = true;
80             distinctValues = new HashSet();
81         }
82
83         if (setType == Expression.VAR_SAMP
84                 || setType == Expression.STDDEV_SAMP) {
85             this.sample = true;
86         }
87     }
88
89     void add(Session session, Object JavaDoc item) throws HsqlException {
90
91         if (item == null) {
92             hasNull = true;
93
94             return;
95         }
96
97         if (isDistinct &&!distinctValues.add(item)) {
98             return;
99         }
100
101         count++;
102
103         switch (setType) {
104
105             case Expression.COUNT :
106                 return;
107
108             case Expression.AVG :
109             case Expression.SUM : {
110                 switch (type) {
111
112                     case Types.TINYINT :
113                     case Types.SMALLINT :
114                     case Types.INTEGER :
115                         currentLong += ((Number JavaDoc) item).intValue();
116
117                         return;
118
119                     case Types.BIGINT :
120                         addLong(((Number JavaDoc) item).longValue());
121
122                         return;
123
124                     case Types.REAL :
125                     case Types.FLOAT :
126                     case Types.DOUBLE :
127                         currentDouble += ((Number JavaDoc) item).doubleValue();
128
129                         return;
130
131                     case Types.NUMERIC :
132                     case Types.DECIMAL :
133                         if (currentBigDecimal == null) {
134                             currentBigDecimal = (BigDecimal JavaDoc) item;
135                         } else {
136                             currentBigDecimal =
137                                 currentBigDecimal.add((BigDecimal JavaDoc) item);
138                         }
139
140                         return;
141
142                     default :
143                         throw Trace.error(Trace.SUM_OF_NON_NUMERIC);
144                 }
145             }
146             case Expression.MIN : {
147                 if (currentValue == null) {
148                     currentValue = item;
149
150                     return;
151                 }
152
153                 if (Column.compare(
154                         session.database.collation, currentValue, item,
155                         type) > 0) {
156                     currentValue = item;
157                 }
158
159                 return;
160             }
161             case Expression.MAX : {
162                 if (currentValue == null) {
163                     currentValue = item;
164
165                     return;
166                 }
167
168                 if (Column.compare(
169                         session.database.collation, currentValue, item,
170                         type) < 0) {
171                     currentValue = item;
172                 }
173
174                 return;
175             }
176             case Expression.EVERY :
177                 if (!(item instanceof Boolean JavaDoc)) {
178                     throw Trace.error(Trace.WRONG_DATA_TYPE);
179                 }
180
181                 every &= ((Boolean JavaDoc) item).booleanValue();
182
183                 return;
184
185             case Expression.SOME :
186                 if (!(item instanceof Boolean JavaDoc)) {
187                     throw Trace.error(Trace.WRONG_DATA_TYPE);
188                 }
189
190                 some |= ((Boolean JavaDoc) item).booleanValue();
191
192                 return;
193
194             case Expression.STDDEV_POP :
195             case Expression.STDDEV_SAMP :
196             case Expression.VAR_POP :
197             case Expression.VAR_SAMP :
198                 if (!(item instanceof Number JavaDoc)) {
199                     throw Trace.error(Trace.WRONG_DATA_TYPE);
200                 }
201
202                 addDataPoint((Number JavaDoc) item);
203
204                 return;
205         }
206     }
207
208     Object JavaDoc getValue() throws HsqlException {
209
210         if (setType == Expression.COUNT) {
211             return ValuePool.getInt(count);
212         }
213
214         if (count == 0) {
215             return null;
216         }
217
218         switch (setType) {
219
220             case Expression.AVG : {
221                 switch (type) {
222
223                     case Types.TINYINT :
224                     case Types.SMALLINT :
225                     case Types.INTEGER :
226                         return new Long JavaDoc(currentLong / count);
227
228                     case Types.BIGINT : {
229                         long value = getLongSum().divide(
230                             BigInteger.valueOf(count)).longValue();
231
232                         return new Long JavaDoc(value);
233                     }
234                     case Types.REAL :
235                     case Types.FLOAT :
236                     case Types.DOUBLE :
237                         return new Double JavaDoc(currentDouble / count);
238
239                     case Types.NUMERIC :
240                     case Types.DECIMAL :
241                         return currentBigDecimal.divide(
242                             new BigDecimal JavaDoc(count),
243                             BigDecimal.ROUND_HALF_DOWN);
244
245                     default :
246                         throw Trace.error(Trace.SUM_OF_NON_NUMERIC);
247                 }
248             }
249             case Expression.SUM : {
250                 switch (type) {
251
252                     case Types.TINYINT :
253                     case Types.SMALLINT :
254                     case Types.INTEGER :
255                         return new Long JavaDoc(currentLong);
256
257                     case Types.BIGINT :
258                         return new BigDecimal JavaDoc(getLongSum());
259
260                     case Types.REAL :
261                     case Types.FLOAT :
262                     case Types.DOUBLE :
263                         return new Double JavaDoc(currentDouble);
264
265                     case Types.NUMERIC :
266                     case Types.DECIMAL :
267                         return currentBigDecimal;
268
269                     default :
270                         throw Trace.error(Trace.SUM_OF_NON_NUMERIC);
271                 }
272             }
273             case Expression.MIN :
274             case Expression.MAX :
275                 return currentValue;
276
277             case Expression.EVERY :
278                 return every ? Boolean.TRUE
279                              : Boolean.FALSE;
280
281             case Expression.SOME :
282                 return some ? Boolean.TRUE
283                             : Boolean.FALSE;
284
285             case Expression.STDDEV_POP :
286             case Expression.STDDEV_SAMP :
287                 return getStdDev();
288
289             case Expression.VAR_POP :
290             case Expression.VAR_SAMP :
291                 return getVariance();
292
293             default :
294                 throw Trace.error(Trace.INVALID_CONVERSION);
295         }
296     }
297
298     /**
299      * During parsing and before an instance of SetFunction is created,
300      * getType is called with type parameter set to correct type when main
301      * SELECT statements contain aggregates. It is called with Types.NULL
302      * when SELECT statements within INSERT or UPDATE contian aggregates.
303      *
304      */

305     static int getType(int setType, int type) throws HsqlException {
306
307         switch (setType) {
308
309             case Expression.COUNT :
310                 return Types.INTEGER;
311
312             case Expression.AVG : {
313                 switch (type) {
314
315                     case Types.TINYINT :
316                     case Types.SMALLINT :
317                     case Types.INTEGER :
318                     case Types.BIGINT :
319                         return Types.BIGINT;
320
321                     case Types.REAL :
322                     case Types.FLOAT :
323                     case Types.DOUBLE :
324                         return Types.DOUBLE;
325
326                     case Types.NUMERIC :
327                     case Types.DECIMAL :
328                         return Types.DECIMAL;
329
330                     default :
331                         return Types.NULL;
332                 }
333             }
334             case Expression.SUM : {
335                 switch (type) {
336
337                     case Types.TINYINT :
338                     case Types.SMALLINT :
339                     case Types.INTEGER :
340                         return Types.BIGINT;
341
342                     case Types.BIGINT :
343                         return Types.DECIMAL;
344
345                     case Types.REAL :
346                     case Types.FLOAT :
347                     case Types.DOUBLE :
348                         return Types.DOUBLE;
349
350                     case Types.NUMERIC :
351                     case Types.DECIMAL :
352                         return Types.DECIMAL;
353
354                     default :
355                         return Types.NULL;
356                 }
357             }
358             case Expression.MIN :
359             case Expression.MAX :
360                 return type;
361
362             case Expression.EVERY :
363             case Expression.SOME :
364                 return Types.BOOLEAN;
365
366             case Expression.STDDEV_POP :
367             case Expression.STDDEV_SAMP :
368             case Expression.VAR_POP :
369             case Expression.VAR_SAMP :
370                 return Types.DOUBLE;
371
372             default :
373                 throw Trace.error(Trace.INVALID_CONVERSION);
374         }
375     }
376
377     // long sum - originally a separate class
378

379     /**
380      * Maintain the sum of multiple long values without creating a new
381      * BigInteger object for each addition.
382      */

383     static BigInteger JavaDoc multiplier = BigInteger.valueOf(0x0000000100000000L);
384
385 // BigInteger bigint = BigInteger.ZERO;
386
long hi;
387     long lo;
388
389     void addLong(long value) {
390
391         if (value == 0) {}
392         else if (value > 0) {
393             hi += value >> 32;
394             lo += value & 0x00000000ffffffffL;
395         } else {
396             if (value == Long.MIN_VALUE) {
397                 hi -= 0x000000080000000L;
398             } else {
399                 long temp = ~value + 1;
400
401                 hi -= temp >> 32;
402                 lo -= temp & 0x00000000ffffffffL;
403             }
404         }
405
406 // bigint = bigint.add(BigInteger.valueOf(value));
407
}
408
409     BigInteger JavaDoc getLongSum() throws HsqlException {
410
411         BigInteger JavaDoc biglo = BigInteger.valueOf(lo);
412         BigInteger JavaDoc bighi = BigInteger.valueOf(hi);
413         BigInteger JavaDoc result = (bighi.multiply(multiplier)).add(biglo);
414
415 /*
416             if ( result.compareTo(bigint) != 0 ){
417                  throw Trace.error(Trace.GENERAL_ERROR, "longSum mismatch");
418             }
419 */

420         return result;
421     }
422
423     // end long sum
424
// statistics support - written by Campbell
425
// this section was orginally an independent class
426
private double sk;
427     private double vk;
428     private long n;
429     private boolean initialized;
430     private boolean sample;
431
432     private void addDataPoint(Number JavaDoc x) { // optimized
433

434         double xi;
435         double xsi;
436         long nm1;
437
438         if (x == null) {
439             return;
440         }
441
442         xi = x.doubleValue();
443
444         if (!initialized) {
445             n = 1;
446             sk = xi;
447             vk = 0.0;
448             initialized = true;
449
450             return;
451         }
452
453         n++;
454
455         nm1 = (n - 1);
456         xsi = (sk - (xi * nm1));
457         vk += ((xsi * xsi) / n) / nm1;
458         sk += xi;
459     }
460
461     private Number JavaDoc getVariance() {
462
463         if (!initialized) {
464             return null;
465         }
466
467         return sample ? (n == 1) ? null // NULL (not NaN) is correct in this case
468
: new Double JavaDoc(vk / (double) (n - 1))
469                       : new Double JavaDoc(vk / (double) (n));
470     }
471
472     private Number JavaDoc getStdDev() {
473
474         if (!initialized) {
475             return null;
476         }
477
478         return sample ? (n == 1) ? null // NULL (not NaN) is correct in this case
479
: new Double JavaDoc(Math.sqrt(vk
480                                  / (double) (n - 1)))
481                       : new Double JavaDoc(Math.sqrt(vk / (double) (n)));
482     }
483
484     // end statistics support
485
}
486
Popular Tags