You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@quickstep.apache.org by hb...@apache.org on 2016/08/31 19:13:48 UTC

[2/2] incubator-quickstep git commit: Separate Date type from Datetime type.

Separate Date type from Datetime type.

- Beginning from the parser to the operator execution level, treat Date type
  sepearately than the Datetime type.
- Provide support for the extract function when applied on the Date
  type, implemented in the DateExtractOperation.
- Modified the tests.


Project: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/commit/9bb2ee46
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/tree/9bb2ee46
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/diff/9bb2ee46

Branch: refs/heads/datetype-fix
Commit: 9bb2ee4606dded12ade5d3875d6449f385b26f42
Parents: cdc1e05
Author: Harshad Deshmukh <hb...@apache.org>
Authored: Mon Aug 29 14:03:52 2016 -0500
Committer: Harshad Deshmukh <hb...@apache.org>
Committed: Wed Aug 31 13:55:56 2016 -0500

----------------------------------------------------------------------
 parser/SqlParser.ypp                            |   2 +-
 parser/tests/Select.test                        |  28 +--
 parser/tests/TPCH.test                          |  47 ++--
 .../tests/execution_generator/Insert.test       |  19 ++
 .../tests/execution_generator/Select.test       |  32 +--
 query_optimizer/tests/resolver/Select.test      |  71 ++++--
 types/DateOperatorOverloads.hpp                 |  63 ++++-
 types/DatetimeLit.hpp                           |   8 +
 .../binary_operations/AddBinaryOperation.cpp    |  84 ++++++-
 .../operations/binary_operations/CMakeLists.txt |   2 +
 .../SubtractBinaryOperation.cpp                 |  81 +++++-
 .../tests/AddBinaryOperation_unittest.cpp       |  23 +-
 .../tests/BinaryOperationTestUtil.hpp           |   4 +-
 .../tests/SubtractBinaryOperation_unittest.cpp  |  23 +-
 .../operations/unary_operations/CMakeLists.txt  |   4 +-
 .../unary_operations/DateExtractOperation.cpp   | 244 ++++++++++++++++---
 .../unary_operations/DateExtractOperation.hpp   |  52 +++-
 .../tests/DateExtractOperation_unittest.cpp     |  93 +++++--
 18 files changed, 707 insertions(+), 173 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/parser/SqlParser.ypp
----------------------------------------------------------------------
diff --git a/parser/SqlParser.ypp b/parser/SqlParser.ypp
index 3f0cc80..547bb40 100644
--- a/parser/SqlParser.ypp
+++ b/parser/SqlParser.ypp
@@ -760,7 +760,7 @@ data_type:
     YYERROR;
   }
   | TOKEN_DATE {
-    $$ = new quickstep::ParseDataType(quickstep::TypeFactory::GetType(quickstep::kDatetime));
+    $$ = new quickstep::ParseDataType(quickstep::TypeFactory::GetType(quickstep::kDate));
   }
   | TOKEN_DATETIME {
     $$ = new quickstep::ParseDataType(quickstep::TypeFactory::GetType(quickstep::kDatetime));

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/parser/tests/Select.test
----------------------------------------------------------------------
diff --git a/parser/tests/Select.test b/parser/tests/Select.test
index b614a99..8e47519 100644
--- a/parser/tests/Select.test
+++ b/parser/tests/Select.test
@@ -961,7 +961,7 @@ SelectStatement
   | |   +-StringLiteral[value=1998-12-01]
   | +-SelectListItem
   |   +-Literal
-  |     +-StringLiteral[value=1998-12-01,explicit_type=Datetime]
+  |     +-StringLiteral[value=1998-12-01,explicit_type=Date]
   +-from_clause=
     +-TableReference[table=test]
 ==
@@ -975,10 +975,10 @@ SelectStatement
   +-select_clause=SelectList
   | +-SelectListItem
   | | +-Literal
-  | |   +-StringLiteral[value=1960-12-12,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1960-12-12,explicit_type=Date]
   | +-SelectListItem
   |   +-Literal
-  |     +-StringLiteral[value=1901-12-14,explicit_type=Datetime]
+  |     +-StringLiteral[value=1901-12-14,explicit_type=Date]
   +-from_clause=
     +-TableReference[table=test]
 ==
@@ -990,10 +990,10 @@ SelectStatement
   +-select_clause=SelectList
   | +-SelectListItem
   | | +-Literal
-  | |   +-StringLiteral[value=1998-2-12,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1998-2-12,explicit_type=Date]
   | +-SelectListItem
   |   +-Literal
-  |     +-StringLiteral[value=1998-12-2,explicit_type=Datetime]
+  |     +-StringLiteral[value=1998-12-2,explicit_type=Date]
   +-from_clause=
     +-TableReference[table=test]
 ==
@@ -1007,10 +1007,10 @@ SelectStatement
   +-select_clause=SelectList
   | +-SelectListItem
   | | +-Literal
-  | |   +-StringLiteral[value=+1921-12-12,explicit_type=Datetime]
+  | |   +-StringLiteral[value=+1921-12-12,explicit_type=Date]
   | +-SelectListItem
   |   +-Literal
-  |     +-StringLiteral[value=+10001-12-12,explicit_type=Datetime]
+  |     +-StringLiteral[value=+10001-12-12,explicit_type=Date]
   +-from_clause=
     +-TableReference[table=test]
 ==
@@ -1059,13 +1059,13 @@ SelectStatement
   +-select_clause=SelectList
   | +-SelectListItem
   | | +-Literal
-  | |   +-StringLiteral[value=1996-02-29,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1996-02-29,explicit_type=Date]
   | +-SelectListItem
   | | +-Literal
-  | |   +-StringLiteral[value=1997-03-31,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1997-03-31,explicit_type=Date]
   | +-SelectListItem
   |   +-Literal
-  |     +-StringLiteral[value=1998-04-30,explicit_type=Datetime]
+  |     +-StringLiteral[value=1998-04-30,explicit_type=Date]
   +-from_clause=
     +-TableReference[table=test]
 ==
@@ -1077,9 +1077,9 @@ SELECT DATE '1999-02-29' FROM test
                        ^
 ==
 
-# Quickstep accepts time in the DATE type.
-SELECT DATE '2007-05-08 12:35:29',
-       DATE '2007-05-08 12:35:29.010'
+# Quickstep accepts time in the DATETIME type.
+SELECT DATETIME '2007-05-08 12:35:29',
+       DATETIME '2007-05-08 12:35:29.010'
 FROM test
 --
 SelectStatement
@@ -1114,7 +1114,7 @@ SelectStatement
   | +-left_operand=AttributeReference[attribute_name=attr_date]
   | +-right_operand=Subtract
   |   +-left_operand=Literal
-  |   | +-StringLiteral[value=1998-12-01,explicit_type=Datetime]
+  |   | +-StringLiteral[value=1998-12-01,explicit_type=Date]
   |   +-right_operand=Literal
   |     +-StringLiteral[value=96 day,explicit_type=DatetimeInterval]
   +-from_clause=

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/parser/tests/TPCH.test
----------------------------------------------------------------------
diff --git a/parser/tests/TPCH.test b/parser/tests/TPCH.test
index e30d373..f0ffaa9 100644
--- a/parser/tests/TPCH.test
+++ b/parser/tests/TPCH.test
@@ -87,7 +87,7 @@ SelectStatement
   | +-left_operand=AttributeReference[attribute_name=l_shipdate]
   | +-right_operand=Subtract
   |   +-left_operand=Literal
-  |   | +-StringLiteral[value=1998-12-01,explicit_type=Datetime]
+  |   | +-StringLiteral[value=1998-12-01,explicit_type=Date]
   |   +-right_operand=Literal
   |     +-StringLiteral[value=96 day,explicit_type=DatetimeInterval]
   +-group_by=GroupBy
@@ -297,11 +297,11 @@ SelectStatement
   | +-Less
   | | +-left_operand=AttributeReference[attribute_name=o_orderdate]
   | | +-right_operand=Literal
-  | |   +-StringLiteral[value=1995-03-17,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1995-03-17,explicit_type=Date]
   | +-Greater
   |   +-left_operand=AttributeReference[attribute_name=l_shipdate]
   |   +-right_operand=Literal
-  |     +-StringLiteral[value=1995-03-17,explicit_type=Datetime]
+  |     +-StringLiteral[value=1995-03-17,explicit_type=Date]
   +-group_by=GroupBy
   | +-AttributeReference[attribute_name=l_orderkey]
   | +-AttributeReference[attribute_name=o_orderdate]
@@ -353,12 +353,12 @@ SelectStatement
   | +-GreaterOrEqual
   | | +-left_operand=AttributeReference[attribute_name=o_orderdate]
   | | +-right_operand=Literal
-  | |   +-StringLiteral[value=1995-08-01,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1995-08-01,explicit_type=Date]
   | +-Less
   | | +-left_operand=AttributeReference[attribute_name=o_orderdate]
   | | +-right_operand=Add
   | |   +-left_operand=Literal
-  | |   | +-StringLiteral[value=1995-08-01,explicit_type=Datetime]
+  | |   | +-StringLiteral[value=1995-08-01,explicit_type=Date]
   | |   +-right_operand=Literal
   | |     +-StringLiteral[value=3 month,explicit_type=YearMonthInterval]
   | +-Exists
@@ -448,12 +448,12 @@ SelectStatement
   | +-GreaterOrEqual
   | | +-left_operand=AttributeReference[attribute_name=o_orderdate]
   | | +-right_operand=Literal
-  | |   +-StringLiteral[value=1997-01-01,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1997-01-01,explicit_type=Date]
   | +-Less
   |   +-left_operand=AttributeReference[attribute_name=o_orderdate]
   |   +-right_operand=Add
   |     +-left_operand=Literal
-  |     | +-StringLiteral[value=1997-01-01,explicit_type=Datetime]
+  |     | +-StringLiteral[value=1997-01-01,explicit_type=Date]
   |     +-right_operand=Literal
   |       +-StringLiteral[value=1 year,explicit_type=YearMonthInterval]
   +-group_by=GroupBy
@@ -493,12 +493,12 @@ SelectStatement
   | +-GreaterOrEqual
   | | +-left_operand=AttributeReference[attribute_name=l_shipdate]
   | | +-right_operand=Literal
-  | |   +-StringLiteral[value=1997-01-01,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1997-01-01,explicit_type=Date]
   | +-Less
   | | +-left_operand=AttributeReference[attribute_name=l_shipdate]
   | | +-right_operand=Add
   | |   +-left_operand=Literal
-  | |   | +-StringLiteral[value=1997-01-01,explicit_type=Datetime]
+  | |   | +-StringLiteral[value=1997-01-01,explicit_type=Date]
   | |   +-right_operand=Literal
   | |     +-StringLiteral[value=1 year,explicit_type=YearMonthInterval]
   | +-Between
@@ -649,9 +649,9 @@ SelectStatement
           | +-Between
           |   +-check_operand=AttributeReference[attribute_name=l_shipdate]
           |   +-lower_bound_operand=Literal
-          |   | +-StringLiteral[value=1995-01-01,explicit_type=Datetime]
+          |   | +-StringLiteral[value=1995-01-01,explicit_type=Date]
           |   +-upper_bound_operand=Literal
-          |     +-StringLiteral[value=1996-12-31,explicit_type=Datetime]
+          |     +-StringLiteral[value=1996-12-31,explicit_type=Date]
           +-from_clause=
             +-TableReference[table=supplier]
             +-TableReference[table=lineitem]
@@ -777,9 +777,9 @@ SelectStatement
           | +-Between
           | | +-check_operand=AttributeReference[attribute_name=o_orderdate]
           | | +-lower_bound_operand=Literal
-          | | | +-StringLiteral[value=1995-01-01,explicit_type=Datetime]
+          | | | +-StringLiteral[value=1995-01-01,explicit_type=Date]
           | | +-upper_bound_operand=Literal
-          | |   +-StringLiteral[value=1996-12-31,explicit_type=Datetime]
+          | |   +-StringLiteral[value=1996-12-31,explicit_type=Date]
           | +-Equal
           |   +-left_operand=AttributeReference[attribute_name=p_type]
           |   +-right_operand=Literal
@@ -973,12 +973,12 @@ SelectStatement
   | +-GreaterOrEqual
   | | +-left_operand=AttributeReference[attribute_name=o_orderdate]
   | | +-right_operand=Literal
-  | |   +-StringLiteral[value=1994-03-01,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1994-03-01,explicit_type=Date]
   | +-Less
   | | +-left_operand=AttributeReference[attribute_name=o_orderdate]
   | | +-right_operand=Add
   | |   +-left_operand=Literal
-  | |   | +-StringLiteral[value=1994-03-01,explicit_type=Datetime]
+  | |   | +-StringLiteral[value=1994-03-01,explicit_type=Date]
   | |   +-right_operand=Literal
   | |     +-StringLiteral[value=3 month,explicit_type=YearMonthInterval]
   | +-Equal
@@ -1198,12 +1198,12 @@ SelectStatement
   | +-GreaterOrEqual
   | | +-left_operand=AttributeReference[attribute_name=l_receiptdate]
   | | +-right_operand=Literal
-  | |   +-StringLiteral[value=1997-01-01,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1997-01-01,explicit_type=Date]
   | +-Less
   |   +-left_operand=AttributeReference[attribute_name=l_receiptdate]
   |   +-right_operand=Add
   |     +-left_operand=Literal
-  |     | +-StringLiteral[value=1997-01-01,explicit_type=Datetime]
+  |     | +-StringLiteral[value=1997-01-01,explicit_type=Date]
   |     +-right_operand=Literal
   |       +-StringLiteral[value=1 year,explicit_type=YearMonthInterval]
   +-group_by=GroupBy
@@ -1335,12 +1335,12 @@ SelectStatement
   | +-GreaterOrEqual
   | | +-left_operand=AttributeReference[attribute_name=l_shipdate]
   | | +-right_operand=Literal
-  | |   +-StringLiteral[value=1994-11-01,explicit_type=Datetime]
+  | |   +-StringLiteral[value=1994-11-01,explicit_type=Date]
   | +-Less
   |   +-left_operand=AttributeReference[attribute_name=l_shipdate]
   |   +-right_operand=Add
   |     +-left_operand=Literal
-  |     | +-StringLiteral[value=1994-11-01,explicit_type=Datetime]
+  |     | +-StringLiteral[value=1994-11-01,explicit_type=Date]
   |     +-right_operand=Literal
   |       +-StringLiteral[value=1 month,explicit_type=YearMonthInterval]
   +-from_clause=
@@ -1433,12 +1433,12 @@ SelectStatement
         | +-GreaterOrEqual
         | | +-left_operand=AttributeReference[attribute_name=l_shipdate]
         | | +-right_operand=Literal
-        | |   +-StringLiteral[value=1996-11-01,explicit_type=Datetime]
+        | |   +-StringLiteral[value=1996-11-01,explicit_type=Date]
         | +-Less
         |   +-left_operand=AttributeReference[attribute_name=l_shipdate]
         |   +-right_operand=Add
         |     +-left_operand=Literal
-        |     | +-StringLiteral[value=1996-11-01,explicit_type=Datetime]
+        |     | +-StringLiteral[value=1996-11-01,explicit_type=Date]
         |     +-right_operand=Literal
         |       +-StringLiteral[value=3 month,explicit_type=YearMonthInterval]
         +-group_by=GroupBy
@@ -1996,14 +1996,13 @@ SelectStatement
   | |     |       | | +-left_operand=AttributeReference[
   | |     |       | | | attribute_name=l_shipdate]
   | |     |       | | +-right_operand=Literal
-  | |     |       | |   +-StringLiteral[value=1993-01-01,explicit_type=Datetime]
+  | |     |       | |   +-StringLiteral[value=1993-01-01,explicit_type=Date]
   | |     |       | +-Less
   | |     |       |   +-left_operand=AttributeReference[
   | |     |       |   | attribute_name=l_shipdate]
   | |     |       |   +-right_operand=Add
   | |     |       |     +-left_operand=Literal
-  | |     |       |     | +-StringLiteral[value=1993-01-01,
-  | |     |       |     |   explicit_type=Datetime]
+  | |     |       |     | +-StringLiteral[value=1993-01-01,explicit_type=Date]
   | |     |       |     +-right_operand=Literal
   | |     |       |       +-StringLiteral[value=1 year,
   | |     |       |         explicit_type=YearMonthInterval]

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/query_optimizer/tests/execution_generator/Insert.test
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/execution_generator/Insert.test b/query_optimizer/tests/execution_generator/Insert.test
index 152e2a3..1be7be9 100644
--- a/query_optimizer/tests/execution_generator/Insert.test
+++ b/query_optimizer/tests/execution_generator/Insert.test
@@ -103,6 +103,25 @@ FROM generate_series(1, 5) AS gs(i);
 
 SELECT * FROM bar3;
 --
++-----------+------------+------------------------+--------------------------------+
+|x          |y           |z                       |w                               |
++-----------+------------+------------------------+--------------------------------+
+|          1|  2016-01-01|                    NULL|                             abc|
+|          2|  2016-01-01|                    NULL|                             abc|
+|          3|  2016-01-01|                    NULL|                             abc|
+|          4|  2016-01-01|                    NULL|                             abc|
+|          5|  2016-01-01|                    NULL|                             abc|
++-----------+------------+------------------------+--------------------------------+
+==
+
+CREATE TABLE bar4 (x INT, y DATETIME, z DOUBLE NULL, w VARCHAR(32));
+
+INSERT INTO bar4
+SELECT i, DATETIME '2016-1-1T00:00:00', NULL, 'abc'
+FROM generate_series(1, 5) AS gs(i);
+
+SELECT * FROM bar4;
+--
 +-----------+-----------------------------------------+------------------------+--------------------------------+
 |x          |y                                        |z                       |w                               |
 +-----------+-----------------------------------------+------------------------+--------------------------------+

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/query_optimizer/tests/execution_generator/Select.test
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/execution_generator/Select.test b/query_optimizer/tests/execution_generator/Select.test
index 7d662e9..494e759 100644
--- a/query_optimizer/tests/execution_generator/Select.test
+++ b/query_optimizer/tests/execution_generator/Select.test
@@ -482,20 +482,20 @@ SELECT DATE '2000-02-29' + INTERVAL '1 year',
        DATE '1998-03-31' + INTERVAL '1 month',
        DATE '2000-03-31' - INTERVAL '1 month',
        DATE '2000-01-31' + INTERVAL '1 month',
-       DATE '2000-02-29' + INTERVAL '1 day',
+       DATETIME '2000-02-29' + INTERVAL '1 day',
        DATE '2000-02-29' - INTERVAL '1 year'
 FROM test
 WHERE int_col = 2;
 --
-+----------------------------------------------------+-----------------------------------------------------+-----------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+----------------------------------------------------+
-|(Datetime('2000-02-29')+YearMonthInterval('1 year'))|(Datetime('1998-03-31')+YearMonthInterval('1 month'))|(Datetime('2000-03-31')-YearMonthInterval('1 month'))|(Datetime('2000-01-31')+YearMonthInterval('1 month'))|(Datetime('2000-02-29')+DatetimeInterval('1 day'))|(Datetime('2000-02-29')-YearMonthInterval('1 year'))|
-+----------------------------------------------------+-----------------------------------------------------+-----------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+----------------------------------------------------+
-|                                 2001-02-28T00:00:00|                                  1998-04-30T00:00:00|                                  2000-02-29T00:00:00|                                  2000-02-29T00:00:00|                               2000-03-01T00:00:00|                                 1999-02-28T00:00:00|
-+----------------------------------------------------+-----------------------------------------------------+-----------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+----------------------------------------------------+
++------------------------------------------------+-------------------------------------------------+-------------------------------------------------+-------------------------------------------------+--------------------------------------------------+------------------------------------------------+
+|(Date('2000-02-29')+YearMonthInterval('1 year'))|(Date('1998-03-31')+YearMonthInterval('1 month'))|(Date('2000-03-31')-YearMonthInterval('1 month'))|(Date('2000-01-31')+YearMonthInterval('1 month'))|(Datetime('2000-02-29')+DatetimeInterval('1 day'))|(Date('2000-02-29')-YearMonthInterval('1 year'))|
++------------------------------------------------+-------------------------------------------------+-------------------------------------------------+-------------------------------------------------+--------------------------------------------------+------------------------------------------------+
+|                                      2001-02-28|                                       1998-04-30|                                       2000-02-29|                                       2000-02-29|                               2000-03-01T00:00:00|                                      1999-02-28|
++------------------------------------------------+-------------------------------------------------+-------------------------------------------------+-------------------------------------------------+--------------------------------------------------+------------------------------------------------+
 ==
 
-SELECT DATE '2000-02-29' - DATE '2000-02-28',
-       DATE '2000-02-29' - DATE '1999-02-28'
+SELECT DATETIME '2000-02-29' - DATETIME '2000-02-28',
+       DATETIME '2000-02-29' - DATETIME '1999-02-28'
 FROM test
 WHERE int_col = 2;
 --
@@ -524,11 +524,11 @@ SELECT DATE '+1980-02-29' + INTERVAL '1 year'
 FROM test
 WHERE int_col = 2;
 --
-+-----------------------------------------------------+
-|(Datetime('+1980-02-29')+YearMonthInterval('1 year'))|
-+-----------------------------------------------------+
-|                                  1981-02-28T00:00:00|
-+-----------------------------------------------------+
++-------------------------------------------------+
+|(Date('+1980-02-29')+YearMonthInterval('1 year'))|
++-------------------------------------------------+
+|                                       1981-02-28|
++-------------------------------------------------+
 ==
 
 SELECT int_col
@@ -633,9 +633,9 @@ ORDER BY group_col1,
 
 
 CREATE TABLE dates (value DATETIME);
-INSERT INTO dates VALUES (DATE '2016-01-02 10:20:30');
-INSERT INTO dates VALUES (DATE '2016-02-03 11:21:31');
-INSERT INTO dates VALUES (DATE '2016-03-04 12:22:32');
+INSERT INTO dates VALUES (DATETIME '2016-01-02 10:20:30');
+INSERT INTO dates VALUES (DATETIME '2016-02-03 11:21:31');
+INSERT INTO dates VALUES (DATETIME '2016-03-04 12:22:32');
 
 SELECT EXTRACT(YEAR FROM value) * 10000 +
        EXTRACT(MONTH FROM value) * 100 +

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/query_optimizer/tests/resolver/Select.test
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/resolver/Select.test b/query_optimizer/tests/resolver/Select.test
index 7033dec..facb3a1 100644
--- a/query_optimizer/tests/resolver/Select.test
+++ b/query_optimizer/tests/resolver/Select.test
@@ -2148,10 +2148,10 @@ name
 ,relation=,type=Float]
 ==
 
-select date '1998-12-12' + interval '5 day',
+select datetime '1998-12-12' + interval '5 day',
        date '1998-12-12' - interval '5 month',
        interval '5 year' + date '1998-12-12',
-       date '1998-12-12' - date '1998-12-11',
+       datetime '1998-12-12' - datetime '1998-12-11',
        interval '10 day' + interval '11 day',
        interval '30 month' + interval '1 year',
        interval '30 month' - interval '1 year'
@@ -2172,18 +2172,16 @@ TopLevelPlan
 |   | +-Add
 |   |   +-Literal[value=1998-12-12T00:00:00,type=Datetime]
 |   |   +-Literal[value=5 days 00:00:00,type=DatetimeInterval]
-|   +-Alias[id=7,name=,
-|   | alias=(Datetime('1998-12-12')-YearMonthInterval('5 month')),relation=,
-|   | type=Datetime]
+|   +-Alias[id=7,name=,alias=(Date('1998-12-12')-YearMonthInterval('5 month')),
+|   | relation=,type=Date]
 |   | +-Subtract
-|   |   +-Literal[value=1998-12-12T00:00:00,type=Datetime]
+|   |   +-Literal[value=1998-12-12,type=Date]
 |   |   +-Literal[value=5 mons,type=YearMonthInterval]
-|   +-Alias[id=8,name=,
-|   | alias=(YearMonthInterval('5 year')+Datetime('1998-12-12')),relation=,
-|   | type=Datetime]
+|   +-Alias[id=8,name=,alias=(YearMonthInterval('5 year')+Date('1998-12-12')),
+|   | relation=,type=Date]
 |   | +-Add
 |   |   +-Literal[value=5 years,type=YearMonthInterval]
-|   |   +-Literal[value=1998-12-12T00:00:00,type=Datetime]
+|   |   +-Literal[value=1998-12-12,type=Date]
 |   +-Alias[id=9,name=,alias=(Datetime('1998-12-12')-Datetime('1998-12-11')),
 |   | relation=,type=DatetimeInterval]
 |   | +-Subtract
@@ -2212,11 +2210,9 @@ TopLevelPlan
   | alias=(Datetime('1998-12-12')+DatetimeInterval('5 day')),relation=,
   | type=Datetime]
   +-AttributeReference[id=7,name=,
-  | alias=(Datetime('1998-12-12')-YearMonthInterval('5 month')),relation=,
-  | type=Datetime]
+  | alias=(Date('1998-12-12')-YearMonthInterval('5 month')),relation=,type=Date]
   +-AttributeReference[id=8,name=,
-  | alias=(YearMonthInterval('5 year')+Datetime('1998-12-12')),relation=,
-  | type=Datetime]
+  | alias=(YearMonthInterval('5 year')+Date('1998-12-12')),relation=,type=Date]
   +-AttributeReference[id=9,name=,
   | alias=(Datetime('1998-12-12')-Datetime('1998-12-11')),relation=,
   | type=DatetimeInterval]
@@ -2270,9 +2266,9 @@ TopLevelPlan
     relation=,type=YearMonthInterval]
 ==
 
-SELECT EXTRACT(YEAR FROM DATE '2016-01-02 10:20:30') * 10000 +
-       EXTRACT(MONTH FROM DATE '2016-01-02 10:20:30') * 100 +
-       EXTRACT(DAY FROM DATE '2016-01-02 10:20:30') AS date_digits
+SELECT EXTRACT(YEAR FROM DATETIME '2016-01-02 10:20:30') * 10000 +
+       EXTRACT(MONTH FROM DATETIME '2016-01-02 10:20:30') * 100 +
+       EXTRACT(DAY FROM DATETIME '2016-01-02 10:20:30') AS date_digits
 FROM generate_series(1, 1);
 --
 TopLevelPlan
@@ -2445,27 +2441,51 @@ select interval '4 day' + interval '5 year'
 select date '1998-12-12' + date '1998-12-12'
 from test
 --
-ERROR: Can not apply binary operation "Add" to arguments of types Datetime and Datetime (1 : 26)
+ERROR: Can not apply binary operation "Add" to arguments of types Date and Date (1 : 26)
 select date '1998-12-12' + date '1998-12-12'
                          ^
 ==
 
+select datetime '1998-12-12' + datetime '1998-12-12'
+from test
+--
+ERROR: Can not apply binary operation "Add" to arguments of types Datetime and Datetime (1 : 30)
+select datetime '1998-12-12' + datetime '1998-12-12'
+                             ^
+==
+
 select date '1998-12-12' * date '1998-12-12'
 from test
 --
-ERROR: Can not apply binary operation "Multiply" to arguments of types Datetime and Datetime (1 : 26)
+ERROR: Can not apply binary operation "Multiply" to arguments of types Date and Date (1 : 26)
 select date '1998-12-12' * date '1998-12-12'
                          ^
 ==
 
+select datetime '1998-12-12' * datetime '1998-12-12'
+from test
+--
+ERROR: Can not apply binary operation "Multiply" to arguments of types Datetime and Datetime (1 : 30)
+select datetime '1998-12-12' * datetime '1998-12-12'
+                             ^
+==
+
 select interval '5 day' - date '1998-12-12'
 from test
 --
-ERROR: Can not apply binary operation "Subtract" to arguments of types DatetimeInterval and Datetime (1 : 25)
+ERROR: Can not apply binary operation "Subtract" to arguments of types DatetimeInterval and Date (1 : 25)
 select interval '5 day' - date '1998-12-12'
                         ^
 ==
 
+select interval '5 day' - datetime '1998-12-12'
+from test
+--
+ERROR: Can not apply binary operation "Subtract" to arguments of types DatetimeInterval and Datetime (1 : 25)
+select interval '5 day' - datetime '1998-12-12'
+                        ^
+==
+
 select (interval '10 day' + interval '3 day') + 5
 from test
 --
@@ -2477,11 +2497,20 @@ ERROR: Can not apply binary operation "Add" to arguments of types DatetimeInterv
 select 5 / (date '1999-10-12' + yearmonth interval '10 year')
 from test
 --
-ERROR: Can not apply binary operation "Divide" to arguments of types Int and Datetime (1 : 10)
+ERROR: Can not apply binary operation "Divide" to arguments of types Int and Date (1 : 10)
 select 5 / (date '1999-10-12' + yearmont...
          ^
 ==
 
+select 5 / (datetime '1999-10-12' + yearmonth interval '10 year')
+from test
+--
+ERROR: Can not apply binary operation "Divide" to arguments of types Int and Datetime (1 : 10)
+select 5 / (datetime '1999-10-12' + yearmont...
+         ^
+==
+
+
 # CASE expressions.
 SELECT CASE int_col%2
            WHEN 1 THEN 'odd'

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/DateOperatorOverloads.hpp
----------------------------------------------------------------------
diff --git a/types/DateOperatorOverloads.hpp b/types/DateOperatorOverloads.hpp
index 5cf8990..b04f44e 100644
--- a/types/DateOperatorOverloads.hpp
+++ b/types/DateOperatorOverloads.hpp
@@ -20,6 +20,7 @@
 #ifndef QUICKSTEP_TYPES_DATE_BINARY_OPERATORS_HPP_
 #define QUICKSTEP_TYPES_DATE_BINARY_OPERATORS_HPP_
 
+#include <cstdint>
 #include <ctime>
 
 #include "types/DatetimeLit.hpp"
@@ -36,7 +37,29 @@ namespace quickstep {
  */
 
 // Month arithmetic clamps to the actual last day of a given month.
-inline void ClampDayOfMonth(struct tm *timeinfo) {
+inline int ClampDayOfMonth(const int year, const int month, const int day) {
+  DCHECK_LT(day, 32);
+  switch (month) {
+    case 2: {
+      const int days_in_february =
+          (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+              ? 29
+              : 28;
+      return (day > days_in_february) ? days_in_february : day;
+    }
+    case 4:
+    case 6:
+    case 9:
+    case 11: {
+      return day == 31 ? 30 : day;
+    }
+    default:
+      return day;
+  }
+}
+
+// We have a separate function here because timeinfo's months begin from 0.
+inline void ClampDayOfMonthStructTM(struct tm *timeinfo) {
   DCHECK_LT(timeinfo->tm_mday, 32);
   switch (timeinfo->tm_mon) {
     case 1: {
@@ -87,7 +110,7 @@ inline DatetimeLit operator+(const DatetimeLit &lhs, const YearMonthIntervalLit
     ++timeinfo.tm_year;
   }
 
-  ClampDayOfMonth(&timeinfo);
+  ClampDayOfMonthStructTM(&timeinfo);
 
   DatetimeLit datetime(DatetimeLit::FromEpochTime(quickstep::timegm(&timeinfo)));
   datetime.ticks += lhs.subseconds();
@@ -98,6 +121,25 @@ inline DatetimeLit operator+(const YearMonthIntervalLit &lhs, const DatetimeLit
   return rhs + lhs;
 }
 
+inline DateLit operator+(const DateLit &lhs, const YearMonthIntervalLit &rhs) {
+  std::int32_t result_year = lhs.year + (rhs.months / 12);
+  std::uint8_t result_month = lhs.month + (rhs.months % 12);
+
+  if (result_month > 11) {
+    result_month -= 12;
+    ++result_year;
+  }
+
+  const std::uint8_t result_day = static_cast<std::uint8_t>(
+      ClampDayOfMonth(result_year, result_month, lhs.day));
+
+  return DateLit::Create(result_year, result_month, result_day);
+}
+
+inline DateLit operator+(const YearMonthIntervalLit &lhs, const DateLit &rhs) {
+  return rhs + lhs;
+}
+
 inline DatetimeIntervalLit operator+(const DatetimeIntervalLit &lhs, const DatetimeIntervalLit &rhs) {
   DatetimeIntervalLit interval(lhs);
   interval += rhs;
@@ -137,13 +179,28 @@ inline DatetimeLit operator-(const DatetimeLit &lhs, const YearMonthIntervalLit
     timeinfo.tm_mon += 12;
   }
 
-  ClampDayOfMonth(&timeinfo);
+  ClampDayOfMonthStructTM(&timeinfo);
 
   DatetimeLit datetime(DatetimeLit::FromEpochTime(quickstep::timegm(&timeinfo)));
   datetime.ticks += lhs.subseconds();
   return datetime;  // Datetime in GMT.
 }
 
+inline DateLit operator-(const DateLit &lhs, const YearMonthIntervalLit &rhs) {
+  std::int32_t result_year = lhs.year - (rhs.months / 12);
+  std::int8_t result_month = lhs.month - (rhs.months % 12);
+
+  if (result_month < 0) {
+    --result_year;
+    result_month += 12;
+  }
+
+  const std::uint8_t result_day = static_cast<std::uint8_t>(
+      ClampDayOfMonth(result_year, result_month, lhs.day));
+
+  return DateLit::Create(result_year, result_month, result_day);
+}
+
 inline DatetimeIntervalLit operator-(const DatetimeIntervalLit &lhs, const DatetimeIntervalLit &rhs) {
   DatetimeIntervalLit interval(lhs);
   interval -= rhs;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/DatetimeLit.hpp
----------------------------------------------------------------------
diff --git a/types/DatetimeLit.hpp b/types/DatetimeLit.hpp
index 580a0ed..58c852f 100644
--- a/types/DatetimeLit.hpp
+++ b/types/DatetimeLit.hpp
@@ -91,6 +91,14 @@ struct DateLit {
   inline bool operator!=(const DateLit& rhs) const {
     return !(*this == rhs);
   }
+
+  inline std::int32_t yearField() const {
+    return year;
+  }
+
+  inline std::int32_t monthField() const {
+    return static_cast<std::int32_t>(month);
+  }
 };
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/binary_operations/AddBinaryOperation.cpp
----------------------------------------------------------------------
diff --git a/types/operations/binary_operations/AddBinaryOperation.cpp b/types/operations/binary_operations/AddBinaryOperation.cpp
index 2ee551b..8f56a61 100644
--- a/types/operations/binary_operations/AddBinaryOperation.cpp
+++ b/types/operations/binary_operations/AddBinaryOperation.cpp
@@ -23,8 +23,9 @@
 #include <utility>
 
 #include "types/DateOperatorOverloads.hpp"
-#include "types/DatetimeLit.hpp"
+#include "types/DateType.hpp"
 #include "types/DatetimeIntervalType.hpp"
+#include "types/DatetimeLit.hpp"
 #include "types/DatetimeType.hpp"
 #include "types/IntervalLit.hpp"
 #include "types/Type.hpp"
@@ -47,6 +48,9 @@ bool AddBinaryOperation::canApplyToTypes(const Type &left, const Type &right) co
     case kDouble: {
       return (right.getSuperTypeID() == Type::kNumeric);
     }
+    case kDate: {
+      return (right.getTypeID() == kYearMonthInterval);
+    }
     case kDatetime: {
       return (right.getTypeID() == kDatetimeInterval ||
               right.getTypeID() == kYearMonthInterval);
@@ -56,7 +60,8 @@ bool AddBinaryOperation::canApplyToTypes(const Type &left, const Type &right) co
               right.getTypeID() == kDatetimeInterval);
     }
     case kYearMonthInterval: {
-      return (right.getTypeID() == kDatetime ||
+      return (right.getTypeID() == kDate ||
+              right.getTypeID() == kDatetime ||
               right.getTypeID() == kYearMonthInterval);
     }
     default:
@@ -72,6 +77,9 @@ const Type* AddBinaryOperation::resultTypeForArgumentTypes(const Type &left, con
              (left.getTypeID() == kDatetime && right.getTypeID() == kYearMonthInterval) ||
              (left.getTypeID() == kYearMonthInterval && right.getTypeID() == kDatetime)) {
     return &(DatetimeType::Instance(left.isNullable() || right.isNullable()));
+  } else if ((left.getTypeID() == kDate && right.getTypeID() == kYearMonthInterval) ||
+             (left.getTypeID() == kYearMonthInterval && right.getTypeID() == kDate)) {
+    return &(DateType::Instance(left.isNullable() || right.isNullable()));
   } else if (left.getTypeID() == kDatetimeInterval && right.getTypeID() == kDatetimeInterval) {
     return &(DatetimeIntervalType::Instance(left.isNullable() || right.isNullable()));
   } else if (left.getTypeID() == kYearMonthInterval && right.getTypeID() == kYearMonthInterval) {
@@ -102,6 +110,10 @@ const Type* AddBinaryOperation::resultTypeForPartialArgumentTypes(const Type *le
       // Datetime can be added with either interval type, and always yields
       // Datetime.
       return &TypeFactory::GetType(kDatetime, true);
+    case kDate:
+      // Date can be added with YearMonthInterval type only, and always yields
+      // Date.
+      return &TypeFactory::GetType(kDate, true);
     default:
       // Ambiguous or inapplicable.
       return nullptr;
@@ -121,9 +133,15 @@ bool AddBinaryOperation::partialTypeSignatureIsPlausible(
       // Type is not plausible with unknown arguments.
       return false;
     } else {
-      return QUICKSTEP_EQUALS_ANY_CONSTANT(
-          result_type->getTypeID(),
-          kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval);
+      return QUICKSTEP_EQUALS_ANY_CONSTANT(result_type->getTypeID(),
+                                           kInt,
+                                           kLong,
+                                           kFloat,
+                                           kDouble,
+                                           kDate,
+                                           kDatetime,
+                                           kDatetimeInterval,
+                                           kYearMonthInterval);
     }
   }
 
@@ -148,9 +166,15 @@ bool AddBinaryOperation::partialTypeSignatureIsPlausible(
                                     ? left_argument_type
                                     : right_argument_type;
   if (result_type == nullptr) {
-    return QUICKSTEP_EQUALS_ANY_CONSTANT(
-        known_argument_type->getTypeID(),
-        kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval);
+    return QUICKSTEP_EQUALS_ANY_CONSTANT(known_argument_type->getTypeID(),
+                                         kInt,
+                                         kLong,
+                                         kFloat,
+                                         kDouble,
+                                         kDate,
+                                         kDatetime,
+                                         kDatetimeInterval,
+                                         kYearMonthInterval);
   }
 
   if (!result_type->isNullable()) {
@@ -176,10 +200,12 @@ bool AddBinaryOperation::partialTypeSignatureIsPlausible(
       return QUICKSTEP_EQUALS_ANY_CONSTANT(
           known_argument_type->getTypeID(),
           kInt, kLong, kFloat, kDouble);
+    case kDate:
+      return (known_argument_type->getTypeID() == kDate);
     case kDatetime:
       return QUICKSTEP_EQUALS_ANY_CONSTANT(
           known_argument_type->getTypeID(),
-          kDatetime, kDatetimeInterval, kYearMonthInterval);
+          kDatetime, kDatetimeInterval);
     case kDatetimeInterval:
       return (known_argument_type->getTypeID() == kDatetimeInterval);
     case kYearMonthInterval:
@@ -208,6 +234,10 @@ std::pair<const Type*, const Type*> AddBinaryOperation::pushDownTypeHint(
       // choose the highest-precision suitable Type (i.e. the same as the
       // result type) in such cases.
       return std::pair<const Type*, const Type*>(result_type_hint, result_type_hint);
+    case kDate:
+      // Hint is ambiguous: one argument should be a Date, other has to be
+      // kYearMonthInterval, but order is not important.
+      return std::pair<const Type*, const Type*>(nullptr, nullptr);
     case kDatetime:
       // Hint is ambiguous: one argument should be a Datetime, the other should
       // be one of the interval types, but either order is acceptable.
@@ -242,6 +272,16 @@ TypedValue AddBinaryOperation::applyToChecked(const TypedValue &left,
       }
       break;
     }
+    case kDate: {
+      if (right_type.getTypeID() == kYearMonthInterval) {
+        if (left.isNull() || right.isNull()) {
+          return TypedValue(kDate);
+        }
+
+        return TypedValue(left.getLiteral<DateLit>() + right.getLiteral<YearMonthIntervalLit>());
+      }
+      break;
+    }
     case kDatetime: {
       if (right_type.getTypeID() == kDatetimeInterval) {
         if (left.isNull() || right.isNull()) {
@@ -275,7 +315,13 @@ TypedValue AddBinaryOperation::applyToChecked(const TypedValue &left,
       break;
     }
     case kYearMonthInterval: {
-      if (right_type.getTypeID() == kDatetime) {
+      if (right_type.getTypeID() == kDate) {
+        if (left.isNull() || right.isNull()) {
+          return TypedValue(kDatetime);
+        }
+
+        return TypedValue(left.getLiteral<YearMonthIntervalLit>() + right.getLiteral<DateLit>());
+      } else if (right_type.getTypeID() == kDatetime) {
         if (left.isNull() || right.isNull()) {
           return TypedValue(kDatetime);
         }
@@ -310,6 +356,16 @@ UncheckedBinaryOperator* AddBinaryOperation::makeUncheckedBinaryOperatorForTypes
       }
       break;
     }
+    case kDate: {
+      if (right.getTypeID() == kYearMonthInterval) {
+        return makeDateBinaryOperatorOuterHelper<
+            AddArithmeticUncheckedBinaryOperator,
+            DateType,
+            DateLit,
+            YearMonthIntervalLit>(left, right);
+      }
+      break;
+    }
     case kDatetime: {
       if (right.getTypeID() == kDatetimeInterval) {
         return makeDateBinaryOperatorOuterHelper<AddArithmeticUncheckedBinaryOperator,
@@ -335,7 +391,13 @@ UncheckedBinaryOperator* AddBinaryOperation::makeUncheckedBinaryOperatorForTypes
       break;
     }
     case kYearMonthInterval: {
-      if (right.getTypeID() == kDatetime) {
+      if (right.getTypeID() == kDate) {
+        return makeDateBinaryOperatorOuterHelper<
+            AddArithmeticUncheckedBinaryOperator,
+            DateType,
+            YearMonthIntervalLit,
+            DateLit>(left, right);
+      } else if (right.getTypeID() == kDatetime) {
         return makeDateBinaryOperatorOuterHelper<AddArithmeticUncheckedBinaryOperator,
                                                  DatetimeType,
                                                  YearMonthIntervalLit, DatetimeLit>(left, right);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/binary_operations/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/types/operations/binary_operations/CMakeLists.txt b/types/operations/binary_operations/CMakeLists.txt
index 071e9fb..4d26b75 100644
--- a/types/operations/binary_operations/CMakeLists.txt
+++ b/types/operations/binary_operations/CMakeLists.txt
@@ -51,6 +51,7 @@ add_library(quickstep_types_operations_binaryoperations_SubtractBinaryOperation
 target_link_libraries(quickstep_types_operations_binaryoperations_AddBinaryOperation
                       glog
                       quickstep_types_DateOperatorOverloads
+                      quickstep_types_DateType
                       quickstep_types_DatetimeIntervalType
                       quickstep_types_DatetimeLit
                       quickstep_types_DatetimeType
@@ -164,6 +165,7 @@ target_link_libraries(quickstep_types_operations_binaryoperations_MultiplyBinary
 target_link_libraries(quickstep_types_operations_binaryoperations_SubtractBinaryOperation
                       glog
                       quickstep_types_DateOperatorOverloads
+                      quickstep_types_DateType
                       quickstep_types_DatetimeIntervalType
                       quickstep_types_DatetimeLit
                       quickstep_types_DatetimeType

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/binary_operations/SubtractBinaryOperation.cpp
----------------------------------------------------------------------
diff --git a/types/operations/binary_operations/SubtractBinaryOperation.cpp b/types/operations/binary_operations/SubtractBinaryOperation.cpp
index fe8644a..53e4266 100644
--- a/types/operations/binary_operations/SubtractBinaryOperation.cpp
+++ b/types/operations/binary_operations/SubtractBinaryOperation.cpp
@@ -23,8 +23,9 @@
 #include <utility>
 
 #include "types/DateOperatorOverloads.hpp"
-#include "types/DatetimeLit.hpp"
+#include "types/DateType.hpp"
 #include "types/DatetimeIntervalType.hpp"
+#include "types/DatetimeLit.hpp"
 #include "types/DatetimeType.hpp"
 #include "types/IntervalLit.hpp"
 #include "types/Type.hpp"
@@ -47,6 +48,9 @@ bool SubtractBinaryOperation::canApplyToTypes(const Type &left, const Type &righ
     case kDouble: {
       return (right.getSuperTypeID() == Type::kNumeric);
     }
+    case kDate: {
+      return (right.getTypeID() == kYearMonthInterval);
+    }
     case kDatetime: {
       return (right.getTypeID() == kDatetime         ||
               right.getTypeID() == kDatetimeInterval ||
@@ -56,7 +60,8 @@ bool SubtractBinaryOperation::canApplyToTypes(const Type &left, const Type &righ
       return (right.getTypeID() == kDatetimeInterval);
     }
     case kYearMonthInterval: {
-      return (right.getTypeID() == kYearMonthInterval);
+      return (right.getTypeID() == kYearMonthInterval ||
+              right.getTypeID() == kDate);
     }
     default:
       return false;
@@ -66,6 +71,9 @@ bool SubtractBinaryOperation::canApplyToTypes(const Type &left, const Type &righ
 const Type* SubtractBinaryOperation::resultTypeForArgumentTypes(const Type &left, const Type &right) const {
   if (left.getSuperTypeID() == Type::kNumeric && right.getSuperTypeID() == Type::kNumeric) {
     return TypeFactory::GetUnifyingType(left, right);
+  } else if ((left.getTypeID() == kDate && right.getTypeID() == kYearMonthInterval)) {
+    // For DATE type, only one possibility: DATE - YEAR-MONTH-INTERVAL.
+    return &(DateType::Instance(left.isNullable() || right.isNullable()));
   } else if ((left.getTypeID() == kDatetime && right.getTypeID() == kDatetime) ||
              (left.getTypeID() == kDatetimeInterval && right.getTypeID() == kDatetimeInterval)) {
     // NOTE(zuyu): we set the result type of the Subtract
@@ -108,6 +116,10 @@ const Type* SubtractBinaryOperation::resultTypeForPartialArgumentTypes(
         case kDouble:
           // Double has highest precedence of numeric types.
           return &TypeFactory::GetType(kDouble, true);
+        case kDate:
+          // If left is a Date, right must be a YearMonthInterval and the result
+          // must be a Date.
+          return &TypeFactory::GetType(kDate, true);
         case kDatetimeInterval:
           // If minuend is a DatetimeInterval, the subtrahend and result must
           // also be DatetimeInterval.
@@ -149,9 +161,15 @@ bool SubtractBinaryOperation::partialTypeSignatureIsPlausible(
       } else {
         // Only result type is known, just check that it is one of the types
         // that can possibly be returned.
-        return QUICKSTEP_EQUALS_ANY_CONSTANT(
-            result_type->getTypeID(),
-            kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval);
+        return QUICKSTEP_EQUALS_ANY_CONSTANT(result_type->getTypeID(),
+                                             kInt,
+                                             kLong,
+                                             kFloat,
+                                             kDouble,
+                                             kDate,
+                                             kDatetime,
+                                             kDatetimeInterval,
+                                             kYearMonthInterval);
       }
     }
 
@@ -159,9 +177,14 @@ bool SubtractBinaryOperation::partialTypeSignatureIsPlausible(
       // Right (minuend) argument type is known, left (subtrahend) argument and
       // result types are unknown. Just check that right (minuend) type can be
       // subtracted.
-      return QUICKSTEP_EQUALS_ANY_CONSTANT(
-          right_argument_type->getTypeID(),
-          kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval);
+      return QUICKSTEP_EQUALS_ANY_CONSTANT(right_argument_type->getTypeID(),
+                                           kInt,
+                                           kLong,
+                                           kFloat,
+                                           kDouble,
+                                           kDatetime,
+                                           kDatetimeInterval,
+                                           kYearMonthInterval);
     }
 
     // Return type and right (minuend) argument type are known, left
@@ -182,6 +205,8 @@ bool SubtractBinaryOperation::partialTypeSignatureIsPlausible(
             kFloat, kDouble);
       case kDouble:
         return (result_type->getTypeID() == kDouble);
+      case kDate:
+        return (result_type->getTypeID() == kDate);
       case kDatetime:
         return (result_type->getTypeID() == kDatetimeInterval);
       case kDatetimeInterval:
@@ -191,7 +216,7 @@ bool SubtractBinaryOperation::partialTypeSignatureIsPlausible(
       case kYearMonthInterval:
         return QUICKSTEP_EQUALS_ANY_CONSTANT(
             result_type->getTypeID(),
-            kDatetime, kYearMonthInterval);
+            kDate, kDatetime, kYearMonthInterval);
       default:
         return false;
     }
@@ -201,9 +226,15 @@ bool SubtractBinaryOperation::partialTypeSignatureIsPlausible(
         // Left (subtrahend) argument type is known, right (minuend) argument
         // type and result type are unknown. Just check that the left
         // (subtrahend) type can be subtracted from.
-        return QUICKSTEP_EQUALS_ANY_CONSTANT(
-            left_argument_type->getTypeID(),
-            kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval);
+        return QUICKSTEP_EQUALS_ANY_CONSTANT(left_argument_type->getTypeID(),
+                                             kInt,
+                                             kLong,
+                                             kFloat,
+                                             kDouble,
+                                             kDate,
+                                             kDatetime,
+                                             kDatetimeInterval,
+                                             kYearMonthInterval);
       }
 
       // Result type and left (subtrahend) argument type are known, but right
@@ -224,6 +255,8 @@ bool SubtractBinaryOperation::partialTypeSignatureIsPlausible(
               kFloat, kDouble);
         case kDouble:
           return (result_type->getTypeID() == kDouble);
+        case kDate:
+          return (result_type->getTypeID() == kDate);
         case kDatetime:
           return QUICKSTEP_EQUALS_ANY_CONSTANT(
               result_type->getTypeID(),
@@ -267,6 +300,10 @@ std::pair<const Type*, const Type*> SubtractBinaryOperation::pushDownTypeHint(
     case kDouble:
     case kYearMonthInterval:
       return std::pair<const Type*, const Type*>(result_type_hint, result_type_hint);
+    case kDate:
+      // Left should be a Date, right should be YearMonthInterval.
+      return std::pair<const Type *, const Type *>(
+          result_type_hint, &TypeFactory::GetType(kYearMonthInterval, true));
     case kDatetime:
       // Left should be a Datetime, right may be either interval type.
       return std::pair<const Type*, const Type*>(result_type_hint, nullptr);
@@ -294,6 +331,16 @@ TypedValue SubtractBinaryOperation::applyToChecked(const TypedValue &left,
       }
       break;
     }
+    case kDate: {
+      if (right_type.getTypeID() == kYearMonthInterval) {
+        if (left.isNull() || right.isNull()) {
+          return TypedValue(kDate);
+        }
+
+        return TypedValue(left.getLiteral<DateLit>() - right.getLiteral<YearMonthIntervalLit>());
+      }
+      break;
+    }
     case kDatetime: {
       if (right_type.getTypeID() == kDatetime) {
         // NOTE(zuyu): The result type of the Subtract between two Datetimes is DatetimeInterval,
@@ -358,6 +405,16 @@ UncheckedBinaryOperator* SubtractBinaryOperation::makeUncheckedBinaryOperatorFor
       }
       break;
     }
+    case kDate: {
+      if (right.getTypeID() == kYearMonthInterval) {
+        return makeDateBinaryOperatorOuterHelper<
+            SubtractArithmeticUncheckedBinaryOperator,
+            DateType,
+            DateLit,
+            YearMonthIntervalLit>(left, right);
+      }
+      break;
+    }
     case kDatetime: {
       if (right.getTypeID() == kDatetime) {
         // NOTE(zuyu): The result type of the Subtract between two Datetimes is DatetimeInterval,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/binary_operations/tests/AddBinaryOperation_unittest.cpp
----------------------------------------------------------------------
diff --git a/types/operations/binary_operations/tests/AddBinaryOperation_unittest.cpp b/types/operations/binary_operations/tests/AddBinaryOperation_unittest.cpp
index e6b0484..4d6b54e 100644
--- a/types/operations/binary_operations/tests/AddBinaryOperation_unittest.cpp
+++ b/types/operations/binary_operations/tests/AddBinaryOperation_unittest.cpp
@@ -62,6 +62,13 @@ TEST(AddBinaryOperationTest, ResultTypeForPartialArgumentTypesTest) {
   ASSERT_NE(result_type, nullptr);
   EXPECT_TRUE(TypeFactory::GetType(kDouble, true).equals(*result_type));
 
+  // A Date can be added with only YearMonthIntervalType resulting in a Date.
+  result_type =
+      AddBinaryOperation::Instance().resultTypeForPartialArgumentTypes(
+          &TypeFactory::GetType(kDate, true), nullptr);
+  ASSERT_NE(result_type, nullptr);
+  EXPECT_TRUE(TypeFactory::GetType(kDate, true).equals(*result_type));
+
   // If one of the arguments is a Datetime, then it can be added with either
   // interval type and will always yield a Datetime.
   result_type = AddBinaryOperation::Instance().resultTypeForPartialArgumentTypes(
@@ -143,13 +150,13 @@ TEST(AddBinaryOperationTest, PartialTypeSignatureIsPlausibleTest) {
   // might possibly return is plausible.
   BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndUnknownArguments(
       AddBinaryOperation::Instance(),
-      {kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval});
+      {kInt, kLong, kFloat, kDouble, kDate, kDatetime, kDatetimeInterval, kYearMonthInterval});
 
   // --------------------------------------------------------------------------
   // Result type unknown, one argument type known.
   BinaryOperationTestUtil::CheckPlausibilityWithUnknownResultAndSingleKnownArgument(
       AddBinaryOperation::Instance(),
-      {kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval},
+      {kInt, kLong, kFloat, kDouble, kDate, kDatetime, kDatetimeInterval, kYearMonthInterval},
       true,
       true);
 
@@ -165,7 +172,10 @@ TEST(AddBinaryOperationTest, PartialTypeSignatureIsPlausibleTest) {
       AddBinaryOperation::Instance(), kDouble, {kInt, kLong, kFloat, kDouble}, true, true);
   BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndSingleArgument(
       AddBinaryOperation::Instance(),
-      kDatetime, {kDatetime, kDatetimeInterval, kYearMonthInterval}, true, true);
+      kDate, {kDate}, true, true);
+  BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndSingleArgument(
+      AddBinaryOperation::Instance(),
+      kDatetime, {kDatetime, kDatetimeInterval}, true, true);
   BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndSingleArgument(
       AddBinaryOperation::Instance(), kDatetimeInterval, {kDatetimeInterval}, true, true);
   BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndSingleArgument(
@@ -200,6 +210,13 @@ TEST(AddBinaryOperationTest, PushDownTypeHintTest) {
     EXPECT_TRUE(result_type->equals(*hints.second));
   }
 
+  // A hint of Date is ambiguous, because one argument should be Date and other
+  // should be YearMonthInterval, but the order does not matter.
+  result_type = &TypeFactory::GetType(kDate, false);
+  hints = AddBinaryOperation::Instance().pushDownTypeHint(result_type);
+  EXPECT_EQ(nullptr, hints.first);
+  EXPECT_EQ(nullptr, hints.second);
+
   // A hint of Datetime is ambiguous, because one argument should be Datetime
   // and the other should be some interval type.
   result_type = &TypeFactory::GetType(kDatetime, false);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/binary_operations/tests/BinaryOperationTestUtil.hpp
----------------------------------------------------------------------
diff --git a/types/operations/binary_operations/tests/BinaryOperationTestUtil.hpp b/types/operations/binary_operations/tests/BinaryOperationTestUtil.hpp
index e23057c..11abe20 100644
--- a/types/operations/binary_operations/tests/BinaryOperationTestUtil.hpp
+++ b/types/operations/binary_operations/tests/BinaryOperationTestUtil.hpp
@@ -92,7 +92,7 @@ class BinaryOperationTestUtil {
       const bool check_left_argument,
       const bool check_right_argument) {
     for (const TypeID argument_type_id
-         : {kInt, kLong, kFloat, kDouble, kChar, kVarChar, kDatetime,
+         : {kInt, kLong, kFloat, kDouble, kChar, kVarChar, kDate, kDatetime,
             kDatetimeInterval, kYearMonthInterval}) {
       const Type *argument_type = TypeFactory::TypeRequiresLengthParameter(argument_type_id)
                                   ? &TypeFactory::GetType(argument_type_id, 10, false)
@@ -159,7 +159,7 @@ class BinaryOperationTestUtil {
     const Type *result_type_nullable = &result_type->getNullableVersion();
 
     for (const TypeID argument_type_id
-        : {kInt, kLong, kFloat, kDouble, kChar, kVarChar, kDatetime,
+        : {kInt, kLong, kFloat, kDouble, kChar, kVarChar, kDate, kDatetime,
             kDatetimeInterval, kYearMonthInterval}) {
       const Type *argument_type = TypeFactory::TypeRequiresLengthParameter(argument_type_id)
                                   ? &TypeFactory::GetType(argument_type_id, 10, false)

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/binary_operations/tests/SubtractBinaryOperation_unittest.cpp
----------------------------------------------------------------------
diff --git a/types/operations/binary_operations/tests/SubtractBinaryOperation_unittest.cpp b/types/operations/binary_operations/tests/SubtractBinaryOperation_unittest.cpp
index 50ac967..15436d8 100644
--- a/types/operations/binary_operations/tests/SubtractBinaryOperation_unittest.cpp
+++ b/types/operations/binary_operations/tests/SubtractBinaryOperation_unittest.cpp
@@ -63,6 +63,13 @@ TEST(SubtractBinaryOperationTest, ResultTypeForPartialArgumentTypesTest) {
   ASSERT_NE(result_type, nullptr);
   EXPECT_TRUE(TypeFactory::GetType(kDouble, true).equals(*result_type));
 
+  // If the left argument is a Date, then the result should be a Date.
+  result_type =
+      SubtractBinaryOperation::Instance().resultTypeForPartialArgumentTypes(
+          &TypeFactory::GetType(kDate, false), nullptr);
+  ASSERT_NE(result_type, nullptr);
+  EXPECT_TRUE(TypeFactory::GetType(kDate, true).equals(*result_type));
+
   // If the left argument (the minuend) is an interval, then the subtrahend and
   // the result must also be the same kind of interval.
   result_type = SubtractBinaryOperation::Instance().resultTypeForPartialArgumentTypes(
@@ -150,8 +157,14 @@ TEST(SubtractBinaryOperationTest, PartialTypeSignatureIsPlausibleTest) {
   // Result type unknown, one argument type known.
   BinaryOperationTestUtil::CheckPlausibilityWithUnknownResultAndSingleKnownArgument(
       SubtractBinaryOperation::Instance(),
-      {kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval},
+      {kInt, kLong, kFloat, kDouble, kDate, kDatetime, kDatetimeInterval, kYearMonthInterval},
       true,
+      false);
+
+  BinaryOperationTestUtil::CheckPlausibilityWithUnknownResultAndSingleKnownArgument(
+      SubtractBinaryOperation::Instance(),
+      {kInt, kLong, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval},
+      false,
       true);
 
   // --------------------------------------------------------------------------
@@ -165,6 +178,8 @@ TEST(SubtractBinaryOperationTest, PartialTypeSignatureIsPlausibleTest) {
   BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndSingleArgument(
       SubtractBinaryOperation::Instance(), kDouble, {kInt, kLong, kFloat, kDouble}, true, false);
   BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndSingleArgument(
+      SubtractBinaryOperation::Instance(), kDate, {kDate}, true, false);
+  BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndSingleArgument(
       SubtractBinaryOperation::Instance(), kDatetime, {kDatetime}, true, false);
   BinaryOperationTestUtil::CheckPlausibilityWithKnownResultAndSingleArgument(
       SubtractBinaryOperation::Instance(),
@@ -224,6 +239,12 @@ TEST(SubtractBinaryOperationTest, PushDownTypeHintTest) {
     EXPECT_TRUE(result_type->equals(*hints.second));
   }
 
+  result_type = &TypeFactory::GetType(kDate, false);
+  hints = SubtractBinaryOperation::Instance().pushDownTypeHint(result_type);
+  ASSERT_NE(hints.first, nullptr);
+  EXPECT_TRUE(result_type->equals(*hints.first));
+  EXPECT_EQ(&TypeFactory::GetType(kYearMonthInterval, true), hints.second);
+
   // A hint of Datetime means the left argument should be Datetime and the
   // right could be either interval type.
   result_type = &TypeFactory::GetType(kDatetime, false);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/unary_operations/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/types/operations/unary_operations/CMakeLists.txt b/types/operations/unary_operations/CMakeLists.txt
index d612464..4a7af91 100644
--- a/types/operations/unary_operations/CMakeLists.txt
+++ b/types/operations/unary_operations/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Licensed to the Apache Software Foundation (ASF) under one
+# Licensed to the Agache 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
@@ -60,6 +60,7 @@ target_link_libraries(quickstep_types_operations_unaryoperations_DateExtractOper
                       quickstep_storage_ValueAccessor
                       quickstep_storage_ValueAccessorUtil
                       quickstep_types_DatetimeLit
+                      quickstep_types_IntType
                       quickstep_types_LongType
                       quickstep_types_Type
                       quickstep_types_TypeFactory
@@ -164,5 +165,6 @@ target_link_libraries(UnaryOperation_tests
                       quickstep_types_operations_unaryoperations_UnaryOperation
                       quickstep_types_operations_unaryoperations_UnaryOperationFactory
                       quickstep_types_operations_unaryoperations_UnaryOperationID
+                      quickstep_utility_EqualsAnyConstant
                       quickstep_utility_Macros)
 add_test(UnaryOperation_tests UnaryOperation_tests)

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/unary_operations/DateExtractOperation.cpp
----------------------------------------------------------------------
diff --git a/types/operations/unary_operations/DateExtractOperation.cpp b/types/operations/unary_operations/DateExtractOperation.cpp
index ad8a0aa..285f554 100644
--- a/types/operations/unary_operations/DateExtractOperation.cpp
+++ b/types/operations/unary_operations/DateExtractOperation.cpp
@@ -23,6 +23,7 @@
 #include <cstdint>
 #include <memory>
 #include <string>
+#include <type_traits>
 
 #ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
 #include <utility>
@@ -35,6 +36,7 @@
 #include "storage/ValueAccessor.hpp"
 #include "storage/ValueAccessorUtil.hpp"
 #include "types/DatetimeLit.hpp"
+#include "types/IntType.hpp"
 #include "types/LongType.hpp"
 #include "types/Type.hpp"
 #include "types/TypeFactory.hpp"
@@ -46,12 +48,13 @@
 
 #include "glog/logging.h"
 
+using std::int32_t;
 using std::int64_t;
 
 namespace quickstep {
 
 template <DateExtractUnit unit, bool argument_nullable>
-TypedValue DateExtractUncheckedOperator<unit, argument_nullable>::applyToTypedValue(
+TypedValue DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToTypedValue(
     const TypedValue &argument) const {
   if (argument_nullable && argument.isNull()) {
     return TypedValue(kLong);
@@ -61,7 +64,17 @@ TypedValue DateExtractUncheckedOperator<unit, argument_nullable>::applyToTypedVa
 }
 
 template <DateExtractUnit unit, bool argument_nullable>
-TypedValue DateExtractUncheckedOperator<unit, argument_nullable>::applyToDataPtr(const void *argument) const {
+TypedValue DateExtractUncheckedOperator<unit, argument_nullable>::applyToTypedValue(
+    const TypedValue &argument) const {
+  if (argument_nullable && argument.isNull()) {
+    return TypedValue(kInt);
+  }
+
+  return TypedValue(dateExtract(argument.getLiteral<DateLit>()));
+}
+
+template <DateExtractUnit unit, bool argument_nullable>
+TypedValue DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToDataPtr(const void *argument) const {
   if (argument_nullable && argument == nullptr) {
     return TypedValue(kLong);
   }
@@ -70,7 +83,16 @@ TypedValue DateExtractUncheckedOperator<unit, argument_nullable>::applyToDataPtr
 }
 
 template <DateExtractUnit unit, bool argument_nullable>
-ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToColumnVector(
+TypedValue DateExtractUncheckedOperator<unit, argument_nullable>::applyToDataPtr(const void *argument) const {
+  if (argument_nullable && argument == nullptr) {
+    return TypedValue(kInt);
+  }
+
+  return TypedValue(dateExtract(*static_cast<const DateLit*>(argument)));
+}
+
+template <DateExtractUnit unit, bool argument_nullable>
+ColumnVector* DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToColumnVector(
     const ColumnVector &argument) const {
   // Datetime are usable with NativeColumnVector, so 'argument' should always
   // be native.
@@ -96,9 +118,36 @@ ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToColu
   return result.release();
 }
 
+template <DateExtractUnit unit, bool argument_nullable>
+ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToColumnVector(
+    const ColumnVector &argument) const {
+  // Date is usable with NativeColumnVector, so 'argument' should always
+  // be native.
+  DCHECK(argument.isNative());
+
+  const NativeColumnVector &native_argument = static_cast<const NativeColumnVector&>(argument);
+  std::unique_ptr<NativeColumnVector> result(
+      new NativeColumnVector(IntType::Instance(argument_nullable), native_argument.size()));
+
+  for (std::size_t pos = 0;
+       pos < native_argument.size();
+       ++pos) {
+    const DateLit *date_arg =
+        static_cast<const DateLit*>(native_argument.getUntypedValue<argument_nullable>(pos));
+    if (argument_nullable && (date_arg == nullptr)) {
+      result->appendNullValue();
+    } else {
+      *static_cast<int32_t*>(result->getPtrForDirectWrite())
+          = dateExtract(*date_arg);
+    }
+  }
+
+  return result.release();
+}
+
 #ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
 template <DateExtractUnit unit, bool argument_nullable>
-ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessor(
+ColumnVector* DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessor(
     ValueAccessor *accessor,
     const attribute_id argument_attr_id) const {
   return InvokeOnValueAccessorMaybeTupleIdSequenceAdapter(
@@ -121,11 +170,36 @@ ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToValu
     return result.release();
   });
 }
+
+template <DateExtractUnit unit, bool argument_nullable>
+ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessor(
+    ValueAccessor *accessor,
+    const attribute_id argument_attr_id) const {
+  return InvokeOnValueAccessorMaybeTupleIdSequenceAdapter(
+      accessor,
+      [&](auto *accessor) -> ColumnVector* {  // NOLINT(build/c++11)
+    std::unique_ptr<NativeColumnVector> result(
+        new NativeColumnVector(IntType::Instance(argument_nullable), accessor->getNumTuples()));
+    accessor->beginIteration();
+    while (accessor->next()) {
+      const DateLit *date_arg =
+          static_cast<const DateLit*>(
+              accessor->template getUntypedValue<argument_nullable>(argument_attr_id));
+      if (argument_nullable && (date_arg == nullptr)) {
+        result->appendNullValue();
+      } else {
+        *static_cast<int32_t*>(result->getPtrForDirectWrite())
+            = this->dateExtract(*date_arg);
+      }
+    }
+    return result.release();
+  });
+}
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
 
 #ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
 template <DateExtractUnit unit, bool argument_nullable>
-ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessorForJoin(
+ColumnVector* DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessorForJoin(
     ValueAccessor *accessor,
     const bool use_left_relation,
     const attribute_id argument_attr_id,
@@ -151,10 +225,38 @@ ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToValu
     return result.release();
   });
 }
+
+template <DateExtractUnit unit, bool argument_nullable>
+ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessorForJoin(
+    ValueAccessor *accessor,
+    const bool use_left_relation,
+    const attribute_id argument_attr_id,
+    const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids) const {
+  std::unique_ptr<NativeColumnVector> result(
+      new NativeColumnVector(IntType::Instance(argument_nullable), joined_tuple_ids.size()));
+  return InvokeOnValueAccessorNotAdapter(
+      accessor,
+      [&](auto *accessor) -> ColumnVector* {  // NOLINT(build/c++11)
+    for (const std::pair<tuple_id, tuple_id> &joined_pair : joined_tuple_ids) {
+      const DatetimeLit *date_arg =
+          static_cast<const DateLit*>(
+              accessor->template getUntypedValueAtAbsolutePosition<argument_nullable>(
+                  argument_attr_id,
+                  use_left_relation ? joined_pair.first : joined_pair.second));
+      if (argument_nullable && (date_arg == nullptr)) {
+        result->appendNullValue();
+      } else {
+        *static_cast<int32_t*>(result->getPtrForDirectWrite())
+            = this->dateExtract(*date_arg);
+      }
+    }
+    return result.release();
+  });
+}
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
 
 template <DateExtractUnit unit, bool argument_nullable>
-inline int64_t DateExtractUncheckedOperator<unit, argument_nullable>::dateExtract(const DatetimeLit &argument) const {
+inline int64_t DatetimeExtractUncheckedOperator<unit, argument_nullable>::dateExtract(const DatetimeLit &argument) const {
   switch (unit) {
     case DateExtractUnit::kYear:
       return argument.yearField();
@@ -169,6 +271,18 @@ inline int64_t DateExtractUncheckedOperator<unit, argument_nullable>::dateExtrac
     case DateExtractUnit::kSecond:
       return argument.secondField();
     default:
+      FATAL_ERROR("Unsupported DateExtractUnit in DatetimeExtractUncheckedOperator::dateExtract.");
+  }
+}
+
+template <DateExtractUnit unit, bool argument_nullable>
+inline int32_t DateExtractUncheckedOperator<unit, argument_nullable>::dateExtract(const DateLit &argument) const {
+  switch (unit) {
+    case DateExtractUnit::kYear:
+      return argument.yearField();
+    case DateExtractUnit::kMonth:
+      return argument.monthField();
+    default:
       FATAL_ERROR("Unsupported DateExtractUnit in DateExtractUncheckedOperator::dateExtract.");
   }
 }
@@ -270,7 +384,20 @@ const Type* DateExtractOperation::pushDownTypeHint(const Type *type_hint) const
   }
 
   if (type_hint->getTypeID() == kLong) {
-    return &TypeFactory::GetType(kDatetime, type_hint->isNullable());
+    switch (unit_) {
+      case DateExtractUnit::kYear:  // Fall through.
+      case DateExtractUnit::kMonth:
+        // There are two possibilities for the return type, based on whether we
+        // have Datetime or Date as the underlying date implementation.
+        return nullptr;
+      case DateExtractUnit::kDay:  // Fall through.
+      case DateExtractUnit::kHour:
+      case DateExtractUnit::kMinute:
+      case DateExtractUnit::kSecond:
+        return &TypeFactory::GetType(kDatetime, type_hint->isNullable());
+      default:
+        return nullptr;
+    }
   } else {
     return nullptr;
   }
@@ -278,8 +405,10 @@ const Type* DateExtractOperation::pushDownTypeHint(const Type *type_hint) const
 
 TypedValue DateExtractOperation::applyToChecked(const TypedValue &argument,
                                                 const Type &argument_type) const {
-  if ((argument.getTypeID() != TypeID::kDatetime)
-      || (argument_type.getTypeID() != TypeID::kDatetime)) {
+  if (((argument.getTypeID() != TypeID::kDatetime) ||
+       (argument_type.getTypeID() != TypeID::kDatetime)) &&
+      ((argument.getTypeID() != TypeID::kDate) ||
+       (argument_type.getTypeID() != TypeID::kDate))) {
     LOG(FATAL) << "UnaryOperation " << getName() << " is only applicable to Type "
                << kTypeNames[TypeID::kDatetime] << ", but applyToChecked() was "
                << "called with 'argument' of Type " << kTypeNames[argument.getTypeID()]
@@ -288,14 +417,34 @@ TypedValue DateExtractOperation::applyToChecked(const TypedValue &argument,
   }
 
   if (argument.isNull()) {
-    return TypedValue(kLong);
+    if (argument.getTypeID() == TypeID::kDatetime) {
+      return TypedValue(kLong);
+    } else {
+      // argument type is kDate.
+      DCHECK_EQ(TypeID::kDate, argument.getTypeID());
+      return TypedValue(kInt);
+    }
   }
 
   switch (unit_) {
-    case DateExtractUnit::kYear:
-      return TypedValue(argument.getLiteral<DatetimeLit>().yearField());
-    case DateExtractUnit::kMonth:
-      return TypedValue(argument.getLiteral<DatetimeLit>().monthField());
+    case DateExtractUnit::kYear: {
+      if (argument.getTypeID() == TypeID::kDatetime) {
+        return TypedValue(argument.getLiteral<DatetimeLit>().yearField());
+      } else {
+        // argument type is kDate.
+        DCHECK_EQ(TypeID::kDate, argument.getTypeID());
+        return TypedValue(argument.getLiteral<DateLit>().yearField());
+      }
+    }
+    case DateExtractUnit::kMonth: {
+      if (argument.getTypeID() == TypeID::kDatetime) {
+        return TypedValue(argument.getLiteral<DatetimeLit>().monthField());
+      } else {
+        // argument type is kDate.
+        DCHECK_EQ(TypeID::kDate, argument.getTypeID());
+        return TypedValue(argument.getLiteral<DateLit>().monthField());
+      }
+    }
     case DateExtractUnit::kDay:
       return TypedValue(argument.getLiteral<DatetimeLit>().dayField());
     case DateExtractUnit::kHour:
@@ -312,45 +461,80 @@ TypedValue DateExtractOperation::applyToChecked(const TypedValue &argument,
 
 UncheckedUnaryOperator* DateExtractOperation::makeUncheckedUnaryOperatorForTypeHelper(const Type &type) const {
   switch (unit_) {
-    case DateExtractUnit::kYear:
-      if (type.isNullable()) {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kYear, true>();
+    case DateExtractUnit::kYear: {
+      if (type.getTypeID() == TypeID::kDatetime) {
+        if (type.isNullable()) {
+          return new DatetimeExtractUncheckedOperator<DateExtractUnit::kYear, true>();
+        } else {
+          return new DatetimeExtractUncheckedOperator<DateExtractUnit::kYear, false>();
+        }
       } else {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kYear, false>();
+        DCHECK_EQ(TypeID::kDate, type.getTypeID());
+        // type is kDate.
+        if (type.isNullable()) {
+          return new DateExtractUncheckedOperator<DateExtractUnit::kYear, true>();
+        } else {
+          return new DateExtractUncheckedOperator<DateExtractUnit::kYear, false>();
+        }
       }
-    case DateExtractUnit::kMonth:
-      if (type.isNullable()) {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kMonth, true>();
+    }
+    case DateExtractUnit::kMonth: {
+      if (type.getTypeID() == TypeID::kDatetime) {
+        if (type.isNullable()) {
+          return new DatetimeExtractUncheckedOperator<DateExtractUnit::kMonth, true>();
+        } else {
+          return new DatetimeExtractUncheckedOperator<DateExtractUnit::kMonth, false>();
+        }
       } else {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kMonth, false>();
+        // type is kDate.
+        DCHECK_EQ(TypeID::kDate, type.getTypeID());
+        if (type.isNullable()) {
+          return new DateExtractUncheckedOperator<DateExtractUnit::kMonth, true>();
+        } else {
+          return new DateExtractUncheckedOperator<DateExtractUnit::kMonth, false>();
+        }
       }
+    }
     case DateExtractUnit::kDay:
       if (type.isNullable()) {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kDay, true>();
+        return new DatetimeExtractUncheckedOperator<DateExtractUnit::kDay, true>();
       } else {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kDay, false>();
+        return new DatetimeExtractUncheckedOperator<DateExtractUnit::kDay, false>();
       }
     case DateExtractUnit::kHour:
       if (type.isNullable()) {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kHour, true>();
+        return new DatetimeExtractUncheckedOperator<DateExtractUnit::kHour, true>();
       } else {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kHour, false>();
+        return new DatetimeExtractUncheckedOperator<DateExtractUnit::kHour, false>();
       }
     case DateExtractUnit::kMinute:
       if (type.isNullable()) {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kMinute, true>();
+        return new DatetimeExtractUncheckedOperator<DateExtractUnit::kMinute, true>();
       } else {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kMinute, false>();
+        return new DatetimeExtractUncheckedOperator<DateExtractUnit::kMinute, false>();
       }
     case DateExtractUnit::kSecond:
       if (type.isNullable()) {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kSecond, true>();
+        return new DatetimeExtractUncheckedOperator<DateExtractUnit::kSecond, true>();
       } else {
-        return new DateExtractUncheckedOperator<DateExtractUnit::kSecond, false>();
+        return new DatetimeExtractUncheckedOperator<DateExtractUnit::kSecond, false>();
       }
     default:
       FATAL_ERROR("Unsupported DateExtractUnit in DateExtractOperation::makeUncheckedUnaryOperatorForTypeHelper.");
   }
 }
 
+const Type* DateExtractOperation::resultTypeForArgumentType(const Type &type) const {
+  if (canApplyToType(type)) {
+    if (type.getTypeID() == kDatetime) {
+      return &LongType::Instance(type.isNullable());
+    } else {
+      DCHECK_EQ(kDate, type.getTypeID());
+      return &IntType::Instance(type.isNullable());
+    }
+  } else {
+    return nullptr;
+  }
+}
+
 }  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9bb2ee46/types/operations/unary_operations/DateExtractOperation.hpp
----------------------------------------------------------------------
diff --git a/types/operations/unary_operations/DateExtractOperation.hpp b/types/operations/unary_operations/DateExtractOperation.hpp
index fd12bed..f8c091b 100644
--- a/types/operations/unary_operations/DateExtractOperation.hpp
+++ b/types/operations/unary_operations/DateExtractOperation.hpp
@@ -61,6 +61,40 @@ enum class DateExtractUnit {
 };
 
 /**
+ * @brief UncheckedUnaryOperator for Datetime Extract.
+ */
+template <DateExtractUnit unit, bool argument_nullable>
+class DatetimeExtractUncheckedOperator : public UncheckedUnaryOperator {
+ public:
+  DatetimeExtractUncheckedOperator()
+      : UncheckedUnaryOperator() {}
+
+  TypedValue applyToTypedValue(const TypedValue &argument) const override;
+
+  TypedValue applyToDataPtr(const void *argument) const override;
+
+  ColumnVector* applyToColumnVector(const ColumnVector &argument) const override;
+
+#ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
+  ColumnVector* applyToValueAccessor(ValueAccessor *accessor,
+                                     const attribute_id argument_attr_id) const override;
+#endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
+
+#ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
+  ColumnVector* applyToValueAccessorForJoin(
+      ValueAccessor *accessor,
+      const bool use_left_relation,
+      const attribute_id argument_attr_id,
+      const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids) const override;
+#endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
+
+ private:
+  inline std::int64_t dateExtract(const DatetimeLit &argument) const;
+
+  DISALLOW_COPY_AND_ASSIGN(DatetimeExtractUncheckedOperator);
+};
+
+/**
  * @brief UncheckedUnaryOperator for Date Extract.
  */
 template <DateExtractUnit unit, bool argument_nullable>
@@ -89,7 +123,7 @@ class DateExtractUncheckedOperator : public UncheckedUnaryOperator {
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
 
  private:
-  inline std::int64_t dateExtract(const DatetimeLit &argument) const;
+  inline std::int32_t dateExtract(const DateLit &argument) const;
 
   DISALLOW_COPY_AND_ASSIGN(DateExtractUncheckedOperator);
 };
@@ -114,23 +148,17 @@ class DateExtractOperation : public UnaryOperation {
   std::string getName() const override;
 
   bool canApplyToType(const Type &type) const override {
-    return type.getTypeID() == TypeID::kDatetime;
+    return type.getTypeID() == TypeID::kDatetime || type.getTypeID() == kDate;
   }
 
-  const Type* resultTypeForArgumentType(const Type &type) const override {
-    if (canApplyToType(type)) {
-      return &LongType::Instance(type.isNullable());
-    } else {
-      return nullptr;
-    }
-  }
+  const Type* resultTypeForArgumentType(const Type &type) const override;
 
   const Type* fixedNullableResultType() const override {
-    return &LongType::InstanceNullable();
+    return nullptr;
   }
 
   bool resultTypeIsPlausible(const Type &result_type) const override {
-    return (result_type.getTypeID() == kLong);
+    return result_type.getTypeID() == kLong || result_type.getTypeID() == kInt;
   }
 
   const Type* pushDownTypeHint(const Type *type_hint) const override;
@@ -139,7 +167,7 @@ class DateExtractOperation : public UnaryOperation {
                             const Type &argument_type) const override;
 
   UncheckedUnaryOperator* makeUncheckedUnaryOperatorForType(const Type &type) const override {
-    DCHECK_EQ(TypeID::kDatetime, type.getTypeID());
+    DCHECK(canApplyToType(type));
 
     return makeUncheckedUnaryOperatorForTypeHelper(type);
   }