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 2016/09/08 19:29:34 UTC

[3/3] phoenix git commit: PHOENIX-2946 Projected comparison between date and timestamp columns always returns true

PHOENIX-2946 Projected comparison between date and timestamp columns always returns true


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/aa05da8a
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/aa05da8a
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/aa05da8a

Branch: refs/heads/4.8-HBase-0.98
Commit: aa05da8aed42d9a2e45dc239ec6246c382782267
Parents: fbda580
Author: James Taylor <ja...@apache.org>
Authored: Wed Sep 7 20:18:04 2016 -0700
Committer: James Taylor <ja...@apache.org>
Committed: Thu Sep 8 12:29:02 2016 -0700

----------------------------------------------------------------------
 .../expression/function/CeilDateExpression.java |   3 +
 .../function/CeilTimestampExpression.java       |   3 +
 .../expression/function/DateScalarFunction.java |  54 ++
 .../expression/function/DayOfMonthFunction.java |   4 +-
 .../expression/function/HourFunction.java       |   4 +-
 .../expression/function/MinuteFunction.java     |   4 +-
 .../expression/function/MonthFunction.java      |   4 +-
 .../function/RoundDateExpression.java           |   3 +
 .../function/RoundJodaDateExpression.java       |   3 +
 .../expression/function/SecondFunction.java     |   4 +-
 .../expression/function/ToDateFunction.java     |  10 +-
 .../expression/function/WeekFunction.java       |   4 +-
 .../expression/function/YearFunction.java       |   4 +-
 .../phoenix/jdbc/PhoenixPreparedStatement.java  |  26 +-
 .../org/apache/phoenix/schema/SortOrder.java    |  11 +
 .../apache/phoenix/schema/types/PDataType.java  |  19 +-
 .../org/apache/phoenix/schema/types/PDate.java  | 283 +++++-----
 .../apache/phoenix/schema/types/PDecimal.java   |   6 +-
 .../org/apache/phoenix/schema/types/PLong.java  | 519 ++++++++++---------
 .../org/apache/phoenix/schema/types/PTime.java  |   2 +-
 .../apache/phoenix/schema/types/PTimestamp.java |  42 +-
 .../phoenix/schema/types/PUnsignedDate.java     | 259 +++++----
 .../phoenix/schema/types/PUnsignedLong.java     | 317 +++++------
 .../phoenix/schema/types/PUnsignedTime.java     |   2 +-
 .../schema/types/PUnsignedTimestamp.java        | 152 ++----
 .../java/org/apache/phoenix/util/DateUtil.java  |  22 +
 .../phoenix/util/csv/CsvUpsertExecutor.java     |   8 +-
 .../phoenix/schema/types/PDataTypeTest.java     |  18 +
 28 files changed, 969 insertions(+), 821 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDateExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDateExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDateExpression.java
index e3cd985..7629409 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDateExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDateExpression.java
@@ -93,6 +93,9 @@ public class CeilDateExpression extends RoundDateExpression {
     @Override
     public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
         if (children.get(0).evaluate(tuple, ptr)) {
+            if (ptr.getLength() == 0) {
+                return true; // child evaluated to null
+            }
             PDataType dataType = getDataType();
             long time = dataType.getCodec().decodeLong(ptr, children.get(0).getSortOrder());
             long value = roundTime(time);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilTimestampExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilTimestampExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilTimestampExpression.java
index f69f2f8..b3a2a97 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilTimestampExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilTimestampExpression.java
@@ -97,6 +97,9 @@ public class CeilTimestampExpression extends CeilDateExpression {
     @Override
     public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
         if (children.get(0).evaluate(tuple, ptr)) {
+            if (ptr.getLength() == 0) {
+                return true; // child evaluated to null
+            }
             SortOrder sortOrder = children.get(0).getSortOrder();
             PDataType dataType = getDataType();
             int nanos = dataType.getNanos(ptr, sortOrder);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DateScalarFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DateScalarFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DateScalarFunction.java
new file mode 100644
index 0000000..aa56a0f
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DateScalarFunction.java
@@ -0,0 +1,54 @@
+/*
+ * 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.expression.function;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PDataType.PDataCodec;
+import org.apache.phoenix.util.DateUtil;
+
+public abstract class DateScalarFunction extends ScalarFunction {
+    protected PDataCodec inputCodec;
+
+    public DateScalarFunction() {
+    }
+
+    public DateScalarFunction(List<Expression> children) {
+        super(children);
+        init();
+    }
+
+    protected final PDataCodec getInputCodec() {
+        return inputCodec;
+    }
+    
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        init();
+    }
+    
+    private void init() {
+        PDataType returnType = getChildren().get(0).getDataType();
+        inputCodec = DateUtil.getCodecFor(returnType);
+    }
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java
index 0c328cf..fb5a68a 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java
@@ -38,7 +38,7 @@ import org.joda.time.DateTime;
  */
 @BuiltInFunction(name=DayOfMonthFunction.NAME, 
 args={@Argument(allowedTypes={PTimestamp.class})})
-public class DayOfMonthFunction extends ScalarFunction {
+public class DayOfMonthFunction extends DateScalarFunction {
     public static final String NAME = "DAYOFMONTH";
 
     public DayOfMonthFunction() {
@@ -57,7 +57,7 @@ public class DayOfMonthFunction extends ScalarFunction {
         if ( ptr.getLength() == 0) {
             return true; //means null
         }
-        long dateTime = expression.getDataType().getCodec().decodeLong(ptr, expression.getSortOrder());
+        long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
         DateTime dt = new DateTime(dateTime);
         int day = dt.getDayOfMonth();
         PDataType returnType = getDataType();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java
index 0e9efd8..7b9c8c0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java
@@ -37,7 +37,7 @@ import org.apache.phoenix.schema.types.PTimestamp;
  */
 @BuiltInFunction(name=HourFunction.NAME, 
 args={@Argument(allowedTypes={PTimestamp.class})})
-public class HourFunction extends ScalarFunction {
+public class HourFunction extends DateScalarFunction {
     public static final String NAME = "HOUR";
 
     public HourFunction() {
@@ -56,7 +56,7 @@ public class HourFunction extends ScalarFunction {
         if ( ptr.getLength() == 0) {
             return true; //means null
         }
-        long dateTime = expression.getDataType().getCodec().decodeLong(ptr, expression.getSortOrder());
+        long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
         int hour = (int)(((dateTime/1000) % (24*3600))/3600);
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java
index fc721fc..6766e35 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java
@@ -37,7 +37,7 @@ import org.apache.phoenix.schema.types.PTimestamp;
  */
 @BuiltInFunction(name=MinuteFunction.NAME, 
 args={@Argument(allowedTypes={PTimestamp.class})})
-public class MinuteFunction extends ScalarFunction {
+public class MinuteFunction extends DateScalarFunction {
     public static final String NAME = "MINUTE";
 
     public MinuteFunction() {
@@ -56,7 +56,7 @@ public class MinuteFunction extends ScalarFunction {
         if ( ptr.getLength() == 0) {
             return true; //means null
         }
-        long dateTime = expression.getDataType().getCodec().decodeLong(ptr, expression.getSortOrder());
+        long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
         int minute = (int)(((dateTime/1000) % 3600)/60);
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java
index 5ad6c34..bd6ff3e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java
@@ -38,7 +38,7 @@ import org.joda.time.DateTime;
  */
 @BuiltInFunction(name=MonthFunction.NAME, 
 args={@Argument(allowedTypes={PTimestamp.class})})
-public class MonthFunction extends ScalarFunction {
+public class MonthFunction extends DateScalarFunction {
     public static final String NAME = "MONTH";
 
     public MonthFunction() {
@@ -57,7 +57,7 @@ public class MonthFunction extends ScalarFunction {
         if ( ptr.getLength() == 0) {
             return true; //means null
         }
-        long dateTime = expression.getDataType().getCodec().decodeLong(ptr, expression.getSortOrder());
+        long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
         DateTime dt = new DateTime(dateTime);
         int month = dt.getMonthOfYear();
         PDataType returnType = getDataType();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java
index e2483ac..a80d745 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java
@@ -151,6 +151,9 @@ public class RoundDateExpression extends ScalarFunction {
     @Override
     public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
         if (children.get(0).evaluate(tuple, ptr)) {
+            if (ptr.getLength() == 0) {
+                return true; // child evaluated to null
+            }
             PDataType dataType = getDataType();
             long time = dataType.getCodec().decodeLong(ptr, children.get(0).getSortOrder());
             long value = roundTime(time);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
index 0dba80b..356c85f 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
@@ -43,6 +43,9 @@ public abstract class RoundJodaDateExpression extends RoundDateExpression{
     @Override
     public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
         if (children.get(0).evaluate(tuple, ptr)) {
+            if (ptr.getLength() == 0) {
+                return true; // child evaluated to null
+            }
             PDataType dataType = getDataType();
             long time = dataType.getCodec().decodeLong(ptr, children.get(0).getSortOrder());
             DateTime dt = new DateTime(time,ISOChronology.getInstanceUTC());

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java
index 5f39786..02bc455 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java
@@ -37,7 +37,7 @@ import org.apache.phoenix.schema.types.PTimestamp;
  */
 @BuiltInFunction(name=SecondFunction.NAME, 
 args={@Argument(allowedTypes={PTimestamp.class})})
-public class SecondFunction extends ScalarFunction {
+public class SecondFunction extends DateScalarFunction {
     public static final String NAME = "SECOND";
 
     public SecondFunction() {
@@ -56,7 +56,7 @@ public class SecondFunction extends ScalarFunction {
         if ( ptr.getLength() == 0) {
             return true; //means null
         }
-        long dateTime = expression.getDataType().getCodec().decodeLong(ptr, expression.getSortOrder());
+        long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
         int sec = (int)((dateTime/1000) % 60);
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
index 17f6847..1930d92 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
@@ -32,6 +32,7 @@ import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
 import org.apache.phoenix.parse.ToDateParseNode;
 import org.apache.phoenix.schema.tuple.Tuple;
 import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PDataType.PDataCodec;
 import org.apache.phoenix.schema.types.PDate;
 import org.apache.phoenix.schema.types.PVarchar;
 import org.apache.phoenix.util.DateUtil;
@@ -53,6 +54,7 @@ import org.apache.phoenix.util.DateUtil;
 public class ToDateFunction extends ScalarFunction {
     public static final String NAME = "TO_DATE";
     private DateUtil.DateTimeParser dateParser;
+    private PDataCodec codec;
     protected String dateFormat;
     protected String timeZoneId;
 
@@ -80,6 +82,7 @@ public class ToDateFunction extends ScalarFunction {
         // server to evaluate using the local time zone. Instead, we want
         // to use the client local time zone.
         this.timeZoneId = this.dateParser.getTimeZone().getID();
+        this.codec = DateUtil.getCodecFor(getDataType());
     }
 
     @Override
@@ -110,15 +113,18 @@ public class ToDateFunction extends ScalarFunction {
     @Override
     public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
         Expression expression = getExpression();
-        if (!expression.evaluate(tuple, ptr) || ptr.getLength() == 0) {
+        if (!expression.evaluate(tuple, ptr)) {
             return false;
         }
+        if (ptr.getLength() == 0) {
+            return true;
+        }
         PDataType type = expression.getDataType();
         String dateStr = (String)type.toObject(ptr, expression.getSortOrder());
         long epochTime = dateParser.parseDateTime(dateStr);
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];
-        returnType.getCodec().encodeLong(epochTime, byteValue, 0);
+        codec.encodeLong(epochTime, byteValue, 0);
         ptr.set(byteValue);
         return true;
      }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java
index 126aba8..3f6d772 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java
@@ -38,7 +38,7 @@ import org.joda.time.DateTime;
  */
 @BuiltInFunction(name=WeekFunction.NAME, 
 args={@Argument(allowedTypes={PTimestamp.class})})
-public class WeekFunction extends ScalarFunction {
+public class WeekFunction extends DateScalarFunction {
     public static final String NAME = "WEEK";
 
     public WeekFunction() {
@@ -57,7 +57,7 @@ public class WeekFunction extends ScalarFunction {
         if ( ptr.getLength() == 0) {
             return true; //means null
         }
-        long dateTime = expression.getDataType().getCodec().decodeLong(ptr, expression.getSortOrder());
+        long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
         DateTime dt = new DateTime(dateTime);
         int week = dt.getWeekOfWeekyear();
         PDataType returnType = getDataType();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java
index f1958e1..fcab8d2 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java
@@ -37,7 +37,7 @@ import org.joda.time.DateTime;
  */
 @BuiltInFunction(name=YearFunction.NAME, 
 args={@Argument(allowedTypes={PTimestamp.class})})
-public class YearFunction extends ScalarFunction {
+public class YearFunction extends DateScalarFunction {
     public static final String NAME = "YEAR";
 
     public YearFunction() {
@@ -56,7 +56,7 @@ public class YearFunction extends ScalarFunction {
         if ( ptr.getLength() == 0) {
             return true; //means null
         }
-        long dateTime = expression.getDataType().getCodec().decodeLong(ptr, expression.getSortOrder());
+        long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
         DateTime dt = new DateTime(dateTime);
         int year = dt.getYear();
         PDataType returnType = getDataType();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixPreparedStatement.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixPreparedStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixPreparedStatement.java
index 9c6a94b..9bba3d3 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixPreparedStatement.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixPreparedStatement.java
@@ -361,11 +361,17 @@ public class PhoenixPreparedStatement extends PhoenixStatement implements Prepar
 
     @Override
     public void setDate(int parameterIndex, Date x) throws SQLException {
+        if (x != null) { // Since Date is mutable, make a copy
+            x = new Date(x.getTime());
+        }
         setParameter(parameterIndex, x);
     }
 
     @Override
     public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
+        if (x != null) { // Since Date is mutable, make a copy
+            x = new Date(x.getTime());
+        }
         cal.setTime(x);
         setParameter(parameterIndex, new Date(cal.getTimeInMillis()));
     }
@@ -475,23 +481,39 @@ public class PhoenixPreparedStatement extends PhoenixStatement implements Prepar
 
     @Override
     public void setTime(int parameterIndex, Time x) throws SQLException {
+        if (x != null) { // Since Time is mutable, make a copy
+            x = new Time(x.getTime());
+        }
         setParameter(parameterIndex, x);
     }
 
     @Override
     public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
+        if (x != null) { // Since Time is mutable, make a copy
+            x = new Time(x.getTime());
+        }
         cal.setTime(x);
         setParameter(parameterIndex, new Time(cal.getTimeInMillis()));
     }
 
+    private void setTimestampParameter(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
+        if (x != null) { // Since Timestamp is mutable, make a copy
+            int nanos = x.getNanos();
+            x = new Timestamp(x.getTime());
+            x.setNanos(nanos);
+        }
+        // TODO: deal with Calendar
+        setParameter(parameterIndex, x);
+    }
+    
     @Override
     public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
-        setParameter(parameterIndex, x);
+        setTimestampParameter(parameterIndex, x, null);
     }
 
     @Override
     public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
-        setParameter(parameterIndex,  x);
+        setTimestampParameter(parameterIndex, x, cal);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/schema/SortOrder.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/SortOrder.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/SortOrder.java
index 91b6cd0..1d32a06 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/SortOrder.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/SortOrder.java
@@ -55,6 +55,11 @@ public enum SortOrder {
 		public CompareOp transform(CompareOp op) {
 			return op;
 		}
+
+        @Override
+        public byte normalize(byte b) {
+            return b;
+        }
 	},
 
 	DESC(1) {
@@ -71,6 +76,11 @@ public enum SortOrder {
 			}
 			throw new IllegalArgumentException("Add the missing case statement!");
 		}
+
+        @Override
+        public byte normalize(byte b) {
+            return SortOrder.invert(b);
+        }
 	};
 	
 	/**
@@ -137,4 +147,5 @@ public enum SortOrder {
 	}
 
 	public abstract CompareOp transform(CompareOp op);
+    public abstract byte normalize(byte b);
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDataType.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDataType.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDataType.java
index 0f0328a..5d611e9 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDataType.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDataType.java
@@ -89,8 +89,7 @@ public abstract class PDataType<T> implements DataType<T>, Comparable<PDataType<
     }
 
     public boolean isBytesComparableWith(PDataType otherType) {
-        return this == otherType || this.getClass() == PVarbinary.class || otherType == PVarbinary.INSTANCE
-                || this.getClass() == PBinary.class || otherType == PBinary.INSTANCE;
+        return equalsAny(this, otherType, PVarbinary.INSTANCE, PBinary.INSTANCE);
     }
 
     public int estimateByteSize(Object o) {
@@ -151,6 +150,18 @@ public abstract class PDataType<T> implements DataType<T>, Comparable<PDataType<
             // Special case as we may be comparing two arrays that have different separator characters due to PHOENIX-2067
             if (!this.isArrayType() || !rhsType.isArrayType() || 
                     PArrayDataType.isRowKeyOrderOptimized(this, lhsSortOrder, lhs, lhsOffset, lhsLength) == PArrayDataType.isRowKeyOrderOptimized(rhsType, rhsSortOrder, rhs, rhsOffset, rhsLength)) {
+                // Ignore trailing zero bytes if fixed byte length (for example TIMESTAMP compared to DATE)
+                if (lhsLength != rhsLength && this.isFixedWidth() && rhsType.isFixedWidth() && this.getByteSize() != null && rhsType.getByteSize() != null) {
+                    if (lhsLength > rhsLength) {
+                        int minOffset = lhsOffset + rhsLength;
+                        for (int i = lhsOffset + lhsLength - 1; i >= minOffset && lhsSortOrder.normalize(lhs[i]) == 0; i--,lhsLength--) {
+                        }
+                    } else {
+                        int minOffset = rhsOffset + lhsLength;
+                        for (int i = rhsOffset + rhsLength - 1; i >= minOffset && rhsSortOrder.normalize(rhs[i]) == 0; i--,rhsLength--) {
+                        }
+                    }
+                }
                 return compareTo(lhs, lhsOffset, lhsLength, lhsSortOrder, rhs, rhsOffset, rhsLength, rhsSortOrder);
             }
         }
@@ -196,8 +207,8 @@ public abstract class PDataType<T> implements DataType<T>, Comparable<PDataType<
             return Bytes.compareTo(lhsConverted, 0, lhsConverted.length, rhs, rhsOffset, rhsLength);
         }
         // convert to native and compare
-        if (this.isCoercibleTo(PLong.INSTANCE) && rhsType.isCoercibleTo(PLong.INSTANCE)) { // native long to long
-                                                                                           // comparison
+        if ( (this.isCoercibleTo(PLong.INSTANCE) || this.isCoercibleTo(PDate.INSTANCE)) && 
+             (rhsType.isCoercibleTo(PLong.INSTANCE) || rhsType.isCoercibleTo(PDate.INSTANCE)) ) {
             return Longs.compare(this.getCodec().decodeLong(lhs, lhsOffset, lhsSortOrder), rhsType.getCodec()
                     .decodeLong(rhs, rhsOffset, rhsSortOrder));
         } else if (isDoubleOrFloat(this) && isDoubleOrFloat(rhsType)) { // native double to double comparison

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java
index c27d0fc..d70a658 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java
@@ -30,122 +30,124 @@ import org.apache.phoenix.util.StringUtil;
 
 public class PDate extends PDataType<Date> {
 
-  public static final PDate INSTANCE = new PDate();
-
-  private PDate() {
-    super("DATE", Types.DATE, Date.class,
-        new DateCodec(), 11); // After TIMESTAMP and DATE to ensure toLiteral finds those first
-  }
-
-  @Override
-  public byte[] toBytes(Object object) {
-    byte[] bytes = new byte[getByteSize()];
-    toBytes(object, bytes, 0);
-    return bytes;
-  }
-
-  @Override
-  public int toBytes(Object object, byte[] bytes, int offset) {
-    if (object == null) {
-        getCodec().encodeLong(0l, bytes, offset);
+    public static final PDate INSTANCE = new PDate();
+
+    private PDate() {
+        super("DATE", Types.DATE, Date.class,
+                new DateCodec(), 11); // After TIMESTAMP and DATE to ensure toLiteral finds those first
+    }
+
+    @Override
+    public byte[] toBytes(Object object) {
+        byte[] bytes = new byte[getByteSize()];
+        toBytes(object, bytes, 0);
+        return bytes;
+    }
+
+    @Override
+    public int toBytes(Object object, byte[] bytes, int offset) {
+        if (object == null) {
+            getCodec().encodeLong(0l, bytes, offset);
+            return this.getByteSize();
+        }
+        getCodec().encodeLong(((java.util.Date) object).getTime(), bytes, offset);
         return this.getByteSize();
     }
-    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;
-    }
-    if (equalsAny(actualType, PTime.INSTANCE, PUnsignedTime.INSTANCE)) {
-      return new Date(((java.sql.Time) object).getTime());
-    } else if (equalsAny(actualType, PTimestamp.INSTANCE, PUnsignedTimestamp.INSTANCE)) {
-      return new Date(((java.sql.Timestamp) object).getTime());
-    } else if (equalsAny(actualType, PDate.INSTANCE, PUnsignedDate.INSTANCE)) {
-      return object;
-    } else if (equalsAny(actualType, PLong.INSTANCE, PUnsignedLong.INSTANCE)) {
-      return new Date((Long) object);
-    } else if (actualType == PDecimal.INSTANCE) {
-      return new Date(((BigDecimal) object).longValueExact());
-    } else if (actualType == PVarchar.INSTANCE) {
-      return DateUtil.parseDate((String) object);
-    }
-    return throwConstraintViolationException(actualType, this);
-  }
-
-  @Override
-  public Date toObject(byte[] b, int o, int l, PDataType actualType, SortOrder sortOrder, Integer maxLength, Integer scale) {
-    if (l == 0) {
-      return null;
-    }
-    if (equalsAny(actualType, PTimestamp.INSTANCE, PUnsignedTimestamp.INSTANCE, PDate.INSTANCE,
-        PUnsignedDate.INSTANCE, PTime.INSTANCE, PUnsignedTime.INSTANCE, PLong.INSTANCE,
-        PUnsignedLong.INSTANCE)) {
-      return new Date(actualType.getCodec().decodeLong(b, o, sortOrder));
-    } else if (actualType == PDecimal.INSTANCE) {
-      BigDecimal bd = (BigDecimal) actualType.toObject(b, o, l, actualType, sortOrder);
-      return new Date(bd.longValueExact());
-    }
-    throwConstraintViolationException(actualType, this);
-    return null;
-  }
-
-  @Override
-  public boolean isCastableTo(PDataType targetType) {
-    return super.isCastableTo(targetType) ||
-            equalsAny(targetType, PDecimal.INSTANCE, PLong.INSTANCE, PUnsignedLong.INSTANCE);
-  }
-
-  @Override
-  public boolean isCoercibleTo(PDataType targetType) {
-    return equalsAny(targetType, PDate.INSTANCE, PTime.INSTANCE, PTimestamp.INSTANCE, PVarbinary.INSTANCE, PBinary.INSTANCE);
-  }
-
-  @Override
-  public boolean isCoercibleTo(PDataType targetType, Object value) {
-    if (value != null) {
-      if (equalsAny(targetType, PUnsignedTimestamp.INSTANCE, PUnsignedDate.INSTANCE,
-          PUnsignedTime.INSTANCE)) {
-        return ((java.util.Date) value).getTime() >= 0;
-      }
-    }
-    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 == PTimestamp.INSTANCE || rhsType == PUnsignedTimestamp.INSTANCE) {
-      return -rhsType.compareTo(rhs, lhs, PTime.INSTANCE);
-    }
-    return ((java.util.Date) lhs).compareTo((java.util.Date) rhs);
-  }
-
-  @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) || otherType == PTime.INSTANCE;
-  }
-
-  @Override
+
+    @Override
+    public Object toObject(Object object, PDataType actualType) {
+        if (object == null) {
+            return null;
+        }
+        if (equalsAny(actualType, PTime.INSTANCE, PUnsignedTime.INSTANCE)) {
+            return new Date(((java.sql.Time) object).getTime());
+        } else if (equalsAny(actualType, PTimestamp.INSTANCE, PUnsignedTimestamp.INSTANCE)) {
+            return new Date(((java.sql.Timestamp) object).getTime());
+        } else if (equalsAny(actualType, PDate.INSTANCE, PUnsignedDate.INSTANCE)) {
+            return object;
+        } else if (equalsAny(actualType, PLong.INSTANCE, PUnsignedLong.INSTANCE)) {
+            return new Date((Long) object);
+        } else if (actualType == PDecimal.INSTANCE) {
+            return new Date(((BigDecimal) object).longValueExact());
+        } else if (actualType == PVarchar.INSTANCE) {
+            return DateUtil.parseDate((String) object);
+        }
+        return throwConstraintViolationException(actualType, this);
+    }
+
+    @Override
+    public Date toObject(byte[] b, int o, int l, PDataType actualType, SortOrder sortOrder, Integer maxLength, Integer scale) {
+        if (l == 0) {
+            return null;
+        }
+        if (actualType.getCodec() != null ) {
+            return new Date(actualType.getCodec().decodeLong(b, o, sortOrder));
+        } else if (actualType == PTimestamp.INSTANCE) {
+            return new Date(PDate.INSTANCE.getCodec().decodeLong(b, o, sortOrder));
+        } else if (actualType == PUnsignedTimestamp.INSTANCE) {
+            return new Date(PUnsignedDate.INSTANCE.getCodec().decodeLong(b, o, sortOrder));
+        } else if (actualType == PDecimal.INSTANCE) {
+            BigDecimal bd = (BigDecimal) actualType.toObject(b, o, l, actualType, sortOrder);
+            return new Date(bd.longValueExact());
+        }
+        throwConstraintViolationException(actualType, this);
+        return null;
+    }
+
+    @Override
+    public boolean isCastableTo(PDataType targetType) {
+        return super.isCastableTo(targetType) ||
+                equalsAny(targetType, PDecimal.INSTANCE, PLong.INSTANCE, PUnsignedLong.INSTANCE);
+    }
+
+    @Override
+    public boolean isCoercibleTo(PDataType targetType) {
+        return equalsAny(targetType, PDate.INSTANCE, PTime.INSTANCE, PTimestamp.INSTANCE, PVarbinary.INSTANCE, PBinary.INSTANCE);
+    }
+
+    @Override
+    public boolean isCoercibleTo(PDataType targetType, Object value) {
+        if (value != null) {
+            if (equalsAny(targetType, PUnsignedTimestamp.INSTANCE, PUnsignedDate.INSTANCE,
+                    PUnsignedTime.INSTANCE)) {
+                return ((java.util.Date) value).getTime() >= 0;
+            }
+        }
+        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 == PTimestamp.INSTANCE || rhsType == PUnsignedTimestamp.INSTANCE) {
+            return -rhsType.compareTo(rhs, lhs, PTime.INSTANCE);
+        }
+        return ((java.util.Date) lhs).compareTo((java.util.Date) rhs);
+    }
+
+    @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) || otherType == PTime.INSTANCE || otherType == PTimestamp.INSTANCE || otherType == PLong.INSTANCE;
+    }
+
+    @Override
     public String toStringLiteral(Object o, Format formatter) {
         if (formatter == null) {
             // If default formatter has not been overridden,
@@ -156,40 +158,39 @@ public class PDate extends PDataType<Date> {
                 + StringUtil.escapeStringConstant(super.toStringLiteral(o, formatter)) + "'";
     }
 
-  @Override
-  public void coerceBytes(ImmutableBytesWritable ptr, Object object, PDataType actualType,
-      Integer maxLength, Integer scale, SortOrder actualModifier, Integer desiredMaxLength, Integer desiredScale,
-      SortOrder expectedModifier) {
-    if (ptr.getLength() > 0 && actualType == PTimestamp.INSTANCE
-        && actualModifier == expectedModifier) {
-      ptr.set(ptr.get(), ptr.getOffset(), getByteSize());
-      return;
+    @Override
+    public void coerceBytes(ImmutableBytesWritable ptr, Object object, PDataType actualType,
+            Integer maxLength, Integer scale, SortOrder actualModifier, Integer desiredMaxLength, Integer desiredScale,
+            SortOrder expectedModifier) {
+        // Decrease size of TIMESTAMP to size of DATE and continue coerce
+        if (ptr.getLength() > getByteSize()) {
+            ptr.set(ptr.get(), ptr.getOffset(), getByteSize());
+        }
+        super.coerceBytes(ptr, object, actualType, maxLength, scale, actualModifier, desiredMaxLength,
+                desiredScale, expectedModifier);
     }
-    super.coerceBytes(ptr, object, actualType, maxLength, scale, actualModifier, desiredMaxLength,
-        desiredScale, expectedModifier);
-  }
-
-  @Override
-  public Object getSampleValue(Integer maxLength, Integer arrayLength) {
-    return new Date((Long) PLong.INSTANCE.getSampleValue(maxLength, arrayLength));
-  }
-
-  static class DateCodec extends PLong.LongCodec {
 
     @Override
-    public int decodeInt(byte[] b, int o, SortOrder sortOrder) {
-      throw new UnsupportedOperationException();
+    public Object getSampleValue(Integer maxLength, Integer arrayLength) {
+        return new Date((Long) PLong.INSTANCE.getSampleValue(maxLength, arrayLength));
     }
 
-    @Override
-    public PhoenixArrayFactory getPhoenixArrayFactory() {
-      return new PhoenixArrayFactory() {
+    static class DateCodec extends PLong.LongCodec {
+
+        @Override
+        public int decodeInt(byte[] b, int o, SortOrder sortOrder) {
+            throw new UnsupportedOperationException();
+        }
 
         @Override
-        public PhoenixArray newArray(PDataType type, Object[] elements) {
-          return new PhoenixArray(type, elements);
+        public PhoenixArrayFactory getPhoenixArrayFactory() {
+            return new PhoenixArrayFactory() {
+
+                @Override
+                public PhoenixArray newArray(PDataType type, Object[] elements) {
+                    return new PhoenixArray(type, elements);
+                }
+            };
         }
-      };
     }
-  }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java
index ff6e186..17910de 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java
@@ -28,6 +28,7 @@ import org.apache.phoenix.query.QueryConstants;
 import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.schema.TypeMismatchException;
 import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.DateUtil;
 import org.apache.phoenix.util.NumberUtil;
 
 import com.google.common.base.Preconditions;
@@ -136,9 +137,8 @@ public class PDecimal extends PRealNumber<BigDecimal> {
       return BigDecimal.valueOf(actualType.getCodec().decodeFloat(b, o, sortOrder));
     } else if (equalsAny(actualType, PDouble.INSTANCE, PUnsignedDouble.INSTANCE)) {
       return BigDecimal.valueOf(actualType.getCodec().decodeDouble(b, o, sortOrder));
-    } else if (equalsAny(actualType, PTimestamp.INSTANCE,
-        PUnsignedTimestamp.INSTANCE)) {
-      long millisPart = actualType.getCodec().decodeLong(b, o, sortOrder);
+    } else if (equalsAny(actualType, PTimestamp.INSTANCE, PUnsignedTimestamp.INSTANCE)) {
+      long millisPart = DateUtil.getCodecFor(actualType).decodeLong(b, o, sortOrder);
       int nanoPart = PUnsignedInt.INSTANCE.getCodec().decodeInt(b, o + Bytes.SIZEOF_LONG, sortOrder);
       BigDecimal nanosPart = BigDecimal.valueOf(
           (nanoPart % QueryConstants.MILLIS_TO_NANOS_CONVERTOR)

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PLong.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PLong.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PLong.java
index 82fd8d3..2d6ff27 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PLong.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PLong.java
@@ -20,6 +20,7 @@ package org.apache.phoenix.schema.types;
 import java.math.BigDecimal;
 import java.sql.Types;
 
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.phoenix.schema.SortOrder;
 
@@ -29,304 +30,316 @@ import com.google.common.primitives.Longs;
 
 public class PLong extends PWholeNumber<Long> {
 
-  public static final PLong INSTANCE = new PLong();
+    public static final PLong INSTANCE = new PLong();
 
-  private PLong() {
-    super("BIGINT", Types.BIGINT, Long.class, new LongCodec(), 2);
-  }
-
-  @Override
-  public Integer getScale(Object o) {
-    return ZERO;
-  }
-
-  @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 newIllegalDataException(this + " may not be null");
+    private PLong() {
+        super("BIGINT", Types.BIGINT, Long.class, new LongCodec(), 2);
     }
-    return this.getCodec().encodeLong(((Number) object).longValue(), b, o);
-  }
 
-  @Override
-  public Object toObject(Object object, PDataType actualType) {
-    if (object == null) {
-      return null;
-    }
-    long s;
-    if (equalsAny(actualType, PLong.INSTANCE, PUnsignedLong.INSTANCE)) {
-      return object;
-    } else if (equalsAny(actualType, PUnsignedInt.INSTANCE,
-        PInteger.INSTANCE)) {
-      s = (Integer) object;
-      return s;
-    } else if (equalsAny(actualType, PTinyint.INSTANCE, PUnsignedTinyint.INSTANCE)) {
-      s = (Byte) object;
-      return s;
-    } else if (equalsAny(actualType, PSmallint.INSTANCE, PUnsignedSmallint.INSTANCE)) {
-      s = (Short) object;
-      return s;
-    } else if (equalsAny(actualType, PFloat.INSTANCE, PUnsignedFloat.INSTANCE)) {
-      Float f = (Float) object;
-      if (f > Long.MAX_VALUE || f < Long.MIN_VALUE) {
-        throw newIllegalDataException(
-            actualType + " value " + f + " cannot be cast to Long without changing its value");
-      }
-      s = f.longValue();
-      return s;
-    } else if (equalsAny(actualType, PDouble.INSTANCE, PUnsignedDouble.INSTANCE)) {
-      Double de = (Double) object;
-      if (de > Long.MAX_VALUE || de < Long.MIN_VALUE) {
-        throw newIllegalDataException(
-            actualType + " value " + de + " cannot be cast to Long without changing its value");
-      }
-      s = de.longValue();
-      return s;
-    } else if (actualType == PDecimal.INSTANCE) {
-      BigDecimal d = (BigDecimal) object;
-      return d.longValueExact();
-    } else if (equalsAny(actualType, PDate.INSTANCE, PUnsignedDate.INSTANCE, PTime.INSTANCE,
-        PUnsignedTime.INSTANCE)) {
-      java.util.Date date = (java.util.Date) object;
-      return date.getTime();
-    }
-    return throwConstraintViolationException(actualType, this);
-  }
-
-  @Override
-  public Long toObject(byte[] b, int o, int l, PDataType actualType, SortOrder sortOrder,
-      Integer maxLength, Integer scale) {
-    if (l == 0) {
-      return null;
-    }
-    if (equalsAny(actualType, PLong.INSTANCE, PUnsignedLong.INSTANCE,
-        PInteger.INSTANCE, PUnsignedInt.INSTANCE, PSmallint.INSTANCE,
-        PUnsignedSmallint.INSTANCE, PTinyint.INSTANCE, PUnsignedTinyint.INSTANCE, PFloat.INSTANCE,
-        PUnsignedFloat.INSTANCE, PDouble.INSTANCE, PUnsignedDouble.INSTANCE, PDate.INSTANCE,
-        PUnsignedDate.INSTANCE, PTime.INSTANCE, PUnsignedTime.INSTANCE)) {
-      return actualType.getCodec().decodeLong(b, o, sortOrder);
-    } else if (actualType == PDecimal.INSTANCE) {
-      BigDecimal bd = (BigDecimal) actualType.toObject(b, o, l, actualType, sortOrder);
-      return bd.longValueExact();
-    }
-    throwConstraintViolationException(actualType, this);
-    return null;
-  }
-
-  @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 equalsAny(targetType, this, PDecimal.INSTANCE, PVarbinary.INSTANCE, PBinary.INSTANCE, PDouble.INSTANCE);
-  }
-
-  @Override
-  public boolean isComparableTo(PDataType targetType) {
-    return PDecimal.INSTANCE.isComparableTo(targetType);
-  }
-
-  @Override
-  public boolean isCoercibleTo(PDataType targetType, Object value) {
-    if (value != null) {
-      long l;
-      if (equalsAny(targetType, PUnsignedDouble.INSTANCE, PUnsignedFloat.INSTANCE,
-          PUnsignedLong.INSTANCE)) {
-        l = (Long) value;
-        return l >= 0;
-      } else if (targetType.equals(PUnsignedInt.INSTANCE)) {
-        l = (Long) value;
-        return (l >= 0 && l <= Integer.MAX_VALUE);
-      } else if (targetType.equals(PInteger.INSTANCE)) {
-        l = (Long) value;
-        return (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE);
-      } else if (targetType.equals(PUnsignedSmallint.INSTANCE)) {
-        l = (Long) value;
-        return (l >= 0 && l <= Short.MAX_VALUE);
-      } else if (targetType.equals(PSmallint.INSTANCE)) {
-        l = (Long) value;
-        return (l >= Short.MIN_VALUE && l <= Short.MAX_VALUE);
-      } else if (targetType.equals(PTinyint.INSTANCE)) {
-        l = (Long) value;
-        return (l >= Byte.MIN_VALUE && l <= Byte.MAX_VALUE);
-      } else if (targetType.equals(PUnsignedTinyint.INSTANCE)) {
-        l = (Long) value;
-        return (l >= 0 && l <= Byte.MAX_VALUE);
-      }
-    }
-    return super.isCoercibleTo(targetType, value);
-  }
-
-  @Override
-  public boolean isCastableTo(PDataType targetType) {
-    return super.isCastableTo(targetType) || targetType.isCoercibleTo(PTimestamp.INSTANCE);
-  }
-
-  @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 int compareTo(Object lhs, Object rhs, PDataType rhsType) {
-    if (rhsType == PDecimal.INSTANCE) {
-      return -((BigDecimal) rhs).compareTo(BigDecimal.valueOf(((Number) lhs).longValue()));
-    } else if (equalsAny(rhsType, PDouble.INSTANCE, PFloat.INSTANCE, PUnsignedDouble.INSTANCE, PUnsignedFloat.INSTANCE)) {
-      return Doubles.compare(((Number) lhs).doubleValue(), ((Number) rhs).doubleValue());
+    @Override
+    public Integer getScale(Object o) {
+        return ZERO;
     }
-    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 newIllegalDataException(e);
+    @Override
+    public byte[] toBytes(Object object) {
+        byte[] b = new byte[Bytes.SIZEOF_LONG];
+        toBytes(object, b, 0);
+        return b;
     }
-  }
 
-  @Override
-  public Object getSampleValue(Integer maxLength, Integer arrayLength) {
-    return RANDOM.get().nextLong();
-  }
+    @Override
+    public int toBytes(Object object, byte[] b, int o) {
+        if (object == null) {
+            throw newIllegalDataException(this + " may not be null");
+        }
+        return this.getCodec().encodeLong(((Number) object).longValue(), b, o);
+    }
 
-  static class LongCodec extends BaseCodec {
+    @Override
+    public Object toObject(Object object, PDataType actualType) {
+        if (object == null) {
+            return null;
+        }
+        long s;
+        if (equalsAny(actualType, PLong.INSTANCE, PUnsignedLong.INSTANCE)) {
+            return object;
+        } else if (equalsAny(actualType, PUnsignedInt.INSTANCE,
+                PInteger.INSTANCE)) {
+            s = (Integer) object;
+            return s;
+        } else if (equalsAny(actualType, PTinyint.INSTANCE, PUnsignedTinyint.INSTANCE)) {
+            s = (Byte) object;
+            return s;
+        } else if (equalsAny(actualType, PSmallint.INSTANCE, PUnsignedSmallint.INSTANCE)) {
+            s = (Short) object;
+            return s;
+        } else if (equalsAny(actualType, PFloat.INSTANCE, PUnsignedFloat.INSTANCE)) {
+            Float f = (Float) object;
+            if (f > Long.MAX_VALUE || f < Long.MIN_VALUE) {
+                throw newIllegalDataException(
+                        actualType + " value " + f + " cannot be cast to Long without changing its value");
+            }
+            s = f.longValue();
+            return s;
+        } else if (equalsAny(actualType, PDouble.INSTANCE, PUnsignedDouble.INSTANCE)) {
+            Double de = (Double) object;
+            if (de > Long.MAX_VALUE || de < Long.MIN_VALUE) {
+                throw newIllegalDataException(
+                        actualType + " value " + de + " cannot be cast to Long without changing its value");
+            }
+            s = de.longValue();
+            return s;
+        } else if (actualType == PDecimal.INSTANCE) {
+            BigDecimal d = (BigDecimal) object;
+            return d.longValueExact();
+        } else if (equalsAny(actualType, PDate.INSTANCE, PUnsignedDate.INSTANCE, PTime.INSTANCE,
+                PUnsignedTime.INSTANCE)) {
+            java.util.Date date = (java.util.Date) object;
+            return date.getTime();
+        }
+        return throwConstraintViolationException(actualType, this);
+    }
 
     @Override
-    public float decodeFloat(byte[] b, int o, SortOrder sortOrder) {
-      return decodeLong(b, o, sortOrder);
+    public Long toObject(byte[] b, int o, int l, PDataType actualType, SortOrder sortOrder,
+            Integer maxLength, Integer scale) {
+        if (l == 0) {
+            return null;
+        }
+        if (equalsAny(actualType, PLong.INSTANCE, PUnsignedLong.INSTANCE,
+                PInteger.INSTANCE, PUnsignedInt.INSTANCE, PSmallint.INSTANCE,
+                PUnsignedSmallint.INSTANCE, PTinyint.INSTANCE, PUnsignedTinyint.INSTANCE, PFloat.INSTANCE,
+                PUnsignedFloat.INSTANCE, PDouble.INSTANCE, PUnsignedDouble.INSTANCE, PDate.INSTANCE,
+                PUnsignedDate.INSTANCE, PTime.INSTANCE, PUnsignedTime.INSTANCE)) {
+            return actualType.getCodec().decodeLong(b, o, sortOrder);
+        } else if (actualType == PDecimal.INSTANCE) {
+            BigDecimal bd = (BigDecimal) actualType.toObject(b, o, l, actualType, sortOrder);
+            return bd.longValueExact();
+        }
+        throwConstraintViolationException(actualType, this);
+        return null;
     }
 
     @Override
-    public double decodeDouble(byte[] b, int o, SortOrder sortOrder) {
-      return decodeLong(b, o, sortOrder);
+    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 equalsAny(targetType, this, PDecimal.INSTANCE, PVarbinary.INSTANCE, PBinary.INSTANCE, PDouble.INSTANCE);
     }
 
     @Override
-    public long decodeLong(byte[] bytes, int o, SortOrder sortOrder) {
-      Preconditions.checkNotNull(sortOrder);
-      checkForSufficientLength(bytes, o, Bytes.SIZEOF_LONG);
-      long v;
-      byte b = bytes[o];
-      if (sortOrder == SortOrder.ASC) {
-        v = b ^ 0x80; // Flip sign bit back
-        for (int i = 1; i < Bytes.SIZEOF_LONG; i++) {
-          b = bytes[o + i];
-          v = (v << 8) + (b & 0xff);
+    public void coerceBytes(ImmutableBytesWritable ptr, Object object, PDataType actualType,
+            Integer maxLength, Integer scale, SortOrder actualModifier, Integer desiredMaxLength, Integer desiredScale,
+            SortOrder expectedModifier) {
+        // Decrease size of TIMESTAMP to size of LONG and continue coerce
+        if (ptr.getLength() > getByteSize()) {
+            ptr.set(ptr.get(), ptr.getOffset(), getByteSize());
         }
-      } else {
-        b = (byte) (b ^ 0xff);
-        v = b ^ 0x80; // Flip sign bit back
-        for (int i = 1; i < Bytes.SIZEOF_LONG; i++) {
-          b = bytes[o + i];
-          b ^= 0xff;
-          v = (v << 8) + (b & 0xff);
-        }
-      }
-      return v;
+        super.coerceBytes(ptr, object, actualType, maxLength, scale, actualModifier, desiredMaxLength,
+                desiredScale, expectedModifier);
     }
 
     @Override
-    public int decodeInt(byte[] b, int o, SortOrder sortOrder) {
-      long v = decodeLong(b, o, sortOrder);
-      if (v < Integer.MIN_VALUE || v > Integer.MAX_VALUE) {
-        throw newIllegalDataException(
-            "Value " + v + " cannot be cast to Integer without changing its value");
-      }
-      return (int) v;
+    public boolean isComparableTo(PDataType targetType) {
+        return PDecimal.INSTANCE.isComparableTo(targetType);
     }
 
     @Override
-    public int encodeFloat(float v, byte[] b, int o) {
-      if (v < Long.MIN_VALUE || v > Long.MAX_VALUE) {
-        throw newIllegalDataException(
-            "Value " + v + " cannot be encoded as an Long without changing its value");
-      }
-      return encodeLong((long) v, b, o);
+    public boolean isCoercibleTo(PDataType targetType, Object value) {
+        if (value != null) {
+            long l;
+            if (equalsAny(targetType, PUnsignedDouble.INSTANCE, PUnsignedFloat.INSTANCE,
+                    PUnsignedLong.INSTANCE)) {
+                l = (Long) value;
+                return l >= 0;
+            } else if (targetType.equals(PUnsignedInt.INSTANCE)) {
+                l = (Long) value;
+                return (l >= 0 && l <= Integer.MAX_VALUE);
+            } else if (targetType.equals(PInteger.INSTANCE)) {
+                l = (Long) value;
+                return (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE);
+            } else if (targetType.equals(PUnsignedSmallint.INSTANCE)) {
+                l = (Long) value;
+                return (l >= 0 && l <= Short.MAX_VALUE);
+            } else if (targetType.equals(PSmallint.INSTANCE)) {
+                l = (Long) value;
+                return (l >= Short.MIN_VALUE && l <= Short.MAX_VALUE);
+            } else if (targetType.equals(PTinyint.INSTANCE)) {
+                l = (Long) value;
+                return (l >= Byte.MIN_VALUE && l <= Byte.MAX_VALUE);
+            } else if (targetType.equals(PUnsignedTinyint.INSTANCE)) {
+                l = (Long) value;
+                return (l >= 0 && l <= Byte.MAX_VALUE);
+            }
+        }
+        return super.isCoercibleTo(targetType, value);
     }
 
     @Override
-    public int encodeDouble(double v, byte[] b, int o) {
-      if (v < Long.MIN_VALUE || v > Long.MAX_VALUE) {
-        throw newIllegalDataException(
-            "Value " + v + " cannot be encoded as an Long without changing its value");
-      }
-      return encodeLong((long) v, b, o);
+    public boolean isCastableTo(PDataType targetType) {
+        return super.isCastableTo(targetType) || targetType.isCoercibleTo(PTimestamp.INSTANCE);
     }
 
     @Override
-    public int encodeLong(long v, byte[] b, int o) {
-      checkForSufficientLength(b, o, Bytes.SIZEOF_LONG);
-      b[o + 0] = (byte) ((v >> 56) ^ 0x80); // Flip sign bit so that INTEGER is binary comparable
-      b[o + 1] = (byte) (v >> 48);
-      b[o + 2] = (byte) (v >> 40);
-      b[o + 3] = (byte) (v >> 32);
-      b[o + 4] = (byte) (v >> 24);
-      b[o + 5] = (byte) (v >> 16);
-      b[o + 6] = (byte) (v >> 8);
-      b[o + 7] = (byte) v;
-      return Bytes.SIZEOF_LONG;
+    public boolean isFixedWidth() {
+        return true;
     }
 
     @Override
-    public byte decodeByte(byte[] b, int o, SortOrder sortOrder) {
-      long v = decodeLong(b, o, sortOrder);
-      if (v < Byte.MIN_VALUE || v > Byte.MAX_VALUE) {
-        throw newIllegalDataException(
-            "Value " + v + " cannot be cast to Byte without changing its value");
-      }
-      return (byte) v;
+    public Integer getByteSize() {
+        return Bytes.SIZEOF_LONG;
     }
 
     @Override
-    public short decodeShort(byte[] b, int o, SortOrder sortOrder) {
-      long v = decodeLong(b, o, sortOrder);
-      if (v < Short.MIN_VALUE || v > Short.MAX_VALUE) {
-        throw newIllegalDataException(
-            "Value " + v + " cannot be cast to Short without changing its value");
-      }
-      return (short) v;
+    public Integer getMaxLength(Object o) {
+        return LONG_PRECISION;
     }
 
     @Override
-    public int encodeByte(byte v, byte[] b, int o) {
-      return encodeLong(v, b, o);
+    public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+        if (rhsType == PDecimal.INSTANCE) {
+            return -((BigDecimal) rhs).compareTo(BigDecimal.valueOf(((Number) lhs).longValue()));
+        } else if (equalsAny(rhsType, PDouble.INSTANCE, PFloat.INSTANCE, PUnsignedDouble.INSTANCE, PUnsignedFloat.INSTANCE)) {
+            return Doubles.compare(((Number) lhs).doubleValue(), ((Number) rhs).doubleValue());
+        }
+        return Longs.compare(((Number) lhs).longValue(), ((Number) rhs).longValue());
     }
 
     @Override
-    public int encodeShort(short v, byte[] b, int o) {
-      return encodeLong(v, b, o);
+    public Object toObject(String value) {
+        if (value == null || value.length() == 0) {
+            return null;
+        }
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            throw newIllegalDataException(e);
+        }
     }
 
     @Override
-    public PhoenixArrayFactory getPhoenixArrayFactory() {
-      return new PhoenixArrayFactory() {
+    public Object getSampleValue(Integer maxLength, Integer arrayLength) {
+        return RANDOM.get().nextLong();
+    }
+
+    static class LongCodec extends BaseCodec {
+
+        @Override
+        public float decodeFloat(byte[] b, int o, SortOrder sortOrder) {
+            return decodeLong(b, o, sortOrder);
+        }
+
+        @Override
+        public double decodeDouble(byte[] b, int o, SortOrder sortOrder) {
+            return decodeLong(b, o, sortOrder);
+        }
+
+        @Override
+        public long decodeLong(byte[] bytes, int o, SortOrder sortOrder) {
+            Preconditions.checkNotNull(sortOrder);
+            checkForSufficientLength(bytes, o, Bytes.SIZEOF_LONG);
+            long v;
+            byte b = bytes[o];
+            if (sortOrder == SortOrder.ASC) {
+                v = b ^ 0x80; // Flip sign bit back
+                for (int i = 1; i < Bytes.SIZEOF_LONG; i++) {
+                    b = bytes[o + i];
+                    v = (v << 8) + (b & 0xff);
+                }
+            } else {
+                b = (byte) (b ^ 0xff);
+                v = b ^ 0x80; // Flip sign bit back
+                for (int i = 1; i < Bytes.SIZEOF_LONG; i++) {
+                    b = bytes[o + i];
+                    b ^= 0xff;
+                    v = (v << 8) + (b & 0xff);
+                }
+            }
+            return v;
+        }
+
+        @Override
+        public int decodeInt(byte[] b, int o, SortOrder sortOrder) {
+            long v = decodeLong(b, o, sortOrder);
+            if (v < Integer.MIN_VALUE || v > Integer.MAX_VALUE) {
+                throw newIllegalDataException(
+                        "Value " + v + " cannot be cast to Integer without changing its value");
+            }
+            return (int) v;
+        }
+
+        @Override
+        public int encodeFloat(float v, byte[] b, int o) {
+            if (v < Long.MIN_VALUE || v > Long.MAX_VALUE) {
+                throw newIllegalDataException(
+                        "Value " + v + " cannot be encoded as an Long without changing its value");
+            }
+            return encodeLong((long) v, b, o);
+        }
+
+        @Override
+        public int encodeDouble(double v, byte[] b, int o) {
+            if (v < Long.MIN_VALUE || v > Long.MAX_VALUE) {
+                throw newIllegalDataException(
+                        "Value " + v + " cannot be encoded as an Long without changing its value");
+            }
+            return encodeLong((long) v, b, o);
+        }
+
+        @Override
+        public int encodeLong(long v, byte[] b, int o) {
+            checkForSufficientLength(b, o, Bytes.SIZEOF_LONG);
+            b[o + 0] = (byte) ((v >> 56) ^ 0x80); // Flip sign bit so that INTEGER is binary comparable
+            b[o + 1] = (byte) (v >> 48);
+            b[o + 2] = (byte) (v >> 40);
+            b[o + 3] = (byte) (v >> 32);
+            b[o + 4] = (byte) (v >> 24);
+            b[o + 5] = (byte) (v >> 16);
+            b[o + 6] = (byte) (v >> 8);
+            b[o + 7] = (byte) v;
+            return Bytes.SIZEOF_LONG;
+        }
+
+        @Override
+        public byte decodeByte(byte[] b, int o, SortOrder sortOrder) {
+            long v = decodeLong(b, o, sortOrder);
+            if (v < Byte.MIN_VALUE || v > Byte.MAX_VALUE) {
+                throw newIllegalDataException(
+                        "Value " + v + " cannot be cast to Byte without changing its value");
+            }
+            return (byte) v;
+        }
+
+        @Override
+        public short decodeShort(byte[] b, int o, SortOrder sortOrder) {
+            long v = decodeLong(b, o, sortOrder);
+            if (v < Short.MIN_VALUE || v > Short.MAX_VALUE) {
+                throw newIllegalDataException(
+                        "Value " + v + " cannot be cast to Short without changing its value");
+            }
+            return (short) v;
+        }
+
+        @Override
+        public int encodeByte(byte v, byte[] b, int o) {
+            return encodeLong(v, b, o);
+        }
+
+        @Override
+        public int encodeShort(short v, byte[] b, int o) {
+            return encodeLong(v, b, o);
+        }
+
         @Override
-        public PhoenixArray newArray(PDataType type, Object[] elements) {
-          return new PhoenixArray.PrimitiveLongPhoenixArray(type, elements);
+        public PhoenixArrayFactory getPhoenixArrayFactory() {
+            return new PhoenixArrayFactory() {
+                @Override
+                public PhoenixArray newArray(PDataType type, Object[] elements) {
+                    return new PhoenixArray.PrimitiveLongPhoenixArray(type, elements);
+                }
+            };
         }
-      };
     }
-  }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java
index 0cfb0e8..03afae9 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java
@@ -123,7 +123,7 @@ public class PTime extends PDataType<Time> {
 
   @Override
   public boolean isBytesComparableWith(PDataType otherType) {
-    return super.isBytesComparableWith(otherType) || otherType.equals(PDate.INSTANCE);
+    return super.isBytesComparableWith(otherType) || otherType == PDate.INSTANCE || otherType == PTimestamp.INSTANCE || otherType == PLong.INSTANCE;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java
index cdfb533..c35a039 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java
@@ -31,13 +31,19 @@ import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.util.ByteUtil;
 import org.apache.phoenix.util.DateUtil;
 
+import com.google.common.base.Preconditions;
+
 public class PTimestamp extends PDataType<Timestamp> {
     public static final int MAX_NANOS_VALUE_EXCLUSIVE = 1000000;
     public static final PTimestamp INSTANCE = new PTimestamp();
 
+    protected PTimestamp(String sqlTypeName, int sqlType, int ordinal) {
+        super(sqlTypeName, sqlType, java.sql.Timestamp.class, null, ordinal);
+    }
+
     private PTimestamp() {
         super("TIMESTAMP", Types.TIMESTAMP, java.sql.Timestamp.class,
-                new PDate.DateCodec(), 9);
+                null, 9);
     }
 
     @Override
@@ -48,6 +54,28 @@ public class PTimestamp extends PDataType<Timestamp> {
     }
 
     @Override
+    public void coerceBytes(ImmutableBytesWritable ptr, Object o, PDataType actualType, Integer actualMaxLength,
+            Integer actualScale, SortOrder actualModifier, Integer desiredMaxLength, Integer desiredScale,
+            SortOrder expectedModifier) {
+        Preconditions.checkNotNull(actualModifier);
+        Preconditions.checkNotNull(expectedModifier);
+        if (ptr.getLength() == 0) { return; }
+        if (this.isBytesComparableWith(actualType)) { // No coerce necessary
+            if (actualModifier != expectedModifier || (actualType.isFixedWidth() && actualType.getByteSize() < this.getByteSize())) {
+                byte[] b = new byte[this.getByteSize()];
+                System.arraycopy(ptr.get(), ptr.getOffset(), b, 0, actualType.getByteSize());
+                ptr.set(b);
+                
+                if (actualModifier != expectedModifier) {
+                    SortOrder.invert(b, 0, b, 0, b.length);
+                }
+            }
+            return;
+        }
+        super.coerceBytes(ptr, o, actualType, actualMaxLength, actualScale, actualModifier, desiredMaxLength, desiredScale, expectedModifier);
+    }
+
+    @Override
     public int toBytes(Object object, byte[] bytes, int offset) {
         if (object == null) {
             // Create the byte[] of size MAX_TIMESTAMP_BYTES
@@ -61,7 +89,7 @@ public class PTimestamp extends PDataType<Timestamp> {
         java.sql.Timestamp value = (java.sql.Timestamp) object;
         // For Timestamp, the getTime() method includes milliseconds that may
         // be stored in the nanos part as well.
-        PDate.INSTANCE.getCodec().encodeLong(value.getTime(), bytes, offset);
+        DateUtil.getCodecFor(this).encodeLong(value.getTime(), bytes, offset);
 
         /*
          * By not getting the stuff that got spilled over from the millis part,
@@ -73,6 +101,11 @@ public class PTimestamp extends PDataType<Timestamp> {
     }
 
     @Override
+    public boolean isBytesComparableWith(PDataType otherType) {
+      return super.isBytesComparableWith(otherType) || otherType == PTime.INSTANCE || otherType == PDate.INSTANCE || otherType == PLong.INSTANCE;
+    }
+
+    @Override
     public Object toObject(Object object, PDataType actualType) {
         if (object == null) {
             return null;
@@ -106,8 +139,7 @@ public class PTimestamp extends PDataType<Timestamp> {
         java.sql.Timestamp v;
         if (equalsAny(actualType, PTimestamp.INSTANCE, PUnsignedTimestamp.INSTANCE)) {
             long millisDeserialized =
-                    (actualType == PTimestamp.INSTANCE ? PDate.INSTANCE : PUnsignedDate.INSTANCE).getCodec()
-                    .decodeLong(b, o, sortOrder);
+                    DateUtil.getCodecFor(actualType).decodeLong(b, o, sortOrder);
             v = new java.sql.Timestamp(millisDeserialized);
             int nanosDeserialized =
                     PUnsignedInt.INSTANCE.getCodec().decodeInt(b, o + Bytes.SIZEOF_LONG, sortOrder);
@@ -205,7 +237,7 @@ public class PTimestamp extends PDataType<Timestamp> {
 
     @Override
     public long getMillis(ImmutableBytesWritable ptr, SortOrder sortOrder) {
-        long millis = PLong.INSTANCE.getCodec().decodeLong(ptr.get(), ptr.getOffset(), sortOrder);
+        long millis = DateUtil.getCodecFor(this).decodeLong(ptr.get(), ptr.getOffset(), sortOrder);
         return millis;
     }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/aa05da8a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PUnsignedDate.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PUnsignedDate.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PUnsignedDate.java
index a6b1bc3..863b0d1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PUnsignedDate.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PUnsignedDate.java
@@ -27,138 +27,137 @@ import org.apache.phoenix.util.DateUtil;
 
 public class PUnsignedDate extends PDataType<Date> {
 
-  public static final PUnsignedDate INSTANCE = new PUnsignedDate();
-
-  private PUnsignedDate() {
-    super("UNSIGNED_DATE", 19, Date.class,
-        new UnsignedDateCodec(), 14); // After TIMESTAMP and DATE to ensure toLiteral finds those first
-  }
-
-  @Override
-  public byte[] toBytes(Object object) {
-    if (object == null) {
-      throw newIllegalDataException(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 newIllegalDataException(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) {
-    Date d = (Date) PDate.INSTANCE.toObject(object, actualType);
-    throwIfNonNegativeDate(d);
-    return d;
-  }
-
-  @Override
-  public Object toObject(byte[] b, int o, int l, PDataType actualType, SortOrder sortOrder, Integer maxLength, Integer scale) {
-    Date d = (Date) PDate.INSTANCE.toObject(b, o, l, actualType, sortOrder);
-    throwIfNonNegativeDate(d);
-    return d;
-  }
-
-  @Override
-  public boolean isCastableTo(PDataType targetType) {
-    return PDate.INSTANCE.isCastableTo(targetType);
-  }
-
-  @Override
-  public boolean isCoercibleTo(PDataType targetType) {
-    return equalsAny(targetType, this, PUnsignedTime.INSTANCE, PUnsignedTimestamp.INSTANCE)
-        || PDate.INSTANCE.isCoercibleTo(targetType);
-  }
-
-  @Override
-  public boolean isCoercibleTo(PDataType targetType, Object value) {
-    return super.isCoercibleTo(targetType, value) || PDate.INSTANCE.isCoercibleTo(targetType, value);
-  }
-
-  @Override
-  public boolean isFixedWidth() {
-    return true;
-  }
-
-  @Override
-  public Integer getByteSize() {
-    return PDate.INSTANCE.getByteSize();
-  }
-
-  @Override
-  public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
-    return PDate.INSTANCE.compareTo(lhs, rhs, rhsType);
-  }
-
-  @Override
-  public Object toObject(String value) {
-    return PDate.INSTANCE.toObject(value);
-  }
-
-  @Override
-  public boolean isBytesComparableWith(PDataType otherType) {
-    return super.isBytesComparableWith(otherType) || otherType.equals(PUnsignedTime.INSTANCE);
-  }
-
-  @Override
-  public String toStringLiteral(Object o, 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(o, formatter) + "'";
-  }
-
-  @Override
-  public void coerceBytes(ImmutableBytesWritable ptr, Object object, PDataType actualType,
-      Integer maxLength, Integer scale, SortOrder actualModifier,
-      Integer desiredMaxLength, Integer desiredScale,
-      SortOrder expectedModifier) {
-    if (ptr.getLength() > 0 && actualType == PUnsignedTimestamp.INSTANCE
-        && actualModifier == expectedModifier) {
-      ptr.set(ptr.get(), ptr.getOffset(), getByteSize());
-      return;
-    }
-    super.coerceBytes(ptr, object, actualType, maxLength, scale, actualModifier, desiredMaxLength,
-        desiredScale, expectedModifier);
-  }
-
-  @Override
-  public int getResultSetSqlType() {
-    return Types.DATE;
-  }
-
-  @Override
-  public Object getSampleValue(Integer maxLength, Integer arrayLength) {
-    return new Date((Long) PUnsignedLong.INSTANCE.getSampleValue(maxLength, arrayLength));
-  }
-
-  static class UnsignedDateCodec extends PUnsignedLong.UnsignedLongCodec {
-
-    @Override
-    public int decodeInt(byte[] b, int o, SortOrder sortOrder) {
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public PhoenixArrayFactory getPhoenixArrayFactory() {
-      return new PhoenixArrayFactory() {
+    public static final PUnsignedDate INSTANCE = new PUnsignedDate();
+
+    private PUnsignedDate() {
+        super("UNSIGNED_DATE", 19, Date.class,
+                new UnsignedDateCodec(), 14); // After TIMESTAMP and DATE to ensure toLiteral finds those first
+    }
+
+    @Override
+    public byte[] toBytes(Object object) {
+        if (object == null) {
+            throw newIllegalDataException(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 newIllegalDataException(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) {
+        Date d = (Date) PDate.INSTANCE.toObject(object, actualType);
+        throwIfNonNegativeDate(d);
+        return d;
+    }
+
+    @Override
+    public Object toObject(byte[] b, int o, int l, PDataType actualType, SortOrder sortOrder, Integer maxLength, Integer scale) {
+        Date d = (Date) PDate.INSTANCE.toObject(b, o, l, actualType, sortOrder);
+        throwIfNonNegativeDate(d);
+        return d;
+    }
+
+    @Override
+    public boolean isCastableTo(PDataType targetType) {
+        return PDate.INSTANCE.isCastableTo(targetType);
+    }
+
+    @Override
+    public boolean isCoercibleTo(PDataType targetType) {
+        return equalsAny(targetType, this, PUnsignedTime.INSTANCE, PUnsignedTimestamp.INSTANCE)
+                || PDate.INSTANCE.isCoercibleTo(targetType);
+    }
+
+    @Override
+    public boolean isCoercibleTo(PDataType targetType, Object value) {
+        return super.isCoercibleTo(targetType, value) || PDate.INSTANCE.isCoercibleTo(targetType, value);
+    }
+
+    @Override
+    public boolean isFixedWidth() {
+        return true;
+    }
+
+    @Override
+    public Integer getByteSize() {
+        return PDate.INSTANCE.getByteSize();
+    }
+
+    @Override
+    public int compareTo(Object lhs, Object rhs, PDataType rhsType) {
+        return PDate.INSTANCE.compareTo(lhs, rhs, rhsType);
+    }
+
+    @Override
+    public Object toObject(String value) {
+        return PDate.INSTANCE.toObject(value);
+    }
+
+    @Override
+    public boolean isBytesComparableWith(PDataType otherType) {
+        return super.isBytesComparableWith(otherType) || otherType == PUnsignedTime.INSTANCE || otherType == PUnsignedTimestamp.INSTANCE || otherType == PUnsignedLong.INSTANCE;
+    }
+
+    @Override
+    public String toStringLiteral(Object o, 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(o, formatter) + "'";
+    }
+
+    // TODO: derive PUnsignedDate from PDate to avoid copy/paste
+    @Override
+    public void coerceBytes(ImmutableBytesWritable ptr, Object object, PDataType actualType,
+            Integer maxLength, Integer scale, SortOrder actualModifier,
+            Integer desiredMaxLength, Integer desiredScale,
+            SortOrder expectedModifier) {
+        if (ptr.getLength() > getByteSize()) {
+            ptr.set(ptr.get(), ptr.getOffset(), getByteSize());
+        }
+        super.coerceBytes(ptr, object, actualType, maxLength, scale, actualModifier, desiredMaxLength,
+                desiredScale, expectedModifier);
+    }
+
+    @Override
+    public int getResultSetSqlType() {
+        return Types.DATE;
+    }
+
+    @Override
+    public Object getSampleValue(Integer maxLength, Integer arrayLength) {
+        return new Date((Long) PUnsignedLong.INSTANCE.getSampleValue(maxLength, arrayLength));
+    }
+
+    static class UnsignedDateCodec extends PUnsignedLong.UnsignedLongCodec {
+
+        @Override
+        public int decodeInt(byte[] b, int o, SortOrder sortOrder) {
+            throw new UnsupportedOperationException();
+        }
 
         @Override
-        public PhoenixArray newArray(PDataType type, Object[] elements) {
-          return new PhoenixArray(type, elements);
+        public PhoenixArrayFactory getPhoenixArrayFactory() {
+            return new PhoenixArrayFactory() {
+
+                @Override
+                public PhoenixArray newArray(PDataType type, Object[] elements) {
+                    return new PhoenixArray(type, elements);
+                }
+            };
         }
-      };
     }
-  }
 }