1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.value; |
7 | |
8 | import java.io.ByteArrayInputStream; |
9 | import java.io.InputStream; |
10 | import java.io.Reader; |
11 | import java.io.StringReader; |
12 | import java.lang.ref.SoftReference; |
13 | import java.math.BigDecimal; |
14 | import java.sql.Date; |
15 | import java.sql.PreparedStatement; |
16 | import java.sql.ResultSet; |
17 | import java.sql.SQLException; |
18 | import java.sql.Time; |
19 | import java.sql.Timestamp; |
20 | import java.sql.Types; |
21 | |
22 | import org.h2.api.ErrorCode; |
23 | import org.h2.engine.Constants; |
24 | import org.h2.engine.SysProperties; |
25 | import org.h2.message.DbException; |
26 | import org.h2.store.DataHandler; |
27 | import org.h2.tools.SimpleResultSet; |
28 | import org.h2.util.DateTimeUtils; |
29 | import org.h2.util.JdbcUtils; |
30 | import org.h2.util.MathUtils; |
31 | import org.h2.util.StringUtils; |
32 | import org.h2.util.Utils; |
33 | |
34 | /** |
35 | * This is the base class for all value classes. |
36 | * It provides conversion and comparison methods. |
37 | * |
38 | * @author Thomas Mueller |
39 | * @author Noel Grandin |
40 | * @author Nicolas Fortin, Atelier SIG, IRSTV FR CNRS 24888 |
41 | */ |
42 | public abstract class Value { |
43 | |
44 | /** |
45 | * The data type is unknown at this time. |
46 | */ |
47 | public static final int UNKNOWN = -1; |
48 | |
49 | /** |
50 | * The value type for NULL. |
51 | */ |
52 | public static final int NULL = 0; |
53 | |
54 | /** |
55 | * The value type for BOOLEAN values. |
56 | */ |
57 | public static final int BOOLEAN = 1; |
58 | |
59 | /** |
60 | * The value type for BYTE values. |
61 | */ |
62 | public static final int BYTE = 2; |
63 | |
64 | /** |
65 | * The value type for SHORT values. |
66 | */ |
67 | public static final int SHORT = 3; |
68 | |
69 | /** |
70 | * The value type for INT values. |
71 | */ |
72 | public static final int INT = 4; |
73 | |
74 | /** |
75 | * The value type for LONG values. |
76 | */ |
77 | public static final int LONG = 5; |
78 | |
79 | /** |
80 | * The value type for DECIMAL values. |
81 | */ |
82 | public static final int DECIMAL = 6; |
83 | |
84 | /** |
85 | * The value type for DOUBLE values. |
86 | */ |
87 | public static final int DOUBLE = 7; |
88 | |
89 | /** |
90 | * The value type for FLOAT values. |
91 | */ |
92 | public static final int FLOAT = 8; |
93 | |
94 | /** |
95 | * The value type for TIME values. |
96 | */ |
97 | public static final int TIME = 9; |
98 | |
99 | /** |
100 | * The value type for DATE values. |
101 | */ |
102 | public static final int DATE = 10; |
103 | |
104 | /** |
105 | * The value type for TIMESTAMP values. |
106 | */ |
107 | public static final int TIMESTAMP = 11; |
108 | |
109 | /** |
110 | * The value type for BYTES values. |
111 | */ |
112 | public static final int BYTES = 12; |
113 | |
114 | /** |
115 | * The value type for STRING values. |
116 | */ |
117 | public static final int STRING = 13; |
118 | |
119 | /** |
120 | * The value type for case insensitive STRING values. |
121 | */ |
122 | public static final int STRING_IGNORECASE = 14; |
123 | |
124 | /** |
125 | * The value type for BLOB values. |
126 | */ |
127 | public static final int BLOB = 15; |
128 | |
129 | /** |
130 | * The value type for CLOB values. |
131 | */ |
132 | public static final int CLOB = 16; |
133 | |
134 | /** |
135 | * The value type for ARRAY values. |
136 | */ |
137 | public static final int ARRAY = 17; |
138 | |
139 | /** |
140 | * The value type for RESULT_SET values. |
141 | */ |
142 | public static final int RESULT_SET = 18; |
143 | /** |
144 | * The value type for JAVA_OBJECT values. |
145 | */ |
146 | public static final int JAVA_OBJECT = 19; |
147 | |
148 | /** |
149 | * The value type for UUID values. |
150 | */ |
151 | public static final int UUID = 20; |
152 | |
153 | /** |
154 | * The value type for string values with a fixed size. |
155 | */ |
156 | public static final int STRING_FIXED = 21; |
157 | |
158 | /** |
159 | * The value type for string values with a fixed size. |
160 | */ |
161 | public static final int GEOMETRY = 22; |
162 | |
163 | /** |
164 | * The number of value types. |
165 | */ |
166 | public static final int TYPE_COUNT = GEOMETRY + 1; |
167 | |
168 | private static SoftReference<Value[]> softCache = |
169 | new SoftReference<Value[]>(null); |
170 | private static final BigDecimal MAX_LONG_DECIMAL = |
171 | BigDecimal.valueOf(Long.MAX_VALUE); |
172 | private static final BigDecimal MIN_LONG_DECIMAL = |
173 | BigDecimal.valueOf(Long.MIN_VALUE); |
174 | |
175 | /** |
176 | * Get the SQL expression for this value. |
177 | * |
178 | * @return the SQL expression |
179 | */ |
180 | public abstract String getSQL(); |
181 | |
182 | /** |
183 | * Get the value type. |
184 | * |
185 | * @return the type |
186 | */ |
187 | public abstract int getType(); |
188 | |
189 | /** |
190 | * Get the precision. |
191 | * |
192 | * @return the precision |
193 | */ |
194 | public abstract long getPrecision(); |
195 | |
196 | /** |
197 | * Get the display size in characters. |
198 | * |
199 | * @return the display size |
200 | */ |
201 | public abstract int getDisplaySize(); |
202 | |
203 | /** |
204 | * Get the memory used by this object. |
205 | * |
206 | * @return the memory used in bytes |
207 | */ |
208 | public int getMemory() { |
209 | return DataType.getDataType(getType()).memory; |
210 | } |
211 | |
212 | /** |
213 | * Get the value as a string. |
214 | * |
215 | * @return the string |
216 | */ |
217 | public abstract String getString(); |
218 | |
219 | /** |
220 | * Get the value as an object. |
221 | * |
222 | * @return the object |
223 | */ |
224 | public abstract Object getObject(); |
225 | |
226 | /** |
227 | * Set the value as a parameter in a prepared statement. |
228 | * |
229 | * @param prep the prepared statement |
230 | * @param parameterIndex the parameter index |
231 | */ |
232 | public abstract void set(PreparedStatement prep, int parameterIndex) |
233 | throws SQLException; |
234 | |
235 | /** |
236 | * Compare the value with another value of the same type. |
237 | * |
238 | * @param v the other value |
239 | * @param mode the compare mode |
240 | * @return 0 if both values are equal, -1 if the other value is smaller, and |
241 | * 1 otherwise |
242 | */ |
243 | protected abstract int compareSecure(Value v, CompareMode mode); |
244 | |
245 | @Override |
246 | public abstract int hashCode(); |
247 | |
248 | /** |
249 | * Check if the two values have the same hash code. No data conversion is |
250 | * made; this method returns false if the other object is not of the same |
251 | * class. For some values, compareTo may return 0 even if equals return |
252 | * false. Example: ValueDecimal 0.0 and 0.00. |
253 | * |
254 | * @param other the other value |
255 | * @return true if they are equal |
256 | */ |
257 | @Override |
258 | public abstract boolean equals(Object other); |
259 | |
260 | /** |
261 | * Get the order of this value type. |
262 | * |
263 | * @param type the value type |
264 | * @return the order number |
265 | */ |
266 | static int getOrder(int type) { |
267 | switch(type) { |
268 | case UNKNOWN: |
269 | return 1; |
270 | case NULL: |
271 | return 2; |
272 | case STRING: |
273 | return 10; |
274 | case CLOB: |
275 | return 11; |
276 | case STRING_FIXED: |
277 | return 12; |
278 | case STRING_IGNORECASE: |
279 | return 13; |
280 | case BOOLEAN: |
281 | return 20; |
282 | case BYTE: |
283 | return 21; |
284 | case SHORT: |
285 | return 22; |
286 | case INT: |
287 | return 23; |
288 | case LONG: |
289 | return 24; |
290 | case DECIMAL: |
291 | return 25; |
292 | case FLOAT: |
293 | return 26; |
294 | case DOUBLE: |
295 | return 27; |
296 | case TIME: |
297 | return 30; |
298 | case DATE: |
299 | return 31; |
300 | case TIMESTAMP: |
301 | return 32; |
302 | case BYTES: |
303 | return 40; |
304 | case BLOB: |
305 | return 41; |
306 | case UUID: |
307 | return 42; |
308 | case JAVA_OBJECT: |
309 | return 43; |
310 | case GEOMETRY: |
311 | return 44; |
312 | case ARRAY: |
313 | return 50; |
314 | case RESULT_SET: |
315 | return 51; |
316 | default: |
317 | throw DbException.throwInternalError("type:"+type); |
318 | } |
319 | } |
320 | |
321 | /** |
322 | * Get the higher value order type of two value types. If values need to be |
323 | * converted to match the other operands value type, the value with the |
324 | * lower order is converted to the value with the higher order. |
325 | * |
326 | * @param t1 the first value type |
327 | * @param t2 the second value type |
328 | * @return the higher value type of the two |
329 | */ |
330 | public static int getHigherOrder(int t1, int t2) { |
331 | if (t1 == Value.UNKNOWN || t2 == Value.UNKNOWN) { |
332 | if (t1 == t2) { |
333 | throw DbException.get( |
334 | ErrorCode.UNKNOWN_DATA_TYPE_1, "?, ?"); |
335 | } else if (t1 == Value.NULL) { |
336 | throw DbException.get( |
337 | ErrorCode.UNKNOWN_DATA_TYPE_1, "NULL, ?"); |
338 | } else if (t2 == Value.NULL) { |
339 | throw DbException.get( |
340 | ErrorCode.UNKNOWN_DATA_TYPE_1, "?, NULL"); |
341 | } |
342 | } |
343 | if (t1 == t2) { |
344 | return t1; |
345 | } |
346 | int o1 = getOrder(t1); |
347 | int o2 = getOrder(t2); |
348 | return o1 > o2 ? t1 : t2; |
349 | } |
350 | |
351 | /** |
352 | * Check if a value is in the cache that is equal to this value. If yes, |
353 | * this value should be used to save memory. If the value is not in the |
354 | * cache yet, it is added. |
355 | * |
356 | * @param v the value to look for |
357 | * @return the value in the cache or the value passed |
358 | */ |
359 | static Value cache(Value v) { |
360 | if (SysProperties.OBJECT_CACHE) { |
361 | int hash = v.hashCode(); |
362 | if (softCache == null) { |
363 | softCache = new SoftReference<Value[]>(null); |
364 | } |
365 | Value[] cache = softCache.get(); |
366 | if (cache == null) { |
367 | cache = new Value[SysProperties.OBJECT_CACHE_SIZE]; |
368 | softCache = new SoftReference<Value[]>(cache); |
369 | } |
370 | int index = hash & (SysProperties.OBJECT_CACHE_SIZE - 1); |
371 | Value cached = cache[index]; |
372 | if (cached != null) { |
373 | if (cached.getType() == v.getType() && v.equals(cached)) { |
374 | // cacheHit++; |
375 | return cached; |
376 | } |
377 | } |
378 | // cacheMiss++; |
379 | // cache[cacheCleaner] = null; |
380 | // cacheCleaner = (cacheCleaner + 1) & |
381 | // (Constants.OBJECT_CACHE_SIZE - 1); |
382 | cache[index] = v; |
383 | } |
384 | return v; |
385 | } |
386 | |
387 | /** |
388 | * Clear the value cache. Used for testing. |
389 | */ |
390 | public static void clearCache() { |
391 | softCache = null; |
392 | } |
393 | |
394 | public Boolean getBoolean() { |
395 | return ((ValueBoolean) convertTo(Value.BOOLEAN)).getBoolean(); |
396 | } |
397 | |
398 | public Date getDate() { |
399 | return ((ValueDate) convertTo(Value.DATE)).getDate(); |
400 | } |
401 | |
402 | public Time getTime() { |
403 | return ((ValueTime) convertTo(Value.TIME)).getTime(); |
404 | } |
405 | |
406 | public Timestamp getTimestamp() { |
407 | return ((ValueTimestamp) convertTo(Value.TIMESTAMP)).getTimestamp(); |
408 | } |
409 | |
410 | public byte[] getBytes() { |
411 | return ((ValueBytes) convertTo(Value.BYTES)).getBytes(); |
412 | } |
413 | |
414 | public byte[] getBytesNoCopy() { |
415 | return ((ValueBytes) convertTo(Value.BYTES)).getBytesNoCopy(); |
416 | } |
417 | |
418 | public byte getByte() { |
419 | return ((ValueByte) convertTo(Value.BYTE)).getByte(); |
420 | } |
421 | |
422 | public short getShort() { |
423 | return ((ValueShort) convertTo(Value.SHORT)).getShort(); |
424 | } |
425 | |
426 | public BigDecimal getBigDecimal() { |
427 | return ((ValueDecimal) convertTo(Value.DECIMAL)).getBigDecimal(); |
428 | } |
429 | |
430 | public double getDouble() { |
431 | return ((ValueDouble) convertTo(Value.DOUBLE)).getDouble(); |
432 | } |
433 | |
434 | public float getFloat() { |
435 | return ((ValueFloat) convertTo(Value.FLOAT)).getFloat(); |
436 | } |
437 | |
438 | public int getInt() { |
439 | return ((ValueInt) convertTo(Value.INT)).getInt(); |
440 | } |
441 | |
442 | public long getLong() { |
443 | return ((ValueLong) convertTo(Value.LONG)).getLong(); |
444 | } |
445 | |
446 | public InputStream getInputStream() { |
447 | return new ByteArrayInputStream(getBytesNoCopy()); |
448 | } |
449 | |
450 | public Reader getReader() { |
451 | return new StringReader(getString()); |
452 | } |
453 | |
454 | /** |
455 | * Add a value and return the result. |
456 | * |
457 | * @param v the value to add |
458 | * @return the result |
459 | */ |
460 | public Value add(Value v) { |
461 | throw throwUnsupportedExceptionForType("+"); |
462 | } |
463 | |
464 | public int getSignum() { |
465 | throw throwUnsupportedExceptionForType("SIGNUM"); |
466 | } |
467 | |
468 | /** |
469 | * Return -value if this value support arithmetic operations. |
470 | * |
471 | * @return the negative |
472 | */ |
473 | public Value negate() { |
474 | throw throwUnsupportedExceptionForType("NEG"); |
475 | } |
476 | |
477 | /** |
478 | * Subtract a value and return the result. |
479 | * |
480 | * @param v the value to subtract |
481 | * @return the result |
482 | */ |
483 | public Value subtract(Value v) { |
484 | throw throwUnsupportedExceptionForType("-"); |
485 | } |
486 | |
487 | /** |
488 | * Divide by a value and return the result. |
489 | * |
490 | * @param v the value to divide by |
491 | * @return the result |
492 | */ |
493 | public Value divide(Value v) { |
494 | throw throwUnsupportedExceptionForType("/"); |
495 | } |
496 | |
497 | /** |
498 | * Multiply with a value and return the result. |
499 | * |
500 | * @param v the value to multiply with |
501 | * @return the result |
502 | */ |
503 | public Value multiply(Value v) { |
504 | throw throwUnsupportedExceptionForType("*"); |
505 | } |
506 | |
507 | /** |
508 | * Take the modulus with a value and return the result. |
509 | * |
510 | * @param v the value to take the modulus with |
511 | * @return the result |
512 | */ |
513 | public Value modulus(Value v) { |
514 | throw throwUnsupportedExceptionForType("%"); |
515 | } |
516 | |
517 | /** |
518 | * Compare a value to the specified type. |
519 | * |
520 | * @param targetType the type of the returned value |
521 | * @return the converted value |
522 | */ |
523 | public Value convertTo(int targetType) { |
524 | // converting NULL is done in ValueNull |
525 | // converting BLOB to CLOB and vice versa is done in ValueLob |
526 | if (getType() == targetType) { |
527 | return this; |
528 | } |
529 | try { |
530 | // decimal conversion |
531 | switch (targetType) { |
532 | case BOOLEAN: { |
533 | switch (getType()) { |
534 | case BYTE: |
535 | case SHORT: |
536 | case INT: |
537 | case LONG: |
538 | case DECIMAL: |
539 | case DOUBLE: |
540 | case FLOAT: |
541 | return ValueBoolean.get(getSignum() != 0); |
542 | case TIME: |
543 | case DATE: |
544 | case TIMESTAMP: |
545 | case BYTES: |
546 | case JAVA_OBJECT: |
547 | case UUID: |
548 | throw DbException.get( |
549 | ErrorCode.DATA_CONVERSION_ERROR_1, getString()); |
550 | } |
551 | break; |
552 | } |
553 | case BYTE: { |
554 | switch (getType()) { |
555 | case BOOLEAN: |
556 | return ValueByte.get(getBoolean().booleanValue() ? (byte) 1 : (byte) 0); |
557 | case SHORT: |
558 | return ValueByte.get(convertToByte(getShort())); |
559 | case INT: |
560 | return ValueByte.get(convertToByte(getInt())); |
561 | case LONG: |
562 | return ValueByte.get(convertToByte(getLong())); |
563 | case DECIMAL: |
564 | return ValueByte.get(convertToByte(convertToLong(getBigDecimal()))); |
565 | case DOUBLE: |
566 | return ValueByte.get(convertToByte(convertToLong(getDouble()))); |
567 | case FLOAT: |
568 | return ValueByte.get(convertToByte(convertToLong(getFloat()))); |
569 | case BYTES: |
570 | return ValueByte.get((byte) Integer.parseInt(getString(), 16)); |
571 | } |
572 | break; |
573 | } |
574 | case SHORT: { |
575 | switch (getType()) { |
576 | case BOOLEAN: |
577 | return ValueShort.get(getBoolean().booleanValue() ? (short) 1 : (short) 0); |
578 | case BYTE: |
579 | return ValueShort.get(getByte()); |
580 | case INT: |
581 | return ValueShort.get(convertToShort(getInt())); |
582 | case LONG: |
583 | return ValueShort.get(convertToShort(getLong())); |
584 | case DECIMAL: |
585 | return ValueShort.get(convertToShort(convertToLong(getBigDecimal()))); |
586 | case DOUBLE: |
587 | return ValueShort.get(convertToShort(convertToLong(getDouble()))); |
588 | case FLOAT: |
589 | return ValueShort.get(convertToShort(convertToLong(getFloat()))); |
590 | case BYTES: |
591 | return ValueShort.get((short) Integer.parseInt(getString(), 16)); |
592 | } |
593 | break; |
594 | } |
595 | case INT: { |
596 | switch (getType()) { |
597 | case BOOLEAN: |
598 | return ValueInt.get(getBoolean().booleanValue() ? 1 : 0); |
599 | case BYTE: |
600 | return ValueInt.get(getByte()); |
601 | case SHORT: |
602 | return ValueInt.get(getShort()); |
603 | case LONG: |
604 | return ValueInt.get(convertToInt(getLong())); |
605 | case DECIMAL: |
606 | return ValueInt.get(convertToInt(convertToLong(getBigDecimal()))); |
607 | case DOUBLE: |
608 | return ValueInt.get(convertToInt(convertToLong(getDouble()))); |
609 | case FLOAT: |
610 | return ValueInt.get(convertToInt(convertToLong(getFloat()))); |
611 | case BYTES: |
612 | return ValueInt.get((int) Long.parseLong(getString(), 16)); |
613 | } |
614 | break; |
615 | } |
616 | case LONG: { |
617 | switch (getType()) { |
618 | case BOOLEAN: |
619 | return ValueLong.get(getBoolean().booleanValue() ? 1 : 0); |
620 | case BYTE: |
621 | return ValueLong.get(getByte()); |
622 | case SHORT: |
623 | return ValueLong.get(getShort()); |
624 | case INT: |
625 | return ValueLong.get(getInt()); |
626 | case DECIMAL: |
627 | return ValueLong.get(convertToLong(getBigDecimal())); |
628 | case DOUBLE: |
629 | return ValueLong.get(convertToLong(getDouble())); |
630 | case FLOAT: |
631 | return ValueLong.get(convertToLong(getFloat())); |
632 | case BYTES: { |
633 | // parseLong doesn't work for ffffffffffffffff |
634 | byte[] d = getBytes(); |
635 | if (d.length == 8) { |
636 | return ValueLong.get(Utils.readLong(d, 0)); |
637 | } |
638 | return ValueLong.get(Long.parseLong(getString(), 16)); |
639 | } |
640 | } |
641 | break; |
642 | } |
643 | case DECIMAL: { |
644 | switch (getType()) { |
645 | case BOOLEAN: |
646 | return ValueDecimal.get(BigDecimal.valueOf( |
647 | getBoolean().booleanValue() ? 1 : 0)); |
648 | case BYTE: |
649 | return ValueDecimal.get(BigDecimal.valueOf(getByte())); |
650 | case SHORT: |
651 | return ValueDecimal.get(BigDecimal.valueOf(getShort())); |
652 | case INT: |
653 | return ValueDecimal.get(BigDecimal.valueOf(getInt())); |
654 | case LONG: |
655 | return ValueDecimal.get(BigDecimal.valueOf(getLong())); |
656 | case DOUBLE: { |
657 | double d = getDouble(); |
658 | if (Double.isInfinite(d) || Double.isNaN(d)) { |
659 | throw DbException.get( |
660 | ErrorCode.DATA_CONVERSION_ERROR_1, "" + d); |
661 | } |
662 | return ValueDecimal.get(BigDecimal.valueOf(d)); |
663 | } |
664 | case FLOAT: { |
665 | float f = getFloat(); |
666 | if (Float.isInfinite(f) || Float.isNaN(f)) { |
667 | throw DbException.get( |
668 | ErrorCode.DATA_CONVERSION_ERROR_1, "" + f); |
669 | } |
670 | // better rounding behavior than BigDecimal.valueOf(f) |
671 | return ValueDecimal.get(new BigDecimal(Float.toString(f))); |
672 | } |
673 | } |
674 | break; |
675 | } |
676 | case DOUBLE: { |
677 | switch (getType()) { |
678 | case BOOLEAN: |
679 | return ValueDouble.get(getBoolean().booleanValue() ? 1 : 0); |
680 | case BYTE: |
681 | return ValueDouble.get(getByte()); |
682 | case SHORT: |
683 | return ValueDouble.get(getShort()); |
684 | case INT: |
685 | return ValueDouble.get(getInt()); |
686 | case LONG: |
687 | return ValueDouble.get(getLong()); |
688 | case DECIMAL: |
689 | return ValueDouble.get(getBigDecimal().doubleValue()); |
690 | case FLOAT: |
691 | return ValueDouble.get(getFloat()); |
692 | } |
693 | break; |
694 | } |
695 | case FLOAT: { |
696 | switch (getType()) { |
697 | case BOOLEAN: |
698 | return ValueFloat.get(getBoolean().booleanValue() ? 1 : 0); |
699 | case BYTE: |
700 | return ValueFloat.get(getByte()); |
701 | case SHORT: |
702 | return ValueFloat.get(getShort()); |
703 | case INT: |
704 | return ValueFloat.get(getInt()); |
705 | case LONG: |
706 | return ValueFloat.get(getLong()); |
707 | case DECIMAL: |
708 | return ValueFloat.get(getBigDecimal().floatValue()); |
709 | case DOUBLE: |
710 | return ValueFloat.get((float) getDouble()); |
711 | } |
712 | break; |
713 | } |
714 | case DATE: { |
715 | switch (getType()) { |
716 | case TIME: |
717 | // because the time has set the date to 1970-01-01, |
718 | // this will be the result |
719 | return ValueDate.fromDateValue( |
720 | DateTimeUtils.dateValue(1970, 1, 1)); |
721 | case TIMESTAMP: |
722 | return ValueDate.fromDateValue( |
723 | ((ValueTimestamp) this).getDateValue()); |
724 | } |
725 | break; |
726 | } |
727 | case TIME: { |
728 | switch (getType()) { |
729 | case DATE: |
730 | // need to normalize the year, month and day because a date |
731 | // has the time set to 0, the result will be 0 |
732 | return ValueTime.fromNanos(0); |
733 | case TIMESTAMP: |
734 | return ValueTime.fromNanos( |
735 | ((ValueTimestamp) this).getTimeNanos()); |
736 | } |
737 | break; |
738 | } |
739 | case TIMESTAMP: { |
740 | switch (getType()) { |
741 | case TIME: |
742 | return DateTimeUtils.normalizeTimestamp( |
743 | 0, ((ValueTime) this).getNanos()); |
744 | case DATE: |
745 | return ValueTimestamp.fromDateValueAndNanos( |
746 | ((ValueDate) this).getDateValue(), 0); |
747 | } |
748 | break; |
749 | } |
750 | case BYTES: { |
751 | switch(getType()) { |
752 | case JAVA_OBJECT: |
753 | case BLOB: |
754 | return ValueBytes.getNoCopy(getBytesNoCopy()); |
755 | case UUID: |
756 | case GEOMETRY: |
757 | return ValueBytes.getNoCopy(getBytes()); |
758 | case BYTE: |
759 | return ValueBytes.getNoCopy(new byte[]{getByte()}); |
760 | case SHORT: { |
761 | int x = getShort(); |
762 | return ValueBytes.getNoCopy(new byte[]{ |
763 | (byte) (x >> 8), |
764 | (byte) x |
765 | }); |
766 | } |
767 | case INT: { |
768 | int x = getInt(); |
769 | return ValueBytes.getNoCopy(new byte[]{ |
770 | (byte) (x >> 24), |
771 | (byte) (x >> 16), |
772 | (byte) (x >> 8), |
773 | (byte) x |
774 | }); |
775 | } |
776 | case LONG: { |
777 | long x = getLong(); |
778 | return ValueBytes.getNoCopy(new byte[]{ |
779 | (byte) (x >> 56), |
780 | (byte) (x >> 48), |
781 | (byte) (x >> 40), |
782 | (byte) (x >> 32), |
783 | (byte) (x >> 24), |
784 | (byte) (x >> 16), |
785 | (byte) (x >> 8), |
786 | (byte) x |
787 | }); |
788 | } |
789 | } |
790 | break; |
791 | } |
792 | case JAVA_OBJECT: { |
793 | switch(getType()) { |
794 | case BYTES: |
795 | case BLOB: |
796 | return ValueJavaObject.getNoCopy( |
797 | null, getBytesNoCopy(), getDataHandler()); |
798 | } |
799 | break; |
800 | } |
801 | case BLOB: { |
802 | switch(getType()) { |
803 | case BYTES: |
804 | return ValueLobDb.createSmallLob( |
805 | Value.BLOB, getBytesNoCopy()); |
806 | } |
807 | break; |
808 | } |
809 | case UUID: { |
810 | switch(getType()) { |
811 | case BYTES: |
812 | return ValueUuid.get(getBytesNoCopy()); |
813 | } |
814 | } |
815 | case GEOMETRY: |
816 | switch(getType()) { |
817 | case BYTES: |
818 | return ValueGeometry.get(getBytesNoCopy()); |
819 | case JAVA_OBJECT: |
820 | Object object = JdbcUtils.deserialize(getBytesNoCopy(), getDataHandler()); |
821 | if (DataType.isGeometry(object)) { |
822 | return ValueGeometry.getFromGeometry(object); |
823 | } |
824 | } |
825 | } |
826 | // conversion by parsing the string value |
827 | String s = getString(); |
828 | switch (targetType) { |
829 | case NULL: |
830 | return ValueNull.INSTANCE; |
831 | case BOOLEAN: { |
832 | if (s.equalsIgnoreCase("true") || |
833 | s.equalsIgnoreCase("t") || |
834 | s.equalsIgnoreCase("yes") || |
835 | s.equalsIgnoreCase("y")) { |
836 | return ValueBoolean.get(true); |
837 | } else if (s.equalsIgnoreCase("false") || |
838 | s.equalsIgnoreCase("f") || |
839 | s.equalsIgnoreCase("no") || |
840 | s.equalsIgnoreCase("n")) { |
841 | return ValueBoolean.get(false); |
842 | } else { |
843 | // convert to a number, and if it is not 0 then it is true |
844 | return ValueBoolean.get(new BigDecimal(s).signum() != 0); |
845 | } |
846 | } |
847 | case BYTE: |
848 | return ValueByte.get(Byte.parseByte(s.trim())); |
849 | case SHORT: |
850 | return ValueShort.get(Short.parseShort(s.trim())); |
851 | case INT: |
852 | return ValueInt.get(Integer.parseInt(s.trim())); |
853 | case LONG: |
854 | return ValueLong.get(Long.parseLong(s.trim())); |
855 | case DECIMAL: |
856 | return ValueDecimal.get(new BigDecimal(s.trim())); |
857 | case TIME: |
858 | return ValueTime.parse(s.trim()); |
859 | case DATE: |
860 | return ValueDate.parse(s.trim()); |
861 | case TIMESTAMP: |
862 | return ValueTimestamp.parse(s.trim()); |
863 | case BYTES: |
864 | return ValueBytes.getNoCopy( |
865 | StringUtils.convertHexToBytes(s.trim())); |
866 | case JAVA_OBJECT: |
867 | return ValueJavaObject.getNoCopy(null, |
868 | StringUtils.convertHexToBytes(s.trim()), getDataHandler()); |
869 | case STRING: |
870 | return ValueString.get(s); |
871 | case STRING_IGNORECASE: |
872 | return ValueStringIgnoreCase.get(s); |
873 | case STRING_FIXED: |
874 | return ValueStringFixed.get(s); |
875 | case DOUBLE: |
876 | return ValueDouble.get(Double.parseDouble(s.trim())); |
877 | case FLOAT: |
878 | return ValueFloat.get(Float.parseFloat(s.trim())); |
879 | case CLOB: |
880 | return ValueLobDb.createSmallLob( |
881 | CLOB, s.getBytes(Constants.UTF8)); |
882 | case BLOB: |
883 | return ValueLobDb.createSmallLob( |
884 | BLOB, StringUtils.convertHexToBytes(s.trim())); |
885 | case ARRAY: |
886 | return ValueArray.get(new Value[]{ValueString.get(s)}); |
887 | case RESULT_SET: { |
888 | SimpleResultSet rs = new SimpleResultSet(); |
889 | rs.setAutoClose(false); |
890 | rs.addColumn("X", Types.VARCHAR, s.length(), 0); |
891 | rs.addRow(s); |
892 | return ValueResultSet.get(rs); |
893 | } |
894 | case UUID: |
895 | return ValueUuid.get(s); |
896 | case GEOMETRY: |
897 | return ValueGeometry.get(s); |
898 | default: |
899 | throw DbException.throwInternalError("type=" + targetType); |
900 | } |
901 | } catch (NumberFormatException e) { |
902 | throw DbException.get( |
903 | ErrorCode.DATA_CONVERSION_ERROR_1, e, getString()); |
904 | } |
905 | } |
906 | |
907 | /** |
908 | * Compare this value against another value given that the values are of the |
909 | * same data type. |
910 | * |
911 | * @param v the other value |
912 | * @param mode the compare mode |
913 | * @return 0 if both values are equal, -1 if the other value is smaller, and |
914 | * 1 otherwise |
915 | */ |
916 | public final int compareTypeSave(Value v, CompareMode mode) { |
917 | if (this == v) { |
918 | return 0; |
919 | } else if (this == ValueNull.INSTANCE) { |
920 | return -1; |
921 | } else if (v == ValueNull.INSTANCE) { |
922 | return 1; |
923 | } |
924 | return compareSecure(v, mode); |
925 | } |
926 | |
927 | /** |
928 | * Compare this value against another value using the specified compare |
929 | * mode. |
930 | * |
931 | * @param v the other value |
932 | * @param mode the compare mode |
933 | * @return 0 if both values are equal, -1 if the other value is smaller, and |
934 | * 1 otherwise |
935 | */ |
936 | public final int compareTo(Value v, CompareMode mode) { |
937 | if (this == v) { |
938 | return 0; |
939 | } |
940 | if (this == ValueNull.INSTANCE) { |
941 | return v == ValueNull.INSTANCE ? 0 : -1; |
942 | } else if (v == ValueNull.INSTANCE) { |
943 | return 1; |
944 | } |
945 | if (getType() == v.getType()) { |
946 | return compareSecure(v, mode); |
947 | } |
948 | int t2 = Value.getHigherOrder(getType(), v.getType()); |
949 | return convertTo(t2).compareSecure(v.convertTo(t2), mode); |
950 | } |
951 | |
952 | public int getScale() { |
953 | return 0; |
954 | } |
955 | |
956 | /** |
957 | * Convert the scale. |
958 | * |
959 | * @param onlyToSmallerScale if the scale should not reduced |
960 | * @param targetScale the requested scale |
961 | * @return the value |
962 | */ |
963 | public Value convertScale(boolean onlyToSmallerScale, int targetScale) { |
964 | return this; |
965 | } |
966 | |
967 | /** |
968 | * Convert the precision to the requested value. The precision of the |
969 | * returned value may be somewhat larger than requested, because values with |
970 | * a fixed precision are not truncated. |
971 | * |
972 | * @param precision the new precision |
973 | * @param force true if losing numeric precision is allowed |
974 | * @return the new value |
975 | */ |
976 | public Value convertPrecision(long precision, boolean force) { |
977 | return this; |
978 | } |
979 | |
980 | private static byte convertToByte(long x) { |
981 | if (x > Byte.MAX_VALUE || x < Byte.MIN_VALUE) { |
982 | throw DbException.get( |
983 | ErrorCode.NUMERIC_VALUE_OUT_OF_RANGE_1, Long.toString(x)); |
984 | } |
985 | return (byte) x; |
986 | } |
987 | |
988 | private static short convertToShort(long x) { |
989 | if (x > Short.MAX_VALUE || x < Short.MIN_VALUE) { |
990 | throw DbException.get( |
991 | ErrorCode.NUMERIC_VALUE_OUT_OF_RANGE_1, Long.toString(x)); |
992 | } |
993 | return (short) x; |
994 | } |
995 | |
996 | private static int convertToInt(long x) { |
997 | if (x > Integer.MAX_VALUE || x < Integer.MIN_VALUE) { |
998 | throw DbException.get( |
999 | ErrorCode.NUMERIC_VALUE_OUT_OF_RANGE_1, Long.toString(x)); |
1000 | } |
1001 | return (int) x; |
1002 | } |
1003 | |
1004 | private static long convertToLong(double x) { |
1005 | if (x > Long.MAX_VALUE || x < Long.MIN_VALUE) { |
1006 | // TODO document that +Infinity, -Infinity throw an exception and |
1007 | // NaN returns 0 |
1008 | throw DbException.get( |
1009 | ErrorCode.NUMERIC_VALUE_OUT_OF_RANGE_1, Double.toString(x)); |
1010 | } |
1011 | return Math.round(x); |
1012 | } |
1013 | |
1014 | private static long convertToLong(BigDecimal x) { |
1015 | if (x.compareTo(MAX_LONG_DECIMAL) > 0 || |
1016 | x.compareTo(Value.MIN_LONG_DECIMAL) < 0) { |
1017 | throw DbException.get( |
1018 | ErrorCode.NUMERIC_VALUE_OUT_OF_RANGE_1, x.toString()); |
1019 | } |
1020 | return x.setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); |
1021 | } |
1022 | |
1023 | /** |
1024 | * Link a large value to a given table. For values that are kept fully in |
1025 | * memory this method has no effect. |
1026 | * |
1027 | * @param handler the data handler |
1028 | * @param tableId the table to link to |
1029 | * @return the new value or itself |
1030 | */ |
1031 | public Value link(DataHandler handler, int tableId) { |
1032 | return this; |
1033 | } |
1034 | |
1035 | /** |
1036 | * Check if this value is linked to a specific table. For values that are |
1037 | * kept fully in memory, this method returns false. |
1038 | * |
1039 | * @return true if it is |
1040 | */ |
1041 | public boolean isLinked() { |
1042 | return false; |
1043 | } |
1044 | |
1045 | /** |
1046 | * Mark any underlying resource as 'not linked to any table'. For values |
1047 | * that are kept fully in memory this method has no effect. |
1048 | * |
1049 | * @param handler the data handler |
1050 | */ |
1051 | public void unlink(DataHandler handler) { |
1052 | // nothing to do |
1053 | } |
1054 | |
1055 | /** |
1056 | * Close the underlying resource, if any. For values that are kept fully in |
1057 | * memory this method has no effect. |
1058 | */ |
1059 | public void close() { |
1060 | // nothing to do |
1061 | } |
1062 | |
1063 | /** |
1064 | * Check if the precision is smaller or equal than the given precision. |
1065 | * |
1066 | * @param precision the maximum precision |
1067 | * @return true if the precision of this value is smaller or equal to the |
1068 | * given precision |
1069 | */ |
1070 | public boolean checkPrecision(long precision) { |
1071 | return getPrecision() <= precision; |
1072 | } |
1073 | |
1074 | /** |
1075 | * Get a medium size SQL expression for debugging or tracing. If the |
1076 | * precision is too large, only a subset of the value is returned. |
1077 | * |
1078 | * @return the SQL expression |
1079 | */ |
1080 | public String getTraceSQL() { |
1081 | return getSQL(); |
1082 | } |
1083 | |
1084 | @Override |
1085 | public String toString() { |
1086 | return getTraceSQL(); |
1087 | } |
1088 | |
1089 | /** |
1090 | * Throw the exception that the feature is not support for the given data |
1091 | * type. |
1092 | * |
1093 | * @param op the operation |
1094 | * @return never returns normally |
1095 | * @throws DbException the exception |
1096 | */ |
1097 | protected DbException throwUnsupportedExceptionForType(String op) { |
1098 | throw DbException.getUnsupportedException( |
1099 | DataType.getDataType(getType()).name + " " + op); |
1100 | } |
1101 | |
1102 | /** |
1103 | * Get the table (only for LOB object). |
1104 | * |
1105 | * @return the table id |
1106 | */ |
1107 | public int getTableId() { |
1108 | return 0; |
1109 | } |
1110 | |
1111 | /** |
1112 | * Get the byte array. |
1113 | * |
1114 | * @return the byte array |
1115 | */ |
1116 | public byte[] getSmall() { |
1117 | return null; |
1118 | } |
1119 | |
1120 | /** |
1121 | * Copy this value to a temporary file if necessary. |
1122 | * |
1123 | * @return the new value |
1124 | */ |
1125 | public Value copyToTemp() { |
1126 | return this; |
1127 | } |
1128 | |
1129 | /** |
1130 | * Create an independent copy of this value if needed, that will be bound to |
1131 | * a result. If the original row is removed, this copy is still readable. |
1132 | * |
1133 | * @return the value (this for small objects) |
1134 | */ |
1135 | public Value copyToResult() { |
1136 | return this; |
1137 | } |
1138 | |
1139 | public ResultSet getResultSet() { |
1140 | SimpleResultSet rs = new SimpleResultSet(); |
1141 | rs.setAutoClose(false); |
1142 | rs.addColumn("X", DataType.convertTypeToSQLType(getType()), |
1143 | MathUtils.convertLongToInt(getPrecision()), getScale()); |
1144 | rs.addRow(getObject()); |
1145 | return rs; |
1146 | } |
1147 | |
1148 | /** |
1149 | * Return the data handler for the values that support it |
1150 | * (actually only Java objects). |
1151 | * @return the data handler |
1152 | */ |
1153 | protected DataHandler getDataHandler() { |
1154 | return null; |
1155 | } |
1156 | |
1157 | /** |
1158 | * A "binary large object". |
1159 | */ |
1160 | public interface ValueClob { |
1161 | // this is a marker interface |
1162 | } |
1163 | |
1164 | /** |
1165 | * A "character large object". |
1166 | */ |
1167 | public interface ValueBlob { |
1168 | // this is a marker interface |
1169 | } |
1170 | |
1171 | } |