phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamestay...@apache.org
Subject [2/3] phoenix git commit: PHOENIX-3396 Valid Multi-byte strings whose total byte size is greater than the max char limit cannot be inserted into VARCHAR fields in the PK
Date Fri, 28 Oct 2016 06:12:44 GMT
http://git-wip-us.apache.org/repos/asf/phoenix/blob/faa2cd04/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/faa2cd04/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/faa2cd04/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/faa2cd04/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/faa2cd04/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();
+        }
+    }
 
 }


Mime
View raw message