KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > Column


1 /* Copyright (c) 1995-2000, The Hypersonic SQL 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 Hypersonic SQL 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 THE HYPERSONIC SQL GROUP,
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  * This software consists of voluntary contributions made by many individuals
31  * on behalf of the Hypersonic SQL Group.
32  *
33  *
34  * For work added by the HSQL Development Group:
35  *
36  * Copyright (c) 2001-2005, The HSQL Development Group
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions are met:
41  *
42  * Redistributions of source code must retain the above copyright notice, this
43  * list of conditions and the following disclaimer.
44  *
45  * Redistributions in binary form must reproduce the above copyright notice,
46  * this list of conditions and the following disclaimer in the documentation
47  * and/or other materials provided with the distribution.
48  *
49  * Neither the name of the HSQL Development Group nor the names of its
50  * contributors may be used to endorse or promote products derived from this
51  * software without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
54  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
57  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64  */

65
66
67 package org.hsqldb;
68
69 import java.io.IOException JavaDoc;
70 import java.io.Serializable JavaDoc;
71 import java.math.BigDecimal JavaDoc;
72 import java.math.BigInteger JavaDoc;
73 import java.sql.Date JavaDoc;
74 import java.sql.Time JavaDoc;
75 import java.sql.Timestamp JavaDoc;
76
77 import org.hsqldb.HsqlNameManager.HsqlName;
78 import org.hsqldb.lib.StringConverter;
79 import org.hsqldb.store.ValuePool;
80 import org.hsqldb.types.Binary;
81 import org.hsqldb.types.JavaObject;
82 import org.hsqldb.lib.java.JavaSystem;
83
84 // fredt@users 20020130 - patch 491987 by jimbag@users
85
// fredt@users 20020320 - doc 1.7.0 - update
86
// fredt@users 20020401 - patch 442993 by fredt - arithmetic expressions
87
// to allow mixed type arithmetic expressions beginning with a narrower type
88
// changes applied to several lines of code and not marked separately
89
// consists of changes to arithmatic functions to allow promotion of
90
// java.lang.Number values and new functions to choose type for promotion
91
// fredt@users 20020401 - patch 455757 by galena@users (Michiel de Roo)
92
// interpretation of TINYINT as Byte instead of Short
93
// fredt@users 20020130 - patch 491987 by jimbag@users
94
// support for sql standard char and varchar. size is maintained as
95
// defined in the DDL and trimming and padding takes place accordingly
96
// modified by fredt - trimming and padding are turned off by default but
97
// can be applied accross the database by defining sql.enforce_size=true in
98
// database.properties file
99
// fredt@users 20020215 - patch 1.7.0 by fredt - quoted identifiers
100
// applied to different parts to support the sql standard for
101
// naming of columns and tables (use of quoted identifiers as names)
102
// fredt@users 20020328 - patch 1.7.0 by fredt - change REAL to Double
103
// fredt@users 20020402 - patch 1.7.0 by fredt - type conversions
104
// frequently used type conversions are done without creating temporary
105
// Strings to reduce execution time and garbage collection
106
// fredt@users 20021013 - patch 1.7.1 by fredt - type conversions
107
// scripting of Double.Nan and infinity values
108
// fredt@users 20030715 - patch 1.7.2 - type narrowing for numeric values
109
// fredt@users - patch 1.8.0 - enforcement of precision and scale
110

111 /**
112  * Implementation of SQL table columns as defined in DDL statements with
113  * static methods to process their values.<p>
114  *
115  * Enhanced type checking and conversion by fredt@users
116  *
117  * @author Thomas Mueller (Hypersonic SQL Group)
118  * @author fredt@users
119  * @version 1.8.0
120  * @since Hypersonic SQL
121  */

122 public class Column {
123
124 // --------------------------------------------------
125
// DDL name, size, scale, null, identity and default values
126
// most variables are final but not declared so because of a bug in
127
// JDK 1.1.8 compiler
128
public HsqlName columnName;
129     private int colType;
130     private int colSize;
131     private int colScale;
132     private boolean isNullable;
133     private boolean isIdentity;
134     private boolean isPrimaryKey;
135     private Expression defaultExpression;
136     long identityStart;
137     long identityIncrement;
138     static final BigInteger JavaDoc MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
139     static final BigInteger JavaDoc MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);
140     static final BigInteger JavaDoc MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE);
141     static final BigInteger JavaDoc MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE);
142     static final BigDecimal JavaDoc BIG_DECIMAL_0 = new BigDecimal JavaDoc(0.0);
143     static final BigDecimal JavaDoc BIG_DECIMAL_1 = new BigDecimal JavaDoc(1.0);
144
145     /**
146      * Creates a column defined in DDL statement.
147      *
148      * @param name
149      * @param nullable
150      * @param type
151      * @param size
152      * @param scale
153      * @param identity
154      * @param startvalue
155      * @param increment
156      * @param primarykey
157      * @param defstring
158      */

159     Column(HsqlName name, boolean nullable, int type, int size, int scale,
160             boolean primarykey,
161             Expression defexpression) throws HsqlException {
162
163         columnName = name;
164         isNullable = nullable;
165         colType = type;
166         colSize = size;
167         colScale = scale;
168         isPrimaryKey = primarykey;
169         defaultExpression = defexpression;
170     }
171
172     void setIdentity(boolean identity, long startvalue,
173                      long increment) throws HsqlException {
174
175         isIdentity = identity;
176         identityStart = startvalue;
177         identityIncrement = increment;
178
179         if (isIdentity) {
180             if (colType == Types.INTEGER) {
181                 if (identityStart > Integer.MAX_VALUE
182                         || identityIncrement > Integer.MAX_VALUE) {
183                     throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE,
184                                       columnName.statementName);
185                 }
186             }
187         }
188     }
189
190     private Column() {}
191
192     /**
193      * Used for primary key changes.
194      */

195     Column duplicate(boolean withIdentity) throws HsqlException {
196
197         Column newCol = new Column();
198
199         newCol.columnName = columnName;
200         newCol.isNullable = isNullable;
201         newCol.colType = colType;
202         newCol.colSize = colSize;
203         newCol.colScale = colScale;
204         newCol.defaultExpression = defaultExpression;
205
206         if (withIdentity) {
207             newCol.setIdentity(isIdentity, identityStart, identityIncrement);
208         }
209
210         return newCol;
211     }
212
213     void setType(Column other) {
214
215         isNullable = other.isNullable;
216         colType = other.colType;
217         colSize = other.colSize;
218         colScale = other.colScale;
219     }
220
221     /**
222      * Is this the identity column in the table.
223      *
224      * @return boolean
225      */

226     boolean isIdentity() {
227         return isIdentity;
228     }
229
230     /**
231      * Is column nullable.
232      *
233      * @return boolean
234      */

235     boolean isNullable() {
236         return isNullable;
237     }
238
239     /**
240      * Set nullable.
241      *
242      */

243     void setNullable(boolean value) {
244         isNullable = value;
245     }
246
247     /**
248      * Is this single column primary key of the table.
249      *
250      * @return boolean
251      */

252     public boolean isPrimaryKey() {
253         return isPrimaryKey;
254     }
255
256     /**
257      * Set primary key.
258      *
259      */

260     void setPrimaryKey(boolean value) {
261         isPrimaryKey = value;
262     }
263
264     /**
265      * Returns default value in the session context.
266      */

267     Object JavaDoc getDefaultValue(Session session) throws HsqlException {
268
269         return defaultExpression == null ? null
270                                          : defaultExpression.getValue(session,
271                                          colType);
272     }
273
274     /**
275      * Returns DDL for default value.
276      */

277     String JavaDoc getDefaultDDL() {
278
279         String JavaDoc ddl = null;
280
281         try {
282             ddl = defaultExpression == null ? null
283                                             : defaultExpression.getDDL();
284         } catch (HsqlException e) {}
285
286         return ddl;
287     }
288
289     /**
290      * Returns default expression for the column.
291      */

292     Expression getDefaultExpression() {
293         return defaultExpression;
294     }
295
296     void setDefaultExpression(Expression expr) {
297         defaultExpression = expr;
298     }
299
300     /**
301      * Type of the column.
302      *
303      * @return java.sql.Types int value for the column
304      */

305     int getType() {
306         return colType;
307     }
308
309     int getDIType() {
310         return colType == Types.VARCHAR_IGNORECASE ? Types.VARCHAR
311                                                    : colType;
312     }
313
314     int getDITypeSub() {
315
316         if (colType == Types.VARCHAR_IGNORECASE) {
317             return Types.TYPE_SUB_IGNORECASE;
318         }
319
320         return Types.TYPE_SUB_DEFAULT;
321     }
322
323     /**
324      * Size of the column in DDL (0 if not defined).
325      *
326      * @return DDL size of column
327      */

328     int getSize() {
329         return colSize;
330     }
331
332     /**
333      * Scale of the column in DDL (0 if not defined).
334      *
335      * @return DDL scale of column
336      */

337     int getScale() {
338         return colScale;
339     }
340
341     /**
342      * Add two object of a given type
343      *
344      * @param a
345      * @param b
346      * @param type
347      * @return result
348      * @throws HsqlException
349      */

350     static Object JavaDoc add(Object JavaDoc a, Object JavaDoc b, int type) throws HsqlException {
351
352         if (a == null || b == null) {
353             return null;
354         }
355
356         switch (type) {
357
358             case Types.NULL :
359                 return null;
360
361             case Types.REAL :
362             case Types.FLOAT :
363             case Types.DOUBLE : {
364                 double ad = ((Number JavaDoc) a).doubleValue();
365                 double bd = ((Number JavaDoc) b).doubleValue();
366
367                 return ValuePool.getDouble(Double.doubleToLongBits(ad + bd));
368
369 // return new Double(ad + bd);
370
}
371             case Types.VARCHAR :
372             case Types.CHAR :
373             case Types.LONGVARCHAR :
374             case Types.VARCHAR_IGNORECASE :
375                 return (String JavaDoc) a + (String JavaDoc) b;
376
377             case Types.NUMERIC :
378             case Types.DECIMAL : {
379                 BigDecimal JavaDoc abd = (BigDecimal JavaDoc) a;
380                 BigDecimal JavaDoc bbd = (BigDecimal JavaDoc) b;
381
382                 return abd.add(bbd);
383             }
384             case Types.TINYINT :
385             case Types.SMALLINT :
386             case Types.INTEGER : {
387                 int ai = ((Number JavaDoc) a).intValue();
388                 int bi = ((Number JavaDoc) b).intValue();
389
390                 return ValuePool.getInt(ai + bi);
391             }
392             case Types.BIGINT : {
393                 long longa = ((Number JavaDoc) a).longValue();
394                 long longb = ((Number JavaDoc) b).longValue();
395
396                 return ValuePool.getLong(longa + longb);
397             }
398             default :
399                 throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
400                                   Types.getTypeString(type));
401         }
402     }
403
404     /**
405      * Concat two objects by turning them into strings first.
406      *
407      * @param a
408      * @param b
409      * @return result
410      * @throws HsqlException
411      */

412     static Object JavaDoc concat(Object JavaDoc a, Object JavaDoc b) throws HsqlException {
413
414         if (a == null || b == null) {
415             return null;
416         }
417
418         return a.toString() + b.toString();
419     }
420
421     /**
422      * Negate a numeric object.
423      *
424      * @param a
425      * @param type
426      * @return result
427      * @throws HsqlException
428      */

429     static Object JavaDoc negate(Object JavaDoc a, int type) throws HsqlException {
430
431         if (a == null) {
432             return null;
433         }
434
435         switch (type) {
436
437             case Types.NULL :
438                 return null;
439
440             case Types.REAL :
441             case Types.FLOAT :
442             case Types.DOUBLE : {
443                 double ad = -((Number JavaDoc) a).doubleValue();
444
445                 return ValuePool.getDouble(Double.doubleToLongBits(ad));
446             }
447             case Types.NUMERIC :
448             case Types.DECIMAL :
449                 return ((BigDecimal JavaDoc) a).negate();
450
451             case Types.TINYINT :
452             case Types.SMALLINT :
453             case Types.INTEGER :
454                 return ValuePool.getInt(-((Number JavaDoc) a).intValue());
455
456             case Types.BIGINT :
457                 return ValuePool.getLong(-((Number JavaDoc) a).longValue());
458
459             default :
460                 throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
461                                   Types.getTypeString(type));
462         }
463     }
464
465     /**
466      * Multiply two numeric objects.
467      *
468      * @param a
469      * @param b
470      * @param type
471      * @return result
472      * @throws HsqlException
473      */

474     static Object JavaDoc multiply(Object JavaDoc a, Object JavaDoc b,
475                            int type) throws HsqlException {
476
477         if (a == null || b == null) {
478             return null;
479         }
480
481 // fredt@users - type conversion - may need to apply to other arithmetic operations too
482
if (!(a instanceof Number JavaDoc && b instanceof Number JavaDoc)) {
483             a = Column.convertObject(a, type);
484             b = Column.convertObject(b, type);
485         }
486
487         switch (type) {
488
489             case Types.NULL :
490                 return null;
491
492             case Types.REAL :
493             case Types.FLOAT :
494             case Types.DOUBLE : {
495                 double ad = ((Number JavaDoc) a).doubleValue();
496                 double bd = ((Number JavaDoc) b).doubleValue();
497
498                 return ValuePool.getDouble(Double.doubleToLongBits(ad * bd));
499             }
500             case Types.NUMERIC :
501             case Types.DECIMAL : {
502                 BigDecimal JavaDoc abd = (BigDecimal JavaDoc) a;
503                 BigDecimal JavaDoc bbd = (BigDecimal JavaDoc) b;
504
505                 return abd.multiply(bbd);
506             }
507             case Types.TINYINT :
508             case Types.SMALLINT :
509             case Types.INTEGER : {
510                 int ai = ((Number JavaDoc) a).intValue();
511                 int bi = ((Number JavaDoc) b).intValue();
512
513                 return ValuePool.getInt(ai * bi);
514             }
515             case Types.BIGINT : {
516                 long longa = ((Number JavaDoc) a).longValue();
517                 long longb = ((Number JavaDoc) b).longValue();
518
519                 return ValuePool.getLong(longa * longb);
520             }
521             default :
522                 throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
523                                   Types.getTypeString(type));
524         }
525     }
526
527     /**
528      * Divide numeric object a by object b.
529      *
530      * @param a
531      * @param b
532      * @param type
533      * @return result
534      * @throws HsqlException
535      */

536     static Object JavaDoc divide(Object JavaDoc a, Object JavaDoc b, int type) throws HsqlException {
537
538         if (a == null || b == null) {
539             return null;
540         }
541
542         switch (type) {
543
544             case Types.NULL :
545                 return null;
546
547             case Types.REAL :
548             case Types.FLOAT :
549             case Types.DOUBLE : {
550                 double ad = ((Number JavaDoc) a).doubleValue();
551                 double bd = ((Number JavaDoc) b).doubleValue();
552
553                 return ValuePool.getDouble(Double.doubleToLongBits(ad / bd));
554             }
555             case Types.NUMERIC :
556             case Types.DECIMAL : {
557                 BigDecimal JavaDoc abd = (BigDecimal JavaDoc) a;
558                 BigDecimal JavaDoc bbd = (BigDecimal JavaDoc) b;
559                 int scale = abd.scale() > bbd.scale() ? abd.scale()
560                                                              : bbd.scale();
561
562                 return (bbd.signum() == 0) ? null
563                                            : abd.divide(bbd, scale,
564                                            BigDecimal.ROUND_HALF_DOWN);
565             }
566             case Types.TINYINT :
567             case Types.SMALLINT :
568             case Types.INTEGER : {
569                 int ai = ((Number JavaDoc) a).intValue();
570                 int bi = ((Number JavaDoc) b).intValue();
571
572                 if (bi == 0) {
573                     throw Trace.error(Trace.DIVISION_BY_ZERO);
574                 }
575
576                 return ValuePool.getInt(ai / bi);
577             }
578             case Types.BIGINT : {
579                 long longa = ((Number JavaDoc) a).longValue();
580                 long longb = ((Number JavaDoc) b).longValue();
581
582                 return (longb == 0) ? null
583                                     : ValuePool.getLong(longa / longb);
584             }
585             default :
586                 throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
587                                   Types.getTypeString(type));
588         }
589     }
590
591     /**
592      * Subtract numeric object b from object a.
593      *
594      * @param a
595      * @param b
596      * @param type
597      * @return result
598      * @throws HsqlException
599      */

600     static Object JavaDoc subtract(Object JavaDoc a, Object JavaDoc b,
601                            int type) throws HsqlException {
602
603         if (a == null || b == null) {
604             return null;
605         }
606
607         switch (type) {
608
609             case Types.NULL :
610                 return null;
611
612             case Types.REAL :
613             case Types.FLOAT :
614             case Types.DOUBLE : {
615                 double ad = ((Number JavaDoc) a).doubleValue();
616                 double bd = ((Number JavaDoc) b).doubleValue();
617
618                 return ValuePool.getDouble(Double.doubleToLongBits(ad - bd));
619             }
620             case Types.NUMERIC :
621             case Types.DECIMAL : {
622                 BigDecimal JavaDoc abd = (BigDecimal JavaDoc) a;
623                 BigDecimal JavaDoc bbd = (BigDecimal JavaDoc) b;
624
625                 return abd.subtract(bbd);
626             }
627             case Types.TINYINT :
628             case Types.SMALLINT :
629             case Types.INTEGER : {
630                 int ai = ((Number JavaDoc) a).intValue();
631                 int bi = ((Number JavaDoc) b).intValue();
632
633                 return ValuePool.getInt(ai - bi);
634             }
635             case Types.BIGINT : {
636                 long longa = ((Number JavaDoc) a).longValue();
637                 long longb = ((Number JavaDoc) b).longValue();
638
639                 return ValuePool.getLong(longa - longb);
640             }
641             default :
642                 throw Trace.error(Trace.FUNCTION_NOT_SUPPORTED,
643                                   Types.getTypeString(type));
644         }
645     }
646
647 // boucherb@users 2003-09-25
648
// TODO: Maybe use //#ifdef tag or reflective static method attribute
649
// instantiation to take advantage of String.compareToIgnoreCase when
650
// available (JDK 1.2 and greater) during ANT build. That or perhaps
651
// consider using either local character-wise comparison or first converting
652
// to lower case and then to upper case. Sun states that the JDK 1.2 introduced
653
// String.compareToIngnorCase() comparison involves calling
654
// Character.toLowerCase(Character.toUpperCase()) on compared characters,
655
// to correctly handle some caveats concering using only the one operation or
656
// the other outside the ascii character range.
657
// fredt@users 20020130 - patch 418022 by deforest@users
658
// use of rtrim() to mimic SQL92 behaviour
659

660     /**
661      * Compare a with b and return int value as result.
662      *
663      * @param a instance of Java wrapper, depending on type, but always same for a & b (can be null)
664      * @param b instance of Java wrapper, depending on type, but always same for a & b (can be null)
665      * @param type one of the java.sql.Types
666      * @return result 1 if a>b, 0 if a=b, -1 if b>a
667      * @throws HsqlException
668      */

669     static int compare(Collation collation, Object JavaDoc a, Object JavaDoc b, int type) {
670
671         int i = 0;
672
673         if (a == b) {
674             return 0;
675         }
676
677         // Current null handling here: null==null and smaller any value
678
// Note, standard SQL null handling is handled by Expression.test() calling testNull() instead of this!
679
// Attention, this is also used for grouping ('null' is one group)
680
if (a == null) {
681             return -1;
682         }
683
684         if (b == null) {
685             return 1;
686         }
687
688         switch (type) {
689
690             case Types.NULL :
691                 return 0;
692
693             case Types.VARCHAR :
694             case Types.LONGVARCHAR :
695                 return collation.compare((String JavaDoc) a, (String JavaDoc) b);
696
697             case Types.CHAR :
698                 return collation.compare(Library.rtrim((String JavaDoc) a),
699                                          Library.rtrim((String JavaDoc) b));
700
701             case Types.VARCHAR_IGNORECASE :
702                 return collation.compareIgnoreCase(((String JavaDoc) a),
703                                                    ((String JavaDoc) b));
704
705             case Types.TINYINT :
706             case Types.SMALLINT :
707             case Types.INTEGER : {
708                 int ai = ((Number JavaDoc) a).intValue();
709                 int bi = ((Number JavaDoc) b).intValue();
710
711                 return (ai > bi) ? 1
712                                  : (bi > ai ? -1
713                                             : 0);
714             }
715             case Types.BIGINT : {
716                 long longa = ((Number JavaDoc) a).longValue();
717                 long longb = ((Number JavaDoc) b).longValue();
718
719                 return (longa > longb) ? 1
720                                        : (longb > longa ? -1
721                                                         : 0);
722             }
723             case Types.REAL :
724             case Types.FLOAT :
725             case Types.DOUBLE : {
726                 double ad = ((Number JavaDoc) a).doubleValue();
727                 double bd = ((Number JavaDoc) b).doubleValue();
728
729                 return (ad > bd) ? 1
730                                  : (bd > ad ? -1
731                                             : 0);
732             }
733             case Types.NUMERIC :
734             case Types.DECIMAL :
735                 i = ((BigDecimal JavaDoc) a).compareTo((BigDecimal JavaDoc) b);
736                 break;
737
738             case Types.DATE :
739                 return HsqlDateTime.compare((Date JavaDoc) a, (Date JavaDoc) b);
740
741             case Types.TIME :
742                 return HsqlDateTime.compare((Time JavaDoc) a, (Time JavaDoc) b);
743
744             case Types.TIMESTAMP :
745                 return HsqlDateTime.compare((Timestamp JavaDoc) a, (Timestamp JavaDoc) b);
746
747             case Types.BOOLEAN : {
748                 boolean boola = ((Boolean JavaDoc) a).booleanValue();
749                 boolean boolb = ((Boolean JavaDoc) b).booleanValue();
750
751                 return (boola == boolb) ? 0
752                                         : (boolb ? -1
753                                                  : 1);
754             }
755             case Types.BINARY :
756             case Types.VARBINARY :
757             case Types.LONGVARBINARY :
758                 if (a instanceof Binary && b instanceof Binary) {
759                     i = compareTo(((Binary) a).getBytes(),
760                                   ((Binary) b).getBytes());
761                 }
762                 break;
763
764             case Types.OTHER :
765                 return 0;
766         }
767
768         return (i == 0) ? 0
769                         : (i < 0 ? -1
770                                  : 1);
771     }
772
773     /**
774      * Convert an object into a Java object that represents its SQL type.<p>
775      * All internal type conversion operations start with
776      * this method. If a direct conversion doesn't take place, the object
777      * is converted into a string first and an attempt is made to convert
778      * the string into the target type.<br>
779      *
780      * One objective of this mehod is to ensure the Object can be converted
781      * to the given SQL type. For example, a very large BIGINT
782      * value cannot be narrowed down to an INTEGER or SMALLINT.<br>
783      *
784      * Type conversion performed by this method has gradually evolved in 1.7.2
785      * to allow narrowing of numeric types in all cases according to the SQL
786      * standard.<br>
787      *
788      * Another new objective is to normalize DATETIME values.<br>
789      *
790      * Objects set via JDBC PreparedStatement use this method to convert
791      * the data to the Java type that is required for custom serialization
792      * by the engine. <br>
793      *
794      * @param o
795      * @param type
796      * @return result
797      * @throws HsqlException
798      */

799     public static Object JavaDoc convertObject(Object JavaDoc o,
800                                        int type) throws HsqlException {
801
802         try {
803             if (o == null) {
804                 return null;
805             }
806
807             switch (type) {
808
809                 case Types.NULL :
810                     return null;
811
812                 case Types.TINYINT :
813                     if (o instanceof java.lang.String JavaDoc) {
814                         o = Library.trim((String JavaDoc) o, " ", true, true);
815
816                         int val = Integer.parseInt((String JavaDoc) o);
817
818                         o = ValuePool.getInt(val);
819                     }
820
821                     if (o instanceof java.lang.Integer JavaDoc) {
822                         int temp = ((Number JavaDoc) o).intValue();
823
824                         if (Byte.MAX_VALUE < temp || temp < Byte.MIN_VALUE) {
825                             throw Trace.error(
826                                 Trace.NUMERIC_VALUE_OUT_OF_RANGE);
827                         }
828
829                         return o;
830                     }
831
832                     if (o instanceof java.lang.Long JavaDoc) {
833                         long temp = ((Number JavaDoc) o).longValue();
834
835                         if (Byte.MAX_VALUE < temp || temp < Byte.MIN_VALUE) {
836                             throw Trace.error(
837                                 Trace.NUMERIC_VALUE_OUT_OF_RANGE);
838                         }
839
840                         return ValuePool.getInt(((Number JavaDoc) o).intValue());
841                     }
842
843                     // fredt@users - direct conversion to optimise JDBC setObject(Byte)
844
if (o instanceof java.lang.Byte JavaDoc) {
845                         return ValuePool.getInt(((Number JavaDoc) o).intValue());
846                     }
847
848                     // fredt@users - returns to this method for range checking
849
if (o instanceof java.lang.Number JavaDoc) {
850                         return convertObject(convertToInt(o), type);
851                     }
852
853                     if (o instanceof java.lang.Boolean JavaDoc) {
854                         return ((Boolean JavaDoc) o).booleanValue()
855                                ? ValuePool.getInt(1)
856                                : ValuePool.getInt(0);
857                     }
858                     break;
859
860                 case Types.SMALLINT :
861                     if (o instanceof java.lang.String JavaDoc) {
862                         o = Library.trim((String JavaDoc) o, " ", true, true);
863
864                         int val = Integer.parseInt((String JavaDoc) o);
865
866                         o = ValuePool.getInt(val);
867                     }
868
869                     if (o instanceof java.lang.Integer JavaDoc) {
870                         int temp = ((Number JavaDoc) o).intValue();
871
872                         if (Short.MAX_VALUE < temp
873                                 || temp < Short.MIN_VALUE) {
874                             throw Trace.error(
875                                 Trace.NUMERIC_VALUE_OUT_OF_RANGE);
876                         }
877
878                         return o;
879                     }
880
881                     if (o instanceof java.lang.Long JavaDoc) {
882                         long temp = ((Number JavaDoc) o).longValue();
883
884                         if (Short.MAX_VALUE < temp
885                                 || temp < Short.MIN_VALUE) {
886                             throw Trace.error(
887                                 Trace.NUMERIC_VALUE_OUT_OF_RANGE);
888                         }
889
890                         return ValuePool.getInt(((Number JavaDoc) o).intValue());
891                     }
892
893                     // fredt@users - direct conversion for JDBC setObject(Short), etc.
894
if (o instanceof Byte JavaDoc || o instanceof Short JavaDoc) {
895                         return ValuePool.getInt(((Number JavaDoc) o).intValue());
896                     }
897
898                     // fredt@users - returns to this method for range checking
899
if (o instanceof Number JavaDoc) {
900                         return convertObject(convertToInt(o), type);
901                     }
902
903                     if (o instanceof java.lang.Boolean JavaDoc) {
904                         return ((Boolean JavaDoc) o).booleanValue()
905                                ? ValuePool.getInt(1)
906                                : ValuePool.getInt(0);
907                     }
908                     break;
909
910                 case Types.INTEGER :
911                     if (o instanceof java.lang.Integer JavaDoc) {
912                         return o;
913                     }
914
915                     if (o instanceof java.lang.String JavaDoc) {
916                         o = Library.trim((String JavaDoc) o, " ", true, true);
917
918                         int val = Integer.parseInt((String JavaDoc) o);
919
920                         return ValuePool.getInt(val);
921                     }
922
923                     if (o instanceof java.lang.Long JavaDoc) {
924                         long temp = ((Number JavaDoc) o).longValue();
925
926                         if (Integer.MAX_VALUE < temp
927                                 || temp < Integer.MIN_VALUE) {
928                             throw Trace.error(
929                                 Trace.NUMERIC_VALUE_OUT_OF_RANGE);
930                         }
931
932                         return ValuePool.getInt(((Number JavaDoc) o).intValue());
933                     }
934
935                     if (o instanceof Byte JavaDoc || o instanceof Short JavaDoc) {
936                         return ValuePool.getInt(((Number JavaDoc) o).intValue());
937                     }
938
939                     if (o instanceof java.lang.Number JavaDoc) {
940                         return convertToInt(o);
941                     }
942
943                     if (o instanceof java.lang.Boolean JavaDoc) {
944                         return ((Boolean JavaDoc) o).booleanValue()
945                                ? ValuePool.getInt(1)
946                                : ValuePool.getInt(0);
947                     }
948                     break;
949
950                 case Types.BIGINT :
951                     if (o instanceof java.lang.Long JavaDoc) {
952                         return o;
953                     }
954
955                     if (o instanceof java.lang.String JavaDoc) {
956                         o = Library.trim((String JavaDoc) o, " ", true, true);
957
958                         long val = Long.parseLong((String JavaDoc) o);
959
960                         return ValuePool.getLong(val);
961                     }
962
963                     if (o instanceof java.lang.Integer JavaDoc) {
964                         return ValuePool.getLong(((Integer JavaDoc) o).longValue());
965                     }
966
967                     if (o instanceof Byte JavaDoc || o instanceof Short JavaDoc) {
968                         return ValuePool.getLong(((Number JavaDoc) o).intValue());
969                     }
970
971                     if (o instanceof java.lang.Number JavaDoc) {
972                         return convertToLong(o);
973                     }
974
975                     if (o instanceof java.lang.Boolean JavaDoc) {
976                         return ((Boolean JavaDoc) o).booleanValue()
977                                ? ValuePool.getLong(1)
978                                : ValuePool.getLong(0);
979                     }
980                     break;
981
982                 case Types.REAL :
983                 case Types.FLOAT :
984                 case Types.DOUBLE :
985                     if (o instanceof java.lang.Double JavaDoc) {
986                         return o;
987                     }
988
989                     if (o instanceof java.lang.String JavaDoc) {
990                         o = Library.trim((String JavaDoc) o, " ", true, true);
991
992                         double d = JavaSystem.parseDouble((String JavaDoc) o);
993                         long l = Double.doubleToLongBits(d);
994
995                         return ValuePool.getDouble(l);
996                     }
997
998                     if (o instanceof java.lang.Number JavaDoc) {
999                         return convertToDouble(o);
1000                    }
1001
1002                    if (o instanceof java.lang.Boolean JavaDoc) {
1003                        return ((Boolean JavaDoc) o).booleanValue()
1004                               ? ValuePool.getDouble(1)
1005                               : ValuePool.getDouble(0);
1006                    }
1007                    break;
1008
1009                case Types.NUMERIC :
1010                case Types.DECIMAL :
1011                    if (o instanceof BigDecimal JavaDoc) {
1012                        return o;
1013                    }
1014
1015                    if (o instanceof Long JavaDoc) {
1016                        return BigDecimal.valueOf(((Long JavaDoc) o).longValue());
1017                    }
1018
1019                    if (o instanceof java.lang.Boolean JavaDoc) {
1020                        return ((Boolean JavaDoc) o).booleanValue() ? BIG_DECIMAL_1
1021                                                            : BIG_DECIMAL_0;
1022                    }
1023                    break;
1024
1025                case Types.BOOLEAN :
1026                    if (o instanceof java.lang.Boolean JavaDoc) {
1027                        return (Boolean JavaDoc) o;
1028                    }
1029
1030                    if (o instanceof java.lang.String JavaDoc) {
1031                        o = Library.trim((String JavaDoc) o, " ", true, true);
1032
1033                        return ((String JavaDoc) o).equalsIgnoreCase("TRUE")
1034                               ? Boolean.TRUE
1035                               : Boolean.FALSE;
1036                    }
1037
1038                    if (o instanceof Integer JavaDoc) {
1039                        return ((Integer JavaDoc) o).intValue() == 0 ? Boolean.FALSE
1040                                                             : Boolean.TRUE;
1041                    }
1042
1043                    if (o instanceof Long JavaDoc) {
1044                        return ((Long JavaDoc) o).longValue() == 0L ? Boolean.FALSE
1045                                                            : Boolean.TRUE;
1046                    }
1047
1048                    if (o instanceof java.lang.Double JavaDoc) {
1049                        return ((Double JavaDoc) o).doubleValue() == 0.0
1050                               ? Boolean.FALSE
1051                               : Boolean.TRUE;
1052                    }
1053
1054                    if (o instanceof BigDecimal JavaDoc) {
1055                        return ((BigDecimal JavaDoc) o).equals(BIG_DECIMAL_0)
1056                               ? Boolean.FALSE
1057                               : Boolean.TRUE;
1058                    }
1059
1060                    throw Trace.error(Trace.WRONG_DATA_TYPE);
1061                case Types.VARCHAR_IGNORECASE :
1062                case Types.VARCHAR :
1063                case Types.CHAR :
1064                case Types.LONGVARCHAR :
1065                    if (o instanceof java.lang.String JavaDoc) {
1066                        return o;
1067                    }
1068
1069                    if (o instanceof Time JavaDoc) {
1070                        return HsqlDateTime.getTimeString((Time JavaDoc) o, null);
1071                    }
1072
1073                    if (o instanceof Timestamp JavaDoc) {
1074                        return HsqlDateTime.getTimestampString((Timestamp JavaDoc) o,
1075                                                               null);
1076                    }
1077
1078                    if (o instanceof Date JavaDoc) {
1079                        return HsqlDateTime.getDateString((Date JavaDoc) o, null);
1080                    }
1081
1082                    if (o instanceof byte[]) {
1083                        return StringConverter.byteToHex((byte[]) o);
1084                    }
1085                    break;
1086
1087                case Types.TIME :
1088                    if (o instanceof Time JavaDoc) {
1089                        return HsqlDateTime.getNormalisedTime((Time JavaDoc) o);
1090                    }
1091
1092                    if (o instanceof Timestamp JavaDoc) {
1093                        return HsqlDateTime.getNormalisedTime((Timestamp JavaDoc) o);
1094                    }
1095
1096                    if (o instanceof String JavaDoc) {
1097                        return HsqlDateTime.timeValue((String JavaDoc) o);
1098                    }
1099
1100                    if (o instanceof Date JavaDoc) {
1101                        throw Trace.error(Trace.INVALID_CONVERSION,
1102                                          Types.getTypeString(type));
1103                    }
1104                    break;
1105
1106                case Types.TIMESTAMP :
1107                    if (o instanceof Timestamp JavaDoc) {
1108                        return o;
1109                    }
1110
1111                    if (o instanceof Time JavaDoc) {
1112                        return HsqlDateTime.getNormalisedTimestamp((Time JavaDoc) o);
1113                    }
1114
1115                    if (o instanceof Date JavaDoc) {
1116                        return HsqlDateTime.getNormalisedTimestamp((Date JavaDoc) o);
1117                    }
1118
1119                    if (o instanceof String JavaDoc) {
1120                        return HsqlDateTime.timestampValue((String JavaDoc) o);
1121                    }
1122                    break;
1123
1124                case Types.DATE :
1125                    if (o instanceof Date JavaDoc) {
1126                        return HsqlDateTime.getNormalisedDate((Date JavaDoc) o);
1127                    }
1128
1129                    if (o instanceof Timestamp JavaDoc) {
1130                        return HsqlDateTime.getNormalisedDate((Timestamp JavaDoc) o);
1131                    }
1132
1133                    if (o instanceof String JavaDoc) {
1134                        return HsqlDateTime.dateValue((String JavaDoc) o);
1135                    }
1136
1137                    if (o instanceof Time JavaDoc) {
1138                        throw Trace.error(Trace.INVALID_CONVERSION,
1139                                          Types.getTypeString(type));
1140                    }
1141                    break;
1142
1143                case Types.BINARY :
1144                case Types.VARBINARY :
1145                case Types.LONGVARBINARY :
1146                    if (o instanceof Binary) {
1147                        return o;
1148                    } else if (o instanceof byte[]) {
1149                        return new Binary((byte[]) o, false);
1150                    } else if (o instanceof String JavaDoc) {
1151
1152                        /**
1153                         * @todo fredt - we need this for script processing only
1154                         * handle the script separately and process normal
1155                         * conversion according to rules in SQL
1156                         * standard
1157                         */

1158                        return new Binary(
1159                            StringConverter.hexToByte((String JavaDoc) o), false);
1160                    }
1161
1162                    throw Trace.error(Trace.INVALID_CONVERSION,
1163                                      Types.getTypeString(type));
1164
1165// fredt@users 20030708 - patch 1.7.2 - OBJECT handling - superseded
1166
case Types.OTHER :
1167                    if (o instanceof JavaObject) {
1168                        return o;
1169                    } else if (o instanceof String JavaDoc) {
1170
1171                        /**
1172                         * @todo fredt - we need this for script processing only
1173                         * handle the script separately and allow normal Sting
1174                         * objects to be stored as JavaObject
1175                         */

1176                        return new JavaObject(
1177                            StringConverter.hexToByte((String JavaDoc) o));
1178                    } else if (o instanceof Binary) {
1179                        return new JavaObject(((Binary) o).getBytes());
1180                    }
1181
1182                    return new JavaObject((Serializable JavaDoc) o);
1183
1184                default :
1185            }
1186
1187            if (o instanceof JavaObject) {
1188                o = ((JavaObject) o).getObject();
1189
1190                return convertObject(o, type);
1191            }
1192
1193            return convertString(o.toString(), type);
1194        } catch (HsqlException e) {
1195            throw e;
1196        } catch (Exception JavaDoc e) {
1197            throw Trace.error(Trace.WRONG_DATA_TYPE, e.toString());
1198        }
1199    }
1200
1201    /**
1202     * Return a java object based on a SQL string. This is called from
1203     * convertObject(Object o, int type).
1204     *
1205     * @param s
1206     * @param type
1207     * @return
1208     * @throws HsqlException
1209     */

1210    private static Object JavaDoc convertString(String JavaDoc s,
1211                                        int type) throws HsqlException {
1212
1213        switch (type) {
1214
1215            case Types.TINYINT :
1216            case Types.SMALLINT :
1217
1218                // fredt - do maximumm / minimum checks on each type
1219
return convertObject(s, type);
1220
1221            case Types.INTEGER :
1222                int val = Integer.parseInt(s);
1223
1224                return ValuePool.getInt(val);
1225
1226            case Types.BIGINT :
1227                return ValuePool.getLong(Long.parseLong(s));
1228
1229            case Types.REAL :
1230            case Types.FLOAT :
1231            case Types.DOUBLE :
1232                double d = JavaSystem.parseDouble(s);
1233                long l = Double.doubleToLongBits(d);
1234
1235                return ValuePool.getDouble(l);
1236
1237            case Types.VARCHAR_IGNORECASE :
1238            case Types.VARCHAR :
1239            case Types.CHAR :
1240            case Types.LONGVARCHAR :
1241                return s;
1242
1243            case Types.DATE :
1244                return HsqlDateTime.dateValue(s);
1245
1246            case Types.TIME :
1247                return HsqlDateTime.timeValue(s);
1248
1249            case Types.TIMESTAMP :
1250                return HsqlDateTime.timestampValue(s);
1251
1252            case Types.NUMERIC :
1253            case Types.DECIMAL :
1254                s = Library.trim(s, " ", true, true);
1255
1256                return new BigDecimal JavaDoc(s);
1257
1258            case Types.BOOLEAN :
1259                return s.equalsIgnoreCase("TRUE") ? Boolean.TRUE
1260                                                  : Boolean.FALSE;
1261
1262            case Types.BINARY :
1263            case Types.VARBINARY :
1264            case Types.LONGVARBINARY :
1265            case Types.OTHER :
1266            default :
1267                throw Trace.error(Trace.INVALID_CONVERSION,
1268                                  Types.getTypeString(type));
1269        }
1270    }
1271
1272    /**
1273     * Return an SQL representation of an object. Strings will be quoted
1274     * with single quotes, other objects will represented as in a SQL
1275     * statement.
1276     *
1277     * @param o
1278     * @param type
1279     * @return result
1280     * @throws HsqlException
1281     */

1282    static String JavaDoc createSQLString(Object JavaDoc o, int type) throws HsqlException {
1283
1284        if (o == null) {
1285            return "NULL";
1286        }
1287
1288        switch (type) {
1289
1290            case Types.NULL :
1291                return "NULL";
1292
1293            case Types.REAL :
1294            case Types.FLOAT :
1295            case Types.DOUBLE :
1296                return createSQLString(((Number JavaDoc) o).doubleValue());
1297
1298            case Types.DATE :
1299            case Types.TIME :
1300            case Types.TIMESTAMP :
1301                return StringConverter.toQuotedString(o.toString(), '\'',
1302                                                      false);
1303
1304            case Types.BINARY :
1305            case Types.VARBINARY :
1306            case Types.LONGVARBINARY :
1307                if (!(o instanceof Binary)) {
1308                    throw Trace.error(Trace.INVALID_CONVERSION);
1309                }
1310
1311                return StringConverter.toQuotedString(
1312                    StringConverter.byteToHex(((Binary) o).getBytes()), '\'',
1313                    false);
1314
1315            case Types.OTHER :
1316                if (!(o instanceof JavaObject)) {
1317                    throw Trace.error(Trace.SERIALIZATION_FAILURE);
1318                }
1319
1320                return StringConverter.toQuotedString(
1321                    StringConverter.byteToHex(((JavaObject) o).getBytes()),
1322                    '\'', false);
1323
1324            case Types.VARCHAR_IGNORECASE :
1325            case Types.VARCHAR :
1326            case Types.CHAR :
1327            case Types.LONGVARCHAR :
1328                return createSQLString((String JavaDoc) o);
1329
1330            default :
1331                return o.toString();
1332        }
1333    }
1334
1335    public static String JavaDoc createSQLString(double x) {
1336
1337        if (x == Double.NEGATIVE_INFINITY) {
1338            return "-1E0/0";
1339        }
1340
1341        if (x == Double.POSITIVE_INFINITY) {
1342            return "1E0/0";
1343        }
1344
1345        if (Double.isNaN(x)) {
1346            return "0E0/0E0";
1347        }
1348
1349        String JavaDoc s = Double.toString(x);
1350
1351        // ensure the engine treats the value as a DOUBLE, not DECIMAL
1352
if (s.indexOf('E') < 0) {
1353            s = s.concat("E0");
1354        }
1355
1356        return s;
1357    }
1358
1359    /**
1360     * Turns a java string into a quoted SQL string
1361     *
1362     * @param s java string
1363     * @return quoted SQL string
1364     */

1365    public static String JavaDoc createSQLString(String JavaDoc s) {
1366
1367        if (s == null) {
1368            return "NULL";
1369        }
1370
1371        return StringConverter.toQuotedString(s, '\'', true);
1372    }
1373
1374    /**
1375     * Explicit casts are handled here. This is separate from the implicit
1376     * casts carried out when inserting/updating rows.
1377     * SQL standard 6.12 rules for enforcement of size, precision and scale
1378     * are implemented here are as follows:
1379     *
1380     * For no size, precision or scale, default to convertObject(Object)
1381     *
1382     * Right truncation is allowed only for CHAR to CHAR casts
1383     * (CHAR is generic for all string types).
1384     *
1385     * For other casts to CHAR, right truncation is not allowed.
1386     *
1387     * For numeric conversions, scale is always converted to target first,
1388     * then precision is imposed. No truncation is allowed. (fredt)
1389     */

1390    public static Object JavaDoc convertObject(Session session, Object JavaDoc o, int type,
1391                                       int precision,
1392                                       int scale) throws HsqlException {
1393
1394        if (o == null) {
1395            return o;
1396        }
1397
1398        if (precision == 0) {
1399            return convertObject(o, type);
1400        }
1401
1402        boolean check = true;
1403
1404        switch (type) {
1405
1406            case Types.VARCHAR_IGNORECASE :
1407            case Types.LONGVARCHAR :
1408                type = Types.VARCHAR;
1409            case Types.VARCHAR :
1410            case Types.CHAR :
1411                if (o instanceof String JavaDoc) {
1412                    check = false;
1413                } else {
1414                    o = convertObject(o, Types.VARCHAR);
1415                }
1416
1417                return enforceSize(o, type, precision, scale, check);
1418
1419            case Types.NUMERIC :
1420            case Types.DECIMAL :
1421                if (!(o instanceof BigDecimal JavaDoc)) {
1422                    o = convertObject(o, type);
1423                }
1424
1425                return enforceSize(o, type, precision, scale, true);
1426
1427            case Types.TIMESTAMP :
1428                if (o instanceof Time JavaDoc) {
1429                    long millis = session.currentDate.getTime()
1430                                  + ((Time JavaDoc) o).getTime();
1431
1432                    o = HsqlDateTime.getTimestamp(millis);
1433                }
1434
1435                if (o instanceof Timestamp JavaDoc) {
1436                    return enforceSize(o, type, precision, scale, false);
1437                }
1438        }
1439
1440        return convertObject(o, type);
1441    }
1442
1443    static int[] tenPower = {
1444        1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000
1445    };
1446
1447    /**
1448     * Check an object for type CHAR and VARCHAR and truncate/pad based on
1449     * the size
1450     *
1451     * @param obj object to check
1452     * @param type the object type
1453     * @param size size to enforce
1454     * @param check throw if too long
1455     * @return the altered object if the right type, else the object
1456     * passed in unaltered
1457     * @throws HsqlException if data too long
1458     */

1459    static Object JavaDoc enforceSize(Object JavaDoc obj, int type, int size, int scale,
1460                              boolean check) throws HsqlException {
1461
1462        if (obj == null) {
1463            return obj;
1464        }
1465
1466        if (size == 0 && type != Types.TIMESTAMP) {
1467            return obj;
1468        }
1469
1470        // todo: need to handle BINARY like this as well
1471
switch (type) {
1472
1473            case Types.CHAR :
1474                return checkChar((String JavaDoc) obj, size, check);
1475
1476            case Types.VARCHAR :
1477            case Types.VARCHAR_IGNORECASE :
1478                return checkVarchar((String JavaDoc) obj, size, check);
1479
1480            case Types.NUMERIC :
1481            case Types.DECIMAL :
1482                BigDecimal JavaDoc dec = (BigDecimal JavaDoc) obj;
1483
1484                dec = dec.setScale(scale, BigDecimal.ROUND_HALF_DOWN);
1485
1486                BigInteger JavaDoc big = JavaSystem.getUnscaledValue(dec);
1487                int sign = big.signum() == -1 ? 1
1488                                                     : 0;
1489
1490                if (big.toString().length() - sign > size) {
1491                    throw Trace.error(Trace.STRING_DATA_TRUNCATION);
1492                }
1493
1494                return dec;
1495
1496            case Types.TIMESTAMP :
1497                if (size == 6) {
1498                    return obj;
1499                }
1500
1501                Timestamp JavaDoc ts = (Timestamp JavaDoc) obj;
1502                int nanos = ts.getNanos();
1503                int divisor = tenPower[size];
1504                int newNanos = (nanos / divisor) * divisor;
1505
1506                ts.setNanos(newNanos);
1507
1508                return ts;
1509
1510            default :
1511                return obj;
1512        }
1513    }
1514
1515    /**
1516     * Checks the length of a VARCHAR string.
1517     *
1518     * @param s the string to pad to truncate
1519     * @param len the len to make the string
1520     * @param check if true, throw an exception if truncation takes place
1521     * @return the string of size len
1522     */

1523    static String JavaDoc checkVarchar(String JavaDoc s, int len,
1524                               boolean check) throws HsqlException {
1525
1526        int slen = s.length();
1527
1528        if (slen > len) {
1529            if (check) {
1530                throw Trace.error(Trace.STRING_DATA_TRUNCATION);
1531            }
1532
1533            return s.substring(0, len);
1534        }
1535
1536        return s;
1537    }
1538
1539    /**
1540     * Checks and pads a CHARACTER string to len size
1541     *
1542     * @param s the string to pad to truncate
1543     * @param len the len to make the string
1544     * @param check if true, throw an exception if truncation takes place
1545     * @return the string of size len
1546     */

1547    static String JavaDoc checkChar(String JavaDoc s, int len,
1548                            boolean check) throws HsqlException {
1549
1550        int slen = s.length();
1551
1552        if (slen == len) {
1553            return s;
1554        }
1555
1556        if (slen > len) {
1557            if (check) {
1558                throw Trace.error(Trace.STRING_DATA_TRUNCATION);
1559            }
1560
1561            return s.substring(0, len);
1562        }
1563
1564        char[] b = new char[len];
1565
1566        s.getChars(0, slen, b, 0);
1567
1568        for (int i = slen; i < len; i++) {
1569            b[i] = ' ';
1570        }
1571
1572        return new String JavaDoc(b);
1573    }
1574
1575    /**
1576     * Type narrowing from DOUBLE/DECIMAL/NUMERIC to BIGINT / INT / SMALLINT / TINYINT
1577     * following the SQL rules. When conversion is from a non-integral type,
1578     * digits to the right of the decimal point are lost.
1579     */

1580
1581    /**
1582     * Converter from a numeric object to Integer. Input is checked to be
1583     * within range represented by Integer.
1584     */

1585    static Integer JavaDoc convertToInt(Object JavaDoc o) throws HsqlException {
1586
1587        if (o instanceof BigDecimal JavaDoc) {
1588            BigInteger JavaDoc bi = ((BigDecimal JavaDoc) o).toBigInteger();
1589
1590            if (bi.compareTo(MAX_INT) > 0 || bi.compareTo(MIN_INT) < 0) {
1591                throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1592            }
1593
1594            return ValuePool.getInt(bi.intValue());
1595        }
1596
1597        if (o instanceof Double JavaDoc || o instanceof Float JavaDoc) {
1598            double d = ((Number JavaDoc) o).doubleValue();
1599
1600            if (Double.isNaN(d) || d >= (double) Integer.MAX_VALUE + 1
1601                    || d <= (double) Integer.MIN_VALUE - 1) {
1602                throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1603            }
1604
1605            return ValuePool.getInt((int) d);
1606        }
1607
1608        throw Trace.error(Trace.INVALID_CONVERSION);
1609    }
1610
1611    /**
1612     * Converter from a numeric object to Long. Input is checked to be
1613     * within range represented by Long.
1614     */

1615    static Long JavaDoc convertToLong(Object JavaDoc o) throws HsqlException {
1616
1617        if (o instanceof BigDecimal JavaDoc) {
1618            BigInteger JavaDoc bi = ((BigDecimal JavaDoc) o).toBigInteger();
1619
1620            if (bi.compareTo(MAX_LONG) > 0 || bi.compareTo(MIN_LONG) < 0) {
1621                throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1622            }
1623
1624            return ValuePool.getLong(bi.longValue());
1625        }
1626
1627        if (o instanceof Double JavaDoc || o instanceof Float JavaDoc) {
1628            double d = ((Number JavaDoc) o).doubleValue();
1629
1630            if (Double.isNaN(d) || d >= (double) Long.MAX_VALUE + 1
1631                    || d <= (double) Long.MIN_VALUE - 1) {
1632                throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1633            }
1634
1635            return ValuePool.getLong((long) d);
1636        }
1637
1638        throw Trace.error(Trace.INVALID_CONVERSION);
1639    }
1640
1641    /**
1642     * Converter from a numeric object to Double. Input is checked to be
1643     * within range represented by Double
1644     */

1645    static Double JavaDoc convertToDouble(Object JavaDoc o) throws HsqlException {
1646
1647        double val;
1648
1649        if (o instanceof BigDecimal JavaDoc) {
1650            BigDecimal JavaDoc bd = (BigDecimal JavaDoc) o;
1651
1652            val = bd.doubleValue();
1653
1654            int signum = bd.signum();
1655            BigDecimal JavaDoc bo = new BigDecimal JavaDoc(val + signum);
1656
1657            if (bo.compareTo(bd) != signum) {
1658                throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1659            }
1660        } else {
1661            val = ((Number JavaDoc) o).doubleValue();
1662        }
1663
1664        return ValuePool.getDouble(Double.doubleToLongBits(val));
1665    }
1666
1667// fredt@users 20020408 - patch 442993 by fredt - arithmetic expressions
1668

1669    /**
1670     * Arithmetic expression terms are promoted to a type that can
1671     * represent the resulting values and avoid incorrect results.<p>
1672     * When the result or the expression is converted to the
1673     * type of the target column for storage, an exception is thrown if the
1674     * resulting value cannot be stored in the column<p>
1675     * Returns a SQL type "wide" enough to represent the result of the
1676     * expression.<br>
1677     * A type is "wider" than the other if it can represent all its
1678     * numeric values.<BR>
1679     * Types narrower than INTEGER (int) are promoted to
1680     * INTEGER. The order is as follows<p>
1681     *
1682     * INTEGER, BIGINT, DOUBLE, DECIMAL<p>
1683     *
1684     * TINYINT and SMALLINT in any combination return INTEGER<br>
1685     * INTEGER and INTEGER return BIGINT<br>
1686     * BIGINT and INTEGER return NUMERIC/DECIMAL<br>
1687     * BIGINT and BIGINT return NUMERIC/DECIMAL<br>
1688     * DOUBLE and INTEGER return DOUBLE<br>
1689     * DOUBLE and BIGINT return DOUBLE<br>
1690     * NUMERIC/DECIMAL and any type returns NUMERIC/DECIMAL<br>
1691     *
1692     * @author fredt@users
1693     * @param type1 java.sql.Types value for the first numeric type
1694     * @param type2 java.sql.Types value for the second numeric type
1695     * @return either type1 or type2 on the basis of the above order
1696     */

1697    static int getCombinedNumberType(int type1, int type2, int expType) {
1698
1699        int typeWidth1 = getNumTypeWidth(type1);
1700        int typeWidth2 = getNumTypeWidth(type2);
1701
1702        if (typeWidth1 == 16 || typeWidth2 == 16) {
1703            return Types.DOUBLE;
1704        }
1705
1706        switch (expType) {
1707
1708            case Expression.EQUAL :
1709            case Expression.BIGGER :
1710            case Expression.BIGGER_EQUAL :
1711            case Expression.SMALLER_EQUAL :
1712            case Expression.SMALLER :
1713            case Expression.NOT_EQUAL :
1714            case Expression.ALTERNATIVE :
1715            case Expression.DIVIDE :
1716                return (typeWidth1 > typeWidth2) ? type1
1717                                                 : type2;
1718
1719            default :
1720                int sum = typeWidth1 + typeWidth2;
1721
1722                if (sum <= 4) {
1723                    return Types.INTEGER;
1724                }
1725
1726                if (sum <= 8) {
1727                    return Types.BIGINT;
1728                }
1729
1730                return Types.NUMERIC;
1731        }
1732    }
1733
1734    /**
1735     * @param type java.sql.Types int for a numeric type
1736     * @return relative width
1737     */

1738    static int getNumTypeWidth(int type) {
1739
1740        switch (type) {
1741
1742            case Types.TINYINT :
1743                return 1;
1744
1745            case Types.SMALLINT :
1746                return 2;
1747
1748            case Types.INTEGER :
1749                return 4;
1750
1751            case Types.BIGINT :
1752                return 8;
1753
1754            case Types.REAL :
1755            case Types.FLOAT :
1756            case Types.DOUBLE :
1757                return 16;
1758
1759            case Types.NUMERIC :
1760            case Types.DECIMAL :
1761                return 32;
1762
1763            default :
1764                return 32;
1765        }
1766    }
1767
1768    /**
1769     * returns -1, 0 , +1
1770     */

1771    static int compareToTypeRange(Object JavaDoc o, int targettype) {
1772
1773        if (!(o instanceof Number JavaDoc)) {
1774            return 0;
1775        }
1776
1777        if (o instanceof Integer JavaDoc || o instanceof Long JavaDoc) {
1778            long temp = ((Number JavaDoc) o).longValue();
1779            int min;
1780            int max;
1781
1782            switch (targettype) {
1783
1784                case Types.TINYINT :
1785                    min = Byte.MIN_VALUE;
1786                    max = Byte.MAX_VALUE;
1787                    break;
1788
1789                case Types.SMALLINT :
1790                    min = Short.MIN_VALUE;
1791                    max = Short.MAX_VALUE;
1792                    break;
1793
1794                case Types.INTEGER :
1795                    min = Integer.MIN_VALUE;
1796                    max = Integer.MAX_VALUE;
1797                    break;
1798
1799                case Types.BIGINT :
1800                case Types.DECIMAL :
1801                case Types.NUMERIC :
1802                default :
1803                    return 0;
1804            }
1805
1806            if (max < temp) {
1807                return 1;
1808            }
1809
1810            if (temp < min) {
1811                return -1;
1812            }
1813
1814            return 0;
1815        } else {
1816            try {
1817                o = convertToLong(o);
1818
1819                return compareToTypeRange(o, targettype);
1820            } catch (HsqlException e) {
1821                if (e.getErrorCode() == -Trace.NUMERIC_VALUE_OUT_OF_RANGE) {
1822                    if (o instanceof BigDecimal JavaDoc) {
1823                        return ((BigDecimal JavaDoc) o).signum();
1824                    } else if (o instanceof Double JavaDoc) {
1825                        return ((Double JavaDoc) o).doubleValue() > 0 ? 1
1826                                                              : -1;
1827                    }
1828                }
1829            }
1830        }
1831
1832        return 0;
1833    }
1834
1835    /**
1836     * Converts the specified hexadecimal digit <CODE>String</CODE>
1837     * to an equivalent array of bytes.
1838     *
1839     * @param hexString a <CODE>String</CODE> of hexadecimal digits
1840     * @throws HsqlException if the specified string contains non-hexadecimal digits.
1841     * @return a byte array equivalent to the specified string of hexadecimal digits
1842     */

1843    public static byte[] hexToByteArray(String JavaDoc hexString)
1844    throws HsqlException {
1845
1846        try {
1847            return StringConverter.hexToByte(hexString);
1848        } catch (IOException JavaDoc e) {
1849            throw Trace.error(Trace.INVALID_CHARACTER_ENCODING);
1850        }
1851    }
1852
1853    /**
1854     * Compares a <CODE>byte[]</CODE> with another specified
1855     * <CODE>byte[]</CODE> for order. Returns a negative integer, zero,
1856     * or a positive integer as the first object is less than, equal to, or
1857     * greater than the specified second <CODE>byte[]</CODE>.<p>
1858     *
1859     * @param o1 the first byte[] to be compared
1860     * @param o2 the second byte[] to be compared
1861     * @return a negative integer, zero, or a positive integer as this object
1862     * is less than, equal to, or greater than the specified object.
1863     */

1864    static int compareTo(byte[] o1, byte[] o2) {
1865
1866        int len = o1.length;
1867        int lenb = o2.length;
1868
1869        for (int i = 0; ; i++) {
1870            int a = 0;
1871            int b = 0;
1872
1873            if (i < len) {
1874                a = ((int) o1[i]) & 0xff;
1875            } else if (i >= lenb) {
1876                return 0;
1877            }
1878
1879            if (i < lenb) {
1880                b = ((int) o2[i]) & 0xff;
1881            }
1882
1883            if (a > b) {
1884                return 1;
1885            }
1886
1887            if (b > a) {
1888                return -1;
1889            }
1890        }
1891    }
1892}
1893
Popular Tags