1010
1111import java .sql .Date ;
1212import java .sql .JDBCType ;
13- import java .sql .SQLDataException ;
1413import java .sql .SQLException ;
1514import java .sql .SQLFeatureNotSupportedException ;
1615import java .sql .Time ;
@@ -56,9 +55,10 @@ private TypeConverter() {
5655
5756 }
5857
59- private static final long DAY_IN_MILLIS = 60 * 60 * 24 ;
58+ private static final long DAY_IN_MILLIS = 60 * 60 * 24 * 1000 ;
6059 private static final Map <Class <?>, JDBCType > javaToJDBC ;
6160
61+
6262 static {
6363 Map <Class <?>, JDBCType > aMap = Arrays .stream (DataType .values ())
6464 .filter (dataType -> dataType .javaClass () != null
@@ -120,6 +120,7 @@ private static <T> T dateTimeConvert(Long millis, Calendar c, Function<Calendar,
120120 }
121121 }
122122
123+
123124 static long convertFromCalendarToUTC (long value , Calendar cal ) {
124125 if (cal == null ) {
125126 return value ;
@@ -143,11 +144,15 @@ static <T> T convert(Object val, JDBCType columnType, Class<T> type) throws SQLE
143144 return (T ) convert (val , columnType );
144145 }
145146
146- if (type .isInstance (val )) {
147+ // converting a Long to a Timestamp shouldn't be possible according to the spec,
148+ // it feels a little brittle to check this scenario here and I don't particularly like it
149+ // TODO: can we do any better or should we go over the spec and allow getLong(date) to be valid?
150+ if (!(type == Long .class && columnType == JDBCType .TIMESTAMP ) && type .isInstance (val )) {
147151 try {
148152 return type .cast (val );
149153 } catch (ClassCastException cce ) {
150- throw new SQLDataException ("Unable to convert " + val .getClass ().getName () + " to " + columnType , cce );
154+ throw new SQLException (format (Locale .ROOT , "Unable to convert value [%.128s] of type [%s] to a %s" , val ,
155+ columnType .getName (), type .getName ()), cce );
151156 }
152157 }
153158
@@ -205,7 +210,8 @@ static <T> T convert(Object val, JDBCType columnType, Class<T> type) throws SQLE
205210 if (type == OffsetDateTime .class ) {
206211 return (T ) asOffsetDateTime (val , columnType );
207212 }
208- throw new SQLException ("Conversion from type [" + columnType + "] to [" + type .getName () + "] not supported" );
213+ throw new SQLException (format (Locale .ROOT , "Unable to convert value [%.128s] of type [%s] to a %s" , val ,
214+ columnType .getName (), type .getName ()));
209215 }
210216
211217 /**
@@ -336,8 +342,11 @@ private static Boolean asBoolean(Object val, JDBCType columnType) throws SQLExce
336342 case FLOAT :
337343 case DOUBLE :
338344 return Boolean .valueOf (Integer .signum (((Number ) val ).intValue ()) != 0 );
345+ case VARCHAR :
346+ return Boolean .valueOf ((String ) val );
339347 default :
340- throw new SQLException ("Conversion from type [" + columnType + "] to [Boolean] not supported" );
348+ throw new SQLException (
349+ format (Locale .ROOT , "Unable to convert value [%.128s] of type [%s] to a Boolean" , val , columnType .getName ()));
341350
342351 }
343352 }
@@ -355,10 +364,16 @@ private static Byte asByte(Object val, JDBCType columnType) throws SQLException
355364 case FLOAT :
356365 case DOUBLE :
357366 return safeToByte (safeToLong (((Number ) val ).doubleValue ()));
367+ case VARCHAR :
368+ try {
369+ return Byte .valueOf ((String ) val );
370+ } catch (NumberFormatException e ) {
371+ throw new SQLException (format (Locale .ROOT , "Unable to convert value [%.128s] of type [VARCHAR] to a Byte" , val ), e );
372+ }
358373 default :
359374 }
360375
361- throw new SQLException ("Conversion from type [" + columnType + " ] to [ Byte] not supported" );
376+ throw new SQLException (format ( Locale . ROOT , "Unable to convert value [%.128s] of type [%s ] to a Byte" , val , columnType . getName ()) );
362377 }
363378
364379 private static Short asShort (Object val , JDBCType columnType ) throws SQLException {
@@ -374,10 +389,16 @@ private static Short asShort(Object val, JDBCType columnType) throws SQLExceptio
374389 case FLOAT :
375390 case DOUBLE :
376391 return safeToShort (safeToLong (((Number ) val ).doubleValue ()));
392+ case VARCHAR :
393+ try {
394+ return Short .valueOf ((String ) val );
395+ } catch (NumberFormatException e ) {
396+ throw new SQLException (format (Locale .ROOT , "Unable to convert value [%.128s] of type [VARCHAR] to a Short" , val ), e );
397+ }
377398 default :
378399 }
379400
380- throw new SQLException ("Conversion from type [" + columnType + " ] to [ Short] not supported" );
401+ throw new SQLException (format ( Locale . ROOT , "Unable to convert value [%.128s] of type [%s ] to a Short" , val , columnType . getName ()) );
381402 }
382403
383404 private static Integer asInteger (Object val , JDBCType columnType ) throws SQLException {
@@ -393,10 +414,18 @@ private static Integer asInteger(Object val, JDBCType columnType) throws SQLExce
393414 case FLOAT :
394415 case DOUBLE :
395416 return safeToInt (safeToLong (((Number ) val ).doubleValue ()));
417+ case VARCHAR :
418+ try {
419+ return Integer .valueOf ((String ) val );
420+ } catch (NumberFormatException e ) {
421+ throw new SQLException (
422+ format (Locale .ROOT , "Unable to convert value [%.128s] of type [VARCHAR] to an Integer" , val ), e );
423+ }
396424 default :
397425 }
398426
399- throw new SQLException ("Conversion from type [" + columnType + "] to [Integer] not supported" );
427+ throw new SQLException (
428+ format (Locale .ROOT , "Unable to convert value [%.128s] of type [%s] to an Integer" , val , columnType .getName ()));
400429 }
401430
402431 private static Long asLong (Object val , JDBCType columnType ) throws SQLException {
@@ -412,12 +441,21 @@ private static Long asLong(Object val, JDBCType columnType) throws SQLException
412441 case FLOAT :
413442 case DOUBLE :
414443 return safeToLong (((Number ) val ).doubleValue ());
415- case TIMESTAMP :
416- return ((Number ) val ).longValue ();
444+ //TODO: should we support conversion to TIMESTAMP?
445+ //The spec says that getLong() should support the following types conversions:
446+ //TINYINT, SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, BOOLEAN, CHAR, VARCHAR, LONGVARCHAR
447+ //case TIMESTAMP:
448+ // return ((Number) val).longValue();
449+ case VARCHAR :
450+ try {
451+ return Long .valueOf ((String ) val );
452+ } catch (NumberFormatException e ) {
453+ throw new SQLException (format (Locale .ROOT , "Unable to convert value [%.128s] of type [VARCHAR] to a Long" , val ), e );
454+ }
417455 default :
418456 }
419457
420- throw new SQLException ("Conversion from type [" + columnType + " ] to [ Long] not supported" );
458+ throw new SQLException (format ( Locale . ROOT , "Unable to convert value [%.128s] of type [%s ] to a Long" , val , columnType . getName ()) );
421459 }
422460
423461 private static Float asFloat (Object val , JDBCType columnType ) throws SQLException {
@@ -433,10 +471,16 @@ private static Float asFloat(Object val, JDBCType columnType) throws SQLExceptio
433471 case FLOAT :
434472 case DOUBLE :
435473 return Float .valueOf ((((float ) ((Number ) val ).doubleValue ())));
474+ case VARCHAR :
475+ try {
476+ return Float .valueOf ((String ) val );
477+ } catch (NumberFormatException e ) {
478+ throw new SQLException (format (Locale .ROOT , "Unable to convert value [%.128s] of type [VARCHAR] to a Float" , val ), e );
479+ }
436480 default :
437481 }
438482
439- throw new SQLException ("Conversion from type [" + columnType + " ] to [ Float] not supported" );
483+ throw new SQLException (format ( Locale . ROOT , "Unable to convert value [%.128s] of type [%s ] to a Float" , val , columnType . getName ()) );
440484 }
441485
442486 private static Double asDouble (Object val , JDBCType columnType ) throws SQLException {
@@ -451,32 +495,41 @@ private static Double asDouble(Object val, JDBCType columnType) throws SQLExcept
451495 case REAL :
452496 case FLOAT :
453497 case DOUBLE :
498+
454499 return Double .valueOf (((Number ) val ).doubleValue ());
500+ case VARCHAR :
501+ try {
502+ return Double .valueOf ((String ) val );
503+ } catch (NumberFormatException e ) {
504+ throw new SQLException (format (Locale .ROOT , "Unable to convert value [%.128s] of type [VARCHAR] to a Double" , val ), e );
505+ }
455506 default :
456507 }
457508
458- throw new SQLException ("Conversion from type [" + columnType + "] to [Double] not supported" );
509+ throw new SQLException (
510+ format (Locale .ROOT , "Unable to convert value [%.128s] of type [%s] to a Double" , val , columnType .getName ()));
459511 }
460512
461513 private static Date asDate (Object val , JDBCType columnType ) throws SQLException {
462514 if (columnType == JDBCType .TIMESTAMP ) {
463515 return new Date (utcMillisRemoveTime (((Number ) val ).longValue ()));
464516 }
465- throw new SQLException ("Conversion from type [" + columnType + " ] to [ Date] not supported" );
517+ throw new SQLException (format ( Locale . ROOT , "Unable to convert value [%.128s] of type [%s ] to a Date" , val , columnType . getName ()) );
466518 }
467519
468520 private static Time asTime (Object val , JDBCType columnType ) throws SQLException {
469521 if (columnType == JDBCType .TIMESTAMP ) {
470522 return new Time (utcMillisRemoveDate (((Number ) val ).longValue ()));
471523 }
472- throw new SQLException ("Conversion from type [" + columnType + " ] to [ Time] not supported" );
524+ throw new SQLException (format ( Locale . ROOT , "Unable to convert value [%.128s] of type [%s ] to a Time" , val , columnType . getName ()) );
473525 }
474526
475527 private static Timestamp asTimestamp (Object val , JDBCType columnType ) throws SQLException {
476528 if (columnType == JDBCType .TIMESTAMP ) {
477529 return new Timestamp (((Number ) val ).longValue ());
478530 }
479- throw new SQLException ("Conversion from type [" + columnType + "] to [Timestamp] not supported" );
531+ throw new SQLException (
532+ format (Locale .ROOT , "Unable to convert value [%.128s] of type [%s] to a Timestamp" , val , columnType .getName ()));
480533 }
481534
482535 private static byte [] asByteArray (Object val , JDBCType columnType ) {
0 commit comments