You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/04/06 09:20:12 UTC

incubator-calcite git commit: [CALCITE-307] Implement CAST between date-time types

Repository: incubator-calcite
Updated Branches:
  refs/heads/master 241f77e25 -> 38a4dd416


[CALCITE-307] Implement CAST between date-time types


Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/38a4dd41
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/38a4dd41
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/38a4dd41

Branch: refs/heads/master
Commit: 38a4dd416287e60d607e9194ee2de317a25706f9
Parents: 241f77e
Author: Julian Hyde <jh...@apache.org>
Authored: Sun Apr 5 23:37:37 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun Apr 5 23:37:37 2015 -0700

----------------------------------------------------------------------
 .../adapter/enumerable/RexToLixTranslator.java  | 30 ++++++++++++++++
 .../java/org/apache/calcite/rex/RexBuilder.java | 11 +++---
 .../apache/calcite/runtime/SqlFunctions.java    | 15 ++++++++
 .../org/apache/calcite/util/BuiltInMethod.java  |  2 ++
 .../calcite/sql/test/SqlOperatorBaseTest.java   | 24 +++++--------
 .../apache/calcite/test/SqlFunctionsTest.java   | 38 +++++++++++++++++---
 core/src/test/resources/sql/misc.oq             | 26 +++++++-------
 7 files changed, 108 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/38a4dd41/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index aceafa5..9e7502d 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -236,6 +236,12 @@ public class RexToLixTranslator {
       case VARCHAR:
         convert =
             Expressions.call(BuiltInMethod.STRING_TO_DATE.method, operand);
+        break;
+      case TIMESTAMP:
+        convert = Expressions.convert_(
+            Expressions.call(BuiltInMethod.FLOOR_DIV.method,
+                operand, Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
+            int.class);
       }
       break;
     case TIME:
@@ -244,6 +250,14 @@ public class RexToLixTranslator {
       case VARCHAR:
         convert =
             Expressions.call(BuiltInMethod.STRING_TO_TIME.method, operand);
+        break;
+      case TIMESTAMP:
+        convert = Expressions.convert_(
+            Expressions.call(
+                BuiltInMethod.FLOOR_MOD.method,
+                operand,
+                Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
+            int.class);
       }
       break;
     case TIMESTAMP:
@@ -252,6 +266,22 @@ public class RexToLixTranslator {
       case VARCHAR:
         convert =
             Expressions.call(BuiltInMethod.STRING_TO_TIMESTAMP.method, operand);
+        break;
+      case DATE:
+        convert = Expressions.multiply(
+            Expressions.convert_(operand, long.class),
+            Expressions.constant(DateTimeUtils.MILLIS_PER_DAY));
+        break;
+      case TIME:
+        convert =
+            Expressions.add(
+                Expressions.multiply(
+                    Expressions.convert_(
+                        Expressions.call(BuiltInMethod.CURRENT_DATE.method, root),
+                        long.class),
+                    Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
+                Expressions.convert_(operand, long.class));
+        break;
       }
       break;
     case BOOLEAN:

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/38a4dd41/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index f66f62e..32b16dc 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -467,12 +467,15 @@ public class RexBuilder {
       RexLiteral literal = (RexLiteral) exp;
       Comparable value = literal.getValue();
       if (RexLiteral.valueMatchesType(value, sqlType, false)
+          && (type.getSqlTypeName() == literal.getTypeName()
+              || !SqlTypeFamily.DATETIME.getTypeNames().contains(
+                  literal.getTypeName()))
           && (!(value instanceof NlsString)
-          || (type.getPrecision()
-          >= ((NlsString) value).getValue().length()))
+              || (type.getPrecision()
+                  >= ((NlsString) value).getValue().length()))
           && (!(value instanceof ByteString)
-          || (type.getPrecision()
-          >= ((ByteString) value).length()))) {
+              || (type.getPrecision()
+                  >= ((ByteString) value).length()))) {
         switch (literal.getTypeName()) {
         case CHAR:
           if (value instanceof NlsString) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/38a4dd41/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 256d15a..58a13fe 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -933,6 +933,21 @@ public class SqlFunctions {
     return x == y ? 0 : x ? 1 : -1;
   }
 
+  /** Divide, rounding towards negative infinity. */
+  public static long floorDiv(long x, long y) {
+    long r = x / y;
+    // if the signs are different and modulo not zero, round down
+    if ((x ^ y) < 0 && (r * y != x)) {
+      r--;
+    }
+    return r;
+  }
+
+  /** Modulo, always returning a non-negative result. */
+  public static long floorMod(long x, long y) {
+    return x - floorDiv(x, y) * y;
+  }
+
   /** CAST(FLOAT AS VARCHAR). */
   public static String toString(float x) {
     if (x == 0) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/38a4dd41/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index b5f2725..2bcf628 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -234,6 +234,8 @@ public enum BuiltInMethod {
       int.class),
   CHAR_LENGTH(SqlFunctions.class, "charLength", String.class),
   STRING_CONCAT(SqlFunctions.class, "concat", String.class, String.class),
+  FLOOR_DIV(SqlFunctions.class, "floorDiv", long.class, long.class),
+  FLOOR_MOD(SqlFunctions.class, "floorMod", long.class, long.class),
   FLOOR(SqlFunctions.class, "floor", int.class, int.class),
   CEIL(SqlFunctions.class, "ceil", int.class, int.class),
   OVERLAY(SqlFunctions.class, "overlay", String.class, String.class, int.class),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/38a4dd41/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 8b0c0c1..2f76859 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -1087,12 +1087,10 @@ public abstract class SqlOperatorBaseTest {
         "DATE NOT NULL");
 
     // timestamp <-> time
-    if (enable) {
-      tester.checkScalar(
-          "cast(TIMESTAMP '1945-02-24 12:42:25.34' as TIME)",
-          "12:42:25",
-          "TIME(0) NOT NULL");
-    }
+    tester.checkScalar(
+        "cast(TIMESTAMP '1945-02-24 12:42:25.34' as TIME)",
+        "12:42:25",
+        "TIME(0) NOT NULL");
 
     // time <-> string
     checkCastToString("TIME '12:42:25'", null, "12:42:25");
@@ -1107,16 +1105,10 @@ public abstract class SqlOperatorBaseTest {
         new SimpleDateFormat("yyyy-MM-dd").format(
             getCalendarNotTooNear(Calendar.DAY_OF_MONTH).getTime());
 
-    if (enable) {
-      tester.checkScalar(
-          "cast(DATE '1945-02-24' as TIMESTAMP)",
-          "1945-02-24 00:00:00",
-          "TIMESTAMP(0) NOT NULL");
-    }
-
-    if (!enable) {
-      return;
-    }
+    tester.checkScalar(
+        "cast(DATE '1945-02-24' as TIMESTAMP)",
+        "1945-02-24 00:00:00",
+        "TIMESTAMP(0) NOT NULL");
 
     // Note: Casting to time(0) should lose date info and fractional
     // seconds, then casting back to timestamp should initialize to

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/38a4dd41/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java b/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
index 9f82294..97f8e59 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
@@ -45,6 +45,8 @@ import static org.apache.calcite.avatica.util.DateTimeUtils.ymdToJulian;
 import static org.apache.calcite.avatica.util.DateTimeUtils.ymdToUnixDate;
 import static org.apache.calcite.runtime.SqlFunctions.charLength;
 import static org.apache.calcite.runtime.SqlFunctions.concat;
+import static org.apache.calcite.runtime.SqlFunctions.floorDiv;
+import static org.apache.calcite.runtime.SqlFunctions.floorMod;
 import static org.apache.calcite.runtime.SqlFunctions.greater;
 import static org.apache.calcite.runtime.SqlFunctions.initcap;
 import static org.apache.calcite.runtime.SqlFunctions.lesser;
@@ -332,8 +334,10 @@ public class SqlFunctionsTest {
     assertThat(SqlFunctions.floor((long) x, (long) y), is((long) result));
     assertThat(SqlFunctions.floor((short) x, (short) y), is((short) result));
     assertThat(SqlFunctions.floor((byte) x, (byte) y), is((byte) result));
-    assertThat(SqlFunctions.floor(BigDecimal.valueOf(x), BigDecimal.valueOf(y)),
-        is(BigDecimal.valueOf(result)));
+    assertThat(
+        SqlFunctions.floor(BigDecimal.valueOf(x), BigDecimal.valueOf(y)), is(
+            BigDecimal.valueOf(
+                result)));
   }
 
   @Test public void testCeil() {
@@ -350,8 +354,10 @@ public class SqlFunctionsTest {
     assertThat(SqlFunctions.ceil((long) x, (long) y), is((long) result));
     assertThat(SqlFunctions.ceil((short) x, (short) y), is((short) result));
     assertThat(SqlFunctions.ceil((byte) x, (byte) y), is((byte) result));
-    assertThat(SqlFunctions.ceil(BigDecimal.valueOf(x), BigDecimal.valueOf(y)),
-        is(BigDecimal.valueOf(result)));
+    assertThat(
+        SqlFunctions.ceil(BigDecimal.valueOf(x), BigDecimal.valueOf(y)), is(
+            BigDecimal.valueOf(
+                result)));
   }
 
   /** Unit test for
@@ -443,6 +449,30 @@ public class SqlFunctionsTest {
     assertEquals(2, digitCount(99));
     assertEquals(3, digitCount(100));
   }
+
+  @Test public void testFloorDiv() {
+    assertThat(floorDiv(13, 3), equalTo(4L));
+    assertThat(floorDiv(12, 3), equalTo(4L));
+    assertThat(floorDiv(11, 3), equalTo(3L));
+    assertThat(floorDiv(-13, 3), equalTo(-5L));
+    assertThat(floorDiv(-12, 3), equalTo(-4L));
+    assertThat(floorDiv(-11, 3), equalTo(-4L));
+    assertThat(floorDiv(0, 3), equalTo(0L));
+    assertThat(floorDiv(1, 3), equalTo(0L));
+    assertThat(floorDiv(-1, 3), equalTo(-1L));
+  }
+
+  @Test public void testFloorMod() {
+    assertThat(floorMod(13, 3), equalTo(1L));
+    assertThat(floorMod(12, 3), equalTo(0L));
+    assertThat(floorMod(11, 3), equalTo(2L));
+    assertThat(floorMod(-13, 3), equalTo(2L));
+    assertThat(floorMod(-12, 3), equalTo(0L));
+    assertThat(floorMod(-11, 3), equalTo(1L));
+    assertThat(floorMod(0, 3), equalTo(0L));
+    assertThat(floorMod(1, 3), equalTo(1L));
+    assertThat(floorMod(-1, 3), equalTo(2L));
+  }
 }
 
 // End SqlFunctionsTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/38a4dd41/core/src/test/resources/sql/misc.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.oq b/core/src/test/resources/sql/misc.oq
index 63422cf..dbd1fbc 100644
--- a/core/src/test/resources/sql/misc.oq
+++ b/core/src/test/resources/sql/misc.oq
@@ -33,9 +33,8 @@ from "hr"."emps";
 
 !ok
 
-# CALCITE-307 CAST(timestamp AS DATE) gives ClassCastException
-# Based on DRILL-1051
-!if (false) {
+# [CALCITE-307] CAST(timestamp AS DATE) gives ClassCastException
+# Based on [DRILL-1051]
 with data(c_row, c_timestamp) as (select * from (values
     (1, TIMESTAMP '1997-01-02 03:04:05'),
     (2, TIMESTAMP '1997-01-02 00:00:00'),
@@ -61,9 +60,9 @@ with data(c_row, c_timestamp) as (select * from (values
     (23, TIMESTAMP '1996-03-01 17:32:01')))
 select cast(c_timestamp as varchar(20)), cast(c_timestamp as date) from data where c_row <> 12;
 
-+------------+------------+
-|   EXPR$0   |   EXPR$1   |
-+------------+------------+
++---------------------+------------+
+| EXPR$0              | EXPR$1     |
++---------------------+------------+
 | 1997-01-02 03:04:05 | 1997-01-02 |
 | 1997-01-02 00:00:00 | 1997-01-02 |
 | 2001-09-22 18:19:20 | 2001-09-22 |
@@ -75,22 +74,21 @@ select cast(c_timestamp as varchar(20)), cast(c_timestamp as date) from data whe
 | 1997-02-14 17:32:01 | 1997-02-14 |
 | 1997-02-15 17:32:01 | 1997-02-15 |
 | 1997-02-16 17:32:01 | 1997-02-16 |
-| 0097-02-16 17:32:01 | 0097-02-17 |
-| 0597-02-16 17:32:01 | 0597-02-13 |
-| 1097-02-16 17:32:01 | 1097-02-09 |
-| 1697-02-16 17:32:01 | 1697-02-15 |
-| 1797-02-16 17:32:01 | 1797-02-15 |
+| 0097-02-14 17:32:01 | 0097-02-14 |
+| 0597-02-18 17:32:01 | 0597-02-18 |
+| 1097-02-22 17:32:01 | 1097-02-22 |
+| 1697-02-16 17:32:01 | 1697-02-16 |
+| 1797-02-16 17:32:01 | 1797-02-16 |
 | 1897-02-16 17:32:01 | 1897-02-16 |
 | 1997-02-16 17:32:01 | 1997-02-16 |
 | 2097-02-16 17:32:01 | 2097-02-16 |
 | 1996-02-28 17:32:01 | 1996-02-28 |
 | 1996-02-29 17:32:01 | 1996-02-29 |
 | 1996-03-01 17:32:01 | 1996-03-01 |
-+------------+------------+
-22 rows selected
++---------------------+------------+
+(22 rows)
 
 !ok
-!}
 
 # [DRILL-1149]
 select *, upper("name")