You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@quickstep.apache.org by ji...@apache.org on 2017/04/12 19:34:25 UTC

[22/27] incubator-quickstep git commit: Refactor type system and operations.

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/TypedValue.cpp
----------------------------------------------------------------------
diff --git a/types/TypedValue.cpp b/types/TypedValue.cpp
index 8dd8b60..ad1eb0f 100644
--- a/types/TypedValue.cpp
+++ b/types/TypedValue.cpp
@@ -47,6 +47,7 @@ bool TypedValue::isPlausibleInstanceOf(const TypeSignature type) const {
   }
 
   switch (type_id) {
+    case kBool:
     case kInt:
     case kLong:
     case kFloat:
@@ -82,33 +83,34 @@ serialization::TypedValue TypedValue::getProto() const {
 
   // NOTE(chasseur): To represent a NULL value, only the 'type_id' field of the
   // proto is filled in, and all the optional value fields are omitted.
+  proto.mutable_type_id()->CopyFrom(TypeIDFactory::GetProto(getTypeID()));
   switch (getTypeID()) {
+    case kBool:
+      if (!isNull()) {
+        proto.set_int_value(getLiteral<bool>());
+      }
+      break;
     case kInt:
-      proto.set_type_id(serialization::Type::INT);
       if (!isNull()) {
         proto.set_int_value(getLiteral<int>());
       }
       break;
     case kLong:
-      proto.set_type_id(serialization::Type::LONG);
       if (!isNull()) {
         proto.set_long_value(getLiteral<std::int64_t>());
       }
       break;
     case kFloat:
-      proto.set_type_id(serialization::Type::FLOAT);
       if (!isNull()) {
         proto.set_float_value(getLiteral<float>());
       }
       break;
     case kDouble:
-      proto.set_type_id(serialization::Type::DOUBLE);
       if (!isNull()) {
         proto.set_double_value(getLiteral<double>());
       }
       break;
     case kDate:
-      proto.set_type_id(serialization::Type::DATE);
       if (!isNull()) {
         serialization::TypedValue::DateLit *literal_date_proto = proto.mutable_date_value();
         literal_date_proto->set_year(value_union_.date_value.year);
@@ -117,37 +119,31 @@ serialization::TypedValue TypedValue::getProto() const {
       }
       break;
     case kDatetime:
-      proto.set_type_id(serialization::Type::DATETIME);
       if (!isNull()) {
         proto.set_datetime_value(value_union_.datetime_value.ticks);
       }
       break;
     case kDatetimeInterval:
-      proto.set_type_id(serialization::Type::DATETIME_INTERVAL);
       if (!isNull()) {
         proto.set_datetime_interval_value(value_union_.datetime_interval_value.interval_ticks);
       }
       break;
     case kYearMonthInterval:
-      proto.set_type_id(serialization::Type::YEAR_MONTH_INTERVAL);
       if (!isNull()) {
         proto.set_year_month_interval_value(value_union_.year_month_interval_value.months);
       }
       break;
     case kChar:
-      proto.set_type_id(serialization::Type::CHAR);
       if (!isNull()) {
         proto.set_out_of_line_data(static_cast<const char*>(getOutOfLineData()), getDataSize());
       }
       break;
     case kVarChar:
-      proto.set_type_id(serialization::Type::VAR_CHAR);
       if (!isNull()) {
         proto.set_out_of_line_data(static_cast<const char*>(getOutOfLineData()), getDataSize());
       }
       break;
     case kNullType:
-      proto.set_type_id(serialization::Type::NULL_TYPE);
       DCHECK(isNull());
       break;
     default:
@@ -166,24 +162,29 @@ TypedValue TypedValue::ReconstructFromProto(const serialization::TypedValue &pro
       << "Attempted to create TypedValue from an invalid proto description:\n"
       << proto.DebugString();
 
-  switch (proto.type_id()) {
-    case serialization::Type::INT:
+  const TypeID type_id = TypeIDFactory::ReconstructFromProto(proto.type_id());
+  switch (type_id) {
+    case kBool:
+      return proto.has_bool_value() ?
+          TypedValue(static_cast<bool>(proto.bool_value())) :
+          TypedValue(kBool);
+    case kInt:
       return proto.has_int_value() ?
           TypedValue(static_cast<int>(proto.int_value())) :
           TypedValue(kInt);
-    case serialization::Type::LONG:
+    case kLong:
       return proto.has_long_value() ?
           TypedValue(static_cast<std::int64_t>(proto.long_value())) :
           TypedValue(kLong);
-    case serialization::Type::FLOAT:
+    case kFloat:
       return proto.has_float_value() ?
           TypedValue(static_cast<float>(proto.float_value())) :
           TypedValue(kFloat);
-    case serialization::Type::DOUBLE:
+    case kDouble:
       return proto.has_double_value() ?
           TypedValue(static_cast<double>(proto.double_value())) :
           TypedValue(kDouble);
-    case serialization::Type::DATE:
+    case kDate:
       if (proto.has_date_value()) {
         return TypedValue(DateLit::Create(proto.date_value().year(),
                                           proto.date_value().month(),
@@ -191,7 +192,7 @@ TypedValue TypedValue::ReconstructFromProto(const serialization::TypedValue &pro
       } else {
         return TypedValue(kDate);
       }
-    case serialization::Type::DATETIME:
+    case kDatetime:
       if (proto.has_datetime_value()) {
         DatetimeLit datetime;
         datetime.ticks = proto.datetime_value();
@@ -199,7 +200,7 @@ TypedValue TypedValue::ReconstructFromProto(const serialization::TypedValue &pro
       } else {
         return TypedValue(kDatetime);
       }
-    case serialization::Type::DATETIME_INTERVAL:
+    case kDatetimeInterval:
       if (proto.has_datetime_interval_value()) {
         DatetimeIntervalLit interval;
         interval.interval_ticks = proto.datetime_interval_value();
@@ -207,7 +208,7 @@ TypedValue TypedValue::ReconstructFromProto(const serialization::TypedValue &pro
       } else {
         return TypedValue(kDatetimeInterval);
       }
-    case serialization::Type::YEAR_MONTH_INTERVAL:
+    case kYearMonthInterval:
       if (proto.has_year_month_interval_value()) {
         YearMonthIntervalLit interval;
         interval.months = proto.year_month_interval_value();
@@ -215,19 +216,19 @@ TypedValue TypedValue::ReconstructFromProto(const serialization::TypedValue &pro
       } else {
         return TypedValue(kYearMonthInterval);
       }
-    case serialization::Type::CHAR:
+    case kChar:
       return proto.has_out_of_line_data() ?
           TypedValue(kChar,
                      static_cast<const void*>(proto.out_of_line_data().c_str()),
                      proto.out_of_line_data().size()).ensureNotReference() :
           TypedValue(kChar);
-    case serialization::Type::VAR_CHAR:
+    case kVarChar:
       return proto.has_out_of_line_data() ?
           TypedValue(kVarChar,
                      static_cast<const void*>(proto.out_of_line_data().c_str()),
                      proto.out_of_line_data().size()).ensureNotReference() :
           TypedValue(kVarChar);
-    case serialization::Type::NULL_TYPE:
+    case kNullType:
       return TypedValue(kNullType);
     default:
       FATAL_ERROR("Unrecognized TypeID in TypedValue::ReconstructFromProto");

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/TypedValue.hpp
----------------------------------------------------------------------
diff --git a/types/TypedValue.hpp b/types/TypedValue.hpp
index 0ba3d53..220b3ac 100644
--- a/types/TypedValue.hpp
+++ b/types/TypedValue.hpp
@@ -90,6 +90,16 @@ class TypedValue {
   }
 
   /**
+   * @brief Constructor for a literal value of BoolType.
+   **/
+  explicit TypedValue(const bool literal_bool)
+      : value_info_(static_cast<std::uint64_t>(kBool)) {
+    // Zero-out all bytes in the union for getHash() and fastEqualCheck().
+    value_union_.hash64 = 0;
+    value_union_.bool_value = literal_bool;
+  }
+
+  /**
    * @brief Constructor for a literal value of IntType.
    **/
   explicit TypedValue(const int literal_int)
@@ -264,9 +274,9 @@ class TypedValue {
    *        TypedValue will take ownership of this memory.
    * @param value_size The number of bytes of data at value_ptr.
    **/
-  static TypedValue CreateWithOwnedData(const TypeID type_id,
-                                        void *value_ptr,
-                                        const std::size_t value_size) {
+  inline static TypedValue CreateWithOwnedData(const TypeID type_id,
+                                               void *value_ptr,
+                                               const std::size_t value_size) {
     TypedValue val(type_id, value_ptr, value_size);
     val.value_info_ |= kOwnershipMask;
     return val;
@@ -282,6 +292,7 @@ class TypedValue {
    **/
   static bool RepresentedInline(const TypeID type_id) {
     switch (type_id) {
+      case kBool:
       case kInt:
       case kLong:
       case kFloat:
@@ -313,6 +324,8 @@ class TypedValue {
    **/
   static bool HashIsReversible(const TypeID type_id) {
     switch (type_id) {
+      case kBool:
+        return true;
       case kInt:
       case kFloat:
         return sizeof(value_union_.int_value) <= sizeof(std::size_t);
@@ -391,6 +404,8 @@ class TypedValue {
   inline std::size_t getDataSize() const {
     DCHECK(!isNull());
     switch (getTypeID()) {
+      case kBool:
+        return sizeof(bool);
       case kInt:
       case kFloat:
         return sizeof(int);
@@ -478,7 +493,8 @@ class TypedValue {
    * @return The out-of-line data this TypedValue points to.
    **/
   inline const void* getOutOfLineData() const {
-    DCHECK(!(getTypeID() == kInt
+    DCHECK(!(getTypeID() == kBool
+                   || getTypeID() == kInt
                    || getTypeID() == kLong
                    || getTypeID() == kFloat
                    || getTypeID() == kDouble
@@ -547,6 +563,10 @@ class TypedValue {
                   value_info_ >> kSizeShift);
     } else {
       switch (getTypeID()) {
+        case kBool:
+          // 1 byte copy.
+          *static_cast<bool*>(destination) = value_union_.bool_value;
+          break;
         case kInt:
         case kFloat:
           // 4 bytes byte-for-byte copy.
@@ -574,6 +594,7 @@ class TypedValue {
    **/
   inline std::size_t getHash() const {
     switch (getTypeID()) {
+      case kBool:
       case kInt:
       case kLong:
       case kFloat:
@@ -670,6 +691,7 @@ class TypedValue {
     DCHECK(!other.isNull());
     DCHECK_EQ(getTypeID(), other.getTypeID());
     switch (getTypeID()) {
+      case kBool:
       case kInt:
       case kLong:
       case kFloat:
@@ -789,6 +811,7 @@ class TypedValue {
   inline void reverseHash(const std::size_t hash);
 
   union ValueUnion {
+    bool bool_value;
     int int_value;
     std::int64_t long_value;
     float float_value;
@@ -842,6 +865,13 @@ class TypedValue {
 
 // Explicit specializations of getLiteral().
 template <>
+inline bool TypedValue::getLiteral<bool>() const {
+  DCHECK_EQ(kBool, getTypeID());
+  DCHECK(!isNull());
+  return value_union_.bool_value;
+}
+
+template <>
 inline int TypedValue::getLiteral<int>() const {
   DCHECK_EQ(kInt, getTypeID());
   DCHECK(!isNull());

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/TypedValue.proto
----------------------------------------------------------------------
diff --git a/types/TypedValue.proto b/types/TypedValue.proto
index 7f3ab7a..7cf3eca 100644
--- a/types/TypedValue.proto
+++ b/types/TypedValue.proto
@@ -22,17 +22,18 @@ package quickstep.serialization;
 import "types/Type.proto";
 
 message TypedValue {
-  required Type.TypeID type_id = 1;
+  required TypeID type_id = 1;
 
   // NOTE(zuyu): For a NULL value, none of the optional fields are filled in.
-  optional int32 int_value = 2;
-  optional int64 long_value = 3;
-  optional float float_value = 4;
-  optional double double_value = 5;
-  optional bytes out_of_line_data = 6;
-  optional int64 datetime_value = 7;
-  optional int64 datetime_interval_value = 8;
-  optional int64 year_month_interval_value = 9;
+  optional bool bool_value = 2;
+  optional int32 int_value = 3;
+  optional int64 long_value = 4;
+  optional float float_value = 5;
+  optional double double_value = 6;
+  optional bytes out_of_line_data = 7;
+  optional int64 datetime_value = 8;
+  optional int64 datetime_interval_value = 9;
+  optional int64 year_month_interval_value = 10;
 
   message DateLit {
     required int32 year = 1;
@@ -40,5 +41,5 @@ message TypedValue {
     required uint32 day = 3;
   }
 
-  optional DateLit date_value = 10;
+  optional DateLit date_value = 11;
 }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/VarCharType.cpp
----------------------------------------------------------------------
diff --git a/types/VarCharType.cpp b/types/VarCharType.cpp
index 02845b1..7eeb04c 100644
--- a/types/VarCharType.cpp
+++ b/types/VarCharType.cpp
@@ -42,38 +42,6 @@ using std::string;
 
 namespace quickstep {
 
-template <bool nullable_internal>
-const VarCharType& VarCharType::InstanceInternal(const std::size_t length) {
-  static PtrMap<size_t, VarCharType> instance_map;
-  PtrMap<size_t, VarCharType>::iterator imit = instance_map.find(length);
-  if (imit == instance_map.end()) {
-    imit = instance_map.insert(length, new VarCharType(length, nullable_internal)).first;
-  }
-  return *(imit->second);
-}
-
-const VarCharType& VarCharType::InstanceNonNullable(const std::size_t length) {
-  return InstanceInternal<false>(length);
-}
-
-const VarCharType& VarCharType::InstanceNullable(const std::size_t length) {
-  return InstanceInternal<true>(length);
-}
-
-const VarCharType& VarCharType::InstanceFromProto(const serialization::Type &proto) {
-  return Instance(proto.GetExtension(serialization::VarCharType::length), proto.nullable());
-}
-
-serialization::Type VarCharType::getProto() const {
-  serialization::Type proto;
-  proto.set_type_id(serialization::Type::VAR_CHAR);
-
-  proto.set_nullable(nullable_);
-
-  proto.SetExtension(serialization::VarCharType::length, length_);
-  return proto;
-}
-
 size_t VarCharType::estimateAverageByteLength() const {
   if (length_ > 160) {
     return 80;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/VarCharType.hpp
----------------------------------------------------------------------
diff --git a/types/VarCharType.hpp b/types/VarCharType.hpp
index bb50e92..05b2aae 100644
--- a/types/VarCharType.hpp
+++ b/types/VarCharType.hpp
@@ -24,8 +24,8 @@
 #include <cstdio>
 #include <string>
 
+#include "types/AsciiStringSuperType.hpp"
 #include "types/Type.hpp"
-#include "types/Type.pb.h"
 #include "types/TypeID.hpp"
 #include "types/TypedValue.hpp"
 #include "utility/Macros.hpp"
@@ -43,72 +43,9 @@ namespace quickstep {
  *       character. This means that the VARCHAR(X) type requires from 1 to X+1
  *       bytes of storage, depending on string length.
  **/
-class VarCharType : public AsciiStringSuperType {
+class VarCharType : public AsciiStringSuperType<kVarChar> {
  public:
   /**
-   * @brief Get a reference to the non-nullable singleton instance of this Type
-   *        for the specified length.
-   *
-   * @param length The length parameter of the VarCharType.
-   * @return A reference to the non-nullable singleton instance of this Type
-   *         for the specified length.
-   **/
-  static const VarCharType& InstanceNonNullable(const std::size_t length);
-
-  /**
-   * @brief Get a reference to the nullable singleton instance of this Type for
-   *        the specified length.
-   *
-   * @param length The length parameter of the VarCharType.
-   * @return A reference to the nullable singleton instance of this Type for
-   *         the specified length.
-   **/
-  static const VarCharType& InstanceNullable(const std::size_t length);
-
-  /**
-   * @brief Get a reference to the singleton instance of this Type for the
-   *        specified length and nullability.
-   *
-   * @param length The length parameter of the VarCharType.
-   * @param nullable Whether to get the nullable version of this Type.
-   * @return A reference to the singleton instance of this Type for the
-   *         specified length and nullability.
-   **/
-  static const VarCharType& Instance(const std::size_t length, const bool nullable) {
-    if (nullable) {
-      return InstanceNullable(length);
-    } else {
-      return InstanceNonNullable(length);
-    }
-  }
-
-  /**
-   * @brief Get a reference to the singleton instance of this Type described
-   *        by the given Protocol Buffer serialization.
-   *
-   * @param type The serialized Protocol Buffer representation of the desired
-   *        VarCharType.
-   * @return A reference to the singleton instance of this Type for the given
-   *         Protocol Buffer.
-   **/
-  static const VarCharType& InstanceFromProto(const serialization::Type &type);
-
-  /**
-   * @brief Generate a serialized Protocol Buffer representation of this Type.
-   *
-   * @return The serialized Protocol Buffer representation of this Type.
-   **/
-  serialization::Type getProto() const override;
-
-  const Type& getNullableVersion() const override {
-    return InstanceNullable(length_);
-  }
-
-  const Type& getNonNullableVersion() const override {
-    return InstanceNonNullable(length_);
-  }
-
-  /**
    * @note Includes an extra byte for a terminating null character.
    **/
   std::size_t estimateAverageByteLength() const override;
@@ -137,11 +74,9 @@ class VarCharType : public AsciiStringSuperType {
 
  private:
   VarCharType(const std::size_t length, const bool nullable)
-      : AsciiStringSuperType(kVarChar, nullable, 1, length + 1, length) {
-  }
+      : AsciiStringSuperType<kVarChar>(nullable, 1, length + 1, length) {}
 
-  template <bool nullable_internal>
-  static const VarCharType& InstanceInternal(const std::size_t length);
+  template <typename, bool> friend class TypeInstance;
 
   DISALLOW_COPY_AND_ASSIGN(VarCharType);
 };

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/YearMonthIntervalType.cpp
----------------------------------------------------------------------
diff --git a/types/YearMonthIntervalType.cpp b/types/YearMonthIntervalType.cpp
index 3c15a91..d656fca 100644
--- a/types/YearMonthIntervalType.cpp
+++ b/types/YearMonthIntervalType.cpp
@@ -30,7 +30,6 @@
 
 #include "types/IntervalLit.hpp"
 #include "types/IntervalParser.hpp"
-#include "types/NullCoercibilityCheckMacro.hpp"
 #include "types/Type.hpp"
 #include "types/TypeID.hpp"
 #include "types/TypedValue.hpp"
@@ -46,16 +45,6 @@ using std::snprintf;
 
 namespace quickstep {
 
-bool YearMonthIntervalType::isCoercibleFrom(const Type &original_type) const {
-  QUICKSTEP_NULL_COERCIBILITY_CHECK();
-  return (original_type.getTypeID() == kYearMonthInterval);
-}
-
-bool YearMonthIntervalType::isSafelyCoercibleFrom(const Type &original_type) const {
-  QUICKSTEP_NULL_COERCIBILITY_CHECK();
-  return (original_type.getTypeID() == kYearMonthInterval);
-}
-
 std::string YearMonthIntervalType::printValueToString(const TypedValue &value) const {
   DCHECK(!value.isNull());
 
@@ -127,14 +116,6 @@ std::string YearMonthIntervalType::printValueToString(const TypedValue &value) c
   return std::string(interval_buf);
 }
 
-void YearMonthIntervalType::printValueToFile(const TypedValue &value,
-                                             FILE *file,
-                                             const int padding) const {
-  // We simply re-use the logic from printValueToString(), as trying to do
-  // padding on-the fly with so many different fields is too much of a hassle.
-  std::fprintf(file, "%*s", static_cast<int>(padding), printValueToString(value).c_str());
-}
-
 bool YearMonthIntervalType::parseValueFromString(const std::string &value_string,
                                                  TypedValue *value) const {
   // Try simple-format parse first.

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/YearMonthIntervalType.hpp
----------------------------------------------------------------------
diff --git a/types/YearMonthIntervalType.hpp b/types/YearMonthIntervalType.hpp
index a2ba175..e890ea9 100644
--- a/types/YearMonthIntervalType.hpp
+++ b/types/YearMonthIntervalType.hpp
@@ -27,6 +27,7 @@
 #include "types/IntervalLit.hpp"
 #include "types/Type.hpp"
 #include "types/TypeID.hpp"
+#include "types/TypeSynthesizer.hpp"
 #include "types/TypedValue.hpp"
 #include "utility/Macros.hpp"
 
@@ -39,73 +40,14 @@ namespace quickstep {
 /**
  * @brief A type representing the year-month interval.
  **/
-class YearMonthIntervalType : public Type {
+class YearMonthIntervalType : public TypeSynthesizer<kYearMonthInterval> {
  public:
-  typedef YearMonthIntervalLit cpptype;
-
-  static const TypeID kStaticTypeID = kYearMonthInterval;
-
-  /**
-   * @brief Get a reference to the non-nullable singleton instance of this
-   *        Type.
-   *
-   * @return A reference to the non-nullable singleton instance of this Type.
-   **/
-  static const YearMonthIntervalType& InstanceNonNullable() {
-    static YearMonthIntervalType instance(false);
-    return instance;
-  }
-
-  /**
-   * @brief Get a reference to the nullable singleton instance of this Type.
-   *
-   * @return A reference to the nullable singleton instance of this Type.
-   **/
-  static const YearMonthIntervalType& InstanceNullable() {
-    static YearMonthIntervalType instance(true);
-    return instance;
-  }
-
-  /**
-   * @brief Get a reference to a singleton instance of this Type.
-   *
-   * @param nullable Whether to get the nullable version of this Type.
-   * @return A reference to the desired singleton instance of this Type.
-   **/
-  static const YearMonthIntervalType& Instance(const bool nullable) {
-    if (nullable) {
-      return InstanceNullable();
-    } else {
-      return InstanceNonNullable();
-    }
-  }
-
-  const Type& getNullableVersion() const override {
-    return InstanceNullable();
-  }
-
-  const Type& getNonNullableVersion() const override {
-    return InstanceNonNullable();
-  }
-
-  std::size_t estimateAverageByteLength() const override {
-    return sizeof(YearMonthIntervalLit);
-  }
-
-  bool isCoercibleFrom(const Type &original_type) const override;
-
-  bool isSafelyCoercibleFrom(const Type &original_type) const override;
-
   int getPrintWidth() const override {
     return YearMonthIntervalLit::kPrintingChars;
   }
 
   std::string printValueToString(const TypedValue &value) const override;
 
-  void printValueToFile(const TypedValue &value,
-                        FILE *file,
-                        const int padding = 0) const override;
-
   TypedValue makeZeroValue() const override {
     return TypedValue(YearMonthIntervalLit{0});
   }
@@ -115,8 +57,9 @@ class YearMonthIntervalType : public Type {
 
  private:
   explicit YearMonthIntervalType(const bool nullable)
-      : Type(Type::kOther, kYearMonthInterval, nullable, sizeof(YearMonthIntervalLit), sizeof(YearMonthIntervalLit)) {
-  }
+      : TypeSynthesizer<kYearMonthInterval>(nullable) {}
+
+  template <typename, bool> friend class TypeInstance;
 
   DISALLOW_COPY_AND_ASSIGN(YearMonthIntervalType);
 };

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/containers/ColumnVector.cpp
----------------------------------------------------------------------
diff --git a/types/containers/ColumnVector.cpp b/types/containers/ColumnVector.cpp
index dfc0fae..ef3587e 100644
--- a/types/containers/ColumnVector.cpp
+++ b/types/containers/ColumnVector.cpp
@@ -41,4 +41,8 @@ ColumnVector* ColumnVector::MakeVectorOfValue(
   }
 }
 
+constexpr bool NativeColumnVector::kNative;
+
+constexpr bool IndirectColumnVector::kNative;
+
 }  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/containers/ColumnVector.hpp
----------------------------------------------------------------------
diff --git a/types/containers/ColumnVector.hpp b/types/containers/ColumnVector.hpp
index fc65656..5d11098 100644
--- a/types/containers/ColumnVector.hpp
+++ b/types/containers/ColumnVector.hpp
@@ -119,6 +119,8 @@ class ColumnVector {
  **/
 class NativeColumnVector : public ColumnVector {
  public:
+  static constexpr bool kNative = true;
+
   /**
    * @brief Constructor for a NativeColumnVector which owns its own array of
    *        values.
@@ -130,8 +132,8 @@ class NativeColumnVector : public ColumnVector {
   NativeColumnVector(const Type &type, const std::size_t reserved_length)
       : ColumnVector(type),
         type_length_(type.maximumByteLength()),
-        values_(std::malloc(type.maximumByteLength() * reserved_length)),
         reserved_length_(reserved_length),
+        values_(std::malloc(type.maximumByteLength() * reserved_length)),
         actual_length_(0u),
         null_bitmap_(type.isNullable() ? new BitVector<false>(reserved_length) : nullptr) {
     DCHECK(UsableForType(type_));
@@ -385,8 +387,9 @@ class NativeColumnVector : public ColumnVector {
 
  private:
   const std::size_t type_length_;
-  void *values_;
   const std::size_t reserved_length_;
+
+  void *values_;
   std::size_t actual_length_;
   std::unique_ptr<BitVector<false>> null_bitmap_;
 
@@ -399,6 +402,8 @@ class NativeColumnVector : public ColumnVector {
  **/
 class IndirectColumnVector : public ColumnVector {
  public:
+  static constexpr bool kNative = false;
+
   /**
    * @brief Constructor.
    *
@@ -493,11 +498,21 @@ class IndirectColumnVector : public ColumnVector {
    * @param value A value to append to this NativeColumnVector.
    **/
   inline void appendTypedValue(TypedValue &&value) {
-    DCHECK(value.isPlausibleInstanceOf(type_.getSignature()));
+    DCHECK(value.isPlausibleInstanceOf(type_.getSignature())) << type_.getName();
     DCHECK_LT(values_.size(), reserved_length_);
     values_.emplace_back(std::move(value));
   }
 
+  inline void appendNullValue() {
+    DCHECK(type_.isNullable());
+    DCHECK_LT(values_.size(), reserved_length_);
+    values_.emplace_back(type_.makeNullValue());
+  }
+
+  inline void fillWithNulls() {
+    fillWithValue(type_.makeNullValue());
+  }
+
   /**
    * @brief Fill this entire ColumnVector with copies of value.
    *
@@ -559,6 +574,7 @@ class IndirectColumnVector : public ColumnVector {
  private:
   const bool type_is_nullable_;
   const std::size_t reserved_length_;
+
   std::vector<TypedValue> values_;
 
   DISALLOW_COPY_AND_ASSIGN(IndirectColumnVector);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/operations/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/types/operations/CMakeLists.txt b/types/operations/CMakeLists.txt
index c5dad0f..948d013 100644
--- a/types/operations/CMakeLists.txt
+++ b/types/operations/CMakeLists.txt
@@ -25,19 +25,62 @@ QS_PROTOBUF_GENERATE_CPP(types_operations_Operation_proto_srcs
 
 # Declare micro-libs:
 add_library(quickstep_types_operations_Operation Operation.cpp Operation.hpp)
+add_library(quickstep_types_operations_OperationFactory OperationFactory.cpp OperationFactory.hpp)
+add_library(quickstep_types_operations_OperationUtil ../../empty_src.cpp OperationUtil.hpp)
+add_library(quickstep_types_operations_OperationSignature OperationSignature.cpp OperationSignature.hpp)
 add_library(quickstep_types_operations_Operation_proto ${types_operations_Operation_proto_srcs})
 
 # Link dependencies:
 target_link_libraries(quickstep_types_operations_Operation
+                      quickstep_types_operations_OperationSignature
+                      quickstep_utility_Macros)
+target_link_libraries(quickstep_types_operations_OperationFactory
+                      quickstep_types_Type
+                      quickstep_types_TypeFactory
+                      quickstep_types_TypeID
+                      quickstep_types_TypeUtil
+                      quickstep_types_TypedValue
+                      quickstep_types_operations_Operation
+                      quickstep_types_operations_OperationSignature
+                      quickstep_types_operations_binaryoperations_ArithmeticBinaryOperations
+                      quickstep_types_operations_binaryoperations_AsciiStringBinaryOperations
+                      quickstep_types_operations_binaryoperations_BinaryOperation
+                      quickstep_types_operations_binaryoperations_BinaryOperationWrapper
+                      quickstep_types_operations_binaryoperations_CMathBinaryOperations
+                      quickstep_types_operations_unaryoperations_ArithmeticUnaryOperations
+                      quickstep_types_operations_unaryoperations_AsciiStringUnaryOperations
+                      quickstep_types_operations_unaryoperations_CMathUnaryOperations
+                      quickstep_types_operations_unaryoperations_CastOperation
+                      quickstep_types_operations_unaryoperations_DateExtractOperation
+                      quickstep_types_operations_unaryoperations_SubstringOperation
+                      quickstep_types_operations_unaryoperations_UnaryOperation
+                      quickstep_types_operations_unaryoperations_UnaryOperationWrapper
+                      quickstep_utility_HashPair
+                      quickstep_utility_Macros
+                      quickstep_utility_StringUtil)
+target_link_libraries(quickstep_types_operations_OperationUtil
+                      quickstep_catalog_CatalogTypedefs
+                      quickstep_types_Type
+                      quickstep_types_TypedValue
+                      quickstep_types_containers_ColumnVector)
+target_link_libraries(quickstep_types_operations_OperationSignature
+                      quickstep_types_TypeID
+                      quickstep_types_Type_proto
+                      quickstep_types_operations_Operation_proto
+                      quickstep_utility_HashPair
                       quickstep_utility_Macros)
 target_link_libraries(quickstep_types_operations_Operation_proto
                       quickstep_types_Type_proto
+                      quickstep_types_TypedValue_proto
                       ${PROTOBUF_LIBRARY})
 
 # Module all-in-one library:
 add_library(quickstep_types_operations ../../empty_src.cpp)
 target_link_libraries(quickstep_types_operations
                       quickstep_types_operations_Operation
+                      quickstep_types_operations_OperationFactory
+                      quickstep_types_operations_OperationUtil
+                      quickstep_types_operations_OperationSignature
                       quickstep_types_operations_Operation_proto
                       quickstep_types_operations_binaryoperations
                       quickstep_types_operations_comparisons

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/operations/Operation.hpp
----------------------------------------------------------------------
diff --git a/types/operations/Operation.hpp b/types/operations/Operation.hpp
index 51178b5..6da0f4c 100644
--- a/types/operations/Operation.hpp
+++ b/types/operations/Operation.hpp
@@ -20,6 +20,10 @@
 #ifndef QUICKSTEP_TYPES_OPERATIONS_OPERATION_HPP_
 #define QUICKSTEP_TYPES_OPERATIONS_OPERATION_HPP_
 
+#include <string>
+#include <vector>
+
+#include "types/operations/OperationSignature.hpp"
 #include "utility/Macros.hpp"
 
 namespace quickstep {
@@ -28,6 +32,9 @@ namespace quickstep {
  *  @{
  */
 
+class Operation;
+typedef std::shared_ptr<const Operation> OperationPtr;
+
 /**
  * @brief An operation which can be applied to typed values. Each exact
  *        concrete Operation is a singleton.
@@ -72,7 +79,7 @@ class Operation {
    * @return The human-readable name of this Operation.
    **/
   inline const char* getName() const {
-    return name_;
+    return "NoName";
   }
 
   /**
@@ -81,7 +88,11 @@ class Operation {
    * @return The short name of this Operation.
    **/
   inline const char* getShortName() const {
-    return short_name_;
+    return "NoShortName";
+  }
+
+  virtual std::vector<OperationSignaturePtr> getSignatures() const {
+    return {};
   }
 
   /**
@@ -98,19 +109,12 @@ class Operation {
   }
 
  protected:
-  Operation(const OperationSuperTypeID super_type_id,
-            const char *name,
-            const char *short_name)
-      : super_type_id_(super_type_id),
-        name_(name),
-        short_name_(short_name) {
+  explicit Operation(const OperationSuperTypeID super_type_id)
+      : super_type_id_(super_type_id) {
   }
 
  private:
   const OperationSuperTypeID super_type_id_;
-  const char *name_;
-  const char *short_name_;
-
 
   DISALLOW_COPY_AND_ASSIGN(Operation);
 };

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/operations/Operation.proto
----------------------------------------------------------------------
diff --git a/types/operations/Operation.proto b/types/operations/Operation.proto
index d6391f0..da2a282 100644
--- a/types/operations/Operation.proto
+++ b/types/operations/Operation.proto
@@ -20,6 +20,7 @@ syntax = "proto2";
 package quickstep.serialization;
 
 import "types/Type.proto";
+import "types/TypedValue.proto";
 
 message Comparison {
   enum ComparisonID {
@@ -38,58 +39,8 @@ message Comparison {
   required ComparisonID comparison_id = 1;
 }
 
-message UnaryOperation {
-  enum UnaryOperationID {
-    NEGATE = 0;
-    CAST = 1;
-    DATE_EXTRACT = 2;
-    SUBSTRING = 3;
-  }
-
-  required UnaryOperationID operation_id = 1;
-
-  extensions 32 to max;
-}
-
-message CastOperation {
-  extend UnaryOperation {
-    // Required when operation_id = CAST.
-    optional Type target_type = 64;
-  }
-}
-
-message DateExtractOperation {
-  enum Unit {
-    YEAR = 0;
-    MONTH = 1;
-    DAY = 2;
-    HOUR = 3;
-    MINUTE = 4;
-    SECOND = 5;
-  }
-
-  extend UnaryOperation {
-    // Required when operation_id = DATE_EXTRACT.
-    optional Unit unit = 96;
-  }
-}
-
-message SubstringOperation {
-  extend UnaryOperation {
-    // Required when operation_id = SUBSTRING.
-    optional int64 start_position = 100;
-    optional int64 substring_length = 101;
-  }
-}
-
-message BinaryOperation {
-  enum BinaryOperationID {
-    ADD = 0;
-    SUBTRACT = 1;
-    MULTIPLY = 2;
-    DIVIDE = 3;
-    MODULO = 4;
-  }
-
-  required BinaryOperationID operation_id = 1;
+message OperationSignature {
+  required string operation_name = 1;
+  repeated TypeID argument_type_ids = 2;
+  required uint32 num_static_arguments = 3;
 }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/operations/OperationFactory.cpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationFactory.cpp b/types/operations/OperationFactory.cpp
new file mode 100644
index 0000000..531318b
--- /dev/null
+++ b/types/operations/OperationFactory.cpp
@@ -0,0 +1,357 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ **/
+
+#include "types/operations/OperationFactory.hpp"
+
+#include <list>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "types/Type.hpp"
+#include "types/TypeFactory.hpp"
+#include "types/TypeID.hpp"
+#include "types/TypeUtil.hpp"
+#include "types/TypedValue.hpp"
+#include "types/operations/Operation.hpp"
+#include "types/operations/OperationSignature.hpp"
+#include "types/operations/binary_operations/ArithmeticBinaryOperations.hpp"
+#include "types/operations/binary_operations/AsciiStringBinaryOperations.hpp"
+#include "types/operations/binary_operations/BinaryOperationWrapper.hpp"
+#include "types/operations/binary_operations/CMathBinaryOperations.hpp"
+#include "types/operations/unary_operations/ArithmeticUnaryOperations.hpp"
+#include "types/operations/unary_operations/AsciiStringUnaryOperations.hpp"
+#include "types/operations/unary_operations/CMathUnaryOperations.hpp"
+#include "types/operations/unary_operations/CastOperation.hpp"
+#include "types/operations/unary_operations/DateExtractOperation.hpp"
+#include "types/operations/unary_operations/SubstringOperation.hpp"
+#include "types/operations/unary_operations/UnaryOperationWrapper.hpp"
+#include "utility/StringUtil.hpp"
+
+namespace quickstep {
+
+namespace {
+
+struct FunctorPackDispatcher {
+  template <typename FunctorT>
+  inline static std::list<OperationPtr> Generate(
+      std::enable_if_t<FunctorT::kOperationSuperTypeID == Operation::kUnaryOperation>* = 0) {
+    return { std::make_shared<const UnaryOperationWrapper<FunctorT>>() };
+  }
+
+  template <typename FunctorT>
+  inline static std::list<OperationPtr> Generate(
+      std::enable_if_t<FunctorT::kOperationSuperTypeID == Operation::kBinaryOperation>* = 0) {
+    return { std::make_shared<const BinaryOperationWrapper<FunctorT>>() };
+  }
+
+  template <typename FunctorT>
+  inline static std::list<OperationPtr> Generate(
+      decltype(FunctorT::template GenerateOperations<FunctorPackDispatcher>())* = 0) {
+    return FunctorT::template GenerateOperations<FunctorPackDispatcher>();
+  }
+};
+
+}  // namespace
+
+OperationFactory::OperationFactory() {
+  registerOperation<CastOperation>();
+  registerOperation<DateExtractOperation>();
+  registerOperation<SubstringOperation>();
+
+  registerFunctorPack<ArithmeticUnaryFunctorPack>();
+  registerFunctorPack<AsciiStringUnaryFunctorPack>();
+  registerFunctorPack<CMathUnaryFunctorPack>();
+
+  registerFunctorPack<ArithmeticBinaryFunctorPack>();
+  registerFunctorPack<AsciiStringBinaryFunctorPack>();
+  registerFunctorPack<CMathBinaryFunctorPack>();
+}
+
+OperationSignaturePtr OperationFactory::resolveOperation(
+    const std::string &operation_name,
+    const std::shared_ptr<const std::vector<const Type*>> &argument_types,
+    const std::shared_ptr<const std::vector<TypedValue>> &static_arguments,
+    std::shared_ptr<const std::vector<const Type*>> *coerced_argument_types,
+    std::shared_ptr<const std::vector<TypedValue>> *coerced_static_arguments,
+    std::string *message) const {
+  const std::string lower_case_name = ToLower(operation_name);
+  const std::size_t arity = argument_types->size();
+  const auto &indices_it =
+      primary_index_.find(std::make_pair(lower_case_name, arity));
+
+  if (indices_it == primary_index_.end()) {
+    *message = "Unrecognized function " + operation_name
+                   + " with " + std::to_string(arity) + " arguments";
+  }
+
+  ResolveStatus status;
+  OperationSignaturePtr op_signature = nullptr;
+  const auto &secondary_index = indices_it->second;
+
+  std::vector<TypeID> argument_type_ids;
+  for (const auto *type : *argument_types) {
+    argument_type_ids.emplace_back(type->getTypeID());
+  }
+
+  // First, try full exact matching.
+  status = resolveOperationWithFullTypeMatch(secondary_index,
+                                             argument_type_ids,
+                                             *argument_types,
+                                             *static_arguments,
+                                             coerced_static_arguments,
+                                             &op_signature,
+                                             message);
+  if (status == ResolveStatus::kSuccess) {
+    DCHECK(op_signature != nullptr);
+    *coerced_argument_types = argument_types;
+    return op_signature;
+  } else if (status == ResolveStatus::kError) {
+    return nullptr;
+  }
+
+  // Otherwise, try partial (non-static arguments) exact matching.
+  status = resolveOperationWithPartialTypeMatch(secondary_index,
+                                                argument_type_ids,
+                                                *argument_types,
+                                                *static_arguments,
+                                                coerced_argument_types,
+                                                coerced_static_arguments,
+                                                &op_signature,
+                                                message);
+  if (status == ResolveStatus::kSuccess) {
+    DCHECK(op_signature != nullptr);
+    return op_signature;
+  } else if (status == ResolveStatus::kError) {
+    return nullptr;
+  }
+
+  // TODO
+  *message = "Unexpected argument types for function " + operation_name;
+  return nullptr;
+}
+
+OperationFactory::ResolveStatus OperationFactory::resolveOperationWithFullTypeMatch(
+    const PartialSignatureIndex &secondary_index,
+    const std::vector<TypeID> &argument_type_ids,
+    const std::vector<const Type*> &argument_types,
+    const std::vector<TypedValue> &static_arguments,
+    std::shared_ptr<const std::vector<TypedValue>> *partial_static_arguments,
+    OperationSignaturePtr *resolved_op_signature,
+    std::string *message) const {
+  const std::size_t max_num_static_arguments = static_arguments.size();
+  auto it = secondary_index.lower_bound(
+      std::make_pair(&argument_type_ids, max_num_static_arguments));
+
+  if (it != secondary_index.end() && *it->first.first == argument_type_ids) {
+    const OperationSignaturePtr op_signature = it->second;
+    const OperationPtr operation = getOperation(op_signature);
+
+    *partial_static_arguments =
+        std::make_shared<const std::vector<TypedValue>>(
+            static_arguments.begin()
+                + (max_num_static_arguments - op_signature->getNumStaticArguments()),
+            static_arguments.end());
+
+    if (canApplyOperationTo(operation,
+                            argument_types,
+                            **partial_static_arguments,
+                            message)) {
+      *resolved_op_signature = op_signature;
+      return ResolveStatus::kSuccess;
+    } else {
+      return ResolveStatus::kError;
+    }
+  }
+
+  return ResolveStatus::kNotFound;
+}
+
+OperationFactory::ResolveStatus OperationFactory::resolveOperationWithPartialTypeMatch(
+    const PartialSignatureIndex &secondary_index,
+    const std::vector<TypeID> &argument_type_ids,
+    const std::vector<const Type*> &argument_types,
+    const std::vector<TypedValue> &static_arguments,
+    std::shared_ptr<const std::vector<const Type*>> *coerced_argument_types,
+    std::shared_ptr<const std::vector<TypedValue>> *coerced_static_arguments,
+    OperationSignaturePtr *resolved_op_signature,
+    std::string *message) const {
+  const std::size_t arity = argument_types.size();
+  const std::size_t max_num_static_arguments = static_arguments.size();
+  const std::size_t first_static_argument_position = arity - max_num_static_arguments;
+
+  auto it = secondary_index.lower_bound(
+      std::make_pair(&argument_type_ids, max_num_static_arguments));
+  while (it != secondary_index.end()) {
+    const std::vector<TypeID> &expected_type_ids = *it->first.first;
+    DCHECK_GE(expected_type_ids.size(), it->first.second);
+    const std::size_t num_non_static_arguments =
+        expected_type_ids.size() - it->first.second;
+
+    if (!std::equal(expected_type_ids.begin(),
+                    expected_type_ids.begin() + num_non_static_arguments,
+                    argument_type_ids.begin())) {
+      break;
+    }
+
+    // Coerce static arguments
+    std::vector<const Type*> coerced_static_arg_types;
+    std::vector<TypedValue> coerced_static_args;
+
+    bool is_coercible = true;
+    for (std::size_t i = num_non_static_arguments; i < arity; ++i) {
+      const Type &arg_type = *argument_types.at(i);
+      const TypedValue &arg_value =
+          static_arguments.at(i - first_static_argument_position);
+      const TypeID &expected_type_id = expected_type_ids.at(i);
+
+      if (arg_type.getTypeID() == expected_type_id) {
+        coerced_static_arg_types.emplace_back(&arg_type);
+        coerced_static_args.emplace_back(arg_value);
+      } else {
+        const Type *expected_type = nullptr;
+        if (TypeFactory::TypeRequiresLengthParameter(expected_type_id)) {
+          // TODO: refactor type system to make this coercion extensible.
+          if (expected_type_id == kChar && arg_type.getTypeID() == kVarChar) {
+            expected_type = &TypeFactory::GetType(
+                expected_type_id, arg_type.maximumByteLength() - 1);
+          } else if (expected_type_id == kVarChar && arg_type.getTypeID() == kChar) {
+            expected_type = &TypeFactory::GetType(
+                expected_type_id, arg_type.maximumByteLength() + 1);
+          }
+        } else {
+          expected_type = &TypeFactory::GetType(expected_type_id);
+        }
+
+        if (expected_type != nullptr && expected_type->isSafelyCoercibleFrom(arg_type)) {
+          coerced_static_arg_types.emplace_back(expected_type);
+          coerced_static_args.emplace_back(
+              expected_type->coerceValue(arg_value, arg_type));
+        } else {
+          is_coercible = false;
+          break;
+        }
+      }
+    }
+
+    if (is_coercible) {
+      std::vector<const Type*> coerced_arg_types(
+          argument_types.begin(),
+          argument_types.begin() + num_non_static_arguments);
+      for (const Type *type : coerced_static_arg_types) {
+        coerced_arg_types.emplace_back(type);
+      }
+
+      const OperationPtr operation = getOperation(it->second);
+      if (canApplyOperationTo(operation,
+                              coerced_arg_types,
+                              coerced_static_args,
+                              message)) {
+        *coerced_argument_types =
+            std::make_shared<const std::vector<const Type*>>(std::move(coerced_arg_types));
+        *coerced_static_arguments =
+            std::make_shared<const std::vector<TypedValue>>(std::move(coerced_static_args));
+        *resolved_op_signature = it->second;
+        return ResolveStatus::kSuccess;
+      }
+    }
+
+    ++it;
+  }
+
+  return ResolveStatus::kNotFound;
+}
+
+bool OperationFactory::canApplyOperationTo(
+    const OperationPtr operation,
+    const std::vector<const Type*> &argument_types,
+    const std::vector<TypedValue> &static_arguments,
+    std::string *message) const {
+  switch (operation->getOperationSuperTypeID()) {
+    case Operation::kUnaryOperation: {
+      const UnaryOperationPtr unary_operation =
+          std::static_pointer_cast<const UnaryOperation>(operation);
+      return unary_operation->canApplyTo(*argument_types[0],
+                                         static_arguments,
+                                         message);
+    }
+    case Operation::kBinaryOperation: {
+      const BinaryOperationPtr binary_operation =
+          std::static_pointer_cast<const BinaryOperation>(operation);
+      return binary_operation->canApplyTo(*argument_types[0],
+                                          *argument_types[1],
+                                          static_arguments,
+                                          message);
+    }
+    default: {
+      const auto operation_id =
+         static_cast<std::underlying_type_t<Operation::OperationSuperTypeID>>(
+             operation->getOperationSuperTypeID());
+      LOG(FATAL) << "Unknown opeation super type id: " << operation_id;
+    }
+  }
+}
+
+
+const OperationFactory& OperationFactory::Instance() {
+  static OperationFactory instance;
+  return instance;
+}
+
+template <typename OperationT>
+void OperationFactory::registerOperation() {
+  registerOperationInternal(std::make_shared<const OperationT>());
+}
+
+template <typename FunctorPackT>
+void OperationFactory::registerFunctorPack() {
+  for (const OperationPtr &operation :
+           FunctorPackT::template GenerateOperations<FunctorPackDispatcher>()) {
+    registerOperationInternal(operation);
+  }
+}
+
+void OperationFactory::registerOperationInternal(const OperationPtr &operation) {
+  DCHECK(operation->getOperationSuperTypeID() == Operation::kUnaryOperation ||
+         operation->getOperationSuperTypeID() == Operation::kBinaryOperation);
+
+  for (const OperationSignaturePtr op_sig_orig : operation->getSignatures()) {
+    DCHECK(operation->getOperationSuperTypeID() != Operation::kUnaryOperation ||
+           op_sig_orig->getNonStaticArity() == 1u);
+    DCHECK(operation->getOperationSuperTypeID() != Operation::kBinaryOperation ||
+           op_sig_orig->getNonStaticArity() == 2u);
+
+    const OperationSignaturePtr op_sig =
+        OperationSignature::Create(ToLower(op_sig_orig->getName()),
+                                   op_sig_orig->getArgumentTypeIDs(),
+                                   op_sig_orig->getNumStaticArguments());
+
+    // TODO: print error message for collision
+    operations_.emplace(op_sig, operation);
+
+    const PartialSignature sig_ref =
+        std::make_pair(&op_sig->getArgumentTypeIDs(),
+                       op_sig->getNumStaticArguments());
+    primary_index_[std::make_pair(op_sig->getName(),
+                                  op_sig->getArity())].emplace(sig_ref, op_sig);
+  }
+}
+
+
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/operations/OperationFactory.hpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationFactory.hpp b/types/operations/OperationFactory.hpp
new file mode 100644
index 0000000..3e90b6d
--- /dev/null
+++ b/types/operations/OperationFactory.hpp
@@ -0,0 +1,203 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ **/
+
+#ifndef QUICKSTEP_TYPES_OPERATIONS_OPERATION_FACTORY_HPP_
+#define QUICKSTEP_TYPES_OPERATIONS_OPERATION_FACTORY_HPP_
+
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "types/TypeID.hpp"
+#include "types/TypedValue.hpp"
+#include "types/operations/Operation.hpp"
+#include "types/operations/OperationSignature.hpp"
+#include "types/operations/binary_operations/BinaryOperation.hpp"
+#include "types/operations/unary_operations/UnaryOperation.hpp"
+#include "utility/HashPair.hpp"
+#include "utility/Macros.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+
+class Type;
+
+/** \addtogroup Types
+ *  @{
+ */
+
+class OperationFactory {
+ public:
+  static const OperationFactory& Instance();
+
+  inline bool hasOperation(const std::string &operation_name,
+                           const std::size_t arity) const {
+    const auto indices_it =
+        primary_index_.find(std::make_pair(operation_name, arity));
+    return indices_it != primary_index_.end();
+  }
+
+  inline OperationPtr getOperation(const OperationSignaturePtr &op_signature) const {
+    DCHECK(operations_.find(op_signature) != operations_.end());
+    return operations_.at(op_signature);
+  }
+
+  inline OperationPtr getOperation(const std::string &operation_name,
+                                   const std::vector<TypeID> &argument_type_ids,
+                                   const std::size_t num_static_arguments = 0) const {
+    return getOperation(
+        OperationSignature::Create(
+            operation_name, argument_type_ids, num_static_arguments));
+  }
+
+  inline UnaryOperationPtr getUnaryOperation(
+      const OperationSignaturePtr &op_signature) const {
+    const OperationPtr operation = getOperation(op_signature);
+    DCHECK(operation->getOperationSuperTypeID() == Operation::kUnaryOperation);
+    return std::static_pointer_cast<const UnaryOperation>(operation);
+  }
+
+  inline UnaryOperationPtr getUnaryOperation(
+      const std::string &operation_name,
+      const std::vector<TypeID> &argument_type_ids,
+      const std::size_t num_static_arguments = 0) const {
+    return getUnaryOperation(
+        OperationSignature::Create(
+            operation_name, argument_type_ids, num_static_arguments));
+  }
+
+  inline BinaryOperationPtr getBinaryOperation(
+      const OperationSignaturePtr &op_signature) const {
+    const OperationPtr operation = getOperation(op_signature);
+    DCHECK(operation->getOperationSuperTypeID() == Operation::kBinaryOperation);
+    return std::static_pointer_cast<const BinaryOperation>(operation);
+  }
+
+  inline BinaryOperationPtr getBinaryOperation(
+      const std::string &operation_name,
+      const std::vector<TypeID> &argument_type_ids,
+      const std::size_t num_static_arguments = 0) const {
+    return getBinaryOperation(
+        OperationSignature::Create(
+            operation_name, argument_type_ids, num_static_arguments));
+  }
+
+  OperationSignaturePtr resolveOperation(
+      const std::string &operation_name,
+      const std::shared_ptr<const std::vector<const Type*>> &argument_types,
+      const std::shared_ptr<const std::vector<TypedValue>> &static_arguments,
+      std::shared_ptr<const std::vector<const Type*>> *coerced_argument_types,
+      std::shared_ptr<const std::vector<TypedValue>> *coerced_static_arguments,
+      std::string *message) const;
+
+ private:
+  OperationFactory();
+
+  template <typename OperationT>
+  void registerOperation();
+
+  template <typename FunctorPackT>
+  void registerFunctorPack();
+
+  void registerOperationInternal(const OperationPtr &operation);
+
+  using PartialSignature = std::pair<const std::vector<TypeID>*, std::size_t>;
+
+  struct PartialSignatureLess {
+    inline bool operator()(const PartialSignature &lhs,
+                           const PartialSignature &rhs) const {
+      int cmp_code = static_cast<int>(lhs.first->size())
+                         - static_cast<int>(lhs.first->size());
+      if (cmp_code != 0) {
+        return cmp_code < 0;
+      }
+      for (std::size_t i = 0; i < lhs.first->size(); ++i) {
+        cmp_code = static_cast<int>(lhs.first->at(i))
+                       - static_cast<int>(rhs.first->at(i));
+        if (cmp_code != 0) {
+          return cmp_code < 0;
+        }
+      }
+      return lhs.second > rhs.second;
+    }
+  };
+
+  using PartialSignatureIndex = std::map<PartialSignature,
+                                         OperationSignaturePtr,
+                                         PartialSignatureLess>;
+
+  enum class ResolveStatus {
+    kSuccess = 0,
+    kError,
+    kNotFound
+  };
+
+  ResolveStatus resolveOperationWithFullTypeMatch(
+      const PartialSignatureIndex &secondary_index,
+      const std::vector<TypeID> &argument_type_ids,
+      const std::vector<const Type*> &argument_types,
+      const std::vector<TypedValue> &static_arguments,
+      std::shared_ptr<const std::vector<TypedValue>> *trimmed_static_arguments,
+      OperationSignaturePtr *resolved_op_signature,
+      std::string *message) const;
+
+  ResolveStatus resolveOperationWithPartialTypeMatch(
+      const PartialSignatureIndex &secondary_index,
+      const std::vector<TypeID> &argument_type_ids,
+      const std::vector<const Type*> &argument_types,
+      const std::vector<TypedValue> &static_arguments,
+      std::shared_ptr<const std::vector<const Type*>> *coerced_argument_types,
+      std::shared_ptr<const std::vector<TypedValue>> *coerced_static_arguments,
+      OperationSignaturePtr *resolved_op_signature,
+      std::string *message) const;
+
+//  ResolveStatus resolveOperationGeneric(
+//      const std::set<OperationSignaturePtr> signatures,
+//      const std::vector<TypeID> &argument_type_ids,
+//      const std::vector<const Type*> &argument_types,
+//      const std::vector<TypedValue> &static_arguments,
+//      std::shared_ptr<const std::vector<const Type*>> *coerced_argument_types,
+//      std::shared_ptr<const std::vector<TypedValue>> *coerced_static_arguments,
+//      OperationSignaturePtr *op_signature,
+//      std::string *message) const;
+
+  bool canApplyOperationTo(const OperationPtr operation,
+                           const std::vector<const Type*> &argument_types,
+                           const std::vector<TypedValue> &static_arguments,
+                           std::string *message) const;
+
+  std::unordered_map<OperationSignaturePtr,
+                     OperationPtr,
+                     OperationSignatureHash,
+                     OperationSignatureEqual> operations_;
+
+  std::unordered_map<std::pair<std::string, std::size_t>,
+                     PartialSignatureIndex> primary_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(OperationFactory);
+};
+
+/** @} */
+
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_TYPES_OPERATIONS_OPERATION_FACTORY_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/operations/OperationSignature.cpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationSignature.cpp b/types/operations/OperationSignature.cpp
new file mode 100644
index 0000000..6b6c4a6
--- /dev/null
+++ b/types/operations/OperationSignature.cpp
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ **/
+
+#include "types/operations/OperationSignature.hpp"
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "types/TypeID.hpp"
+#include "types/Type.pb.h"
+#include "types/operations/Operation.pb.h"
+
+namespace quickstep {
+
+serialization::OperationSignature OperationSignature::getProto() const {
+  serialization::OperationSignature op_signature;
+
+  op_signature.set_operation_name(operation_name_);
+  for (const TypeID tid : argument_type_ids_) {
+    op_signature.add_argument_type_ids()->CopyFrom(TypeIDFactory::GetProto(tid));
+  }
+  op_signature.set_num_static_arguments(
+      static_cast<std::uint32_t>(num_static_arguments_));
+
+  return op_signature;
+}
+
+OperationSignaturePtr OperationSignature::ReconstructFromProto(
+    const serialization::OperationSignature &proto) {
+  std::vector<TypeID> argument_type_ids;
+  for (int i = 0; i < proto.argument_type_ids_size(); ++i) {
+    argument_type_ids.emplace_back(
+        TypeIDFactory::ReconstructFromProto(proto.argument_type_ids(i)));
+  }
+
+  return Create(proto.operation_name(),
+                argument_type_ids,
+                proto.num_static_arguments());
+}
+
+std::string OperationSignature::toString() const {
+  const std::size_t num_regular_arguments =
+      argument_type_ids_.size() - num_static_arguments_;
+
+  std::string str;
+  str.append(operation_name_);
+  str.push_back('(');
+  for (std::size_t i = 0; i < num_regular_arguments; ++i) {
+    if (i != 0) {
+      str.append(", ");
+    }
+    str.append(
+        kTypeNames[static_cast<std::underlying_type_t<TypeID>>(
+            argument_type_ids_[i])]);
+  }
+  if (num_static_arguments_ > 0) {
+    str.append(", static(");
+    for (std::size_t i = 0; i < num_static_arguments_; ++i) {
+      if (i != 0) {
+        str.append(", ");
+      }
+      str.append(
+          kTypeNames[static_cast<std::underlying_type_t<TypeID>>(
+              argument_type_ids_[i + num_regular_arguments])]);
+    }
+    str.push_back(')');
+  }
+  str.push_back(')');
+
+  return str;
+}
+
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/operations/OperationSignature.hpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationSignature.hpp b/types/operations/OperationSignature.hpp
new file mode 100644
index 0000000..b326aef
--- /dev/null
+++ b/types/operations/OperationSignature.hpp
@@ -0,0 +1,192 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ **/
+
+#ifndef QUICKSTEP_TYPES_OPERATIONS_OPERATION_SIGNATURE_HPP_
+#define QUICKSTEP_TYPES_OPERATIONS_OPERATION_SIGNATURE_HPP_
+
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "types/TypeID.hpp"
+#include "types/operations/Operation.pb.h"
+
+#include "utility/HashPair.hpp"
+#include "utility/Macros.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+
+/** \addtogroup Types
+ *  @{
+ */
+
+class OperationSignature;
+typedef std::shared_ptr<const OperationSignature> OperationSignaturePtr;
+
+class OperationSignature {
+ public:
+  serialization::OperationSignature getProto() const;
+
+  static OperationSignaturePtr ReconstructFromProto(
+      const serialization::OperationSignature &proto);
+
+  inline const std::string& getName() const {
+    return operation_name_;
+  }
+
+  inline std::size_t getArity() const {
+    return argument_type_ids_.size();
+  }
+
+  inline std::size_t getNonStaticArity() const {
+    return argument_type_ids_.size() - num_static_arguments_;
+  }
+
+  inline const std::vector<TypeID>& getArgumentTypeIDs() const {
+    return argument_type_ids_;
+  }
+
+  inline std::size_t getNumStaticArguments() const {
+    return num_static_arguments_;
+  }
+
+  inline bool operator==(const OperationSignature &r) const {
+    return operation_name_ == r.operation_name_
+        && argument_type_ids_ == r.argument_type_ids_
+        && num_static_arguments_ == r.num_static_arguments_;
+  }
+
+  inline bool operator<(const OperationSignature &r) const {
+    int cmp_code = operation_name_.compare(r.operation_name_);
+    if (cmp_code != 0) {
+      return cmp_code < 0;
+    }
+    cmp_code = static_cast<int>(getArity() - r.getArity());
+    if (cmp_code != 0) {
+      return cmp_code < 0;
+    }
+    cmp_code = static_cast<int>(num_static_arguments_ - r.num_static_arguments_);
+    if (cmp_code != 0) {
+      return cmp_code > 0;
+    }
+    for (std::size_t i = 0; i < getArity(); ++i) {
+      const auto l_tid =
+          static_cast<std::underlying_type_t<TypeID>>(argument_type_ids_.at(i));
+      const auto r_tid =
+          static_cast<std::underlying_type_t<TypeID>>(r.argument_type_ids_.at(i));
+      if (l_tid != r_tid) {
+        return l_tid < r_tid;
+      }
+    }
+    return false;
+  }
+
+  std::string toString() const;
+
+  static OperationSignaturePtr Create(
+      const std::string &operation_name,
+      const std::vector<TypeID> &argument_type_ids,
+      const std::size_t num_static_arguments) {
+    return OperationSignaturePtr(
+        new OperationSignature(operation_name,
+                               argument_type_ids,
+                               num_static_arguments));
+  }
+
+  static OperationSignaturePtr Create(
+      const std::string &operation_name,
+      const std::vector<TypeID> &regular_argument_type_ids,
+      const std::vector<TypeID> &static_argument_type_ids) {
+    std::vector<TypeID> argument_type_ids = regular_argument_type_ids;
+    argument_type_ids.insert(argument_type_ids.end(),
+                             static_argument_type_ids.begin(),
+                             static_argument_type_ids.end());
+    return OperationSignaturePtr(
+        new OperationSignature(operation_name,
+                               argument_type_ids,
+                               static_argument_type_ids.size()));
+  }
+
+ private:
+  OperationSignature(const std::string &operation_name,
+                     const std::vector<TypeID> &argument_type_ids,
+                     const std::size_t num_static_arguments)
+      : operation_name_(operation_name),
+        argument_type_ids_(argument_type_ids),
+        num_static_arguments_(num_static_arguments) {
+    DCHECK_GE(argument_type_ids_.size(), num_static_arguments_);
+  }
+
+  const std::string operation_name_;
+  const std::vector<TypeID> argument_type_ids_;
+  const std::size_t num_static_arguments_;
+
+  friend struct OperationSignatureHash;
+  friend struct OperationSignatureNumStaticArgumentsGreater;
+
+  DISALLOW_COPY_AND_ASSIGN(OperationSignature);
+};
+
+/**
+ * @brief Implements the equal function for operation signatures.
+ */
+struct OperationSignatureEqual {
+  inline bool operator()(const OperationSignaturePtr &lhs,
+                         const OperationSignaturePtr &rhs) const {
+    return *lhs == *rhs;
+  }
+};
+
+/**
+ * @brief Implements the hash function for operation signatures.
+ */
+struct OperationSignatureHash {
+  inline std::size_t operator()(const OperationSignaturePtr &op_sig) const {
+    std::size_t hash = std::hash<std::string>()(op_sig->operation_name_);
+    for (const TypeID tid : op_sig->argument_type_ids_) {
+      hash = CombineHashes(hash, static_cast<std::size_t>(tid));
+    }
+    hash = CombineHashes(hash, op_sig->num_static_arguments_);
+    return hash;
+  }
+};
+
+/**
+ * @brief Implements the greater function for sorting operation signature
+ *        in descending order of num_static_arguments_.
+ */
+struct OperationSignatureNumStaticArgumentsGreater {
+  inline bool operator()(const OperationSignaturePtr &lhs,
+                         const OperationSignaturePtr &rhs) const {
+    if (lhs->num_static_arguments_ != rhs->num_static_arguments_) {
+      return lhs->num_static_arguments_ > rhs->num_static_arguments_;
+    } else {
+      return *lhs < *rhs;
+    }
+  }
+};
+
+/** @} */
+
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_TYPES_OPERATIONS_OPERATION_SIGNATURE_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/da9baf7e/types/operations/OperationUtil.hpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationUtil.hpp b/types/operations/OperationUtil.hpp
new file mode 100644
index 0000000..076dc0c
--- /dev/null
+++ b/types/operations/OperationUtil.hpp
@@ -0,0 +1,334 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ **/
+
+#ifndef QUICKSTEP_TYPES_OPERATIONS_OPERATION_UTIL_HPP_
+#define QUICKSTEP_TYPES_OPERATIONS_OPERATION_UTIL_HPP_
+
+#include <cstddef>
+#include <list>
+#include <string>
+#include <type_traits>
+
+#include "catalog/CatalogTypedefs.hpp"
+#include "types/Type.hpp"
+#include "types/TypedValue.hpp"
+#include "types/containers/ColumnVector.hpp"
+
+namespace quickstep {
+
+/** \addtogroup Types
+ *  @{
+ */
+
+template <typename FunctorT, typename ...SpecArgs>
+struct FunctorSpecializer {
+  template <bool specialize = (sizeof...(SpecArgs) != 0),
+            typename EnableT = void>
+  struct Implementation;
+
+  typedef Implementation<> type;
+};
+
+template <typename FunctorT, typename ...SpecArgs>
+template <bool specialize>
+struct FunctorSpecializer<FunctorT, SpecArgs...>
+    ::Implementation<specialize, std::enable_if_t<specialize>> {
+  template <typename ...FuncArgs>
+  inline static auto Invoke(const FunctorT &functor, FuncArgs &&...args) {
+    return functor.template apply<SpecArgs...>(std::forward<FuncArgs>(args)...);
+  }
+  typedef FunctorT FunctorType;
+};
+
+template <typename FunctorT, typename ...SpecArgs>
+template <bool specialize>
+struct FunctorSpecializer<FunctorT, SpecArgs...>
+    ::Implementation<specialize, std::enable_if_t<!specialize>> {
+  template <typename ...FuncArgs>
+  inline static auto Invoke(const FunctorT &functor, FuncArgs &&...args) {
+    return functor.apply(std::forward<FuncArgs>(args)...);
+  }
+  typedef FunctorT FunctorType;
+};
+
+template <typename ColumnVectorT>
+struct ColumnVectorValueAccessor {
+  explicit ColumnVectorValueAccessor(const ColumnVectorT &column_vector_in)
+      : column_vector(column_vector_in),
+        length(column_vector.size()) {}
+
+  inline void beginIteration() {
+    pos = static_cast<std::size_t>(-1);
+  }
+
+  inline bool next() {
+    return (++pos) < length;
+  }
+
+  inline std::size_t getNumTuples() const {
+    return length;
+  }
+
+  template <bool nullable>
+  inline const void* getUntypedValue(const attribute_id) const {
+    return column_vector.template getUntypedValue<nullable>(pos);
+  }
+
+  inline TypedValue getTypedValue(const attribute_id) const {
+    return column_vector.getTypedValue(pos);
+  }
+
+  const ColumnVectorT &column_vector;
+  const std::size_t length;
+  std::size_t pos;
+};
+
+template <typename FuncSpec, typename T, typename EnableT = void>
+struct Codegen;
+
+template <typename FuncSpec, typename T>
+struct Codegen<FuncSpec, T, std::enable_if_t<T::kLayout == kNativeEmbedded>> {
+  using ColumnVectorType = NativeColumnVector;
+  using FunctorSpecializer = FuncSpec;
+
+  using NativeType = typename T::cpptype;
+  using NativeTypeConst = const typename T::cpptype;
+  using NativeTypeConstRef = const NativeType&;
+  using NativeTypeConstPtr = const NativeType*;
+
+  template <typename ArgumentGen>
+  inline static TypedValue ApplyUnaryTypedValue(
+      typename ArgumentGen::NativeTypeConstRef argument,
+      const Type &result_type,
+      const typename FuncSpec::FunctorType &functor) {
+    return TypedValue(FuncSpec::Invoke(functor, argument));
+  }
+
+  template <typename ArgumentGen>
+  inline static void ApplyUnaryColumnVector(
+      const typename ArgumentGen::NativeTypeConstRef argument,
+      const typename FuncSpec::FunctorType &functor,
+      ColumnVectorType *cv) {
+    *static_cast<NativeType *>(cv->getPtrForDirectWrite()) =
+        FuncSpec::Invoke(functor, argument);
+  }
+
+  template <typename LeftGen, typename RightGen>
+  inline static TypedValue ApplyBinaryTypedValue(
+      typename LeftGen::NativeTypeConstRef left,
+      typename RightGen::NativeTypeConstRef right,
+      const Type &result_type,
+      const typename FuncSpec::FunctorType &functor) {
+    return TypedValue(FuncSpec::Invoke(functor, left, right));
+  }
+
+  template <typename LeftGen, typename RightGen>
+  inline static void ApplyBinaryColumnVector(
+      const typename LeftGen::NativeTypeConstRef left,
+      const typename RightGen::NativeTypeConstRef right,
+      const typename FuncSpec::FunctorType &functor,
+      ColumnVectorType *cv) {
+    *static_cast<NativeType *>(cv->getPtrForDirectWrite()) =
+        FuncSpec::Invoke(functor, left, right);
+  }
+
+  template <bool nullable, typename AccessorT>
+  inline static NativeTypeConstPtr GetValuePtr(
+      const AccessorT *accessor,
+      const attribute_id attr_id) {
+    return static_cast<NativeTypeConstPtr>(
+        accessor->template getUntypedValue<nullable>(attr_id));
+  }
+
+  inline static bool IsNull(const NativeType *value) {
+    return value == nullptr;
+  }
+
+  // Dereference: NativeTypeConstPtr& -> const NativeType&
+  inline static const NativeType& Dereference(const NativeType *value) {
+    return *value;
+  }
+
+  inline static const NativeType ToNativeValueConst(const TypedValue &value) {
+    return value.getLiteral<NativeType>();
+  }
+};
+
+template <typename FuncSpec, typename T>
+struct Codegen<FuncSpec, T, std::enable_if_t<T::kLayout == kNonNativeInline>> {
+  using ColumnVectorType = NativeColumnVector;
+  using FunctorSpecializer = FuncSpec;
+
+  using NativeType = void*;
+  using NativeTypeConst = const void*;
+  using NativeTypeConstRef = const void*;
+  using NativeTypeConstPtr = const void*;
+
+  template <typename ArgumentGen>
+  inline static TypedValue ApplyUnaryTypedValue(
+      typename ArgumentGen::NativeTypeConstRef argument,
+      const Type &result_type,
+      const typename FuncSpec::FunctorType &functor) {
+    void *result = std::malloc(result_type.maximumByteLength());
+    FuncSpec::Invoke(functor, argument, result);
+    return TypedValue::CreateWithOwnedData(T::kStaticTypeID,
+                                           result,
+                                           result_type.maximumByteLength());
+  }
+
+  template <typename ArgumentGen>
+  inline static void ApplyUnaryColumnVector(
+      const typename ArgumentGen::NativeTypeConstRef argument,
+      const typename FuncSpec::FunctorType &functor,
+      ColumnVectorType *cv) {
+    FuncSpec::Invoke(functor, argument, cv->getPtrForDirectWrite());
+  }
+
+  template <typename LeftGen, typename RightGen>
+  inline static TypedValue ApplyBinaryTypedValue(
+      typename LeftGen::NativeTypeConstRef left,
+      typename RightGen::NativeTypeConstRef right,
+      const Type &result_type,
+      const typename FuncSpec::FunctorType &functor) {
+    void *result = std::malloc(result_type.maximumByteLength());
+    FuncSpec::Invoke(functor, left, right, result);
+    return TypedValue::CreateWithOwnedData(T::kStaticTypeID,
+                                           result,
+                                           result_type.maximumByteLength());
+  }
+
+  template <typename LeftGen, typename RightGen>
+  inline static void ApplyBinaryColumnVector(
+      const typename LeftGen::NativeTypeConstRef left,
+      const typename RightGen::NativeTypeConstRef right,
+      const typename FuncSpec::FunctorType &functor,
+      ColumnVectorType *cv) {
+    FuncSpec::Invoke(functor, left, right, cv->getPtrForDirectWrite());
+  }
+
+  template <bool nullable, typename AccessorT>
+  inline static NativeTypeConstPtr GetValuePtr(
+      const AccessorT *accessor,
+      const attribute_id attr_id) {
+    return accessor->template getUntypedValue<nullable>(attr_id);
+  }
+
+  inline static bool IsNull(const void *value) {
+    return value == nullptr;
+  }
+
+  // Dereference: NativeTypeConstPtr& -> const NativeType&
+  inline static const void* Dereference(const void *value) {
+    return value;
+  }
+
+  inline static const void* ToNativeValueConst(const TypedValue &value) {
+    return value.getDataPtr();
+  }
+};
+
+template <typename FuncSpec, typename T>
+struct Codegen<FuncSpec, T, std::enable_if_t<T::kLayout == kOutOfLine>> {
+  using ColumnVectorType = IndirectColumnVector;
+  using FunctorSpecializer = FuncSpec;
+
+  using NativeType = TypedValue;
+  using NativeTypeConst = const TypedValue;
+  using NativeTypeConstRef = const TypedValue&;
+  using NativeTypeConstPtr = const TypedValue;
+
+  template <typename ArgumentGen>
+  inline static TypedValue ApplyUnaryTypedValue(
+      typename ArgumentGen::NativeTypeConstRef argument,
+      const Type &result_type,
+      const typename FuncSpec::FunctorType &functor) {
+    return FuncSpec::Invoke(functor, argument);
+  }
+
+  template <typename ArgumentGen>
+  inline static void ApplyUnaryColumnVector(
+      const typename ArgumentGen::NativeTypeConstRef argument,
+      const typename FuncSpec::FunctorType &functor,
+      ColumnVectorType *cv) {
+    cv->appendTypedValue(FuncSpec::Invoke(functor, argument));
+  }
+
+  template <typename LeftGen, typename RightGen>
+  inline static TypedValue ApplyBinaryTypedValue(
+      typename LeftGen::NativeTypeConstRef left,
+      typename RightGen::NativeTypeConstRef right,
+      const Type &result_type,
+      const typename FuncSpec::FunctorType &functor) {
+    return FuncSpec::Invoke(functor, left, right);
+  }
+
+  template <typename LeftGen, typename RightGen>
+  inline static void ApplyBinaryColumnVector(
+      const typename LeftGen::NativeTypeConstRef left,
+      const typename RightGen::NativeTypeConstRef right,
+      const typename FuncSpec::FunctorType &functor,
+      ColumnVectorType *cv) {
+    cv->appendTypedValue(FuncSpec::Invoke(functor, left, right));
+  }
+
+  template <bool nullable, typename AccessorT>
+  inline static NativeTypeConstPtr GetValuePtr(
+      const AccessorT *accessor,
+      const attribute_id attr_id) {
+    return accessor->getTypedValue(attr_id);
+  }
+
+  inline static bool IsNull(NativeTypeConstPtr &value) {
+    return value.isNull();
+  }
+
+  // Dereference: NativeTypeConstPtr& -> const NativeType&
+  inline static const NativeType& Dereference(NativeTypeConstPtr &value) {
+    return value;
+  }
+
+  inline static const NativeType& ToNativeValueConst(const TypedValue &value) {
+    return value;
+  }
+};
+
+template <typename ...FunctorTypes>
+struct FunctorPack {
+  template <typename Dispatcher>
+  inline static std::list<OperationPtr> GenerateOperations() {
+    std::vector<std::list<OperationPtr>> op_list_groups =
+        { Dispatcher::template Generate<FunctorTypes>()... };
+
+    std::list<OperationPtr> operations;
+    for (std::list<OperationPtr> &op_list : op_list_groups) {
+      operations.splice(operations.end(), std::move(op_list));
+    }
+    return operations;
+  }
+};
+
+struct OperationPack {
+  virtual std::vector<OperationPtr> generateOperations() = 0;
+};
+
+/** @} */
+
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_TYPES_OPERATIONS_OPERATION_UTIL_HPP_