KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > value > Value


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.value;
6
7 import java.io.ByteArrayInputStream JavaDoc;
8 import java.io.InputStream JavaDoc;
9 import java.io.Reader JavaDoc;
10 import java.lang.ref.WeakReference JavaDoc;
11 import java.math.BigDecimal JavaDoc;
12 import java.sql.Date JavaDoc;
13 import java.sql.PreparedStatement JavaDoc;
14 import java.sql.SQLException JavaDoc;
15 import java.sql.Time JavaDoc;
16 import java.sql.Timestamp JavaDoc;
17 import java.sql.Types JavaDoc;
18
19 import org.h2.engine.Constants;
20 import org.h2.engine.Mode;
21 import org.h2.message.Message;
22 import org.h2.store.DataHandler;
23 import org.h2.tools.SimpleResultSet;
24 import org.h2.util.ByteUtils;
25 import org.h2.util.IOUtils;
26 import org.h2.util.MathUtils;
27 import org.h2.util.StringUtils;
28
29 /**
30  * @author Thomas
31  */

32 public abstract class Value {
33
34     // TODO value: float is missing
35

36     // remember to keep the order
37
public static final int UNKNOWN = -1;
38     public static final int NULL = 0, BOOLEAN = 1, BYTE = 2, SHORT = 3, INT = 4, LONG = 5, DECIMAL = 6;
39     public static final int DOUBLE = 7, FLOAT = 8, TIME = 9, DATE = 10, TIMESTAMP = 11, BYTES = 12;
40     public static final int STRING = 13, STRING_IGNORECASE = 14, BLOB = 15, CLOB = 16;
41     public static final int ARRAY = 17, RESULT_SET = 18, JAVA_OBJECT = 19, UUID = 20;
42
43     public static final int TYPE_COUNT = UUID + 1;
44
45     private static WeakReference JavaDoc weakCache = new WeakReference JavaDoc(null);
46     // private static int cacheCleaner = 0;
47
// testing: cacheHit / miss are public!
48
// public static int cacheHit = 0, cacheMiss = 0;
49
// private static Value[] cache = new Value[Constants.OBJECT_CACHE_SIZE];
50

51     private static final BigDecimal JavaDoc MAX_LONG_DECIMAL = new BigDecimal JavaDoc("" + Long.MAX_VALUE);
52
53     private static final BigDecimal JavaDoc MIN_LONG_DECIMAL = new BigDecimal JavaDoc("" + Long.MIN_VALUE);
54
55     static Value cache(Value v) {
56         if (Constants.OBJECT_CACHE) {
57             Value[] cache = (Value[]) weakCache.get();
58             int hash = v.hashCode();
59             if (cache == null) {
60                 cache = new Value[Constants.OBJECT_CACHE_SIZE];
61                 weakCache = new WeakReference JavaDoc(cache);
62             }
63             int index = hash & (Constants.OBJECT_CACHE_SIZE - 1);
64             Value cached = cache[index];
65             if (cached != null) {
66                 if (cached.getType() == v.getType() && v.isEqual(cached)) {
67                     // cacheHit++;
68
return cached;
69                 }
70             }
71             // cacheMiss++;
72
// cache[cacheCleaner] = null;
73
// cacheCleaner = (cacheCleaner + 1) & (Constants.OBJECT_CACHE_SIZE - 1);
74
cache[index] = v;
75         }
76         return v;
77     }
78
79     public abstract String JavaDoc getSQL();
80     public abstract int getType();
81     public abstract long getPrecision();
82     public abstract int getDisplaySize();
83     public abstract String JavaDoc getString() throws SQLException JavaDoc;
84 // public abstract String getJavaString();
85
protected abstract int compareSecure(Value v, CompareMode mode) throws SQLException JavaDoc;
86     protected abstract boolean isEqual(Value v);
87     public abstract Object JavaDoc getObject() throws SQLException JavaDoc;
88     public abstract void set(PreparedStatement JavaDoc prep, int parameterIndex) throws SQLException JavaDoc;
89
90     public Boolean JavaDoc getBoolean() throws SQLException JavaDoc {
91         return ((ValueBoolean) convertTo(Value.BOOLEAN)).getBoolean();
92     }
93
94     public Date JavaDoc getDate() throws SQLException JavaDoc {
95         return ((ValueDate) convertTo(Value.DATE)).getDate();
96     }
97     
98     public Date JavaDoc getDateNoCopy() throws SQLException JavaDoc {
99         return ((ValueDate) convertTo(Value.DATE)).getDateNoCopy();
100     }
101
102     public Time JavaDoc getTime() throws SQLException JavaDoc {
103         return ((ValueTime) convertTo(Value.TIME)).getTime();
104     }
105
106     public Time JavaDoc getTimeNoCopy() throws SQLException JavaDoc {
107         return ((ValueTime) convertTo(Value.TIME)).getTimeNoCopy();
108     }
109
110     public Timestamp JavaDoc getTimestamp() throws SQLException JavaDoc {
111         return ((ValueTimestamp) convertTo(Value.TIMESTAMP)).getTimestamp();
112     }
113
114     public Timestamp JavaDoc getTimestampNoCopy() throws SQLException JavaDoc {
115         return ((ValueTimestamp) convertTo(Value.TIMESTAMP)).getTimestampNoCopy();
116     }
117
118     public byte[] getBytes() throws SQLException JavaDoc {
119         return ((ValueBytes) convertTo(Value.BYTES)).getBytes();
120     }
121     
122     public byte[] getBytesNoCopy() throws SQLException JavaDoc {
123         return ((ValueBytes) convertTo(Value.BYTES)).getBytesNoCopy();
124     }
125
126     public byte getByte() throws SQLException JavaDoc {
127         return ((ValueByte) convertTo(Value.BYTE)).getByte();
128     }
129
130     public short getShort() throws SQLException JavaDoc {
131         return ((ValueShort) convertTo(Value.SHORT)).getShort();
132     }
133
134     public BigDecimal JavaDoc getBigDecimal() throws SQLException JavaDoc {
135         return ((ValueDecimal) convertTo(Value.DECIMAL)).getBigDecimal();
136     }
137
138     public double getDouble() throws SQLException JavaDoc {
139         return ((ValueDouble) convertTo(Value.DOUBLE)).getDouble();
140     }
141
142     public float getFloat() throws SQLException JavaDoc {
143         return ((ValueFloat) convertTo(Value.FLOAT)).getFloat();
144     }
145
146     public int getInt() throws SQLException JavaDoc {
147         return ((ValueInt) convertTo(Value.INT)).getInt();
148     }
149
150     public long getLong() throws SQLException JavaDoc {
151         return ((ValueLong) convertTo(Value.LONG)).getLong();
152     }
153
154     public InputStream JavaDoc getInputStream() throws SQLException JavaDoc {
155         return new ByteArrayInputStream JavaDoc(getBytesNoCopy());
156     }
157
158     public Reader JavaDoc getReader() throws SQLException JavaDoc {
159         return IOUtils.getReader(getString());
160     }
161     
162     public Value add(Value v) throws SQLException JavaDoc {
163         throw Message.getUnsupportedException();
164     }
165
166     public int getSignum() throws SQLException JavaDoc {
167         throw Message.getUnsupportedException();
168     }
169
170     public Value negate() throws SQLException JavaDoc {
171         throw Message.getUnsupportedException();
172     }
173
174     public Value subtract(Value v) throws SQLException JavaDoc {
175         throw Message.getUnsupportedException();
176     }
177
178     public Value divide(Value v) throws SQLException JavaDoc {
179         throw Message.getUnsupportedException();
180     }
181
182     public Value multiply(Value v) throws SQLException JavaDoc {
183         throw Message.getUnsupportedException();
184     }
185
186     public static int getHigherOrder(int t1, int t2) throws SQLException JavaDoc {
187         if(t1 == t2) {
188             if(t1 == Value.UNKNOWN) {
189                 throw Message.getSQLException(Message.UNKNOWN_DATA_TYPE_1, "?, ?");
190             }
191             return t1;
192         }
193         int type = Math.max(t1, t2);
194         switch(type) {
195         case Value.STRING:
196         case Value.STRING_IGNORECASE: {
197             int b = Math.min(t1, t2);
198             switch(b) {
199             case Value.BLOB:
200             case Value.BYTES:
201             case Value.DATE:
202             case Value.JAVA_OBJECT:
203             case Value.TIME:
204             case Value.TIMESTAMP:
205             case Value.UUID:
206                 return b;
207             }
208         }
209         }
210         return type;
211     }
212
213     public Value convertTo(int type) throws SQLException JavaDoc {
214         // converting NULL done in ValueNull
215
// converting BLOB to CLOB and vice versa is done in ValueLob
216
if (getType() == type) {
217             return this;
218         }
219         // decimal conversion
220
switch (type) {
221         case BOOLEAN: {
222             switch (getType()) {
223             case BYTE:
224             case SHORT:
225             case INT:
226             case LONG:
227             case DECIMAL:
228             case DOUBLE:
229             case FLOAT:
230                 return ValueBoolean.get(getSignum() != 0);
231             case TIME:
232             case DATE:
233             case TIMESTAMP:
234             case BYTES:
235             case JAVA_OBJECT:
236             case UUID:
237                 throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, getString());
238             }
239             break;
240         }
241         case BYTE: {
242             switch (getType()) {
243             case BOOLEAN:
244                 return ValueByte.get(getBoolean().booleanValue() ? (byte)1 : (byte)0);
245             case SHORT:
246                 return ValueByte.get(convertToByte(getShort()));
247             case INT:
248                 return ValueByte.get(convertToByte(getInt()));
249             case LONG:
250                 return ValueByte.get(convertToByte(getLong()));
251             case DECIMAL:
252                 return ValueByte.get(convertToByte(convertToLong(getBigDecimal())));
253             case DOUBLE:
254                 return ValueByte.get(convertToByte(convertToLong(getDouble())));
255             case FLOAT:
256                 return ValueByte.get(convertToByte(convertToLong(getFloat())));
257             }
258             break;
259         }
260         case SHORT: {
261             switch (getType()) {
262             case BOOLEAN:
263                 return ValueShort.get(getBoolean().booleanValue() ? (short)1 : (short)0);
264             case BYTE:
265                 return ValueShort.get(getByte());
266             case INT:
267                 return ValueShort.get(convertToShort(getInt()));
268             case LONG:
269                 return ValueShort.get(convertToShort(getLong()));
270             case DECIMAL:
271                 return ValueShort.get(convertToShort(convertToLong(getBigDecimal())));
272             case DOUBLE:
273                 return ValueShort.get(convertToShort(convertToLong(getDouble())));
274             case FLOAT:
275                 return ValueShort.get(convertToShort(convertToLong(getFloat())));
276             }
277             break;
278         }
279         case INT: {
280             switch (getType()) {
281             case BOOLEAN:
282                 return ValueInt.get(getBoolean().booleanValue() ? 1 : 0);
283             case BYTE:
284                 return ValueInt.get(getByte());
285             case SHORT:
286                 return ValueInt.get(getShort());
287             case LONG:
288                 return ValueInt.get(convertToInt(getLong()));
289             case DECIMAL:
290                 return ValueInt.get(convertToInt(convertToLong(getBigDecimal())));
291             case DOUBLE:
292                 return ValueInt.get(convertToInt(convertToLong(getDouble())));
293             case FLOAT:
294                 return ValueInt.get(convertToInt(convertToLong(getFloat())));
295             }
296             break;
297         }
298         case LONG: {
299             switch (getType()) {
300             case BOOLEAN:
301                 return ValueLong.get(getBoolean().booleanValue() ? 1 : 0);
302             case BYTE:
303                 return ValueLong.get(getByte());
304             case SHORT:
305                 return ValueLong.get(getShort());
306             case INT:
307                 return ValueLong.get(getInt());
308             case DECIMAL:
309                 return ValueLong.get(convertToLong(getBigDecimal()));
310             case DOUBLE:
311                 return ValueLong.get(convertToLong(getDouble()));
312             case FLOAT:
313                 return ValueLong.get(convertToLong(getFloat()));
314             }
315             break;
316         }
317         case DECIMAL: {
318             // convert to string is required for JDK 1.4
319
switch (getType()) {
320             case BOOLEAN:
321                 return ValueDecimal.get(new BigDecimal JavaDoc(getBoolean().booleanValue() ? "1" : "0"));
322             case BYTE:
323                 return ValueDecimal.get(new BigDecimal JavaDoc("" + getByte()));
324             case SHORT:
325                 return ValueDecimal.get(new BigDecimal JavaDoc("" + getShort()));
326             case INT:
327                 return ValueDecimal.get(new BigDecimal JavaDoc("" + getInt()));
328             case LONG:
329                 return ValueDecimal.get(new BigDecimal JavaDoc("" + getLong()));
330             case DOUBLE: {
331                 double d = getDouble();
332                 if(Double.isInfinite(d) || Double.isNaN(d)) {
333                     throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, ""+d);
334                 }
335                 return ValueDecimal.get(new BigDecimal JavaDoc(d));
336             }
337             case FLOAT: {
338                 float f = getFloat();
339                 if(Float.isInfinite(f) || Float.isNaN(f)) {
340                     throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, ""+f);
341                 }
342                 return ValueDecimal.get(new BigDecimal JavaDoc(f));
343             }
344             }
345             break;
346         }
347         case DOUBLE: {
348             switch (getType()) {
349             case BOOLEAN:
350                 return ValueDouble.get(getBoolean().booleanValue() ? 1 : 0);
351             case BYTE:
352                 return ValueDouble.get(getByte());
353             case SHORT:
354                 return ValueDouble.get(getShort());
355             case INT:
356                 return ValueDouble.get(getInt());
357             case LONG:
358                 return ValueDouble.get(getLong());
359             case DECIMAL:
360                 return ValueDouble.get(getBigDecimal().doubleValue());
361             case FLOAT:
362                 return ValueDouble.get(getFloat());
363             }
364             break;
365         }
366         case FLOAT: {
367             switch (getType()) {
368             case BOOLEAN:
369                 return ValueFloat.get(getBoolean().booleanValue() ? 1 : 0);
370             case BYTE:
371                 return ValueFloat.get(getByte());
372             case SHORT:
373                 return ValueFloat.get(getShort());
374             case INT:
375                 return ValueFloat.get(getInt());
376             case LONG:
377                 return ValueFloat.get(getLong());
378             case DECIMAL:
379                 return ValueFloat.get(getBigDecimal().floatValue());
380             case DOUBLE:
381                 return ValueFloat.get((float)getDouble());
382             }
383             break;
384         }
385         case DATE: {
386             switch (getType()) {
387             case TIME:
388                 return ValueDate.get(new Date JavaDoc(getTimeNoCopy().getTime()));
389             case TIMESTAMP:
390                 return ValueDate.get(new Date JavaDoc(getTimestampNoCopy().getTime()));
391             }
392             break;
393         }
394         case TIME: {
395             switch (getType()) {
396             case DATE:
397                 // need to normalize the year, month and day
398
return ValueTime.get(new Time JavaDoc(getDateNoCopy().getTime()));
399             case TIMESTAMP:
400                 // need to normalize the year, month and day
401
return ValueTime.get(new Time JavaDoc(getTimestampNoCopy().getTime()));
402             }
403             break;
404         }
405         case TIMESTAMP: {
406             switch (getType()) {
407             case TIME:
408                 return ValueTimestamp.getNoCopy(new Timestamp JavaDoc(getTimeNoCopy().getTime()));
409             case DATE:
410                 return ValueTimestamp.getNoCopy(new Timestamp JavaDoc(getDateNoCopy().getTime()));
411             }
412             break;
413         }
414         case BYTES: {
415             switch(getType()) {
416             case JAVA_OBJECT:
417             case BLOB:
418             case UUID:
419                 return ValueBytes.getNoCopy(getBytesNoCopy());
420             }
421             break;
422         }
423         case JAVA_OBJECT: {
424             switch(getType()) {
425             case BYTES:
426             case BLOB:
427                 return ValueBytes.getNoCopy(getBytesNoCopy());
428             }
429             break;
430         }
431         case BLOB: {
432             switch(getType()) {
433             case BYTES:
434                 return ValueLob.createSmallLob(Value.BLOB, getBytesNoCopy());
435             }
436             break;
437         }
438         case UUID: {
439             switch(getType()) {
440             case BYTES:
441                 return ValueUuid.get(getBytesNoCopy());
442             }
443         }
444         }
445         // conversion by parsing the string value
446
String JavaDoc s = getString();
447         try {
448             switch (type) {
449             case NULL:
450                 return ValueNull.INSTANCE;
451             case BOOLEAN: {
452                 if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("t") || s.equalsIgnoreCase("yes") || s.equalsIgnoreCase("y")) {
453                     return ValueBoolean.get(true);
454                 } else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("f") || s.equalsIgnoreCase("no") || s.equalsIgnoreCase("n")) {
455                     return ValueBoolean.get(false);
456                 } else {
457                     // convert to a number, and if it is not 0 then it is true
458
return ValueBoolean.get(new BigDecimal JavaDoc(s).signum() != 0);
459                 }
460             }
461             case BYTE:
462                 return ValueByte.get(MathUtils.decodeByte(s.trim()));
463             case SHORT:
464                 return ValueShort.get(MathUtils.decodeShort(s.trim()));
465             case INT:
466                 return ValueInt.get(MathUtils.decodeInt(s.trim()));
467             case LONG:
468                 return ValueLong.get(MathUtils.decodeLong(s.trim()));
469             case DECIMAL:
470                 return ValueDecimal.get(new BigDecimal JavaDoc(s.trim()));
471             case TIME:
472                 return ValueTime.get(ValueTime.parseTime(s.trim()));
473             case DATE:
474                 return ValueDate.get(ValueDate.parseDate(s.trim()));
475             case TIMESTAMP:
476                 return ValueTimestamp.get(ValueTimestamp.parseTimestamp(s.trim()));
477             case BYTES:
478                 return ValueBytes.getNoCopy(ByteUtils.convertStringToBytes(s.trim()));
479             case JAVA_OBJECT:
480                 return ValueJavaObject.getNoCopy(ByteUtils.convertStringToBytes(s.trim()));
481             case STRING:
482                 return ValueString.get(s);
483             case STRING_IGNORECASE:
484                 return ValueStringIgnoreCase.get(s);
485             case DOUBLE:
486                 return ValueDouble.get(Double.parseDouble(s.trim()));
487             case FLOAT:
488                 return ValueFloat.get(Float.parseFloat(s.trim()));
489             case CLOB:
490                 return ValueLob.createSmallLob(CLOB, StringUtils.utf8Encode(s));
491             case BLOB:
492                 return ValueLob.createSmallLob(BLOB, ByteUtils.convertStringToBytes(s.trim()));
493             case ARRAY:
494                 return ValueArray.get(new Value[]{ValueString.get(s)});
495             case RESULT_SET: {
496                 SimpleResultSet rs = new SimpleResultSet();
497                 rs.addColumn("X", Types.VARCHAR, s.length(), 0);
498                 rs.addRow(new String JavaDoc[]{s});
499                 return ValueResultSet.get(rs);
500             }
501             case UUID:
502                 return ValueUuid.get(s);
503             default:
504                 throw Message.getInternalError("type=" + type);
505             }
506         } catch (NumberFormatException JavaDoc e) {
507             throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, new String JavaDoc[] { s }, e);
508         }
509     }
510
511     public final int compareTypeSave(Value v, CompareMode mode) throws SQLException JavaDoc {
512         if (this == ValueNull.INSTANCE) {
513             return v == ValueNull.INSTANCE ? 0 : -1;
514         } else if (v == ValueNull.INSTANCE) {
515             return 1;
516         }
517         return compareSecure(v, mode);
518     }
519
520     public final boolean compareEqual(Value v) throws SQLException JavaDoc {
521         if (this == ValueNull.INSTANCE) {
522             return v == ValueNull.INSTANCE;
523         } else if (v == ValueNull.INSTANCE) {
524             return false;
525         }
526         if (getType() == v.getType()) {
527             return isEqual(v);
528         }
529         int t2 = Value.getHigherOrder(getType(), v.getType());
530         return convertTo(t2).isEqual(v.convertTo(t2));
531     }
532     
533     public final int compareTo(Value v, CompareMode mode) throws SQLException JavaDoc {
534         if (this == ValueNull.INSTANCE) {
535             return v == ValueNull.INSTANCE ? 0 : -1;
536         } else if (v == ValueNull.INSTANCE) {
537             return 1;
538         }
539         if (getType() == v.getType()) {
540             return compareSecure(v, mode);
541         }
542         int t2 = Value.getHigherOrder(getType(), v.getType());
543         return convertTo(t2).compareSecure(v.convertTo(t2), mode);
544     }
545
546     public int getScale() {
547         return 0;
548     }
549
550     public Value convertScale(boolean onlyToSmallerScale, int targetScale) throws SQLException JavaDoc {
551         return this;
552     }
553
554     public Value convertPrecision(long precision) throws SQLException JavaDoc {
555         return this;
556     }
557
558     private byte convertToByte(long x) throws SQLException JavaDoc {
559         if (x > Byte.MAX_VALUE || x < Byte.MIN_VALUE) {
560             throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
561         }
562         return (byte) x;
563     }
564
565     private short convertToShort(long x) throws SQLException JavaDoc {
566         if (x > Short.MAX_VALUE || x < Short.MIN_VALUE) {
567             throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
568         }
569         return (short) x;
570     }
571
572     private int convertToInt(long x) throws SQLException JavaDoc {
573         if (x > Integer.MAX_VALUE || x < Integer.MIN_VALUE) {
574             throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
575         }
576         return (int) x;
577     }
578
579     private long convertToLong(double x) throws SQLException JavaDoc {
580         if (x > Long.MAX_VALUE || x < Long.MIN_VALUE) {
581             // TODO document that +Infinity, -Infinity throw an exception and NaN returns 0
582
throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
583         }
584         if(Mode.getCurrentMode().roundWhenConvertToLong) {
585             return Math.round(x);
586         } else {
587             return (long) x;
588         }
589     }
590
591     private long convertToLong(BigDecimal JavaDoc x) throws SQLException JavaDoc {
592         if (x.compareTo(MAX_LONG_DECIMAL) > 0 || x.compareTo(Value.MIN_LONG_DECIMAL) < 0) {
593             throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
594         }
595         if(Mode.getCurrentMode().roundWhenConvertToLong) {
596             return Math.round(x.doubleValue());
597         } else {
598             return x.longValue();
599         }
600     }
601
602     public Value link(DataHandler handler, int tableId) throws SQLException JavaDoc {
603         return this;
604     }
605     
606     public boolean isLinked() {
607         return false;
608     }
609     
610     public void unlink(DataHandler handler) throws SQLException JavaDoc {
611     }
612
613 }
614
Popular Tags