You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/01/27 23:15:26 UTC

[10/51] [partial] Initial commit of master branch from github

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
new file mode 100644
index 0000000..8d14fb0
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
@@ -0,0 +1,6926 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.schema;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.text.Format;
+import java.util.Map;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Base64;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.math.LongMath;
+import com.google.common.primitives.Booleans;
+import com.google.common.primitives.Doubles;
+import com.google.common.primitives.Longs;
+import org.apache.phoenix.query.KeyRange;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.DateUtil;
+import org.apache.phoenix.util.NumberUtil;
+import org.apache.phoenix.util.StringUtil;
+
+
+/**
+ * The data types of PColumns
+ *
+ * @author wmacklem
+ * @author jtaylor
+ * @since 0.1
+ *
+ * TODO: cleanup implementation to reduce copy/paste duplication
+ */
+@SuppressWarnings("rawtypes")
+public enum PDataType {
+	
+    VARCHAR("VARCHAR", Types.VARCHAR, String.class, null) {
+        @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) {
+            if (!actualType.isCoercibleTo(this)) {
+                throw new ConstraintViolationException(actualType + " cannot be coerced to " + this);
+            }
+            return length == 0 ? null : Bytes.toString(bytes, offset, length);
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            switch (actualType) {
+            case VARCHAR:
+            case CHAR:
+                return object;
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            // TODO: should CHAR not be here?
+            return this == targetType || targetType == CHAR || targetType == VARBINARY || targetType == BINARY;
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (isCoercibleTo(targetType)) {
+                if (targetType == PDataType.CHAR) {
+                    return value != null;
+                }
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean isSizeCompatible(PDataType srcType, Object value, byte[] b,
+                Integer maxLength, Integer desiredMaxLength, Integer scale, Integer desiredScale) {
+            if (srcType == PDataType.CHAR && 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) || this == CHAR;
+        }
+
+        @Override
+        public String toStringLiteral(byte[] b, int offset, int length, Format formatter) {
+            while (b[length-1] == 0) {
+                length--;
+            }
+            if (formatter != null) {
+                Object o = toObject(b,offset,length);
+                return "'" + formatter.format(o) + "'";
+            }
+            return "'" + Bytes.toStringBinary(b, offset, length) + "'";
+        }
+    },
+    /**
+     * Fixed length single byte characters
+     */
+    CHAR("CHAR", Types.CHAR, String.class, null) { // Delegate to VARCHAR
+        @Override
+        public byte[] toBytes(Object object) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            byte[] b = VARCHAR.toBytes(object);
+            if (b.length != ((String) object).length()) {
+                throw new IllegalDataException("CHAR types may only contain single byte characters (" + object + ")");
+            }
+            return b;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            int len = VARCHAR.toBytes(object, bytes, offset);
+            if (len != ((String) object).length()) {
+                throw new IllegalDataException("CHAR types may only contain single byte characters (" + object + ")");
+            }
+            return len;
+        }
+
+        @Override
+        public Object toObject(byte[] bytes, int offset, int length, PDataType actualType) {
+            if (!actualType.isCoercibleTo(this)) { // TODO: have isCoercibleTo that takes bytes, offset?
+                throw new ConstraintViolationException(actualType + " cannot be coerced to " + this);
+            }
+            if (length == 0) {
+                return null;
+            }
+            length = StringUtil.getUnpaddedCharLength(bytes, offset, length, null);
+            String s = Bytes.toString(bytes, offset, length);
+            if (length != s.length()) {
+               throw new IllegalDataException("CHAR types may only contain single byte characters (" + s + ")");
+            }
+            return s;
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            switch (actualType) {
+            case VARCHAR:
+            case CHAR:
+                return object;
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == VARCHAR || targetType == BINARY || targetType == VARBINARY;
+        }
+
+        @Override
+        public boolean isSizeCompatible(PDataType srcType, Object value, byte[] b,
+                Integer maxLength, Integer desiredMaxLength, Integer scale, Integer desiredScale) {
+            if ((srcType == PDataType.VARCHAR && ((String)value).length() != b.length) ||
+                    (maxLength != null && desiredMaxLength != null && maxLength > desiredMaxLength)){
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return null;
+        }
+
+        @Override
+        public Integer getMaxLength(Object o) {
+            if (o == null) {
+                return null;
+            }
+            String value = (String) o;
+            return value.length();
+        }
+
+        @Override
+        public int estimateByteSize(Object o) {
+            String value = (String) o;
+            return value.length();
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            return VARCHAR.compareTo(lhs, rhs, rhsType);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            if (StringUtil.hasMultiByteChars(value)) {
+                throw new IllegalDataException("CHAR types may only contain single byte characters (" + value + ")");
+            }
+            return value;
+        }
+
+        @Override
+        public Integer estimateByteSizeFromLength(Integer length) {
+            return length;
+        }
+
+        @Override
+        public boolean isBytesComparableWith(PDataType otherType) {
+            return super.isBytesComparableWith(otherType) || this == VARCHAR;
+        }
+        
+        @Override
+        public String toStringLiteral(byte[] b, int offset, int length, Format formatter) {
+            return VARCHAR.toStringLiteral(b, offset, length, formatter);
+        }
+    },
+    LONG("BIGINT", Types.BIGINT, Long.class, new LongCodec()) {
+
+        @Override
+        public byte[] toBytes(Object object) {
+            byte[] b = new byte[Bytes.SIZEOF_LONG];
+            toBytes(object, b, 0);
+            return b;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] b, int o) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            return this.getCodec().encodeLong(((Number)object).longValue(), b, o);
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            if (object == null) {
+                return null;
+            }
+            switch (actualType) {
+            case LONG:
+            case UNSIGNED_LONG:
+                return object;
+            case UNSIGNED_INT:
+            case INTEGER:
+                long s = (Integer)object;
+                return s;
+            case TINYINT:
+            case UNSIGNED_TINYINT:
+                s = (Byte)object;
+                return s;
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+                s = (Short)object;
+                return s;
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+                Float f = (Float)object;
+                if (f > Long.MAX_VALUE || f < Long.MIN_VALUE) {
+                    throw new IllegalDataException(actualType + " value " + f + " cannot be cast to Long without changing its value");
+                }
+                s = f.longValue();
+                return s;
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+                Double de = (Double) object;
+                if (de > Long.MAX_VALUE || de < Long.MIN_VALUE) {
+                    throw new IllegalDataException(actualType + " value " + de + " cannot be cast to Long without changing its value");
+                }
+                s = de.longValue();
+                return s;
+            case DECIMAL:
+                BigDecimal d = (BigDecimal)object;
+                return d.longValueExact();
+            case VARBINARY:
+            case BINARY:
+                byte[] o = (byte[]) object;
+                if (o.length == Bytes.SIZEOF_LONG) {
+                    return Bytes.toLong(o);
+                } else if (o.length == Bytes.SIZEOF_INT) {
+                    int iv = Bytes.toInt(o);
+                    return (long) iv;
+                } else {
+                    throw new IllegalDataException("Bytes passed doesn't represent an integer.");
+                }
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            if (l == 0) {
+                return null;
+            }
+            switch (actualType) {
+            case LONG:
+            case UNSIGNED_LONG:
+            case INTEGER:
+            case UNSIGNED_INT:
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+            case UNSIGNED_TINYINT:
+            case TINYINT:
+            case UNSIGNED_FLOAT:
+            case FLOAT:
+            case UNSIGNED_DOUBLE:
+            case DOUBLE:
+                return actualType.getCodec().decodeLong(b, o, null);
+            default:
+                return super.toObject(b,o,l,actualType);
+            }
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            // In general, don't allow conversion of LONG to INTEGER. There are times when
+            // we check isComparableTo for a more relaxed check and then throw a runtime
+            // exception if we overflow
+            return this == targetType || targetType == DECIMAL
+                    || targetType == VARBINARY || targetType == BINARY
+                    || targetType == FLOAT || targetType == DOUBLE;
+        }
+
+        @Override
+        public boolean isComparableTo(PDataType targetType) {
+            return DECIMAL.isComparableTo(targetType);
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (value != null) {
+                long l;
+                switch (targetType) {
+                    case UNSIGNED_DOUBLE:
+                    case UNSIGNED_FLOAT:
+                    case UNSIGNED_LONG:
+                        l = (Long) value;
+                        return l >= 0;
+                    case UNSIGNED_INT:
+                        l = (Long) value;
+                        return (l >= 0 && l <= Integer.MAX_VALUE);
+                    case INTEGER:
+                        l = (Long) value;
+                        return (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE);
+                    case UNSIGNED_SMALLINT:
+                        l = (Long) value;
+                        return (l >= 0 && l <= Short.MAX_VALUE);
+                    case SMALLINT:
+                        l = (Long) value;
+                        return (l >=Short.MIN_VALUE && l<=Short.MAX_VALUE);
+                    case TINYINT:
+                        l = (Long)value;
+                        return (l >=Byte.MIN_VALUE && l<Byte.MAX_VALUE);
+                    case UNSIGNED_TINYINT:
+                        l = (Long)value;
+                        return (l >=0 && l<Byte.MAX_VALUE);
+                    default:
+                        break;
+                }
+            }
+            return super.isCoercibleTo(targetType, value);
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return Bytes.SIZEOF_LONG;
+        }
+
+        @Override
+        public Integer getMaxLength(Object o) {
+            return LONG_PRECISION;
+        }
+
+        @Override
+        public Integer getScale(Object o) {
+            return ZERO;
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            if (rhsType == DECIMAL) {
+                return -((BigDecimal)rhs).compareTo(BigDecimal.valueOf(((Number)lhs).longValue()));
+            } else if (rhsType == DOUBLE || rhsType == FLOAT || rhsType == UNSIGNED_DOUBLE || rhsType == UNSIGNED_FLOAT) {
+                return Doubles.compare(((Number)lhs).doubleValue(), ((Number)rhs).doubleValue());
+            }
+            return Longs.compare(((Number)lhs).longValue(), ((Number)rhs).longValue());
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                return null;
+            }
+            try {
+                return Long.parseLong(value);
+            } catch (NumberFormatException e) {
+                throw new IllegalDataException(e);
+            }
+        }
+    },
+    INTEGER("INTEGER", Types.INTEGER, Integer.class, new IntCodec()) {
+    	
+        @Override
+        public byte[] toBytes(Object object) {
+            byte[] b = new byte[Bytes.SIZEOF_INT];
+            toBytes(object, b, 0);
+            return b;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] b, int o) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            return this.getCodec().encodeInt(((Number)object).intValue(), b, o);
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            Object o = LONG.toObject(object, actualType);
+            if (!(o instanceof Long) || o == null) {
+                return o;
+            }
+            long l = (Long)o;
+            if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
+                throw new IllegalDataException(actualType + " value " + l + " cannot be cast to Integer without changing its value");
+            }
+            int v = (int)l;
+            return v;
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            if (l == 0) {
+                return null;
+            }
+            switch (actualType) {
+            case LONG:
+            case UNSIGNED_LONG:
+            case INTEGER:
+            case UNSIGNED_INT:
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+            case TINYINT:
+            case UNSIGNED_TINYINT:
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+                return actualType.getCodec().decodeInt(b, o, null);
+            default:
+                return super.toObject(b,o,l,actualType);
+            }
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (value != null) {
+                switch (targetType) {
+                    case UNSIGNED_DOUBLE:
+                    case UNSIGNED_FLOAT:
+                    case UNSIGNED_LONG:
+                    case UNSIGNED_INT:
+                        int i = (Integer) value;
+                        return i >= 0;
+                    case UNSIGNED_SMALLINT:
+                        i = (Integer) value;
+                        return (i >= 0 && i <= Short.MAX_VALUE);
+                    case SMALLINT:
+                        i = (Integer) value;
+                        return (i >=Short.MIN_VALUE && i<=Short.MAX_VALUE);
+                    case TINYINT:
+                        i = (Integer)value;
+                        return (i >=Byte.MIN_VALUE && i<=Byte.MAX_VALUE);
+                    case UNSIGNED_TINYINT:
+                        i = (Integer)value;
+                        return (i >=0 && i<Byte.MAX_VALUE);
+                    default:
+                        break;
+                }
+            }
+            return super.isCoercibleTo(targetType, value);
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || LONG.isCoercibleTo(targetType);
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return Bytes.SIZEOF_INT;
+        }
+
+        @Override
+        public Integer getMaxLength(Object o) {
+            return INT_PRECISION;
+        }
+
+        @Override
+        public Integer getScale(Object o) {
+            return ZERO;
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            return LONG.compareTo(lhs,rhs,rhsType);
+        }
+
+        @Override
+        public boolean isComparableTo(PDataType targetType) {
+            return DECIMAL.isComparableTo(targetType);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                return null;
+            }
+            try {
+                return Integer.parseInt(value);
+            } catch (NumberFormatException e) {
+                throw new IllegalDataException(e);
+            }
+        }
+    },
+    SMALLINT("SMALLINT", Types.SMALLINT, Short.class, new ShortCodec()){
+
+      @Override
+      public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+        return LONG.compareTo(lhs, rhs, rhsType);
+      }
+      
+      @Override
+      public boolean isComparableTo(PDataType targetType) {
+          return DECIMAL.isComparableTo(targetType);
+      }
+
+      @Override
+      public boolean isFixedWidth() {
+        return true;
+      }
+
+      @Override
+      public Integer getByteSize() {
+        return Bytes.SIZEOF_SHORT;
+      }
+
+      @Override
+      public Integer getScale(Object o) {
+          return ZERO;
+      }
+      
+      @Override
+      public Integer getMaxLength(Object o) {
+          return SHORT_PRECISION;
+      }
+
+      @Override
+      public byte[] toBytes(Object object) {
+        byte[] b = new byte[Bytes.SIZEOF_SHORT];
+        toBytes(object, b, 0);
+        return b;
+      }
+
+      @Override
+      public int toBytes(Object object, byte[] bytes, int offset) {
+        if (object == null) {
+          throw new ConstraintViolationException(this + " may not be null");
+        }
+        return this.getCodec().encodeShort(((Number)object).shortValue(), bytes, offset);
+      }
+      
+      @Override
+      public Object toObject(Object object, PDataType actualType) {
+          Object o = LONG.toObject(object, actualType);
+          if (!(o instanceof Long) || o == null) {
+              return o;
+          }
+          long l = (Long)o;
+          if (l < Short.MIN_VALUE || l > Short.MAX_VALUE) {
+              throw new IllegalDataException(actualType + " value " + l + " cannot be cast to Short without changing its value");
+          }
+          short s = (short)l;
+          return s;
+      }
+
+      @Override
+      public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+          if (l == 0) {
+              return null;
+          }
+          switch (actualType) {
+          case SMALLINT:
+          case UNSIGNED_SMALLINT:
+          case TINYINT:
+          case UNSIGNED_TINYINT:
+          case LONG:
+          case UNSIGNED_LONG:
+          case INTEGER:
+          case UNSIGNED_INT:
+          case FLOAT:
+          case UNSIGNED_FLOAT:
+          case DOUBLE:
+          case UNSIGNED_DOUBLE:
+              return actualType.getCodec().decodeShort(b, o, null);
+          default:
+              return super.toObject(b,o,l,actualType);
+          }
+      }
+
+      @Override
+      public Object toObject(String value) {
+        if (value == null || value.length() == 0) {
+          return null;
+        }
+        try {
+            return Short.parseShort(value);
+        } catch (NumberFormatException e) {
+            throw new IllegalDataException(e);
+        }
+      }
+      
+      @Override
+      public boolean isCoercibleTo(PDataType targetType, Object value) {
+          if (value != null) {
+              switch (targetType) {
+                  case UNSIGNED_DOUBLE:
+                  case UNSIGNED_FLOAT:
+                  case UNSIGNED_LONG:
+                  case UNSIGNED_INT:
+                  case UNSIGNED_SMALLINT:
+                      short i = (Short) value;
+                      return i >= 0;
+                  case UNSIGNED_TINYINT:
+                      i = (Short) value;
+                      return (i>=0 && i<= Byte.MAX_VALUE);
+                  case TINYINT:
+                      i = (Short)value;
+                      return (i>=Byte.MIN_VALUE && i<= Byte.MAX_VALUE);
+                  default:
+                      break;
+              }
+          }
+          return super.isCoercibleTo(targetType, value);
+      }
+
+      @Override
+      public boolean isCoercibleTo(PDataType targetType) {
+          return this == targetType || INTEGER.isCoercibleTo(targetType);
+      }
+      
+    },
+    TINYINT("TINYINT", Types.TINYINT, Byte.class, new ByteCodec()) {
+
+      @Override
+      public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+        return LONG.compareTo(lhs, rhs, rhsType);
+      }
+      
+      @Override
+      public boolean isComparableTo(PDataType targetType) {
+          return DECIMAL.isComparableTo(targetType);
+      }
+
+      @Override
+      public boolean isFixedWidth() {
+        return true;
+      }
+
+      @Override
+      public Integer getByteSize() {
+        return Bytes.SIZEOF_BYTE;
+      }
+      
+      @Override
+      public Integer getScale(Object o) {
+          return ZERO;
+      }
+      
+      @Override
+      public Integer getMaxLength(Object o) {
+          return BYTE_PRECISION;
+      }
+
+      @Override
+      public byte[] toBytes(Object object) {
+        byte[] b = new byte[Bytes.SIZEOF_BYTE];
+        toBytes(object, b, 0);
+        return b;
+      }
+
+      @Override
+      public int toBytes(Object object, byte[] bytes, int offset) {
+        if (object == null) {
+          throw new ConstraintViolationException(this + " may not be null");
+        }
+        return this.getCodec().encodeByte(((Number)object).byteValue(), bytes, offset);
+      }
+
+      @Override
+      public Object toObject(String value) {
+        if (value == null || value.length() == 0) {
+          return null;
+        }
+        try {
+          Byte b = Byte.parseByte(value);
+          return b;
+        } catch (NumberFormatException e) {
+          throw new IllegalDataException(e);
+        }
+      }
+      
+      @Override
+      public Object toObject(Object object, PDataType actualType) {
+          Object o = LONG.toObject(object, actualType);
+          if(!(o instanceof Long) || o == null) {
+              return o;
+          }
+          long l = (Long)o;
+          if (l < Byte.MIN_VALUE || l > Byte.MAX_VALUE) {
+              throw new IllegalDataException(actualType + " value " + l + " cannot be cast to Byte without changing its value");
+          }
+          return (byte)l;
+      }
+      
+      @Override
+      public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+          if (l == 0) {
+              return null;
+          }
+          switch (actualType) {
+          case UNSIGNED_DOUBLE:
+          case DOUBLE:
+          case UNSIGNED_FLOAT:
+          case FLOAT:
+          case UNSIGNED_LONG:
+          case LONG:
+          case UNSIGNED_INT:
+          case INTEGER:
+          case UNSIGNED_SMALLINT:
+          case SMALLINT:
+          case UNSIGNED_TINYINT:
+          case TINYINT:
+              return actualType.getCodec().decodeByte(b, o, null);
+          default:
+              return super.toObject(b,o,l,actualType);
+          }
+      }
+      
+      @Override
+      public boolean isCoercibleTo(PDataType targetType, Object value) {
+          if (value != null) {
+              switch (targetType) {
+                  case UNSIGNED_DOUBLE:
+                  case UNSIGNED_FLOAT:
+                  case UNSIGNED_LONG:
+                  case UNSIGNED_INT:
+                  case UNSIGNED_SMALLINT:
+                  case UNSIGNED_TINYINT:
+                      byte i = (Byte) value;
+                      return i >= 0;
+                  default:
+                      break;
+              }
+          }
+          return super.isCoercibleTo(targetType, value);
+      }
+      
+      @Override
+      public boolean isCoercibleTo(PDataType targetType) {
+          return this == targetType || SMALLINT.isCoercibleTo(targetType);
+      }
+      
+    },
+    FLOAT("FLOAT", Types.FLOAT, Float.class, new FloatCodec()) {
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            return DOUBLE.compareTo(lhs, rhs, rhsType);
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return Bytes.SIZEOF_INT;
+        }
+        
+        @Override
+        public Integer getScale(Object o) {
+            if (o == null) {
+                return null;
+            }
+            Float v = (Float) o;
+            BigDecimal bd = BigDecimal.valueOf(v);
+            return bd.scale();
+        }
+        
+        @Override
+        public Integer getMaxLength(Object o) {
+            if (o == null) {
+                return null;
+            }
+            Float v = (Float) o;
+            BigDecimal bd = BigDecimal.valueOf(v);
+            return bd.precision();
+        }
+
+        @Override
+        public byte[] toBytes(Object object) {
+            byte[] b = new byte[Bytes.SIZEOF_INT];
+            toBytes(object, b, 0);
+            return b;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            return this.getCodec().encodeFloat(((Number) object).floatValue(),
+                    bytes, offset);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                return null;
+            }
+            try {
+                return Float.parseFloat(value);
+            } catch (NumberFormatException e) {
+                throw new IllegalDataException(e);
+            }
+        }
+        
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            if (object == null) {
+                return null;
+            }
+            switch (actualType) {
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+                return object;
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+                double d = (Double)object;
+                if (Double.isNaN(d)
+                        || d == Double.POSITIVE_INFINITY
+                        || d == Double.NEGATIVE_INFINITY
+                        || (d >= -Float.MAX_VALUE && d <= Float.MAX_VALUE)) {
+                    return (float) d;
+                } else {
+                    throw new IllegalDataException(actualType + " value " + d + " cannot be cast to Float without changing its value");
+                }
+            case LONG:
+            case UNSIGNED_LONG:
+                float f = (Long)object;
+                return f;
+            case UNSIGNED_INT:
+            case INTEGER:
+                f = (Integer)object;
+                return f;
+            case TINYINT:
+            case UNSIGNED_TINYINT:
+                f = (Byte)object;
+                return f;
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+                f = (Short)object;
+                return f;
+            case DECIMAL:
+                BigDecimal dl = (BigDecimal)object;
+                return dl.floatValue();
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+        
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            if (l <= 0) {
+                return null;
+            }
+            switch (actualType) {
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+            case UNSIGNED_LONG:
+            case LONG:
+            case UNSIGNED_INT:
+            case INTEGER:
+            case UNSIGNED_SMALLINT:
+            case SMALLINT:
+            case UNSIGNED_TINYINT:
+            case TINYINT:
+                return actualType.getCodec().decodeFloat(b, o, null);
+            default:
+                return super.toObject(b,o,l,actualType);
+            }
+        }
+        
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (value != null) {
+                float f = (Float)value;
+                switch (targetType) {
+                case UNSIGNED_FLOAT:
+                    return f >= 0;
+                case UNSIGNED_LONG:
+                    return (f >= 0 && f <= Long.MAX_VALUE);
+                case LONG:
+                    return (f >= Long.MIN_VALUE && f <= Long.MAX_VALUE);
+                case UNSIGNED_INT:
+                    return (f >= 0 && f <= Integer.MAX_VALUE);
+                case INTEGER:
+                    return (f >= Integer.MIN_VALUE && f <= Integer.MAX_VALUE);
+                case UNSIGNED_SMALLINT:
+                    return (f >= 0 && f <= Short.MAX_VALUE);
+                case SMALLINT:
+                    return (f >=Short.MIN_VALUE && f<=Short.MAX_VALUE);
+                case TINYINT:
+                    return (f >=Byte.MIN_VALUE && f<Byte.MAX_VALUE);
+                case UNSIGNED_TINYINT:
+                    return (f >=0 && f<Byte.MAX_VALUE);
+                default:
+                    break;
+                }
+            }
+            return super.isCoercibleTo(targetType, value);
+        }
+        
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || DOUBLE.isCoercibleTo(targetType);
+        }
+        
+    },
+    DOUBLE("DOUBLE", Types.DOUBLE, Double.class, new DoubleCodec()) {
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            if (rhsType == DECIMAL) {
+                return -((BigDecimal)rhs).compareTo(BigDecimal.valueOf(((Number)lhs).doubleValue()));
+            }
+            return Doubles.compare(((Number)lhs).doubleValue(), ((Number)rhs).doubleValue());
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return Bytes.SIZEOF_LONG;
+        }
+        
+        @Override
+        public Integer getScale(Object o) {
+            if (o == null) {
+                return null;
+            }
+            Double v = (Double) o;
+            BigDecimal bd = BigDecimal.valueOf(v);
+            return bd.scale();
+        }
+        
+        @Override
+        public Integer getMaxLength(Object o) {
+            if (o == null) {
+                return null;
+            }
+            Double v = (Double) o;
+            BigDecimal db = BigDecimal.valueOf(v);
+            return db.precision();
+        }
+
+        @Override
+        public byte[] toBytes(Object object) {
+            byte[] b = new byte[Bytes.SIZEOF_LONG];
+            toBytes(object, b, 0);
+            return b;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            } 
+            return this.getCodec().encodeDouble(((Number) object).doubleValue(),
+                    bytes, offset); 
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                return null;
+            }
+            try {
+                return Double.parseDouble(value);
+            } catch (NumberFormatException e) {
+                throw new IllegalDataException(e);
+            }
+        }
+        
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            if (object == null) {
+                return null;
+            }
+            double de;
+            switch (actualType) {
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+                return object; 
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+                de = (Float)object;
+                return de;
+            case LONG:
+            case UNSIGNED_LONG:
+                de = (Long)object;
+                return de;
+            case UNSIGNED_INT:
+            case INTEGER:
+                de = (Integer)object;
+                return de;
+            case TINYINT:
+            case UNSIGNED_TINYINT:
+                de = (Byte)object;
+                return de;
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+                de = (Short)object;
+                return de;
+            case DECIMAL:
+                BigDecimal d = (BigDecimal)object;
+                return d.doubleValue();
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+        
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            if (l <= 0) {
+                return null;
+            }
+            switch (actualType) {
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+            case UNSIGNED_LONG:
+            case LONG:
+            case UNSIGNED_INT:
+            case INTEGER:
+            case UNSIGNED_SMALLINT:
+            case SMALLINT:
+            case UNSIGNED_TINYINT:
+            case TINYINT:
+                return actualType.getCodec().decodeDouble(b, o, null);
+            default:
+                return super.toObject(b,o,l,actualType);
+            }
+        }
+        
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (value != null) {
+                double d = (Double)value;
+                switch (targetType) {
+                case UNSIGNED_DOUBLE:
+                    return d >= 0;
+                case FLOAT:
+                    return Double.isNaN(d)
+                            || d == Double.POSITIVE_INFINITY
+                            || d == Double.NEGATIVE_INFINITY
+                            || (d >= -Float.MAX_VALUE && d <= Float.MAX_VALUE);
+                case UNSIGNED_FLOAT:
+                    return Double.isNaN(d) || d == Double.POSITIVE_INFINITY
+                            || (d >= 0 && d <= Float.MAX_VALUE);
+                case UNSIGNED_LONG:
+                    return (d >= 0 && d <= Long.MAX_VALUE);
+                case LONG:
+                    return (d >= Long.MIN_VALUE && d <= Long.MAX_VALUE);
+                case UNSIGNED_INT:
+                    return (d >= 0 && d <= Integer.MAX_VALUE);
+                case INTEGER:
+                    return (d >= Integer.MIN_VALUE && d <= Integer.MAX_VALUE);
+                case UNSIGNED_SMALLINT:
+                    return (d >= 0 && d <= Short.MAX_VALUE);
+                case SMALLINT:
+                    return (d >=Short.MIN_VALUE && d<=Short.MAX_VALUE);
+                case TINYINT:
+                    return (d >=Byte.MIN_VALUE && d<Byte.MAX_VALUE);
+                case UNSIGNED_TINYINT:
+                    return (d >=0 && d<Byte.MAX_VALUE);
+                default:
+                    break;
+                }
+            }
+            return super.isCoercibleTo(targetType, value);
+        }
+        
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == DECIMAL
+                    || targetType == VARBINARY || targetType == BINARY;
+        }
+        
+    },
+    DECIMAL("DECIMAL", Types.DECIMAL, BigDecimal.class, null) {
+        @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;
+        }
+
+        @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);
+        }
+
+        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;
+        }
+
+        @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);
+        }
+
+        @Override
+        public Integer getMaxLength(Object o) {
+            if (o == null) {
+                return null;
+            }
+            BigDecimal v = (BigDecimal) o;
+            return v.precision();
+        }
+
+        @Override
+        public Integer getScale(Object o) {
+            if (o == null) {
+                return null;
+            }
+            BigDecimal v = (BigDecimal) o;
+            return v.scale();
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType, ColumnModifier columnModifier) {
+            if (l == 0) {
+                return null;
+            }
+            if (columnModifier != null) {
+                b = columnModifier.apply(b, o, new byte[l], 0, l);
+                o = 0;
+            }
+            switch (actualType) {
+            case DECIMAL:
+                return toBigDecimal(b, o, l);
+            case DATE:
+            case TIME:
+            case LONG:
+            case INTEGER:
+            case SMALLINT:
+            case TINYINT:
+            case UNSIGNED_LONG:
+            case UNSIGNED_INT:
+            case UNSIGNED_SMALLINT:
+            case UNSIGNED_TINYINT:
+                return BigDecimal.valueOf(actualType.getCodec().decodeLong(b, o, null));
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+                return BigDecimal.valueOf(actualType.getCodec().decodeFloat(b, o, null));
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+                return BigDecimal.valueOf(actualType.getCodec().decodeDouble(b, o, null));
+            case TIMESTAMP:
+            case UNSIGNED_TIMESTAMP:
+                Timestamp ts = (Timestamp) actualType.toObject(b, o, l) ;
+                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;
+            default:
+                return super.toObject(b,o,l,actualType);
+            }
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            if (object == null) {
+                return null;
+            }
+            switch (actualType) {
+            case INTEGER:
+            case UNSIGNED_INT:
+                return BigDecimal.valueOf((Integer)object);
+            case LONG:
+            case UNSIGNED_LONG:
+                return BigDecimal.valueOf((Long)object);
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+                return BigDecimal.valueOf((Short)object);
+            case TINYINT:
+            case UNSIGNED_TINYINT:
+                return BigDecimal.valueOf((Byte)object);
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+                return BigDecimal.valueOf((Float)object);
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+                return BigDecimal.valueOf((Double)object);
+            case DECIMAL:
+                return object;
+            case TIMESTAMP:
+            case UNSIGNED_TIMESTAMP:
+                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;
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return false;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return MAX_BIG_DECIMAL_BYTES;
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            if (rhsType == DECIMAL) {
+                return ((BigDecimal)lhs).compareTo((BigDecimal)rhs);
+            }
+            return -rhsType.compareTo(rhs, lhs, this);
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (value != null) {
+                BigDecimal bd;
+                switch (targetType) {
+                    case UNSIGNED_LONG:
+                    case UNSIGNED_INT:
+                    case UNSIGNED_SMALLINT:
+                    case UNSIGNED_TINYINT:
+                        bd = (BigDecimal) value;
+                        if (bd.signum() == -1) {
+                            return false;
+                        }
+                    case LONG:
+                        bd = (BigDecimal) value;
+                        try {
+                            bd.longValueExact();
+                            return true;
+                        } catch (ArithmeticException e) {
+                            return false;
+                        }
+                    case INTEGER:
+                        bd = (BigDecimal) value;
+                        try {
+                            bd.intValueExact();
+                            return true;
+                        } catch (ArithmeticException e) {
+                            return false;
+                        }
+                    case SMALLINT:
+                        bd = (BigDecimal) value;
+                        try {
+                            bd.shortValueExact();
+                            return true;
+                        } catch (ArithmeticException e) {
+                            return false;
+                        }
+                    case TINYINT:
+                        bd = (BigDecimal) value;
+                        try {
+                            bd.byteValueExact();
+                            return true;
+                        } catch (ArithmeticException e) {
+                            return false;
+                        }
+                    case UNSIGNED_FLOAT:
+                        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;
+                        }
+                    case FLOAT:
+                        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;
+                        }
+                    case UNSIGNED_DOUBLE:
+                        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;
+                        }
+                    case DOUBLE:
+                        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;
+                        }
+                    default:
+                        break;
+                }
+            }
+            return super.isCoercibleTo(targetType, value);
+        }
+
+        @Override
+        public boolean isSizeCompatible(PDataType srcType, Object value, byte[] b, Integer maxLength,
+        		Integer desiredMaxLength, Integer scale, Integer desiredScale) {
+            // Get precision and scale if it is not already passed in and either the object or byte values
+            // is meaningful.
+            if (maxLength == null && scale == null) {
+                if (value != null) {
+                    BigDecimal v = (BigDecimal) value;
+                    maxLength = v.precision();
+                    scale = v.scale();
+                } else if (b != null && b.length > 0) {
+                    int[] v = getDecimalPrecisionAndScale(b, 0, b.length);
+                    maxLength = v[0];
+                    scale = v[1];
+                } else {
+                    // the value does not contains maxLength nor scale. Just return true.
+                    return true;
+                }
+            }
+            if (desiredMaxLength != null && desiredScale != null && maxLength != null && scale != null &&
+            		((desiredScale == null && desiredMaxLength < maxLength) || 
+            				(desiredMaxLength - desiredScale) < (maxLength - scale))) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public byte[] coerceBytes(byte[] b, Object object, PDataType actualType, Integer maxLength, Integer scale,
+                Integer desiredMaxLength, Integer desiredScale) {
+            if (desiredScale == null) {
+                // deiredScale not available, or we do not have scale requirement, delegate to parents.
+                return super.coerceBytes(b, object, actualType);
+            }
+            if (scale == null) {
+                if (object != null) {
+                    BigDecimal v = (BigDecimal) object;
+                    scale = v.scale();
+                } else if (b != null && b.length > 0) {
+                    int[] v = getDecimalPrecisionAndScale(b, 0, b.length);
+                    scale = v[1];
+                } else {
+                    // Neither the object value nor byte value is meaningful, delegate to super.
+                    return super.coerceBytes(b, object, actualType);
+                }
+            }
+            if (this == actualType && scale <= desiredScale) {
+                // No coerce and rescale necessary
+                return b;
+            } 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(b);
+                }
+                decimal = decimal.setScale(desiredScale, BigDecimal.ROUND_DOWN);
+                return 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 new IllegalDataException(e);
+            }
+        }
+
+        @Override
+        public Integer estimateByteSizeFromLength(Integer length) {
+            // No association of runtime byte size from decimal precision.
+            return null;
+        }
+    },
+    TIMESTAMP("TIMESTAMP", Types.TIMESTAMP, Timestamp.class, new DateCodec()) {
+
+        @Override
+        public byte[] toBytes(Object object) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            byte[] bytes = new byte[getByteSize()];
+            toBytes(object, bytes, 0);
+            return bytes;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            Timestamp value = (Timestamp)object;
+            DATE.getCodec().encodeLong(value.getTime(), bytes, offset);
+            
+            /*
+             * By not getting the stuff that got spilled over from the millis part,
+             * it leaves the timestamp's byte representation saner - 8 bytes of millis | 4 bytes of nanos.
+             * Also, it enables timestamp bytes to be directly compared with date/time bytes.   
+             */
+            Bytes.putInt(bytes, offset + Bytes.SIZEOF_LONG, value.getNanos() % 1000000);  
+            return getByteSize();
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            if (object == null) {
+                return null;
+            }
+            switch (actualType) {
+            case DATE:
+            case TIME:
+            case UNSIGNED_DATE:
+            case UNSIGNED_TIME:
+                return new Timestamp(((java.util.Date)object).getTime());
+            case TIMESTAMP:
+            case UNSIGNED_TIMESTAMP:
+                return object;
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType, ColumnModifier columnModifier) {
+            if (actualType == null || l == 0) {
+                return null;
+            }
+            if (columnModifier != null) {
+                b = columnModifier.apply(b, o, new byte[l], 0, l);
+                o = 0;
+            }
+            switch (actualType) {
+            case TIMESTAMP:
+            case UNSIGNED_TIMESTAMP:
+                long millisDeserialized = (actualType == TIMESTAMP ? DATE : UNSIGNED_DATE).getCodec().decodeLong(b, o, null);
+                Timestamp v = new Timestamp(millisDeserialized);
+                int nanosDeserialized = Bytes.toInt(b, o + Bytes.SIZEOF_LONG, Bytes.SIZEOF_INT);
+                /*
+                 * There was a bug in serialization of timestamps which was causing the sub-second millis part
+                 * of time stamp to be present both in the LONG and INT bytes. Having the <100000 check
+                 * makes this serialization fix backward compatible.
+                 */
+                v.setNanos(nanosDeserialized < 1000000 ? v.getNanos() + nanosDeserialized : nanosDeserialized);
+                return v;
+            case DATE:
+            case TIME:
+            case UNSIGNED_DATE:
+            case UNSIGNED_TIME:
+                return new Timestamp(actualType.getCodec().decodeLong(b, o, null));
+            case DECIMAL:
+                BigDecimal bd = (BigDecimal) actualType.toObject(b, o, l);
+                long ms = bd.longValue();
+                int nanos = (bd.remainder(BigDecimal.ONE).multiply(QueryConstants.BD_MILLIS_NANOS_CONVERSION)).intValue();
+                v = DateUtil.getTimestamp(ms, nanos);
+                return v;
+            default:
+                throw new ConstraintViolationException(actualType + " cannot be coerced to " + this);
+            }
+        }
+        
+        @Override
+        public boolean isCastableTo(PDataType targetType) {
+            return DATE.isCastableTo(targetType);
+        }
+
+       @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == VARBINARY || targetType == BINARY;
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            return DATE.isCoercibleTo(targetType, value) && (targetType == UNSIGNED_TIMESTAMP || targetType == this || ((Timestamp)value).getNanos() == 0);
+        }
+        
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return MAX_TIMESTAMP_BYTES;
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            if (rhsType == TIMESTAMP || rhsType == UNSIGNED_TIMESTAMP) {
+                return ((Timestamp)lhs).compareTo((Timestamp)rhs);
+            }
+            int c = ((Date)rhs).compareTo((Date)lhs);
+            if (c != 0) return c;
+            return ((Timestamp)lhs).getNanos();
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                return null;
+            }
+            return DateUtil.parseTimestamp(value);
+        }
+        
+        @Override
+        public String toStringLiteral(byte[] b, int offset, int length, Format formatter) {
+            Timestamp value = (Timestamp)toObject(b,offset,length);
+            if (formatter == null || formatter == DateUtil.DEFAULT_DATE_FORMATTER) {
+                // If default formatter has not been overridden,
+                // use one that displays milliseconds.
+                formatter = DateUtil.DEFAULT_MS_DATE_FORMATTER;
+            }
+            return "'" + super.toStringLiteral(b, offset, length, formatter) + "." + value.getNanos() + "'";
+        }
+        
+        @Override
+        public int getNanos(ImmutableBytesWritable ptr, ColumnModifier cm) {
+            int nanos = PDataType.UNSIGNED_INT.getCodec().decodeInt(ptr.get(), ptr.getOffset() + PDataType.LONG.getByteSize(), cm);
+            return nanos;
+        }
+        
+        @Override
+        public long getMillis(ImmutableBytesWritable ptr, ColumnModifier cm) {
+            long millis = PDataType.LONG.getCodec().decodeLong(ptr.get(),ptr.getOffset(), cm);
+            return millis;
+        }
+
+    },
+    TIME("TIME", Types.TIME, Time.class, new DateCodec()) {
+
+        @Override
+        public byte[] toBytes(Object object) {
+            return DATE.toBytes(object);
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            return DATE.toBytes(object, bytes, offset);
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            if (l == 0) {
+                return null;
+            }
+            switch (actualType) {
+            case TIMESTAMP:
+            case UNSIGNED_TIMESTAMP:
+            case DATE:
+            case TIME:
+            case UNSIGNED_DATE:
+            case UNSIGNED_TIME:
+                return new Time(actualType.getCodec().decodeLong(b, o, null));
+            default:
+                throw new ConstraintViolationException(actualType + " cannot be coerced to " + this);
+            }
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            if (object == null) {
+                return null;
+            }
+            switch (actualType) {
+            case DATE:
+            case UNSIGNED_DATE:
+                return new Time(((Date)object).getTime());
+            case TIMESTAMP:
+            case UNSIGNED_TIMESTAMP:
+                return new Time(((Timestamp)object).getTime());
+            case TIME:
+            case UNSIGNED_TIME:
+                return object;
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+
+        @Override
+        public boolean isCastableTo(PDataType targetType) {
+            return DATE.isCastableTo(targetType);
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == DATE || targetType == TIMESTAMP
+                    || targetType == VARBINARY || targetType == BINARY;
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            return DATE.isCoercibleTo(targetType, value);
+        }
+        
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return Bytes.SIZEOF_LONG;
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            return DATE.compareTo(lhs, rhs, rhsType);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                return null;
+            }
+            return DateUtil.parseTime(value);
+        }
+
+        @Override
+        public boolean isBytesComparableWith(PDataType otherType) {
+            return super.isBytesComparableWith(otherType) ||  this == DATE;
+        }
+        
+        @Override
+        public String toStringLiteral(byte[] b, int offset, int length, Format formatter) {
+            // TODO: different default formatter for TIME?
+            return DATE.toStringLiteral(b, offset, length, formatter);
+        }
+    },
+    DATE("DATE", Types.DATE, Date.class, new DateCodec()) { // After TIMESTAMP and DATE to ensure toLiteral finds those first
+
+        @Override
+        public byte[] toBytes(Object object) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            byte[] bytes = new byte[getByteSize()];
+            toBytes(object, bytes, 0);
+            return bytes;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            getCodec().encodeLong(((java.util.Date)object).getTime(), bytes, offset);
+            return this.getByteSize();
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            if (object == null) {
+                return null;
+            }
+            switch (actualType) {
+            case TIME:
+            case UNSIGNED_TIME:
+                return new Date(((Time)object).getTime());
+            case TIMESTAMP:
+            case UNSIGNED_TIMESTAMP:
+                return new Date(((Timestamp)object).getTime());
+            case DATE:
+            case UNSIGNED_DATE:
+                return object;
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            if (l == 0) {
+                return null;
+            }
+            switch (actualType) {
+            case TIMESTAMP:
+            case UNSIGNED_TIMESTAMP:
+            case DATE:
+            case TIME:
+            case UNSIGNED_DATE:
+            case UNSIGNED_TIME:
+                return new Date(actualType.getCodec().decodeLong(b, o, null));
+            default:
+                throw new ConstraintViolationException(actualType + " cannot be coerced to " + this);
+            }
+        }
+
+        @Override
+        public boolean isCastableTo(PDataType targetType) {
+            return super.isCastableTo(targetType) || DECIMAL.isCastableTo(targetType);
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == TIME || targetType == TIMESTAMP
+                    || targetType == VARBINARY || targetType == BINARY;
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (value != null) {
+                switch (targetType) {
+                    case UNSIGNED_DATE:
+                    case UNSIGNED_TIME:
+                    case UNSIGNED_TIMESTAMP:
+                        return ((java.util.Date)value).getTime() >= 0;
+                    default:
+                        break;
+                }
+            }
+            return super.isCoercibleTo(targetType, value);
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return Bytes.SIZEOF_LONG;
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            if (rhsType == TIMESTAMP || rhsType == UNSIGNED_TIMESTAMP) {
+                return -rhsType.compareTo(rhs, lhs, TIME);
+            }
+            return ((java.util.Date)rhs).compareTo((java.util.Date)lhs);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                return null;
+            }
+            return DateUtil.parseDate(value);
+        }
+
+        @Override
+        public boolean isBytesComparableWith(PDataType otherType) {
+            return super.isBytesComparableWith(otherType) || this == TIME;
+        }
+        
+        @Override
+        public String toStringLiteral(byte[] b, int offset, int length, Format formatter) {
+            if (formatter == null || formatter == DateUtil.DEFAULT_DATE_FORMATTER) {
+                // If default formatter has not been overridden,
+                // use one that displays milliseconds.
+                formatter = DateUtil.DEFAULT_MS_DATE_FORMATTER;
+            }
+            return "'" + super.toStringLiteral(b, offset, length, formatter) + "'";
+        }
+        
+        @Override
+        public void coerceBytes(ImmutableBytesWritable ptr, PDataType actualType, ColumnModifier actualModifier, ColumnModifier expectedModifier) {
+            if (ptr.getLength() > 0 && actualType  == PDataType.TIMESTAMP && actualModifier == expectedModifier) {
+                ptr.set(ptr.get(), ptr.getOffset(), getByteSize());
+                return;
+            }
+            super.coerceBytes(ptr, actualType, actualModifier, expectedModifier);
+        }
+    },
+    UNSIGNED_TIMESTAMP("UNSIGNED_TIMESTAMP", 19, Timestamp.class, null) {
+
+        @Override
+        public byte[] toBytes(Object object) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            byte[] bytes = new byte[getByteSize()];
+            toBytes(object, bytes, 0);
+            return bytes;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            Timestamp value = (Timestamp)object;
+            UNSIGNED_DATE.getCodec().encodeLong(value.getTime(), bytes, offset);
+            
+            /*
+             * By not getting the stuff that got spilled over from the millis part,
+             * it leaves the timestamp's byte representation saner - 8 bytes of millis | 4 bytes of nanos.
+             * Also, it enables timestamp bytes to be directly compared with date/time bytes.   
+             */
+            Bytes.putInt(bytes, offset + Bytes.SIZEOF_LONG, value.getNanos() % 1000000);  
+            return getByteSize();
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            return TIMESTAMP.toObject(object, actualType);
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            return TIMESTAMP.toObject(b, o, l, actualType);
+        }
+        
+        @Override
+        public boolean isCastableTo(PDataType targetType) {
+            return TIMESTAMP.isCastableTo(targetType);
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == TIMESTAMP || targetType == VARBINARY || targetType == BINARY;
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return TIMESTAMP.getByteSize();
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            return TIMESTAMP.compareTo(lhs, rhs, rhsType);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            return TIMESTAMP.toObject(value);
+        }
+        
+        @Override
+        public String toStringLiteral(byte[] b, int offset, int length, Format formatter) {
+            Timestamp value = (Timestamp)toObject(b,offset,length);
+            if (formatter == null || formatter == DateUtil.DEFAULT_DATE_FORMATTER) {
+                // If default formatter has not been overridden,
+                // use one that displays milliseconds.
+                formatter = DateUtil.DEFAULT_MS_DATE_FORMATTER;
+            }
+            return "'" + super.toStringLiteral(b, offset, length, formatter) + "." + value.getNanos() + "'";
+        }
+        
+        @Override
+        public int getNanos(ImmutableBytesWritable ptr, ColumnModifier cm) {
+            int nanos = PDataType.UNSIGNED_INT.getCodec().decodeInt(ptr.get(), ptr.getOffset() + PDataType.LONG.getByteSize(), cm);
+            return nanos;
+        }
+        
+        @Override
+        public long getMillis(ImmutableBytesWritable ptr, ColumnModifier cm) {
+            long millis = PDataType.UNSIGNED_LONG.getCodec().decodeLong(ptr.get(),ptr.getOffset(), cm);
+            return millis;
+        }
+    },
+    UNSIGNED_TIME("UNSIGNED_TIME", 18, Time.class, new UnsignedDateCodec()) {
+
+        @Override
+        public byte[] toBytes(Object object) {
+            return UNSIGNED_DATE.toBytes(object);
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            return UNSIGNED_DATE.toBytes(object, bytes, offset);
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            return TIME.toObject(b, o, l, actualType);
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            return TIME.toObject(object, actualType);
+        }
+
+        @Override
+        public boolean isCastableTo(PDataType targetType) {
+            return TIME.isCastableTo(targetType);
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == TIME || targetType == UNSIGNED_DATE || targetType == DATE || targetType == UNSIGNED_TIMESTAMP || targetType == TIMESTAMP
+                    || targetType == VARBINARY || targetType == BINARY;
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return Bytes.SIZEOF_LONG;
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            return TIME.compareTo(lhs, rhs, rhsType);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            return TIME.toObject(value);
+        }
+
+        @Override
+        public boolean isBytesComparableWith(PDataType otherType) {
+            return super.isBytesComparableWith(otherType) ||  this == UNSIGNED_DATE;
+        }
+        
+        @Override
+        public String toStringLiteral(byte[] b, int offset, int length, Format formatter) {
+            return UNSIGNED_DATE.toStringLiteral(b, offset, length, formatter);
+        }
+    },
+    UNSIGNED_DATE("UNSIGNED_DATE", 19, Date.class, new UnsignedDateCodec()) { // After TIMESTAMP and DATE to ensure toLiteral finds those first
+
+        @Override
+        public byte[] toBytes(Object object) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            byte[] bytes = new byte[getByteSize()];
+            toBytes(object, bytes, 0);
+            return bytes;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] bytes, int offset) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            getCodec().encodeLong(((java.util.Date)object).getTime(), bytes, offset);
+            return this.getByteSize();
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            return DATE.toObject(object, actualType);
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            return DATE.toObject(b,o,l,actualType);
+        }
+
+        @Override
+        public boolean isCastableTo(PDataType targetType) {
+            return DATE.isCastableTo(targetType);
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == DATE || targetType == UNSIGNED_TIME || targetType == TIME || targetType == UNSIGNED_TIMESTAMP || targetType == TIMESTAMP
+                    || targetType == VARBINARY || targetType == BINARY;
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return DATE.getByteSize();
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            return DATE.compareTo(lhs, rhs, rhsType);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            return DATE.toObject(value);
+        }
+
+        @Override
+        public boolean isBytesComparableWith(PDataType otherType) {
+            return super.isBytesComparableWith(otherType) || this == UNSIGNED_TIME;
+        }
+        
+        @Override
+        public String toStringLiteral(byte[] b, int offset, int length, Format formatter) {
+            // Can't delegate, as the super.toStringLiteral calls this.toBytes
+            if (formatter == null || formatter == DateUtil.DEFAULT_DATE_FORMATTER) {
+                // If default formatter has not been overridden,
+                // use one that displays milliseconds.
+                formatter = DateUtil.DEFAULT_MS_DATE_FORMATTER;
+            }
+            return "'" + super.toStringLiteral(b, offset, length, formatter) + "'";
+        }
+        
+        @Override
+        public void coerceBytes(ImmutableBytesWritable ptr, PDataType actualType, ColumnModifier actualModifier, ColumnModifier expectedModifier) {
+            if (ptr.getLength() > 0 && actualType  == PDataType.UNSIGNED_TIMESTAMP && actualModifier == expectedModifier) {
+                ptr.set(ptr.get(), ptr.getOffset(), getByteSize());
+                return;
+            }
+            super.coerceBytes(ptr, actualType, actualModifier, expectedModifier);
+        }
+    },
+    /**
+     * Unsigned long type that restricts values to be from 0 to {@link java.lang.Long#MAX_VALUE} inclusive. May be used to map to existing HTable values created through {@link org.apache.hadoop.hbase.util.Bytes#toBytes(long)}
+     * as long as all values are non negative (the leading sign bit of negative numbers would cause them to sort ahead of positive numbers when
+     * they're used as part of the row key when using the HBase utility methods).
+     */
+    UNSIGNED_LONG("UNSIGNED_LONG", 10 /* no constant available in Types */, Long.class, new UnsignedLongCodec()) {
+
+        @Override
+        public byte[] toBytes(Object object) {
+            byte[] b = new byte[Bytes.SIZEOF_LONG];
+            toBytes(object, b, 0);
+            return b;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] b, int o) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            return this.getCodec().encodeLong(((Number)object).longValue(), b, o);
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            if (object == null) {
+                return null;
+            }
+            switch (actualType) {
+            case LONG:
+            case UNSIGNED_LONG:
+                long v = (Long) object;
+                if (v < 0) {
+                    throw new IllegalDataException("Value may not be negative(" + v + ")");
+                }
+                return v;
+            case UNSIGNED_INT:
+            case INTEGER:
+                v = (Integer) object;
+                if (v < 0) {
+                    throw new IllegalDataException("Value may not be negative(" + v + ")");
+                }
+                return v;
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+                v = (Short) object;
+                if (v < 0) {
+                    throw new IllegalDataException("Value may not be negative(" + v + ")");
+                }
+                return v;
+            case UNSIGNED_TINYINT:
+            case TINYINT:
+                v = (Byte) object;
+                if (v < 0) {
+                    throw new IllegalDataException("Value may not be negative(" + v + ")");
+                }
+                return v;
+            case UNSIGNED_FLOAT:
+            case FLOAT:
+                Float f = (Float) object;
+                v = f.longValue();
+                if (v < 0) {
+                    throw new IllegalDataException("Value may not be negative(" + v + ")");
+                }
+                return v;
+            case UNSIGNED_DOUBLE:
+            case DOUBLE:
+                Double de = (Double) object;
+                v = de.longValue();
+                if (v < 0) {
+                    throw new IllegalDataException("Value may not be negative(" + v + ")");
+                }
+                return v;
+            case DECIMAL:
+                BigDecimal d = (BigDecimal) object;
+                if (d.signum() == -1) {
+                    throw new IllegalDataException("Value may not be negative(" + d + ")");
+                }
+                return d.longValueExact();
+            default:
+                return super.toObject(object, actualType);
+            }
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            if (l == 0) {
+                return null;
+            }
+            switch (actualType) {
+            case INTEGER:
+            case LONG:
+            case UNSIGNED_LONG:
+            case UNSIGNED_INT:
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+            case TINYINT:
+            case UNSIGNED_TINYINT:
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+                return actualType.getCodec().decodeLong(b, o, null);
+            default:
+                return super.toObject(b,o,l,actualType);
+            }
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == LONG || targetType == DECIMAL
+                    || targetType == VARBINARY || targetType == BINARY 
+                    || targetType == FLOAT || targetType == DOUBLE || targetType == UNSIGNED_FLOAT
+                    || targetType == UNSIGNED_DOUBLE;
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (value != null) {
+                switch (targetType) {
+                    case UNSIGNED_INT:
+                    case INTEGER:
+                        long l = (Long) value;
+                        return (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE);
+                    case UNSIGNED_SMALLINT:
+                    case SMALLINT:
+                        long s = (Long)value;
+                        return (s>=Short.MIN_VALUE && s<=Short.MAX_VALUE);
+                    case TINYINT:
+                        long t = (Long)value;
+                        return (t>=Byte.MIN_VALUE && t<=Byte.MAX_VALUE);
+                    case UNSIGNED_TINYINT:
+                        t = (Long)value;
+                        return (t>=0 && t<=Byte.MAX_VALUE);
+                    default:
+                        break;
+                }
+            }
+            return super.isCoercibleTo(targetType, value);
+        }
+
+        @Override
+        public boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public Integer getByteSize() {
+            return Bytes.SIZEOF_LONG;
+        }
+
+        @Override
+        public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+            if (rhsType == DECIMAL) {
+                return -((BigDecimal)rhs).compareTo(BigDecimal.valueOf(((Number)lhs).longValue()));
+            } else if (rhsType == DOUBLE || rhsType == FLOAT || rhsType == UNSIGNED_DOUBLE || rhsType == UNSIGNED_FLOAT) {
+                return Doubles.compare(((Number)lhs).doubleValue(), ((Number)rhs).doubleValue());
+            }
+            return Longs.compare(((Number)lhs).longValue(), ((Number)rhs).longValue());
+        }
+
+        @Override
+        public boolean isComparableTo(PDataType targetType) {
+            return DECIMAL.isComparableTo(targetType);
+        }
+
+        @Override
+        public Object toObject(String value) {
+            if (value == null || value.length() == 0) {
+                return null;
+            }
+            try {
+                Long l = Long.parseLong(value);
+                if (l.longValue() < 0) {
+                    throw new IllegalDataException("Value may not be negative(" + l + ")");
+                }
+                return l;
+            } catch (NumberFormatException e) {
+                throw new IllegalDataException(e);
+            }
+        }
+        
+        @Override
+        public int getResultSetSqlType() {
+            return LONG.getResultSetSqlType();
+        }
+    },
+    /**
+     * Unsigned integer type that restricts values to be from 0 to {@link java.lang.Integer#MAX_VALUE} inclusive. May be used to map to existing HTable values created through {@link org.apache.hadoop.hbase.util.Bytes#toBytes(int)}
+     * as long as all values are non negative (the leading sign bit of negative numbers would cause them to sort ahead of positive numbers when
+     * they're used as part of the row key when using the HBase utility methods).
+     */
+    UNSIGNED_INT("UNSIGNED_INT", 9 /* no constant available in Types */, Integer.class, new UnsignedIntCodec()) {
+
+        @Override
+        public byte[] toBytes(Object object) {
+            byte[] b = new byte[Bytes.SIZEOF_INT];
+            toBytes(object, b, 0);
+            return b;
+        }
+
+        @Override
+        public int toBytes(Object object, byte[] b, int o) {
+            if (object == null) {
+                throw new ConstraintViolationException(this + " may not be null");
+            }
+            return this.getCodec().encodeInt(((Number)object).intValue(), b, o);
+        }
+
+        @Override
+        public Object toObject(Object object, PDataType actualType) {
+            Object o = UNSIGNED_LONG.toObject(object, actualType);
+            if(!(o instanceof Long) || o == null) {
+                return o;
+            }
+            long l = (Long)o;
+            if (l > Integer.MAX_VALUE) {
+                throw new IllegalDataException(actualType + " value " + l + " cannot be cast to Unsigned Integer without changing its value");
+            }
+            return (int)l;
+        }
+
+        @Override
+        public Object toObject(byte[] b, int o, int l, PDataType actualType) {
+            if (l == 0) {
+                return null;
+            }
+            switch (actualType) {
+            case UNSIGNED_LONG:
+            case LONG:
+            case UNSIGNED_INT:
+            case INTEGER:
+            case SMALLINT:
+            case UNSIGNED_SMALLINT:
+            case TINYINT:
+            case UNSIGNED_TINYINT:
+            case FLOAT:
+            case UNSIGNED_FLOAT:
+            case DOUBLE:
+            case UNSIGNED_DOUBLE:
+                return actualType.getCodec().decodeInt(b, o, null);
+            default:
+                return super.toObject(b,o,l,actualType);
+            }
+        }
+
+        @Override
+        public boolean isCoercibleTo(PDataType targetType) {
+            return this == targetType || targetType == INTEGER || UNSIGNED_LONG.isCoercibleTo(targetType);
+        }
+        
+        @Override
+        public boolean isCoercibleTo(PDataType targetType, Object value) {
+            if (value != null) {
+                switch (targetType) {
+                    case UNSIGNED_SMALLINT:
+           

<TRUNCATED>