You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by se...@apache.org on 2019/03/08 20:02:08 UTC

[calcite] branch master updated: [CALCITE-2818] EXTRACT returns wrong results for DATE and TIMESTAMP values before epoch (Haisheng Yuan)

This is an automated email from the ASF dual-hosted git repository.

sereda pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 5ee592a  [CALCITE-2818] EXTRACT returns wrong results for DATE and TIMESTAMP values before epoch (Haisheng Yuan)
5ee592a is described below

commit 5ee592a19bf377438aa100dbc19d40ae8b2e2cd9
Author: Haisheng Yuan <h....@alibaba-inc.com>
AuthorDate: Wed Feb 27 15:54:04 2019 -0600

    [CALCITE-2818] EXTRACT returns wrong results for DATE and TIMESTAMP values before epoch (Haisheng Yuan)
---
 .../calcite/adapter/enumerable/RexImpTable.java    | 13 ++---
 .../calcite/sql/test/SqlOperatorBaseTest.java      | 67 ++++++++++++++++++++++
 core/src/test/resources/sql/misc.iq                | 12 ++--
 3 files changed, 79 insertions(+), 13 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index dcab895..1237ad2 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -2236,8 +2236,8 @@ public class RexImpTable {
               Expressions.call(BuiltInMethod.TIME_ZONE.method, translator.getRoot()));
           // fall through
         case TIMESTAMP:
-          operand = Expressions.divide(operand,
-              Expressions.constant(TimeUnit.DAY.multiplier.longValue()));
+          operand = Expressions.call(BuiltInMethod.FLOOR_DIV.method,
+              operand, Expressions.constant(TimeUnit.DAY.multiplier.longValue()));
           // fall through
         case DATE:
           return Expressions.call(BuiltInMethod.UNIX_DATE_EXTRACT.method,
@@ -2247,11 +2247,9 @@ public class RexImpTable {
         }
         break;
       case MILLISECOND:
-        return Expressions.modulo(
-              operand, Expressions.constant(TimeUnit.MINUTE.multiplier.longValue()));
+        return mod(operand, TimeUnit.MINUTE.multiplier.longValue());
       case MICROSECOND:
-        operand = Expressions.modulo(
-              operand, Expressions.constant(TimeUnit.MINUTE.multiplier.longValue()));
+        operand = mod(operand, TimeUnit.MINUTE.multiplier.longValue());
         return Expressions.multiply(
               operand, Expressions.constant(TimeUnit.SECOND.multiplier.longValue()));
       case EPOCH:
@@ -2317,7 +2315,8 @@ public class RexImpTable {
     if (factor == 1L) {
       return operand;
     } else {
-      return Expressions.modulo(operand, Expressions.constant(factor));
+      return Expressions.call(BuiltInMethod.FLOOR_MOD.method,
+          operand, Expressions.constant(factor));
     }
   }
 
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 bb9c880..0e876bc 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
@@ -6723,6 +6723,73 @@ public abstract class SqlOperatorBaseTest {
         "extract(microsecond from cast(null as time))");
   }
 
+  @Test public void testExtractWithDatesBeforeUnixEpoch() {
+    tester.checkScalar(
+        "extract(year from TIMESTAMP '1970-01-01 00:00:00')",
+        "1970",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(year from TIMESTAMP '1969-12-31 10:13:17')",
+        "1969",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(quarter from TIMESTAMP '1969-12-31 08:13:17')",
+        "4",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(quarter from TIMESTAMP '1969-5-31 21:13:17')",
+        "2",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(month from TIMESTAMP '1969-12-31 00:13:17')",
+        "12",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(day from TIMESTAMP '1969-12-31 12:13:17')",
+        "31",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(week from TIMESTAMP '1969-2-23 01:23:45')",
+        "8",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(doy from TIMESTAMP '1969-12-31 21:13:17.357')",
+        "365",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(dow from TIMESTAMP '1969-12-31 01:13:17.357')",
+        "4",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(decade from TIMESTAMP '1969-12-31 21:13:17.357')",
+        "196",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(century from TIMESTAMP '1969-12-31 21:13:17.357')",
+        "20",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(hour from TIMESTAMP '1969-12-31 21:13:17.357')",
+        "21",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(minute from TIMESTAMP '1969-12-31 21:13:17.357')",
+        "13",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(second from TIMESTAMP '1969-12-31 21:13:17.357')",
+        "17",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(millisecond from TIMESTAMP '1969-12-31 21:13:17.357')",
+        "17357",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "extract(microsecond from TIMESTAMP '1969-12-31 21:13:17.357')",
+        "17357000",
+        "BIGINT NOT NULL");
+  }
+
   @Test public void testArrayValueConstructor() {
     tester.setFor(SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR);
     tester.checkScalar(
diff --git a/core/src/test/resources/sql/misc.iq b/core/src/test/resources/sql/misc.iq
index aada308..c692f42 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -2109,14 +2109,14 @@ and "sqlTimestamp" < {ts '1998-01-01 00:00:00'};
 !ok
 
 # [CALCITE-1188] NullPointerException in EXTRACT with WHERE ... IN clause if field has null value
-select extract(YEAR from "sqlTimestamp") Y
+select "sqlTimestamp" T
 from "everyTypes"
 where extract(YEAR from "sqlTimestamp") IN (1969, 1970);
-+------+
-| Y    |
-+------+
-| 1970 |
-+------+
++---------------------+
+| T                   |
++---------------------+
+| 1970-01-01 00:00:00 |
++---------------------+
 (1 row)
 
 !ok