Skip to content

Commit

Permalink
Overhaul type conversion exception messages to provide more details
Browse files Browse the repository at this point in the history
  • Loading branch information
mrotteveel committed Oct 30, 2021
1 parent 942927d commit bdf7033
Show file tree
Hide file tree
Showing 18 changed files with 395 additions and 278 deletions.
15 changes: 15 additions & 0 deletions src/main/org/firebirdsql/jdbc/field/AbstractWithTimeZoneField.java
Expand Up @@ -24,6 +24,7 @@
import java.sql.SQLException;
import java.sql.SQLNonTransientException;
import java.time.*;
import java.time.format.DateTimeParseException;
import java.util.Calendar;

import static org.firebirdsql.jdbc.JavaTypeNameConstants.*;
Expand Down Expand Up @@ -182,4 +183,18 @@ void setStringParse(String value) throws SQLException {
setOffsetTime(offsetTime);
}
}

@Override
public void setString(String value) throws SQLException {
if (setWhenNull(value)) return;

String string = value.trim();
try {
setStringParse(string);
} catch (DateTimeParseException e) {
SQLException conversionException = invalidSetConversion(String.class, string);
conversionException.initCause(e);
throw conversionException;
}
}
}
50 changes: 33 additions & 17 deletions src/main/org/firebirdsql/jdbc/field/FBBigDecimalField.java
Expand Up @@ -18,7 +18,6 @@
*/
package org.firebirdsql.jdbc.field;

import org.firebirdsql.extern.decimal.Decimal128;
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.JaybirdErrorCodes;
import org.firebirdsql.gds.ng.FbExceptionBuilder;
Expand All @@ -29,6 +28,8 @@
import java.math.RoundingMode;
import java.sql.SQLException;

import static org.firebirdsql.jdbc.JavaTypeNameConstants.BIG_DECIMAL_CLASS_NAME;

/**
* Describe class <code>FBBigDecimalField</code> here.
*
Expand Down Expand Up @@ -74,8 +75,9 @@ public byte getByte() throws SQLException {
long longValue = getLong();

// check if value is within bounds
if (longValue > MAX_BYTE_VALUE || longValue < MIN_BYTE_VALUE)
throw new TypeConversionException(BYTE_CONVERSION_ERROR);
if (longValue > MAX_BYTE_VALUE || longValue < MIN_BYTE_VALUE) {
throw invalidGetConversion("byte", String.format("value %d out of range", longValue));
}

return (byte) longValue;
}
Expand All @@ -99,8 +101,9 @@ public int getInt() throws SQLException {
long longValue = getLong();

// check if value is within bounds
if (longValue > MAX_INT_VALUE || longValue < MIN_INT_VALUE)
throw new TypeConversionException(INT_CONVERSION_ERROR);
if (longValue > MAX_INT_VALUE || longValue < MIN_INT_VALUE) {
throw invalidGetConversion("int", String.format("value %d out of range", longValue));
}

return (int) longValue;
}
Expand All @@ -110,7 +113,7 @@ public long getLong() throws SQLException {
if (value == null) return LONG_NULL_VALUE;

if (BD_MIN_LONG.compareTo(value) > 0 || value.compareTo(BD_MAX_LONG) > 0) {
throw new TypeConversionException(LONG_CONVERSION_ERROR);
throw invalidGetConversion("long", String.format("value %f out of range", value));
}
return value.longValue();
}
Expand All @@ -120,8 +123,9 @@ public short getShort() throws SQLException {
long longValue = getLong();

// check if value is within bounds
if (longValue > MAX_SHORT_VALUE || longValue < MIN_SHORT_VALUE)
throw new TypeConversionException(SHORT_CONVERSION_ERROR);
if (longValue > MAX_SHORT_VALUE || longValue < MIN_SHORT_VALUE) {
throw invalidGetConversion("short", String.format("value %d out of range", longValue));
}

return (short) longValue;
}
Expand Down Expand Up @@ -179,10 +183,13 @@ public void setShort(short value) throws SQLException {
public void setString(String value) throws SQLException {
if (setWhenNull(value)) return;

String string = value.trim();
try {
setBigDecimal(new BigDecimal(value));
setBigDecimal(new BigDecimal(string));
} catch (NumberFormatException nex) {
throw new TypeConversionException(STRING_CONVERSION_ERROR);
SQLException conversionException = invalidSetConversion(String.class, string);
conversionException.initCause(nex);
throw conversionException;
}
}

Expand Down Expand Up @@ -216,7 +223,7 @@ protected BigDecimal decode(FieldDescriptor fieldDescriptor, byte[] fieldData) {
protected byte[] encode(FieldDescriptor fieldDescriptor, BigDecimal value) throws SQLException {
BigInteger unscaledValue = normalize(value, -1 * fieldDescriptor.getScale());
if (unscaledValue.compareTo(MAX_SHORT) > 0 || unscaledValue.compareTo(MIN_SHORT) < 0) {
throw new TypeConversionException(BIGDECIMAL_CONVERSION_ERROR);
throw bigDecimalConversionError(fieldDescriptor, value);
}
return fieldDescriptor.getDatatypeCoder().encodeShort(unscaledValue.shortValue());
}
Expand All @@ -232,7 +239,7 @@ protected BigDecimal decode(FieldDescriptor fieldDescriptor, byte[] fieldData) {
protected byte[] encode(FieldDescriptor fieldDescriptor, BigDecimal value) throws SQLException {
BigInteger unscaledValue = normalize(value, -1 * fieldDescriptor.getScale());
if (unscaledValue.compareTo(MAX_INT) > 0 || unscaledValue.compareTo(MIN_INT) < 0) {
throw new TypeConversionException(BIGDECIMAL_CONVERSION_ERROR);
throw bigDecimalConversionError(fieldDescriptor, value);
}
return fieldDescriptor.getDatatypeCoder().encodeInt(unscaledValue.intValue());
}
Expand All @@ -248,7 +255,7 @@ protected BigDecimal decode(FieldDescriptor fieldDescriptor, byte[] fieldData) {
protected byte[] encode(FieldDescriptor fieldDescriptor, BigDecimal value) throws SQLException {
BigInteger unscaledValue = normalize(value, -1 * fieldDescriptor.getScale());
if (unscaledValue.compareTo(MAX_LONG) > 0 || unscaledValue.compareTo(MIN_LONG) < 0) {
throw new TypeConversionException(BIGDECIMAL_CONVERSION_ERROR);
throw bigDecimalConversionError(fieldDescriptor, value);
}
return fieldDescriptor.getDatatypeCoder().encodeLong(unscaledValue.longValue());
}
Expand All @@ -263,9 +270,9 @@ protected BigDecimal decode(FieldDescriptor fieldDescriptor, byte[] fieldData) {
@Override
protected byte[] encode(FieldDescriptor fieldDescriptor, BigDecimal value) throws SQLException {
// check if value is within bounds
if (value.compareTo(BD_MAX_DOUBLE) > 0 ||
value.compareTo(BD_MIN_DOUBLE) < 0)
throw new TypeConversionException(DOUBLE_CONVERSION_ERROR + " " + value);
if (value.compareTo(BD_MAX_DOUBLE) > 0 || value.compareTo(BD_MIN_DOUBLE) < 0) {
throw bigDecimalConversionError(fieldDescriptor, value);
}

return fieldDescriptor.getDatatypeCoder().encodeDouble(value.doubleValue());
}
Expand All @@ -283,7 +290,7 @@ protected byte[] encode(FieldDescriptor fieldDescriptor, BigDecimal value) throw
if (unscaledValue.bitLength() > 127) {
// value will not fit in a 16-byte byte array,
// using 127 and not 128 because bitLength() does not include sign bit
throw new TypeConversionException(INT128_CONVERSION_ERROR + ": " + OVERFLOW_ERROR);
throw bigDecimalConversionError(fieldDescriptor, value);
}
return fieldDescriptor.getDatatypeCoder().encodeInt128(unscaledValue);
}
Expand Down Expand Up @@ -353,6 +360,15 @@ protected static FieldDataSize getFieldDataSize(FieldDescriptor fieldDescriptor)
.toFlatSQLException();
}
}

SQLException bigDecimalConversionError(FieldDescriptor fieldDescriptor, BigDecimal value) {
String message = String.format(
"Unsupported set conversion requested for field \"%s\" at %d (JDBC type %s), "
+ "source type: " + BIG_DECIMAL_CLASS_NAME + ", reason: value %f out of range",
fieldDescriptor.getOriginalName(), fieldDescriptor.getPosition() + 1,
getJdbcTypeName(JdbcTypeConverter.toJdbcType(fieldDescriptor)), value);
return new TypeConversionException(message);
}
}

}
8 changes: 6 additions & 2 deletions src/main/org/firebirdsql/jdbc/field/FBBinaryField.java
Expand Up @@ -98,7 +98,9 @@ protected void setBinaryStreamInternal(InputStream in, long length) throws SQLEx
try {
setBytes(IOUtils.toBytes(in, (int) length));
} catch (IOException ioex) {
throw new TypeConversionException(BINARY_STREAM_CONVERSION_ERROR);
SQLException conversionException = invalidSetConversion(InputStream.class);
conversionException.initCause(ioex);
throw conversionException;
}
}

Expand All @@ -114,7 +116,9 @@ protected void setCharacterStreamInternal(Reader in, long length) throws SQLExce
try {
setString(IOUtils.toString(in, (int) length));
} catch (IOException ioex) {
throw new TypeConversionException(CHARACTER_STREAM_CONVERSION_ERROR);
SQLException conversionException = invalidSetConversion(Reader.class);
conversionException.initCause(ioex);
throw conversionException;
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/main/org/firebirdsql/jdbc/field/FBBlobField.java
Expand Up @@ -132,8 +132,7 @@ public byte[] getBytesInternal() throws SQLException {
final byte[] segmentBuffer = blobHandle.getSegment(bufferLength);

if (segmentBuffer.length == 0) {
// unexpected EOF
throw new TypeConversionException(BYTES_CONVERSION_ERROR);
throw invalidGetConversion("byte[]", "unexpected EOF");
}

System.arraycopy(segmentBuffer, 0, resultBuffer, offset, segmentBuffer.length);
Expand Down Expand Up @@ -175,8 +174,9 @@ public void setCachedObject(FBFlushableField.CachedObject cachedObject) throws S
@Override
public String getString() throws SQLException {
// getString() is not defined for BLOB fields, only for BINARY
if (fieldDescriptor.getSubType() < 0)
throw new TypeConversionException(STRING_CONVERSION_ERROR);
if (fieldDescriptor.getSubType() < 0) {
throw invalidGetConversion(String.class, String.format("BLOB SUB_TYPE %d", fieldDescriptor.getSubType()));
}

Blob blob = getBlobInternal();

Expand Down
46 changes: 33 additions & 13 deletions src/main/org/firebirdsql/jdbc/field/FBDecfloatField.java
Expand Up @@ -32,6 +32,9 @@
import java.math.BigInteger;
import java.sql.SQLException;

import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

/**
* Field for the SQL:2016 DECFLOAT type (decimal floating point), backed by an IEEE-754 Decimal64 or Decimal128.
*
Expand Down Expand Up @@ -70,7 +73,10 @@ public BigDecimal getBigDecimal() throws SQLException {
try {
return value.toBigDecimal();
} catch (ArithmeticException e) {
throw new TypeConversionException(OVERFLOW_ERROR, e);
SQLException conversionException = invalidGetConversion(BigDecimal.class,
format("value %s out of range", value));
conversionException.initCause(e);
throw conversionException;
}
}

Expand All @@ -79,7 +85,10 @@ public void setBigDecimal(BigDecimal value) throws SQLException {
try {
setDecimalInternal(value != null ? decimalHandling.valueOf(value) : null);
} catch (ArithmeticException e) {
throw new TypeConversionException(OVERFLOW_ERROR, e);
SQLException conversionException = invalidSetConversion(BigDecimal.class,
format("value %f out of range", value));
conversionException.initCause(e);
throw conversionException;
}
}

Expand All @@ -95,7 +104,10 @@ public void setDecimal(Decimal<?> value) throws SQLException {
try {
setDecimalInternal(value != null ? value.toDecimal(decimalType, OverflowHandling.THROW_EXCEPTION) : null);
} catch (ArithmeticException e) {
throw new TypeConversionException(OVERFLOW_ERROR, e);
SQLException conversionException = invalidSetConversion(requireNonNull(value).getClass(),
format("value %s out of range", value));
conversionException.initCause(e);
throw conversionException;
}
}

Expand All @@ -105,7 +117,10 @@ private void setDecimalInternal(T value) throws SQLException {
try {
setFieldData(decimalHandling.encode(fieldDescriptor, value));
} catch (ArithmeticException e) {
throw new TypeConversionException(OVERFLOW_ERROR, e);
SQLException conversionException = invalidSetConversion(requireNonNull(value).getClass(),
format("value %s out of range", value));
conversionException.initCause(e);
throw conversionException;
}
}

Expand Down Expand Up @@ -136,7 +151,7 @@ public long getLong() throws SQLException {
if (value == null) return LONG_NULL_VALUE;

if (BD_MIN_LONG.compareTo(value) > 0 || value.compareTo(BD_MAX_LONG) > 0) {
throw new TypeConversionException(LONG_CONVERSION_ERROR);
throw invalidGetConversion("long", format("value %f out of range", value));
}
return value.longValue();
}
Expand All @@ -153,10 +168,9 @@ public int getInt() throws SQLException {

// check if value is within bounds
if (longValue > MAX_INT_VALUE || longValue < MIN_INT_VALUE) {
throw new TypeConversionException(INT_CONVERSION_ERROR);
} else {
return (int) longValue;
throw invalidGetConversion("int", format("value %d out of range", longValue));
}
return (int) longValue;
}

@Override
Expand All @@ -171,7 +185,7 @@ public short getShort() throws SQLException {

// check if value is within bounds
if (longValue > MAX_SHORT_VALUE || longValue < MIN_SHORT_VALUE) {
throw new TypeConversionException(SHORT_CONVERSION_ERROR);
throw invalidGetConversion("short", format("value %d out of range", longValue));
}

return (short) longValue;
Expand All @@ -189,7 +203,7 @@ public byte getByte() throws SQLException {

// check if value is within bounds
if (longValue > MAX_BYTE_VALUE || longValue < MIN_BYTE_VALUE) {
throw new TypeConversionException(BYTE_CONVERSION_ERROR);
throw invalidGetConversion("byte", format("value %d out of range", longValue));
}

return (byte) longValue;
Expand Down Expand Up @@ -236,12 +250,18 @@ public String getString() throws SQLException {
public void setString(String value) throws SQLException {
if (setWhenNull(value)) return;

String string = value.trim();
try {
setDecimalInternal(decimalHandling.valueOf(value));
setDecimalInternal(decimalHandling.valueOf(string));
} catch (NumberFormatException nex) {
throw new TypeConversionException(STRING_CONVERSION_ERROR);
SQLException conversionException = invalidSetConversion(String.class, string);
conversionException.initCause(nex);
throw conversionException;
} catch (ArithmeticException e) {
throw new TypeConversionException(OVERFLOW_ERROR, e);
SQLException conversionException = invalidSetConversion(String.class,
format("value %s out of range", string));
conversionException.initCause(e);
throw conversionException;
}
}

Expand Down

0 comments on commit bdf7033

Please sign in to comment.