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 16:35:12 UTC

incubator-quickstep git commit: Separate code paths for Datetime and Date in Extract

Repository: incubator-quickstep
Updated Branches:
  refs/heads/datetype-fix 4913b7f67 -> 483901f4f


Separate code paths for Datetime and Date in Extract


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

Branch: refs/heads/datetype-fix
Commit: 483901f4fb7ad4753e91f331da3b15a3fc59e47c
Parents: 4913b7f
Author: Harshad Deshmukh <hb...@apache.org>
Authored: Wed Aug 31 11:34:27 2016 -0500
Committer: Harshad Deshmukh <hb...@apache.org>
Committed: Wed Aug 31 11:34:27 2016 -0500

----------------------------------------------------------------------
 query_optimizer/tests/resolver/Select.test      |  37 +--
 types/DateOperatorOverloads.hpp                 |   9 -
 types/DatetimeLit.hpp                           |   8 +
 .../operations/unary_operations/CMakeLists.txt  |   3 +-
 .../unary_operations/DateExtractOperation.cpp   | 248 ++++++++++++++++---
 .../unary_operations/DateExtractOperation.hpp   |  52 +++-
 .../tests/DateExtractOperation_unittest.cpp     |  24 +-
 7 files changed, 302 insertions(+), 79 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/483901f4/query_optimizer/tests/resolver/Select.test
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/resolver/Select.test b/query_optimizer/tests/resolver/Select.test
index 41fbbcb..facb3a1 100644
--- a/query_optimizer/tests/resolver/Select.test
+++ b/query_optimizer/tests/resolver/Select.test
@@ -2151,7 +2151,7 @@ name
 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=(Date('1998-12-12')-YearMonthInterval('5 month')),relation=,
-|   | type=Date]
+|   +-Alias[id=7,name=,alias=(Date('1998-12-12')-YearMonthInterval('5 month')),
+|   | relation=,type=Date]
 |   | +-Subtract
 |   |   +-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
@@ -2501,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/483901f4/types/DateOperatorOverloads.hpp
----------------------------------------------------------------------
diff --git a/types/DateOperatorOverloads.hpp b/types/DateOperatorOverloads.hpp
index 05b5b85..b04f44e 100644
--- a/types/DateOperatorOverloads.hpp
+++ b/types/DateOperatorOverloads.hpp
@@ -38,7 +38,6 @@ namespace quickstep {
 
 // Month arithmetic clamps to the actual last day of a given month.
 inline int ClampDayOfMonth(const int year, const int month, const int day) {
-  std::cout << "ClampDayOfMonth : year = " << year << " month = " << month << " day = " << day << "\n";
   DCHECK_LT(day, 32);
   switch (month) {
     case 2: {
@@ -46,10 +45,6 @@ inline int ClampDayOfMonth(const int year, const int month, const int day) {
           (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
               ? 29
               : 28;
-      const int return_val = (day > days_in_february) ? days_in_february : day;
-      std::cout << "year " << year << " month: " << month
-                << " days in february: " << days_in_february
-                << " return: " << return_val << "\n";
       return (day > days_in_february) ? days_in_february : day;
     }
     case 4:
@@ -138,8 +133,6 @@ inline DateLit operator+(const DateLit &lhs, const YearMonthIntervalLit &rhs) {
   const std::uint8_t result_day = static_cast<std::uint8_t>(
       ClampDayOfMonth(result_year, result_month, lhs.day));
 
-  std::cout << "Result day: " << unsigned(result_day) << "\n";
-
   return DateLit::Create(result_year, result_month, result_day);
 }
 
@@ -205,8 +198,6 @@ inline DateLit operator-(const DateLit &lhs, const YearMonthIntervalLit &rhs) {
   const std::uint8_t result_day = static_cast<std::uint8_t>(
       ClampDayOfMonth(result_year, result_month, lhs.day));
 
-  std::cout << "Result day: " << unsigned(result_day) << "\n";
-
   return DateLit::Create(result_year, result_month, result_day);
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/483901f4/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/483901f4/types/operations/unary_operations/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/types/operations/unary_operations/CMakeLists.txt b/types/operations/unary_operations/CMakeLists.txt
index d612464..8aee499 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

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/483901f4/types/operations/unary_operations/DateExtractOperation.cpp
----------------------------------------------------------------------
diff --git a/types/operations/unary_operations/DateExtractOperation.cpp b/types/operations/unary_operations/DateExtractOperation.cpp
index a86afc4..325adb0 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.");
   }
 }
@@ -265,22 +379,35 @@ std::string DateExtractOperation::getName() const {
 }
 
 const Type* DateExtractOperation::pushDownTypeHint(const Type *type_hint) const {
-  /*if (type_hint == nullptr) {
+  if (type_hint == nullptr) {
     return nullptr;
   }
 
   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::kMinute:
+      case DateExtractUnit::kSecond:
+        return &TypeFactory::GetType(kDatetime, type_hint->isNullable());
+      default:
+        return nullptr;
+    }
   } else {
     return nullptr;
-  }*/
-  return nullptr;
+  }
 }
 
 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()]
@@ -289,14 +416,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:
@@ -313,45 +460,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/483901f4/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);
   }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/483901f4/types/operations/unary_operations/tests/DateExtractOperation_unittest.cpp
----------------------------------------------------------------------
diff --git a/types/operations/unary_operations/tests/DateExtractOperation_unittest.cpp b/types/operations/unary_operations/tests/DateExtractOperation_unittest.cpp
index ec14408..6cff66c 100644
--- a/types/operations/unary_operations/tests/DateExtractOperation_unittest.cpp
+++ b/types/operations/unary_operations/tests/DateExtractOperation_unittest.cpp
@@ -77,19 +77,22 @@ class DateExtractOperationTest : public ::testing::Test {
   static void CheckFixedNullableResultTypeForField(const DateExtractUnit field) {
     const Type *fixed_result_type
         = DateExtractOperation::Instance(field).fixedNullableResultType();
-    ASSERT_NE(fixed_result_type, nullptr);
-    EXPECT_TRUE(TypeFactory::GetType(kLong, true).equals(*fixed_result_type));
+    ASSERT_EQ(fixed_result_type, nullptr);
   }
 
   static void CheckResultTypeIsPlausibleForField(const DateExtractUnit field) {
-    // Only Long is plausible.
+    // Long and Int are plausible.
     EXPECT_TRUE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
         TypeFactory::GetType(kLong, false)));
     EXPECT_TRUE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
         TypeFactory::GetType(kLong, true)));
+    EXPECT_TRUE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
+        TypeFactory::GetType(kInt, false)));
+    EXPECT_TRUE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
+        TypeFactory::GetType(kInt, true)));
 
     for (const TypeID type_id
-         : {kInt, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval}) {
+         : {kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval}) {
       EXPECT_FALSE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
           TypeFactory::GetType(type_id, false)));
       EXPECT_FALSE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
@@ -109,12 +112,17 @@ class DateExtractOperationTest : public ::testing::Test {
   static void CheckPushDownTypeHintForField(const DateExtractUnit field) {
     const UnaryOperation &op = DateExtractOperation::Instance(field);
 
-    // If hint is Long, then the argument is a Datetime with the same
-    // nullability.
     const Type *argument_hint
         = op.pushDownTypeHint(&TypeFactory::GetType(kLong, true));
-    ASSERT_NE(argument_hint, nullptr);
-    EXPECT_TRUE(TypeFactory::GetType(kDatetime, true).equals(*argument_hint));
+    if ((field == DateExtractUnit::kMonth) || (field == DateExtractUnit::kYear)) {
+      // If field is either Year or Month, the argument is NULL.
+      ASSERT_EQ(argument_hint, nullptr);
+    } else {
+      // Otherwise, if hint is Long, then the argument is a Datetime with the
+      // same nullability.
+      ASSERT_NE(argument_hint, nullptr);
+      EXPECT_TRUE(TypeFactory::GetType(kDatetime, true).equals(*argument_hint));
+    }
 
     argument_hint = op.pushDownTypeHint(&TypeFactory::GetType(kLong, false));
     ASSERT_NE(argument_hint, nullptr);