http://git-wip-us.apache.org/repos/asf/phoenix/blob/a54a06cf/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java index 17910de..9fff730 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java @@ -35,384 +35,385 @@ import com.google.common.base.Preconditions; public class PDecimal extends PRealNumber<BigDecimal> { - public static final PDecimal INSTANCE = new PDecimal(); + public static final PDecimal INSTANCE = new PDecimal(); - private static final BigDecimal MIN_DOUBLE_AS_BIG_DECIMAL = - BigDecimal.valueOf(-Double.MAX_VALUE); - private static final BigDecimal MAX_DOUBLE_AS_BIG_DECIMAL = - BigDecimal.valueOf(Double.MAX_VALUE); - private static final BigDecimal MIN_FLOAT_AS_BIG_DECIMAL = - BigDecimal.valueOf(-Float.MAX_VALUE); - private static final BigDecimal MAX_FLOAT_AS_BIG_DECIMAL = - BigDecimal.valueOf(Float.MAX_VALUE); + private static final BigDecimal MIN_DOUBLE_AS_BIG_DECIMAL = + BigDecimal.valueOf(-Double.MAX_VALUE); + private static final BigDecimal MAX_DOUBLE_AS_BIG_DECIMAL = + BigDecimal.valueOf(Double.MAX_VALUE); + private static final BigDecimal MIN_FLOAT_AS_BIG_DECIMAL = + BigDecimal.valueOf(-Float.MAX_VALUE); + private static final BigDecimal MAX_FLOAT_AS_BIG_DECIMAL = + BigDecimal.valueOf(Float.MAX_VALUE); - private PDecimal() { - super("DECIMAL", Types.DECIMAL, BigDecimal.class, null, 8); - } - - @Override - public byte[] toBytes(Object object) { - if (object == null) { - return ByteUtil.EMPTY_BYTE_ARRAY; + private PDecimal() { + super("DECIMAL", Types.DECIMAL, BigDecimal.class, null, 8); } - BigDecimal v = (BigDecimal) object; - v = NumberUtil.normalize(v); - int len = getLength(v); - byte[] result = new byte[Math.min(len, MAX_BIG_DECIMAL_BYTES)]; - PDataType.toBytes(v, result, 0, len); - return result; - } - @Override - public int toBytes(Object object, byte[] bytes, int offset) { - if (object == null) { - return 0; + @Override + public byte[] toBytes(Object object) { + if (object == null) { + return ByteUtil.EMPTY_BYTE_ARRAY; + } + BigDecimal v = (BigDecimal) object; + v = NumberUtil.normalize(v); + int len = getLength(v); + byte[] result = new byte[Math.min(len, MAX_BIG_DECIMAL_BYTES)]; + PDataType.toBytes(v, result, 0, len); + return result; } - BigDecimal v = (BigDecimal) object; - v = NumberUtil.normalize(v); - int len = getLength(v); - return PDataType.toBytes(v, bytes, offset, len); - } - private int getLength(BigDecimal v) { - int signum = v.signum(); - if (signum == 0) { // Special case for zero - return 1; + @Override + public int toBytes(Object object, byte[] bytes, int offset) { + if (object == null) { + return 0; + } + BigDecimal v = (BigDecimal) object; + v = NumberUtil.normalize(v); + int len = getLength(v); + return PDataType.toBytes(v, bytes, offset, len); } - /* - * Size of DECIMAL includes: - * 1) one byte for exponent - * 2) one byte for terminal byte if negative - * 3) one byte for every two digits with the following caveats: - * a) add one to round up in the case when there is an odd number of digits - * b) add one in the case that the scale is odd to account for 10x of lowest significant digit - * (basically done to increase the range of exponents that can be represented) - */ - return (signum < 0 ? 2 : 1) + (v.precision() + 1 + (v.scale() % 2 == 0 ? 0 : 1)) / 2; - } - @Override - public int estimateByteSize(Object o) { - if (o == null) { - return 1; + private int getLength(BigDecimal v) { + int signum = v.signum(); + if (signum == 0) { // Special case for zero + return 1; + } + /* + * Size of DECIMAL includes: + * 1) one byte for exponent + * 2) one byte for terminal byte if negative + * 3) one byte for every two digits with the following caveats: + * a) add one to round up in the case when there is an odd number of digits + * b) add one in the case that the scale is odd to account for 10x of lowest significant digit + * (basically done to increase the range of exponents that can be represented) + */ + return (signum < 0 ? 2 : 1) + (v.precision() + 1 + (v.scale() % 2 == 0 ? 0 : 1)) / 2; } - BigDecimal v = (BigDecimal) o; - // TODO: should we strip zeros and round here too? - return Math.min(getLength(v), MAX_BIG_DECIMAL_BYTES); - } - @Override - public Integer getMaxLength(Object o) { - if (o == null) { - return MAX_PRECISION; + @Override + public int estimateByteSize(Object o) { + if (o == null) { + return 1; + } + BigDecimal v = (BigDecimal) o; + // TODO: should we strip zeros and round here too? + return Math.min(getLength(v), MAX_BIG_DECIMAL_BYTES); } - BigDecimal v = (BigDecimal) o; - return v.precision(); - } - @Override - public Integer getScale(Object o) { - return null; - } + @Override + public Integer getMaxLength(Object o) { + if (o == null) { + return MAX_PRECISION; + } + BigDecimal v = (BigDecimal) o; + return v.precision(); + } - @Override - public Object toObject(byte[] b, int o, int l, PDataType actualType, SortOrder sortOrder, - Integer maxLength, Integer scale) { - Preconditions.checkNotNull(sortOrder); - if (l == 0) { - return null; + @Override + public Integer getScale(Object o) { + return null; } - if (actualType == PDecimal.INSTANCE) { - if (sortOrder == SortOrder.DESC) { - b = SortOrder.invert(b, o, new byte[l], 0, l); - o = 0; - } - return toBigDecimal(b, o, l); - } else if (equalsAny(actualType, PDate.INSTANCE, PTime.INSTANCE, PUnsignedDate.INSTANCE, - PUnsignedTime.INSTANCE, PLong.INSTANCE, PUnsignedLong.INSTANCE, PInteger.INSTANCE, - PUnsignedInt.INSTANCE, PSmallint.INSTANCE, PUnsignedSmallint.INSTANCE, PTinyint.INSTANCE, - PUnsignedTinyint.INSTANCE)) { - return BigDecimal.valueOf(actualType.getCodec().decodeLong(b, o, sortOrder)); - } else if (equalsAny(actualType, PFloat.INSTANCE, PUnsignedFloat.INSTANCE)) { - return BigDecimal.valueOf(actualType.getCodec().decodeFloat(b, o, sortOrder)); - } else if (equalsAny(actualType, PDouble.INSTANCE, PUnsignedDouble.INSTANCE)) { - return BigDecimal.valueOf(actualType.getCodec().decodeDouble(b, o, sortOrder)); - } else if (equalsAny(actualType, PTimestamp.INSTANCE, PUnsignedTimestamp.INSTANCE)) { - long millisPart = DateUtil.getCodecFor(actualType).decodeLong(b, o, sortOrder); - int nanoPart = PUnsignedInt.INSTANCE.getCodec().decodeInt(b, o + Bytes.SIZEOF_LONG, sortOrder); - BigDecimal nanosPart = BigDecimal.valueOf( - (nanoPart % QueryConstants.MILLIS_TO_NANOS_CONVERTOR) - / QueryConstants.MILLIS_TO_NANOS_CONVERTOR); - return BigDecimal.valueOf(millisPart).add(nanosPart); - } else if (actualType == PBoolean.INSTANCE) { - return (Boolean) PBoolean.INSTANCE.toObject(b, o, l, actualType, sortOrder) ? - BigDecimal.ONE : - BigDecimal.ZERO; + + @Override + public Object toObject(byte[] b, int o, int l, PDataType actualType, SortOrder sortOrder, + Integer maxLength, Integer scale) { + Preconditions.checkNotNull(sortOrder); + if (l == 0) { + return null; + } + if (actualType == PDecimal.INSTANCE) { + if (sortOrder == SortOrder.DESC) { + b = SortOrder.invert(b, o, new byte[l], 0, l); + o = 0; + } + return toBigDecimal(b, o, l); + } else if (equalsAny(actualType, PDate.INSTANCE, PTime.INSTANCE, PUnsignedDate.INSTANCE, + PUnsignedTime.INSTANCE, PLong.INSTANCE, PUnsignedLong.INSTANCE, PInteger.INSTANCE, + PUnsignedInt.INSTANCE, PSmallint.INSTANCE, PUnsignedSmallint.INSTANCE, PTinyint.INSTANCE, + PUnsignedTinyint.INSTANCE)) { + return BigDecimal.valueOf(actualType.getCodec().decodeLong(b, o, sortOrder)); + } else if (equalsAny(actualType, PFloat.INSTANCE, PUnsignedFloat.INSTANCE)) { + return BigDecimal.valueOf(actualType.getCodec().decodeFloat(b, o, sortOrder)); + } else if (equalsAny(actualType, PDouble.INSTANCE, PUnsignedDouble.INSTANCE)) { + return BigDecimal.valueOf(actualType.getCodec().decodeDouble(b, o, sortOrder)); + } else if (equalsAny(actualType, PTimestamp.INSTANCE, PUnsignedTimestamp.INSTANCE)) { + long millisPart = DateUtil.getCodecFor(actualType).decodeLong(b, o, sortOrder); + int nanoPart = PUnsignedInt.INSTANCE.getCodec().decodeInt(b, o + Bytes.SIZEOF_LONG, sortOrder); + BigDecimal nanosPart = BigDecimal.valueOf( + (nanoPart % QueryConstants.MILLIS_TO_NANOS_CONVERTOR) + / QueryConstants.MILLIS_TO_NANOS_CONVERTOR); + return BigDecimal.valueOf(millisPart).add(nanosPart); + } else if (actualType == PBoolean.INSTANCE) { + return (Boolean) PBoolean.INSTANCE.toObject(b, o, l, actualType, sortOrder) ? + BigDecimal.ONE : + BigDecimal.ZERO; + } + return throwConstraintViolationException(actualType, this); } - return throwConstraintViolationException(actualType, this); - } - @Override - public Object toObject(Object object, PDataType actualType) { - if (object == null) { - return null; + @Override + public Object toObject(Object object, PDataType actualType) { + if (object == null) { + return null; + } + if (equalsAny(actualType, PInteger.INSTANCE, PUnsignedInt.INSTANCE)) { + return BigDecimal.valueOf((Integer) object); + } else if (equalsAny(actualType, PLong.INSTANCE, PUnsignedLong.INSTANCE)) { + return BigDecimal.valueOf((Long) object); + } else if (equalsAny(actualType, PSmallint.INSTANCE, PUnsignedSmallint.INSTANCE)) { + return BigDecimal.valueOf((Short) object); + } else if (equalsAny(actualType, PTinyint.INSTANCE, PUnsignedTinyint.INSTANCE)) { + return BigDecimal.valueOf((Byte) object); + } else if (equalsAny(actualType, PFloat.INSTANCE, PUnsignedFloat.INSTANCE)) { + return BigDecimal.valueOf((Float) object); + } else if (equalsAny(actualType, PDouble.INSTANCE, PUnsignedDouble.INSTANCE)) { + return BigDecimal.valueOf((Double) object); + } else if (actualType == PDecimal.INSTANCE) { + return object; + } else if (equalsAny(actualType, PDate.INSTANCE, PUnsignedDate.INSTANCE, PTime.INSTANCE, + PUnsignedTime.INSTANCE)) { + java.util.Date d = (java.util.Date) object; + return BigDecimal.valueOf(d.getTime()); + } else if (equalsAny(actualType, PTimestamp.INSTANCE, + PUnsignedTimestamp.INSTANCE)) { + Timestamp ts = (Timestamp) object; + long millisPart = ts.getTime(); + BigDecimal nanosPart = BigDecimal.valueOf( + (ts.getNanos() % QueryConstants.MILLIS_TO_NANOS_CONVERTOR) + / QueryConstants.MILLIS_TO_NANOS_CONVERTOR); + BigDecimal value = BigDecimal.valueOf(millisPart).add(nanosPart); + return value; + } else if (actualType == PBoolean.INSTANCE) { + return ((Boolean) object) ? BigDecimal.ONE : BigDecimal.ZERO; + } + return throwConstraintViolationException(actualType, this); } - if (equalsAny(actualType, PInteger.INSTANCE, PUnsignedInt.INSTANCE)) { - return BigDecimal.valueOf((Integer) object); - } else if (equalsAny(actualType, PLong.INSTANCE, PUnsignedLong.INSTANCE)) { - return BigDecimal.valueOf((Long) object); - } else if (equalsAny(actualType, PSmallint.INSTANCE, PUnsignedSmallint.INSTANCE)) { - return BigDecimal.valueOf((Short) object); - } else if (equalsAny(actualType, PTinyint.INSTANCE, PUnsignedTinyint.INSTANCE)) { - return BigDecimal.valueOf((Byte) object); - } else if (equalsAny(actualType, PFloat.INSTANCE, PUnsignedFloat.INSTANCE)) { - return BigDecimal.valueOf((Float) object); - } else if (equalsAny(actualType, PDouble.INSTANCE, PUnsignedDouble.INSTANCE)) { - return BigDecimal.valueOf((Double) object); - } else if (actualType == PDecimal.INSTANCE) { - return object; - } else if (equalsAny(actualType, PDate.INSTANCE, PUnsignedDate.INSTANCE, PTime.INSTANCE, - PUnsignedTime.INSTANCE)) { - java.util.Date d = (java.util.Date) object; - return BigDecimal.valueOf(d.getTime()); - } else if (equalsAny(actualType, PTimestamp.INSTANCE, - PUnsignedTimestamp.INSTANCE)) { - Timestamp ts = (Timestamp) object; - long millisPart = ts.getTime(); - BigDecimal nanosPart = BigDecimal.valueOf( - (ts.getNanos() % QueryConstants.MILLIS_TO_NANOS_CONVERTOR) - / QueryConstants.MILLIS_TO_NANOS_CONVERTOR); - BigDecimal value = BigDecimal.valueOf(millisPart).add(nanosPart); - return value; - } else if (actualType == PBoolean.INSTANCE) { - return ((Boolean) object) ? BigDecimal.ONE : BigDecimal.ZERO; + + @Override + public boolean isFixedWidth() { + return false; } - return throwConstraintViolationException(actualType, this); - } - @Override - public boolean isFixedWidth() { - return false; - } + @Override + public Integer getByteSize() { + return MAX_BIG_DECIMAL_BYTES; + } - @Override - public Integer getByteSize() { - return MAX_BIG_DECIMAL_BYTES; - } + @Override + public int compareTo(Object lhs, Object rhs, PDataType rhsType) { + if (rhsType == PDecimal.INSTANCE) { + return ((BigDecimal) lhs).compareTo((BigDecimal) rhs); + } + return -rhsType.compareTo(rhs, lhs, this); + } - @Override - public int compareTo(Object lhs, Object rhs, PDataType rhsType) { - if (rhsType == PDecimal.INSTANCE) { - return ((BigDecimal) lhs).compareTo((BigDecimal) rhs); + @Override + public boolean isCastableTo(PDataType targetType) { + return super.isCastableTo(targetType) || targetType.isCoercibleTo( + PTimestamp.INSTANCE) || targetType.equals(PBoolean.INSTANCE); } - return -rhsType.compareTo(rhs, lhs, this); - } - @Override - public boolean isCastableTo(PDataType targetType) { - return super.isCastableTo(targetType) || targetType.isCoercibleTo( - PTimestamp.INSTANCE) || targetType.equals(PBoolean.INSTANCE); - } + @Override + public boolean isCoercibleTo(PDataType targetType, Object value) { + if (value != null) { + BigDecimal bd; + if (equalsAny(targetType, PUnsignedLong.INSTANCE, PUnsignedInt.INSTANCE, + PUnsignedSmallint.INSTANCE, PUnsignedTinyint.INSTANCE)) { + bd = (BigDecimal) value; + if (bd.signum() == -1) { + return false; + } + } else if (targetType.equals(PLong.INSTANCE)) { + bd = (BigDecimal) value; + try { + bd.longValueExact(); + return true; + } catch (ArithmeticException e) { + return false; + } + } else if (targetType.equals(PInteger.INSTANCE)) { + bd = (BigDecimal) value; + try { + bd.intValueExact(); + return true; + } catch (ArithmeticException e) { + return false; + } + } else if (targetType.equals(PSmallint.INSTANCE)) { + bd = (BigDecimal) value; + try { + bd.shortValueExact(); + return true; + } catch (ArithmeticException e) { + return false; + } + } else if (targetType.equals(PTinyint.INSTANCE)) { + bd = (BigDecimal) value; + try { + bd.byteValueExact(); + return true; + } catch (ArithmeticException e) { + return false; + } + } else if (targetType.equals(PUnsignedFloat.INSTANCE)) { + bd = (BigDecimal) value; + try { + BigDecimal maxFloat = MAX_FLOAT_AS_BIG_DECIMAL; + boolean isNegtive = (bd.signum() == -1); + return bd.compareTo(maxFloat) <= 0 && !isNegtive; + } catch (Exception e) { + return false; + } + } else if (targetType.equals(PFloat.INSTANCE)) { + bd = (BigDecimal) value; + try { + BigDecimal maxFloat = MAX_FLOAT_AS_BIG_DECIMAL; + // Float.MIN_VALUE should not be used here, as this is the + // smallest in terms of closest to zero. + BigDecimal minFloat = MIN_FLOAT_AS_BIG_DECIMAL; + return bd.compareTo(maxFloat) <= 0 && bd.compareTo(minFloat) >= 0; + } catch (Exception e) { + return false; + } + } else if (targetType.equals(PUnsignedDouble.INSTANCE)) { + bd = (BigDecimal) value; + try { + BigDecimal maxDouble = MAX_DOUBLE_AS_BIG_DECIMAL; + boolean isNegtive = (bd.signum() == -1); + return bd.compareTo(maxDouble) <= 0 && !isNegtive; + } catch (Exception e) { + return false; + } + } else if (targetType.equals(PDouble.INSTANCE)) { + bd = (BigDecimal) value; + try { + BigDecimal maxDouble = MAX_DOUBLE_AS_BIG_DECIMAL; + BigDecimal minDouble = MIN_DOUBLE_AS_BIG_DECIMAL; + return bd.compareTo(maxDouble) <= 0 && bd.compareTo(minDouble) >= 0; + } catch (Exception e) { + return false; + } + } + } + return super.isCoercibleTo(targetType, value); + } - @Override - public boolean isCoercibleTo(PDataType targetType, Object value) { - if (value != null) { - BigDecimal bd; - if (equalsAny(targetType, PUnsignedLong.INSTANCE, PUnsignedInt.INSTANCE, - PUnsignedSmallint.INSTANCE, PUnsignedTinyint.INSTANCE)) { - bd = (BigDecimal) value; - if (bd.signum() == -1) { - return false; + @Override + public boolean isSizeCompatible(ImmutableBytesWritable ptr, Object value, PDataType srcType, + SortOrder sortOrder, Integer maxLength, Integer scale, Integer desiredMaxLength, Integer desiredScale) { + if (ptr.getLength() == 0) { + return true; } - } else if (targetType.equals(PLong.INSTANCE)) { - bd = (BigDecimal) value; - try { - bd.longValueExact(); - return true; - } catch (ArithmeticException e) { - return false; + // Any numeric type fits into a DECIMAL + if (srcType != PDecimal.INSTANCE) { + if(!srcType.isCoercibleTo(this)) { + throw new IllegalArgumentException(TypeMismatchException.newException(srcType, this)); + } + return true; } - } else if (targetType.equals(PInteger.INSTANCE)) { - bd = (BigDecimal) value; - try { - bd.intValueExact(); - return true; - } catch (ArithmeticException e) { - return false; + // Use the scale from the value if provided, as it prevents a deserialization. + // The maxLength and scale for the underlying expression are ignored, because they + // are not relevant in this case: for example a DECIMAL(10,2) may be assigned to a + // DECIMAL(5,0) as long as the value fits. + if (value != null) { + BigDecimal v = (BigDecimal) value; + maxLength = v.precision(); + scale = v.scale(); + } else { + this.coerceBytes(ptr, value, srcType, maxLength, scale, SortOrder.getDefault(), desiredMaxLength, desiredScale, sortOrder, true); + int[] v = getDecimalPrecisionAndScale(ptr.get(), ptr.getOffset(), ptr.getLength()); + maxLength = v[0]; + scale = v[1]; } - } else if (targetType.equals(PSmallint.INSTANCE)) { - bd = (BigDecimal) value; - try { - bd.shortValueExact(); - return true; - } catch (ArithmeticException e) { - return false; + if (desiredMaxLength != null && desiredScale != null && maxLength != null && scale != null && + ((desiredScale == null && desiredMaxLength < maxLength) || + (desiredMaxLength - desiredScale) < (maxLength - scale))) { + return false; } - } else if (targetType.equals(PTinyint.INSTANCE)) { - bd = (BigDecimal) value; - try { - bd.byteValueExact(); - return true; - } catch (ArithmeticException e) { - return false; - } - } else if (targetType.equals(PUnsignedFloat.INSTANCE)) { - bd = (BigDecimal) value; - try { - BigDecimal maxFloat = MAX_FLOAT_AS_BIG_DECIMAL; - boolean isNegtive = (bd.signum() == -1); - return bd.compareTo(maxFloat) <= 0 && !isNegtive; - } catch (Exception e) { - return false; + return true; + } + + @Override + public void coerceBytes(ImmutableBytesWritable ptr, Object object, PDataType actualType, + Integer maxLength, Integer scale, SortOrder actualModifier, Integer desiredMaxLength, Integer desiredScale, + SortOrder expectedModifier) { + if (desiredScale == null) { + // deiredScale not available, or we do not have scale requirement, delegate to parents. + super.coerceBytes(ptr, object, actualType, maxLength, scale, actualModifier, desiredMaxLength, + desiredScale, expectedModifier); + return; } - } else if (targetType.equals(PFloat.INSTANCE)) { - bd = (BigDecimal) value; - try { - BigDecimal maxFloat = MAX_FLOAT_AS_BIG_DECIMAL; - // Float.MIN_VALUE should not be used here, as this is the - // smallest in terms of closest to zero. - BigDecimal minFloat = MIN_FLOAT_AS_BIG_DECIMAL; - return bd.compareTo(maxFloat) <= 0 && bd.compareTo(minFloat) >= 0; - } catch (Exception e) { - return false; + if (ptr.getLength() == 0) { + return; } - } else if (targetType.equals(PUnsignedDouble.INSTANCE)) { - bd = (BigDecimal) value; - try { - BigDecimal maxDouble = MAX_DOUBLE_AS_BIG_DECIMAL; - boolean isNegtive = (bd.signum() == -1); - return bd.compareTo(maxDouble) <= 0 && !isNegtive; - } catch (Exception e) { - return false; + if (scale == null) { + if (object != null) { + BigDecimal v = (BigDecimal) object; + scale = v.scale(); + } else { + int[] v = getDecimalPrecisionAndScale(ptr.get(), ptr.getOffset(), ptr.getLength()); + scale = v[1]; + } } - } else if (targetType.equals(PDouble.INSTANCE)) { - bd = (BigDecimal) value; - try { - BigDecimal maxDouble = MAX_DOUBLE_AS_BIG_DECIMAL; - BigDecimal minDouble = MIN_DOUBLE_AS_BIG_DECIMAL; - return bd.compareTo(maxDouble) <= 0 && bd.compareTo(minDouble) >= 0; - } catch (Exception e) { - return false; + if (this == actualType && scale <= desiredScale) { + // No coerce and rescale necessary + return; + } else { + BigDecimal decimal; + // Rescale is necessary. + if (object != null) { // value object is passed in. + decimal = (BigDecimal) toObject(object, actualType); + } else { // only value bytes is passed in, need to convert to object first. + decimal = (BigDecimal) toObject(ptr); + } + decimal = decimal.setScale(desiredScale, BigDecimal.ROUND_DOWN); + ptr.set(toBytes(decimal)); } - } } - return super.isCoercibleTo(targetType, value); - } - @Override - public boolean isSizeCompatible(ImmutableBytesWritable ptr, Object value, PDataType srcType, - Integer maxLength, Integer scale, Integer desiredMaxLength, Integer desiredScale) { - if (ptr.getLength() == 0) { - return true; - } - // Any numeric type fits into a DECIMAL - if (srcType != PDecimal.INSTANCE) { - if(!srcType.isCoercibleTo(this)) { - throw new IllegalArgumentException(TypeMismatchException.newException(srcType, this)); + @Override + public Object toObject(String value) { + if (value == null || value.length() == 0) { + return null; + } + try { + return new BigDecimal(value); + } catch (NumberFormatException e) { + throw newIllegalDataException(e); } - return true; - } - // Use the scale from the value if provided, as it prevents a deserialization. - // The maxLength and scale for the underlying expression are ignored, because they - // are not relevant in this case: for example a DECIMAL(10,2) may be assigned to a - // DECIMAL(5,0) as long as the value fits. - if (value != null) { - BigDecimal v = (BigDecimal) value; - maxLength = v.precision(); - scale = v.scale(); - } else { - int[] v = getDecimalPrecisionAndScale(ptr.get(), ptr.getOffset(), ptr.getLength()); - maxLength = v[0]; - scale = v[1]; - } - if (desiredMaxLength != null && desiredScale != null && maxLength != null && scale != null && - ((desiredScale == null && desiredMaxLength < maxLength) || - (desiredMaxLength - desiredScale) < (maxLength - scale))) { - return false; - } - return true; - } - - @Override - public void coerceBytes(ImmutableBytesWritable ptr, Object object, PDataType actualType, - Integer maxLength, Integer scale, SortOrder actualModifier, Integer desiredMaxLength, Integer desiredScale, - SortOrder expectedModifier) { - if (desiredScale == null) { - // deiredScale not available, or we do not have scale requirement, delegate to parents. - super.coerceBytes(ptr, object, actualType, maxLength, scale, actualModifier, desiredMaxLength, - desiredScale, expectedModifier); - return; - } - if (ptr.getLength() == 0) { - return; - } - if (scale == null) { - if (object != null) { - BigDecimal v = (BigDecimal) object; - scale = v.scale(); - } else { - int[] v = getDecimalPrecisionAndScale(ptr.get(), ptr.getOffset(), ptr.getLength()); - scale = v[1]; - } - } - if (this == actualType && scale <= desiredScale) { - // No coerce and rescale necessary - return; - } else { - BigDecimal decimal; - // Rescale is necessary. - if (object != null) { // value object is passed in. - decimal = (BigDecimal) toObject(object, actualType); - } else { // only value bytes is passed in, need to convert to object first. - decimal = (BigDecimal) toObject(ptr); - } - decimal = decimal.setScale(desiredScale, BigDecimal.ROUND_DOWN); - ptr.set(toBytes(decimal)); } - } - @Override - public Object toObject(String value) { - if (value == null || value.length() == 0) { - return null; - } - try { - return new BigDecimal(value); - } catch (NumberFormatException e) { - throw newIllegalDataException(e); + @Override + public Integer estimateByteSizeFromLength(Integer length) { + // No association of runtime byte size from decimal precision. + return null; } - } - - @Override - public Integer estimateByteSizeFromLength(Integer length) { - // No association of runtime byte size from decimal precision. - return null; - } - @Override - public String toStringLiteral(byte[] b, int offset, int length, Format formatter) { - if (formatter == null) { - BigDecimal o = (BigDecimal) toObject(b, offset, length); - return o.toPlainString(); + @Override + public String toStringLiteral(byte[] b, int offset, int length, Format formatter) { + if (formatter == null) { + BigDecimal o = (BigDecimal) toObject(b, offset, length); + return o.toPlainString(); + } + return super.toStringLiteral(b, offset, length, formatter); } - return super.toStringLiteral(b, offset, length, formatter); - } - @Override - public String toStringLiteral(Object o, Format formatter) { - if (formatter == null) { - if(o == null) { - return String.valueOf(o); - } - return ((BigDecimal)o).toPlainString(); + @Override + public String toStringLiteral(Object o, Format formatter) { + if (formatter == null) { + if(o == null) { + return String.valueOf(o); + } + return ((BigDecimal)o).toPlainString(); } return super.toStringLiteral(o, formatter); - } + } - @Override - public Object getSampleValue(Integer maxLength, Integer arrayLength) { - return new BigDecimal((Long) PLong.INSTANCE.getSampleValue(maxLength, arrayLength)); - } + @Override + public Object getSampleValue(Integer maxLength, Integer arrayLength) { + return new BigDecimal((Long) PLong.INSTANCE.getSampleValue(maxLength, arrayLength)); + } // take details from org.apache.phoenix.schema.types.PDataType#toBigDecimal(byte[], int, int) @Override
http://git-wip-us.apache.org/repos/asf/phoenix/blob/a54a06cf/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarbinary.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarbinary.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarbinary.java index aafa1c6..d96650d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarbinary.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarbinary.java @@ -20,7 +20,6 @@ package org.apache.phoenix.schema.types; import java.sql.Types; import java.text.Format; -import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Base64; import org.apache.hadoop.hbase.util.Bytes; import org.apache.phoenix.schema.SortOrder; @@ -28,149 +27,138 @@ import org.apache.phoenix.util.ByteUtil; public class PVarbinary extends PBinaryBase { - public static final PVarbinary INSTANCE = new PVarbinary(); + public static final PVarbinary INSTANCE = new PVarbinary(); - private PVarbinary() { - super("VARBINARY", Types.VARBINARY, byte[].class, null, 22); - } + private PVarbinary() { + super("VARBINARY", Types.VARBINARY, byte[].class, null, 22); + } + + @Override + public byte[] toBytes(Object object) { + if (object == null) { + return ByteUtil.EMPTY_BYTE_ARRAY; + } + return (byte[]) object; + } - @Override - public byte[] toBytes(Object object) { - if (object == null) { - return ByteUtil.EMPTY_BYTE_ARRAY; + @Override + public int toBytes(Object object, byte[] bytes, int offset) { + if (object == null) { + return 0; + } + byte[] o = (byte[]) object; + // assumes there's enough room + System.arraycopy(bytes, offset, o, 0, o.length); + return o.length; } - return (byte[]) object; - } - @Override - public int toBytes(Object object, byte[] bytes, int offset) { - if (object == null) { - return 0; + /** + * Override because we must always create a new byte array + */ + @Override + public byte[] toBytes(Object object, SortOrder sortOrder) { + byte[] bytes = toBytes(object); + // Override because we need to allocate a new buffer in this case + if (sortOrder == SortOrder.DESC) { + return SortOrder.invert(bytes, 0, new byte[bytes.length], 0, bytes.length); + } + return bytes; } - byte[] o = (byte[]) object; - // assumes there's enough room - System.arraycopy(bytes, offset, o, 0, o.length); - return o.length; - } - - /** - * Override because we must always create a new byte array - */ - @Override - public byte[] toBytes(Object object, SortOrder sortOrder) { - byte[] bytes = toBytes(object); - // Override because we need to allocate a new buffer in this case - if (sortOrder == SortOrder.DESC) { - return SortOrder.invert(bytes, 0, new byte[bytes.length], 0, bytes.length); + + @Override + public Object toObject(byte[] bytes, int offset, int length, PDataType actualType, + SortOrder sortOrder, Integer maxLength, Integer scale) { + if (length == 0) { + return null; + } + if (offset == 0 && bytes.length == length && sortOrder == SortOrder.ASC) { + return bytes; + } + byte[] bytesCopy = new byte[length]; + System.arraycopy(bytes, offset, bytesCopy, 0, length); + if (sortOrder == SortOrder.DESC) { + bytesCopy = SortOrder.invert(bytes, offset, bytesCopy, 0, length); + offset = 0; + } + return bytesCopy; } - return bytes; - } - - @Override - public Object toObject(byte[] bytes, int offset, int length, PDataType actualType, - SortOrder sortOrder, Integer maxLength, Integer scale) { - if (length == 0) { - return null; + + @Override + public Object toObject(Object object, PDataType actualType) { + return actualType.toBytes(object); } - if (offset == 0 && bytes.length == length && sortOrder == SortOrder.ASC) { - return bytes; + + @Override + public boolean isFixedWidth() { + return false; } - byte[] bytesCopy = new byte[length]; - System.arraycopy(bytes, offset, bytesCopy, 0, length); - if (sortOrder == SortOrder.DESC) { - bytesCopy = SortOrder.invert(bytes, offset, bytesCopy, 0, length); - offset = 0; + + @Override + public int estimateByteSize(Object o) { + byte[] value = (byte[]) o; + return value == null ? 1 : value.length; } - return bytesCopy; - } - - @Override - public Object toObject(Object object, PDataType actualType) { - return actualType.toBytes(object); - } - - @Override - public boolean isFixedWidth() { - return false; - } - - @Override - public int estimateByteSize(Object o) { - byte[] value = (byte[]) o; - return value == null ? 1 : value.length; - } - - @Override - public Integer getByteSize() { - return null; - } - - @Override - public boolean isCoercibleTo(PDataType targetType) { - return equalsAny(targetType, this, PBinary.INSTANCE); - } - - @Override - public boolean isSizeCompatible(ImmutableBytesWritable ptr, Object value, PDataType srcType, - Integer maxLength, Integer scale, Integer desiredMaxLength, - Integer desiredScale) { - if (ptr.getLength() != 0 && srcType.equals(PBinary.INSTANCE) && maxLength != null - && desiredMaxLength != null) { - return maxLength <= desiredMaxLength; + + @Override + public Integer getByteSize() { + return null; } - return true; - } - - @Override - public int compareTo(Object lhs, Object rhs, PDataType rhsType) { - if (lhs == null && rhs == null) { - return 0; - } else if (lhs == null) { - return -1; - } else if (rhs == null) { - return 1; + + @Override + public boolean isCoercibleTo(PDataType targetType) { + return equalsAny(targetType, this, PBinary.INSTANCE); } - if (equalsAny(rhsType, this, PBinary.INSTANCE)) { - return Bytes.compareTo((byte[]) lhs, (byte[]) rhs); - } else { - byte[] rhsBytes = rhsType.toBytes(rhs); - return Bytes.compareTo((byte[]) lhs, rhsBytes); + + @Override + public int compareTo(Object lhs, Object rhs, PDataType rhsType) { + if (lhs == null && rhs == null) { + return 0; + } else if (lhs == null) { + return -1; + } else if (rhs == null) { + return 1; + } + if (equalsAny(rhsType, this, PBinary.INSTANCE)) { + return Bytes.compareTo((byte[]) lhs, (byte[]) rhs); + } else { + byte[] rhsBytes = rhsType.toBytes(rhs); + return Bytes.compareTo((byte[]) lhs, rhsBytes); + } } - } - @Override - public Object toObject(String value) { - if (value == null || value.length() == 0) { - return null; + @Override + public Object toObject(String value) { + if (value == null || value.length() == 0) { + return null; + } + return Base64.decode(value); } - return Base64.decode(value); - } - - @Override - public String toStringLiteral(byte[] b, int o, int length, Format formatter) { - StringBuilder buf = new StringBuilder(); - buf.append('['); - if (length > 0) { - for (int i = o; i < length; i++) { - buf.append(0xFF & b[i]); - buf.append(','); + + @Override + public String toStringLiteral(byte[] b, int o, int length, Format formatter) { + StringBuilder buf = new StringBuilder(); + buf.append('['); + if (length > 0) { + for (int i = o; i < length; i++) { + buf.append(0xFF & b[i]); + buf.append(','); + } + buf.setLength(buf.length()-1); } - buf.setLength(buf.length()-1); + buf.append(']'); + return buf.toString(); + } + + @Override + public String toStringLiteral(Object o, Format formatter) { + return toStringLiteral((byte[])o, 0, ((byte[]) o).length, formatter); + } + + @Override + public Object getSampleValue(Integer maxLength, Integer arrayLength) { + int length = maxLength != null && maxLength > 0 ? maxLength : 1; + byte[] b = new byte[length]; + RANDOM.get().nextBytes(b); + return b; } - buf.append(']'); - return buf.toString(); - } - - @Override - public String toStringLiteral(Object o, Format formatter) { - return toStringLiteral((byte[])o, 0, ((byte[]) o).length, formatter); - } - - @Override - public Object getSampleValue(Integer maxLength, Integer arrayLength) { - int length = maxLength != null && maxLength > 0 ? maxLength : 1; - byte[] b = new byte[length]; - RANDOM.get().nextBytes(b); - return b; - } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a54a06cf/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarchar.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarchar.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarchar.java index 2575115..0ddf622 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarchar.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PVarchar.java @@ -30,134 +30,142 @@ import com.google.common.base.Preconditions; public class PVarchar extends PDataType<String> { - public static final PVarchar INSTANCE = new PVarchar(); - - private PVarchar() { - super("VARCHAR", Types.VARCHAR, String.class, null, 0); - } - - @Override - public byte[] toBytes(Object object) { - // TODO: consider using avro UTF8 object instead of String - // so that we get get the size easily - if (object == null) { - return ByteUtil.EMPTY_BYTE_ARRAY; - } - return Bytes.toBytes((String) object); - } - - @Override - public int toBytes(Object object, byte[] bytes, int offset) { - if (object == null) { - return 0; - } - byte[] b = toBytes(object); // TODO: no byte[] allocation: use CharsetEncoder - System.arraycopy(b, 0, bytes, offset, b.length); - return b.length; - } - - @Override - public Object toObject(byte[] bytes, int offset, int length, PDataType actualType, - SortOrder sortOrder, Integer maxLength, Integer scale) { - if (length == 0) { - return null; - } - if (!actualType.isCoercibleTo(this)) { - throwConstraintViolationException(actualType, this); - } - if (sortOrder == SortOrder.DESC) { - bytes = SortOrder.invert(bytes, offset, length); - offset = 0; - } - return Bytes.toString(bytes, offset, length); - } - - @Override - public Object toObject(Object object, PDataType actualType) { - if (equalsAny(actualType, this, PChar.INSTANCE)) { - String s = (String) object; - return s == null || s.length() > 0 ? s : null; - } - return throwConstraintViolationException(actualType, this); - } - - @Override - public boolean isCoercibleTo(PDataType targetType) { - return equalsAny(targetType, this, PChar.INSTANCE, PVarbinary.INSTANCE, PBinary.INSTANCE); - } - - @Override - public boolean isCoercibleTo(PDataType targetType, Object value) { - if (isCoercibleTo(targetType)) { - if (targetType.equals(PChar.INSTANCE)) { - return value != null; - } - return true; - } - return false; - } - - @Override - public boolean isSizeCompatible(ImmutableBytesWritable ptr, Object value, PDataType srcType, - Integer maxLength, Integer scale, Integer desiredMaxLength, - Integer desiredScale) { - if (ptr.getLength() != 0 && maxLength != null && desiredMaxLength != null) { - return maxLength <= desiredMaxLength; - } - return true; - } - - @Override - public boolean isFixedWidth() { - return false; - } - - @Override - public int estimateByteSize(Object o) { - String value = (String) o; - return value == null ? 1 : value.length(); - } - - @Override - public Integer getByteSize() { - return null; - } - - @Override - public int compareTo(Object lhs, Object rhs, PDataType rhsType) { - return ((String) lhs).compareTo((String) rhs); - } - - @Override - public Object toObject(String value) { - return value; - } - - @Override - public boolean isBytesComparableWith(PDataType otherType) { - return super.isBytesComparableWith(otherType) || otherType == PChar.INSTANCE; - } - - @Override - public String toStringLiteral(Object o, Format formatter) { - if (formatter != null) { - return "'" + formatter.format(o) + "'"; - } - return null == o ? String.valueOf(o) : "'" + StringUtil.escapeStringConstant(o.toString()) + "'"; - } - - private char[] sampleChars = new char[1]; - - @Override - public Object getSampleValue(Integer maxLength, Integer arrayLength) { - Preconditions.checkArgument(maxLength == null || maxLength >= 0); - int length = maxLength != null ? maxLength : 1; - if (length != sampleChars.length) { - sampleChars = new char[length]; - } - for (int i = 0; i < length; i++) { - sampleChars[i] = (char) RANDOM.get().nextInt(Byte.MAX_VALUE); - } - return new String(sampleChars); - } + public static final PVarchar INSTANCE = new PVarchar(); + + private PVarchar() { + super("VARCHAR", Types.VARCHAR, String.class, null, 0); + } + + @Override + public byte[] toBytes(Object object) { + // TODO: consider using avro UTF8 object instead of String + // so that we get get the size easily + if (object == null) { + return ByteUtil.EMPTY_BYTE_ARRAY; + } + return Bytes.toBytes((String) object); + } + + @Override + public int toBytes(Object object, byte[] bytes, int offset) { + if (object == null) { + return 0; + } + byte[] b = toBytes(object); // TODO: no byte[] allocation: use CharsetEncoder + System.arraycopy(b, 0, bytes, offset, b.length); + return b.length; + } + + @Override + public Object toObject(byte[] bytes, int offset, int length, PDataType actualType, + SortOrder sortOrder, Integer maxLength, Integer scale) { + if (length == 0) { + return null; + } + if (!actualType.isCoercibleTo(this)) { + throwConstraintViolationException(actualType, this); + } + if (sortOrder == SortOrder.DESC) { + bytes = SortOrder.invert(bytes, offset, length); + offset = 0; + } + return Bytes.toString(bytes, offset, length); + } + + @Override + public Object toObject(Object object, PDataType actualType) { + if (equalsAny(actualType, this, PChar.INSTANCE)) { + String s = (String) object; + return s == null || s.length() > 0 ? s : null; + } + return throwConstraintViolationException(actualType, this); + } + + @Override + public boolean isCoercibleTo(PDataType targetType) { + return equalsAny(targetType, this, PChar.INSTANCE, PVarbinary.INSTANCE, PBinary.INSTANCE); + } + + @Override + public boolean isCoercibleTo(PDataType targetType, Object value) { + if (isCoercibleTo(targetType)) { + if (targetType.equals(PChar.INSTANCE)) { + return value != null; + } + return true; + } + return false; + } + + @Override + public boolean isSizeCompatible(ImmutableBytesWritable ptr, Object value, PDataType srcType, + SortOrder sortOrder, Integer maxLength, Integer scale, + Integer desiredMaxLength, Integer desiredScale) { + if (ptr.getLength() != 0 && desiredMaxLength != null) { + if (maxLength == null) { + if (value != null) { // Use value if provided + maxLength = value.toString().length(); + } else { + coerceBytes(ptr, value, srcType, maxLength, scale, sortOrder, desiredMaxLength, desiredScale, sortOrder, true); + maxLength = StringUtil.calculateUTF8Length(ptr.get(), ptr.getOffset(), ptr.getLength(), sortOrder); + } + } + return maxLength <= desiredMaxLength; + } + return true; + } + + @Override + public boolean isFixedWidth() { + return false; + } + + @Override + public int estimateByteSize(Object o) { + String value = (String) o; + return value == null ? 1 : value.length(); + } + + @Override + public Integer getByteSize() { + return null; + } + + @Override + public int compareTo(Object lhs, Object rhs, PDataType rhsType) { + return ((String) lhs).compareTo((String) rhs); + } + + @Override + public Object toObject(String value) { + return value; + } + + @Override + public boolean isBytesComparableWith(PDataType otherType) { + return super.isBytesComparableWith(otherType) || otherType == PChar.INSTANCE; + } + + @Override + public String toStringLiteral(Object o, Format formatter) { + if (formatter != null) { + return "'" + formatter.format(o) + "'"; + } + return null == o ? String.valueOf(o) : "'" + StringUtil.escapeStringConstant(o.toString()) + "'"; + } + + private char[] sampleChars = new char[1]; + + @Override + public Object getSampleValue(Integer maxLength, Integer arrayLength) { + Preconditions.checkArgument(maxLength == null || maxLength >= 0); + int length = maxLength != null ? maxLength : 1; + if (length != sampleChars.length) { + sampleChars = new char[length]; + } + for (int i = 0; i < length; i++) { + sampleChars[i] = (char) RANDOM.get().nextInt(Byte.MAX_VALUE); + } + return new String(sampleChars); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a54a06cf/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java index b53daea..5fc7564 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java @@ -44,6 +44,7 @@ import javax.annotation.Nullable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; import org.apache.hadoop.hbase.util.Bytes; import org.apache.phoenix.exception.SQLExceptionCode; @@ -419,8 +420,16 @@ public class SchemaUtil { } public static String toString(PDataType type, byte[] value) { + return toString(type, value, 0, value.length); + } + + public static String toString(PDataType type, ImmutableBytesWritable value) { + return toString(type, value.get(), value.getOffset(), value.getLength()); + } + + public static String toString(PDataType type, byte[] value, int offset, int length) { boolean isString = type.isCoercibleTo(PVarchar.INSTANCE); - return isString ? ("'" + type.toObject(value).toString() + "'") : type.toObject(value).toString(); + return isString ? ("'" + type.toObject(value).toString() + "'") : type.toObject(value, offset, length).toString(); } public static byte[] getEmptyColumnFamily(PName defaultColumnFamily, List<PColumnFamily> families) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/a54a06cf/phoenix-core/src/test/java/org/apache/phoenix/schema/MutationTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/schema/MutationTest.java b/phoenix-core/src/test/java/org/apache/phoenix/schema/MutationTest.java index ccbda54..ce2e22f 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/schema/MutationTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/schema/MutationTest.java @@ -20,6 +20,7 @@ package org.apache.phoenix.schema; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.sql.Connection; import java.sql.DriverManager; @@ -30,8 +31,10 @@ import java.util.List; import org.apache.hadoop.hbase.client.Durability; import org.apache.hadoop.hbase.client.Mutation; import org.apache.hadoop.hbase.util.Pair; +import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.query.BaseConnectionlessQueryTest; +import org.apache.phoenix.schema.types.PVarchar; import org.junit.Test; public class MutationTest extends BaseConnectionlessQueryTest { @@ -70,5 +73,56 @@ public class MutationTest extends BaseConnectionlessQueryTest { } } } + + @Test + public void testSizeConstraint() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + try { + int maxLength1 = 3; + int maxLength2 = 20; + conn.setAutoCommit(false); + String bvalue = "01234567890123456789"; + assertEquals(20,PVarchar.INSTANCE.toBytes(bvalue).length); + String value = "æ¾´ç²è¤à¤¯è¤»é 岤豦íè°é©è¼Õªë¦ç¢ç¢ç¢ç¢ç¢ç¢"; + assertTrue(value.length() <= maxLength2 && value.getBytes().length > maxLength2); + conn.createStatement().execute("CREATE TABLE t1 (k1 char(" + maxLength1 + ") not null, k2 varchar(" + maxLength2 + "), " + + "v1 varchar(" + maxLength2 + "), v2 varbinary(" + maxLength2 + "), v3 binary(" + maxLength2 + "), constraint pk primary key (k1, k2))"); + conn.createStatement().execute("UPSERT INTO t1 VALUES('a','" + value + "', '" + value + "','" + bvalue + "','" + bvalue + "')"); + try { + conn.createStatement().execute("UPSERT INTO t1(k1,v1) VALUES('abcd','" + value + "')"); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.DATA_EXCEEDS_MAX_CAPACITY.getErrorCode(),e.getErrorCode()); + } + try { + conn.createStatement().execute("UPSERT INTO t1(k1,v2) VALUES('b','" + value + "')"); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.DATA_EXCEEDS_MAX_CAPACITY.getErrorCode(),e.getErrorCode()); + } + try { + conn.createStatement().execute("UPSERT INTO t1(k1,v3) VALUES('b','" + value + "')"); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.DATA_EXCEEDS_MAX_CAPACITY.getErrorCode(),e.getErrorCode()); + } + value = "æ¾´ç²è¤à¤¯è¤»é 岤豦íè°é©è¼Õªë¦ç¢ç¢ç¢ç¢ç¢ç¢ç¢ç¢ç¢"; + assertTrue(value.length() > maxLength2); + try { + conn.createStatement().execute("UPSERT INTO t1(k1,k2) VALUES('a','" + value + "')"); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.DATA_EXCEEDS_MAX_CAPACITY.getErrorCode(),e.getErrorCode()); + } + try { + conn.createStatement().execute("UPSERT INTO t1(k1,v1) VALUES('a','" + value + "')"); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.DATA_EXCEEDS_MAX_CAPACITY.getErrorCode(),e.getErrorCode()); + } + } finally { + conn.close(); + } + } }
