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>