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/03/14 14:55:29 UTC

[6/8] incubator-quickstep git commit: Updates

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/parser/preprocessed/SqlParser_gen.hpp
----------------------------------------------------------------------
diff --git a/parser/preprocessed/SqlParser_gen.hpp b/parser/preprocessed/SqlParser_gen.hpp
index 18a3aa0..02f090e 100644
--- a/parser/preprocessed/SqlParser_gen.hpp
+++ b/parser/preprocessed/SqlParser_gen.hpp
@@ -185,7 +185,7 @@ extern int quickstep_yydebug;
 
 union YYSTYPE
 {
-#line 117 "../SqlParser.ypp" /* yacc.c:1915  */
+#line 114 "../SqlParser.ypp" /* yacc.c:1915  */
 
   quickstep::ParseString *string_value_;
 
@@ -257,7 +257,7 @@ union YYSTYPE
 
   const quickstep::Comparison *comparison_;
   quickstep::ParseString *unary_operation_;
-  const quickstep::BinaryOperation *binary_operation_;
+  quickstep::ParseString *binary_operation_;
 
   quickstep::ParseFunctionCall *function_call_;
   quickstep::PtrList<quickstep::ParseExpression> *expression_list_;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/LogicalGenerator.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/LogicalGenerator.cpp b/query_optimizer/LogicalGenerator.cpp
index 49481d3..940b728 100644
--- a/query_optimizer/LogicalGenerator.cpp
+++ b/query_optimizer/LogicalGenerator.cpp
@@ -51,7 +51,8 @@ L::LogicalPtr LogicalGenerator::generatePlan(
     const CatalogDatabase &catalog_database,
     const ParseStatement &parse_statement) {
   resolver::Resolver resolver(catalog_database, optimizer_context_);
-  DVLOG(4) << "Parse tree:\n" << parse_statement.toString();
+//  DVLOG(4) << "Parse tree:\n" << parse_statement.toString();
+  std::cerr << "Parse tree:\n" << parse_statement.toString();
   logical_plan_ = resolver.resolve(parse_statement);
   std::cerr << "Initial logical plan:\n" << logical_plan_->toString();
 //  exit(0);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/expressions/BinaryExpression.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/BinaryExpression.cpp b/query_optimizer/expressions/BinaryExpression.cpp
index 446dd55..2178e2e 100644
--- a/query_optimizer/expressions/BinaryExpression.cpp
+++ b/query_optimizer/expressions/BinaryExpression.cpp
@@ -29,8 +29,8 @@
 #include "query_optimizer/expressions/ExprId.hpp"
 #include "query_optimizer/expressions/Expression.hpp"
 #include "query_optimizer/expressions/PatternMatcher.hpp"
+#include "query_optimizer/expressions/ScalarLiteral.hpp"
 #include "types/operations/binary_operations/BinaryOperation.hpp"
-#include "types/operations/binary_operations/BinaryOperationID.hpp"
 
 #include "glog/logging.h"
 
@@ -41,37 +41,8 @@ class Type;
 namespace optimizer {
 namespace expressions {
 
-BinaryExpression::BinaryExpression(const BinaryOperation &operation,
-                                   const ScalarPtr &left,
-                                   const ScalarPtr &right)
-    : operation_(operation), left_(left), right_(right) {
-  DCHECK(operation_.canApplyToTypes(left_->getValueType(),
-                                    right_->getValueType()))
-      << toString();
-  addChild(left_);
-  addChild(right_);
-}
-
 std::string BinaryExpression::getName() const {
-  switch (operation_.getBinaryOperationID()) {
-    case BinaryOperationID::kAdd:
-      return "Add";
-    case BinaryOperationID::kSubtract:
-      return "Subtract";
-    case BinaryOperationID::kMultiply:
-      return "Multiply";
-    case BinaryOperationID::kDivide:
-      return "Divide";
-    case BinaryOperationID::kModulo:
-      return "Modulo";
-    default:
-      LOG(FATAL) << "Unknown binary operation";
-  }
-}
-
-const Type &BinaryExpression::getValueType() const {
-  return *operation_.resultTypeForArgumentTypes(left_->getValueType(),
-                                                right_->getValueType());
+  return op_signature_->getName();
 }
 
 ExpressionPtr BinaryExpression::copyWithNewChildren(
@@ -80,9 +51,12 @@ ExpressionPtr BinaryExpression::copyWithNewChildren(
   DCHECK(SomeScalar::Matches(new_children[0]));
   DCHECK(SomeScalar::Matches(new_children[1]));
   return BinaryExpression::Create(
+      op_signature_,
       operation_,
       std::static_pointer_cast<const Scalar>(new_children[0]),
-      std::static_pointer_cast<const Scalar>(new_children[1]));
+      std::static_pointer_cast<const Scalar>(new_children[1]),
+      static_arguments_,
+      static_argument_types_);
 }
 
 std::vector<AttributeReferencePtr> BinaryExpression::getReferencedAttributes() const {
@@ -99,9 +73,11 @@ std::vector<AttributeReferencePtr> BinaryExpression::getReferencedAttributes() c
 ::quickstep::Scalar *BinaryExpression::concretize(
     const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const {
   return new ::quickstep::ScalarBinaryExpression(
+      op_signature_,
       operation_,
       left_->concretize(substitution_map),
-      right_->concretize(substitution_map));
+      right_->concretize(substitution_map),
+      static_arguments_);
 }
 
 void BinaryExpression::getFieldStringItems(
@@ -111,8 +87,26 @@ void BinaryExpression::getFieldStringItems(
     std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
     std::vector<std::string> *container_child_field_names,
     std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const {
-  container_child_field_names->push_back("");
-  container_child_fields->push_back({left_, right_});
+  inline_field_names->emplace_back("op_signature");
+  inline_field_values->emplace_back(op_signature_->toString());
+
+  inline_field_names->emplace_back("result_type");
+  inline_field_values->emplace_back(result_type_.getName());
+
+  non_container_child_field_names->emplace_back("left_operand");
+  non_container_child_fields->emplace_back(left_);
+  non_container_child_field_names->emplace_back("right_operand");
+  non_container_child_fields->emplace_back(right_);
+
+  if (!static_arguments_->empty()) {
+    container_child_field_names->emplace_back("static_arguments");
+    container_child_fields->emplace_back();
+    for (std::size_t i = 0; i < static_arguments_->size(); ++i) {
+      container_child_fields->back().emplace_back(
+          ScalarLiteral::Create(static_arguments_->at(i),
+                                *static_argument_types_->at(i)));
+    }
+  }
 }
 
 }  // namespace expressions

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/expressions/BinaryExpression.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/BinaryExpression.hpp b/query_optimizer/expressions/BinaryExpression.hpp
index 9b11ed1..9692dff 100644
--- a/query_optimizer/expressions/BinaryExpression.hpp
+++ b/query_optimizer/expressions/BinaryExpression.hpp
@@ -31,6 +31,8 @@
 #include "query_optimizer/expressions/Expression.hpp"
 #include "query_optimizer/expressions/ExpressionType.hpp"
 #include "query_optimizer/expressions/Scalar.hpp"
+#include "types/operations/OperationSignature.hpp"
+#include "types/operations/binary_operations/BinaryOperation.hpp"
 #include "utility/Macros.hpp"
 
 namespace quickstep {
@@ -61,7 +63,9 @@ class BinaryExpression : public Scalar {
 
   std::string getName() const override;
 
-  const Type& getValueType() const override;
+  const Type& getValueType() const override {
+    return result_type_;
+  }
 
   bool isConstant() const override {
     return left_->isConstant() && right_->isConstant();
@@ -70,7 +74,7 @@ class BinaryExpression : public Scalar {
   /**
    * @return The binary operation.
    */
-  const BinaryOperation& operation() const { return operation_; }
+  const BinaryOperationPtr& operation() const { return operation_; }
 
   /**
    * @return The left operand.
@@ -90,10 +94,20 @@ class BinaryExpression : public Scalar {
   ::quickstep::Scalar* concretize(
       const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const override;
 
-  static BinaryExpressionPtr Create(const BinaryOperation &operation,
-                                    const ScalarPtr &left,
-                                    const ScalarPtr &right) {
-    return BinaryExpressionPtr(new BinaryExpression(operation, left, right));
+  static BinaryExpressionPtr Create(
+      const OperationSignaturePtr &op_signature,
+      const BinaryOperationPtr &operation,
+      const ScalarPtr &left,
+      const ScalarPtr &right,
+      const std::shared_ptr<const std::vector<TypedValue>> &static_arguments,
+      const std::shared_ptr<const std::vector<const Type*>> &static_argument_types) {
+    return BinaryExpressionPtr(
+        new BinaryExpression(op_signature,
+                             operation,
+                             left,
+                             right,
+                             static_arguments,
+                             static_argument_types));
   }
 
  protected:
@@ -106,14 +120,32 @@ class BinaryExpression : public Scalar {
       std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const override;
 
  private:
-  BinaryExpression(const BinaryOperation &operation,
+  BinaryExpression(const OperationSignaturePtr &op_signature,
+                   const BinaryOperationPtr &operation,
                    const ScalarPtr &left,
-                   const ScalarPtr &right);
-
-  const BinaryOperation &operation_;
+                   const ScalarPtr &right,
+                   const std::shared_ptr<const std::vector<TypedValue>> &static_arguments,
+                   const std::shared_ptr<const std::vector<const Type*>> &static_argument_types)
+      : op_signature_(op_signature),
+        operation_(operation),
+        left_(left),
+        right_(right),
+        static_arguments_(static_arguments),
+        static_argument_types_(static_argument_types),
+        result_type_(*(operation_->getResultType(left_->getValueType(),
+                                                 right_->getValueType(),
+                                                 *static_arguments))) {
+    addChild(left);
+    addChild(right);
+  }
 
-  ScalarPtr left_;
-  ScalarPtr right_;
+  const OperationSignaturePtr op_signature_;
+  const BinaryOperationPtr operation_;
+  const ScalarPtr left_;
+  const ScalarPtr right_;
+  const std::shared_ptr<const std::vector<TypedValue>> static_arguments_;
+  const std::shared_ptr<const std::vector<const Type*>> static_argument_types_;
+  const Type &result_type_;
 
   DISALLOW_COPY_AND_ASSIGN(BinaryExpression);
 };

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/expressions/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/CMakeLists.txt b/query_optimizer/expressions/CMakeLists.txt
index d7ce686..086636c 100644
--- a/query_optimizer/expressions/CMakeLists.txt
+++ b/query_optimizer/expressions/CMakeLists.txt
@@ -89,8 +89,9 @@ target_link_libraries(quickstep_queryoptimizer_expressions_BinaryExpression
                       quickstep_queryoptimizer_expressions_ExpressionType
                       quickstep_queryoptimizer_expressions_PatternMatcher
                       quickstep_queryoptimizer_expressions_Scalar
+                      quickstep_queryoptimizer_expressions_ScalarLiteral
+                      quickstep_types_operations_OperationSignature
                       quickstep_types_operations_binaryoperations_BinaryOperation
-                      quickstep_types_operations_binaryoperations_BinaryOperationID
                       quickstep_utility_Macros)
 target_link_libraries(quickstep_queryoptimizer_expressions_Cast
                       glog

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/expressions/UnaryExpression.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/UnaryExpression.cpp b/query_optimizer/expressions/UnaryExpression.cpp
index d7bde71..6780802 100644
--- a/query_optimizer/expressions/UnaryExpression.cpp
+++ b/query_optimizer/expressions/UnaryExpression.cpp
@@ -39,7 +39,7 @@ namespace optimizer {
 namespace expressions {
 
 std::string UnaryExpression::getName() const {
-  return operation_->getName();
+  return op_signature_->getName();
 }
 
 ExpressionPtr UnaryExpression::copyWithNewChildren(
@@ -73,6 +73,9 @@ void UnaryExpression::getFieldStringItems(
   inline_field_names->emplace_back("op_signature");
   inline_field_values->emplace_back(op_signature_->toString());
 
+  inline_field_names->emplace_back("result_type");
+  inline_field_values->emplace_back(result_type_.getName());
+
   non_container_child_field_names->emplace_back("operand");
   non_container_child_fields->emplace_back(operand_);
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/expressions/UnaryExpression.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/UnaryExpression.hpp b/query_optimizer/expressions/UnaryExpression.hpp
index c08519f..e742990 100644
--- a/query_optimizer/expressions/UnaryExpression.hpp
+++ b/query_optimizer/expressions/UnaryExpression.hpp
@@ -129,7 +129,6 @@ class UnaryExpression : public Scalar {
         static_arguments_(static_arguments),
         static_argument_types_(static_argument_types),
         result_type_(*(operation_->getResultType(operand_->getValueType(), *static_arguments_))) {
-    DCHECK(operation_->canApplyTo(operand_->getValueType(), *static_arguments)) << toString();
     addChild(operand);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/resolver/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/CMakeLists.txt b/query_optimizer/resolver/CMakeLists.txt
index 27497a2..be33972 100644
--- a/query_optimizer/resolver/CMakeLists.txt
+++ b/query_optimizer/resolver/CMakeLists.txt
@@ -124,13 +124,13 @@ target_link_libraries(quickstep_queryoptimizer_resolver_Resolver
                       quickstep_types_TypeUtil
                       quickstep_types_TypedValue
                       quickstep_types_TypeFactory
+                      quickstep_types_operations_OperationFactory
                       quickstep_types_operations_OperationSignature
                       quickstep_types_operations_binaryoperations_BinaryOperation
                       quickstep_types_operations_comparisons_Comparison
                       quickstep_types_operations_comparisons_ComparisonFactory
                       quickstep_types_operations_comparisons_ComparisonID
                       quickstep_types_operations_unaryoperations_UnaryOperation
-                      quickstep_types_operations_unaryoperations_UnaryOperationFactory
                       quickstep_utility_Macros
                       quickstep_utility_PtrList
                       quickstep_utility_PtrVector

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/resolver/Resolver.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/Resolver.cpp b/query_optimizer/resolver/Resolver.cpp
index 1741409..892c183 100644
--- a/query_optimizer/resolver/Resolver.cpp
+++ b/query_optimizer/resolver/Resolver.cpp
@@ -22,6 +22,7 @@
 #include <algorithm>
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
@@ -118,13 +119,13 @@
 #include "types/TypeFactory.hpp"
 #include "types/TypeUtil.hpp"
 #include "types/TypedValue.hpp"
+#include "types/operations/OperationFactory.hpp"
 #include "types/operations/OperationSignature.hpp"
 #include "types/operations/binary_operations/BinaryOperation.hpp"
 #include "types/operations/comparisons/Comparison.hpp"
 #include "types/operations/comparisons/ComparisonFactory.hpp"
 #include "types/operations/comparisons/ComparisonID.hpp"
 #include "types/operations/unary_operations/UnaryOperation.hpp"
-#include "types/operations/unary_operations/UnaryOperationFactory.hpp"
 #include "utility/PtrList.hpp"
 #include "utility/PtrVector.hpp"
 #include "utility/SqlError.hpp"
@@ -2120,109 +2121,6 @@ E::ScalarPtr Resolver::resolveExpression(
           parse_attribute_scalar.attr_name(),
           parse_attribute_scalar.rel_name());
     }
-    case ParseExpression::kBinaryExpression: {
-      const ParseBinaryExpression &parse_binary_scalar =
-          static_cast<const ParseBinaryExpression&>(parse_expression);
-
-      std::pair<const Type*, const Type*> argument_type_hints
-          = parse_binary_scalar.op().pushDownTypeHint(type_hint);
-
-      ExpressionResolutionInfo left_resolution_info(
-          *expression_resolution_info);
-      E::ScalarPtr left_argument = resolveExpression(
-          *parse_binary_scalar.left_operand(),
-           argument_type_hints.first,
-           &left_resolution_info);
-
-      ExpressionResolutionInfo right_resolution_info(
-          *expression_resolution_info);
-      E::ScalarPtr right_argument = resolveExpression(
-          *parse_binary_scalar.right_operand(),
-          argument_type_hints.second,
-          &right_resolution_info);
-
-      if (left_resolution_info.hasAggregate()) {
-        expression_resolution_info->parse_aggregate_expression =
-            left_resolution_info.parse_aggregate_expression;
-      } else if (right_resolution_info.hasAggregate()) {
-        expression_resolution_info->parse_aggregate_expression =
-            right_resolution_info.parse_aggregate_expression;
-      }
-
-      // Check if either argument is a NULL literal of an unknown type.
-      const bool left_is_nulltype = (left_argument->getValueType().getTypeID() == kNullType);
-      const bool right_is_nulltype = (right_argument->getValueType().getTypeID() == kNullType);
-
-      // If either argument is a NULL of unknown type, we try to resolve the
-      // type of this BinaryExpression as follows:
-      //
-      //     1. If there is only one possible result type for the expression
-      //        based on what is known about its argument types, then the
-      //        result is a NULL of that type.
-      //     2. Otherwise, if there is a type hint for the BinaryExpression's
-      //        result, and if it is a plausible result type based on what we
-      //        know about argument types, then the result is a NULL of the
-      //        hint type.
-      //     3. Otherwise, check if the BinaryExpression can plausibly be
-      //        applied to the known argument types at all. If so, then the
-      //        result is a NULL of unknown type (i.e. NullType).
-      //     4. If all of the above steps fail, then the BinaryExpression is
-      //        not possibly applicable to the given arguments.
-      //
-      // NOTE(chasseur): Step #3 above does not completely capture knowledge
-      // about the result type of a BinaryExpression with one or more unknown
-      // arguments. For instance, DivideBinaryOperation can never return a
-      // DateTime or any string type, so even if we do not know its specific
-      // return type, we do know that there are some restrictions on what it
-      // may be. However, NullType is implicitly convertable to ANY Type, so
-      // such restrictions could be violated if a parent node in the expression
-      // tree converts a value of NullType to something that it shouldn't be.
-      if (left_is_nulltype || right_is_nulltype) {
-        const Type *fixed_result_type
-            = parse_binary_scalar.op().resultTypeForPartialArgumentTypes(
-                left_is_nulltype ? nullptr : &(left_argument->getValueType()),
-                right_is_nulltype ? nullptr : &(right_argument->getValueType()));
-        if (fixed_result_type != nullptr) {
-          return E::ScalarLiteral::Create(fixed_result_type->makeNullValue(),
-                                          *fixed_result_type);
-        }
-
-        if (type_hint != nullptr) {
-          const Type &nullable_type_hint = type_hint->getNullableVersion();
-          if (parse_binary_scalar.op().partialTypeSignatureIsPlausible(
-                  &nullable_type_hint,
-                  left_is_nulltype ? nullptr : &(left_argument->getValueType()),
-                  right_is_nulltype ? nullptr : &(right_argument->getValueType()))) {
-            return E::ScalarLiteral::Create(nullable_type_hint.makeNullValue(),
-                                            nullable_type_hint);
-          }
-        }
-
-        if (parse_binary_scalar.op().partialTypeSignatureIsPlausible(
-                nullptr,
-                left_is_nulltype ? nullptr : &(left_argument->getValueType()),
-                right_is_nulltype ? nullptr : &(right_argument->getValueType()))) {
-          const Type &null_type = TypeFactory::GetType(kNullType, true);
-          return E::ScalarLiteral::Create(null_type.makeNullValue(),
-                                          null_type);
-        }
-
-        // If nothing above worked, fall through to canApplyToTypes() below,
-        // which should fail.
-      }
-
-      if (!parse_binary_scalar.op().canApplyToTypes(left_argument->getValueType(),
-                                                    right_argument->getValueType())) {
-        THROW_SQL_ERROR_AT(&parse_binary_scalar)
-            << "Can not apply binary operation \"" << parse_binary_scalar.op().getName()
-            << "\" to arguments of types " << left_argument->getValueType().getName()
-            << " and " << right_argument->getValueType().getName();
-      }
-
-      return E::BinaryExpression::Create(parse_binary_scalar.op(),
-                                         left_argument,
-                                         right_argument);
-    }
     case ParseExpression::kScalarLiteral: {
       const ParseScalarLiteral &parse_literal_scalar =
           static_cast<const ParseScalarLiteral&>(parse_expression);
@@ -2525,118 +2423,77 @@ E::ScalarPtr Resolver::resolveScalarFunction(
     const std::vector<E::ScalarPtr> &resolved_arguments,
     ExpressionResolutionInfo *expression_resolution_info) {
   const std::size_t arity = resolved_arguments.size();
-
   std::vector<const Type*> argument_types;
-  std::vector<TypeID> argument_type_ids;
   std::size_t first_static_argument_position = 0;
   for (std::size_t i = 0; i < arity; ++i) {
     const E::ScalarPtr &argument = resolved_arguments[i];
     if (argument->getExpressionType() != E::ExpressionType::kScalarLiteral) {
       first_static_argument_position = i + 1;
     }
-
-    const Type &type = argument->getValueType();
-    argument_types.emplace_back(&type);
-    argument_type_ids.emplace_back(type.getTypeID());
+    argument_types.emplace_back(&argument->getValueType());
   }
 
-  std::vector<TypedValue> maximal_static_arguments;
+  std::vector<TypedValue> static_arguments;
   for (std::size_t i = first_static_argument_position; i < arity; ++i) {
-    maximal_static_arguments.emplace_back(
+    static_arguments.emplace_back(
         std::static_pointer_cast<const E::ScalarLiteral>(
             resolved_arguments[i])->value());
-    DCHECK(maximal_static_arguments.back().getTypeID() == argument_type_ids[i]);
-  }
-  const std::size_t max_num_static_arguments = maximal_static_arguments.size();
-
-  const UnaryOperationFactory &factory = UnaryOperationFactory::Instance();
-
-  // First, check exact matching of name + non static types, possibly safe
-  // coercion of static arguments.
-  const auto &op_sig_candidates = factory.getUnaryOperations(function_name, arity);
-  for (const OperationSignaturePtr &op_sig : op_sig_candidates) {
-    const std::size_t op_num_static_arguments = op_sig->getNumStaticArguments();
-    if (op_num_static_arguments > max_num_static_arguments) {
-      continue;
-    }
-
-    bool is_match = true;
-    for (std::size_t i = 0; i < arity - op_num_static_arguments; ++i) {
-      if (op_sig->getArgumentTypeIDs().at(i) != argument_type_ids[i]) {
-        is_match = false;
-        break;
-      }
-    }
-    if (!is_match) {
-      continue;
-    }
-
-    std::vector<TypedValue> coerced_static_arguments;
-    std::vector<const Type*> coerced_static_argument_types;
-    bool is_coercible = true;
-    for (std::size_t i = arity - op_num_static_arguments; i < arity; ++i) {
-      const Type &arg_type = *argument_types.at(i);
-      const TypedValue &arg_value =
-          maximal_static_arguments.at(i - first_static_argument_position);
-      const TypeID expected_type_id = op_sig->getArgumentTypeIDs().at(i);
-      if (arg_type.getTypeID() == expected_type_id) {
-        coerced_static_arguments.emplace_back(arg_value);
-        coerced_static_argument_types.emplace_back(&arg_type);
-      } else {
-        const Type *expected_type = nullptr;
-        if (TypeUtil::IsParameterized(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_arguments.emplace_back(
-              expected_type->coerceValue(arg_value, arg_type));
-          coerced_static_argument_types.emplace_back(expected_type);
-        } else {
-          is_coercible = false;
-          break;
-        }
-      }
-    }
-    if (!is_coercible) {
-      continue;
-    }
-
-    // TODO: switch on operation non-static arity here.
-    CHECK_EQ(1u, arity - op_num_static_arguments);
-
-    const UnaryOperationPtr op = factory.getUnaryOperation(op_sig);
-    const auto static_arguments =
-        std::make_shared<const std::vector<TypedValue>>(
-            std::move(coerced_static_arguments));
-    const auto static_argument_types =
-        std::make_shared<const std::vector<const Type*>>(
-            std::move(coerced_static_argument_types));
-
-    std::string message;
-    if (op->canApplyTo(*argument_types.front(), *static_arguments, &message)) {
-      return E::UnaryExpression::Create(op_sig,
-                                        op,
-                                        resolved_arguments.front(),
-                                        static_arguments,
-                                        static_argument_types);
-    } else {
+    DCHECK(static_arguments.back().getTypeID() == argument_types[i]->getTypeID());
+  }
+
+  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 OperationSignaturePtr op_signature =
+      OperationFactory::Instance().resolveOperation(
+          function_name,
+          std::make_shared<const std::vector<const Type*>>(std::move(argument_types)),
+          std::make_shared<const std::vector<TypedValue>>(std::move(static_arguments)),
+          &coerced_argument_types,
+          &coerced_static_arguments,
+          &message);
+
+  if (op_signature == nullptr) {
+    if (message.empty()) {
       THROW_SQL_ERROR_AT(&parse_function_call) << message;
+    } else {
+      THROW_SQL_ERROR_AT(&parse_function_call)
+          << "Cannot resolve scalar function " << function_name;
+    }
+  }
+
+  // TODO: add cast if neccessary.
+
+  const auto coerced_static_argument_types =
+      std::make_shared<const std::vector<const Type*>>(
+          coerced_argument_types->begin() + op_signature->getNonStaticArity(),
+          coerced_argument_types->end());
+
+  const OperationPtr operation =
+      OperationFactory::Instance().getOperation(op_signature);
+  switch (operation->getOperationSuperTypeID()) {
+    case Operation::kUnaryOperation:
+      return E::UnaryExpression::Create(
+          op_signature,
+          std::static_pointer_cast<const UnaryOperation>(operation),
+          resolved_arguments[0],
+          coerced_static_arguments,
+          coerced_static_argument_types);
+    case Operation::kBinaryOperation:
+      return E::BinaryExpression::Create(
+          op_signature,
+          std::static_pointer_cast<const BinaryOperation>(operation),
+          resolved_arguments[0],
+          resolved_arguments[1],
+          coerced_static_arguments,
+          coerced_static_argument_types);
+    default: {
+      const auto operation_id =
+         static_cast<std::underlying_type_t<Operation::OperationSuperTypeID>>(
+             operation->getOperationSuperTypeID());
+      LOG(FATAL) << "Unknown opeation super type id: " << operation_id;
     }
   }
-
-  THROW_SQL_ERROR_AT(&parse_function_call)
-      << "Cannot resolve scalar function";
-
-  return nullptr;
 }
 
 // TODO(chasseur): For now this only handles resolving aggregate functions. In
@@ -2686,8 +2543,8 @@ E::ScalarPtr Resolver::resolveFunctionCall(
     }
   }
 
-  if (UnaryOperationFactory::Instance().hasUnaryOperation(function_name,
-                                                          resolved_arguments.size())) {
+  if (OperationFactory::Instance().hasOperation(function_name,
+                                                resolved_arguments.size())) {
     E::ScalarPtr scalar = resolveScalarFunction(parse_function_call,
                                                 function_name,
                                                 resolved_arguments,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/rules/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/rules/tests/CMakeLists.txt b/query_optimizer/rules/tests/CMakeLists.txt
index 0d913e2..cdb5fe6 100644
--- a/query_optimizer/rules/tests/CMakeLists.txt
+++ b/query_optimizer/rules/tests/CMakeLists.txt
@@ -85,7 +85,6 @@ target_link_libraries(quickstep_queryoptimizer_rules_tests
                       quickstep_queryoptimizer_rules_tests_RuleTest
                       quickstep_types_operations_binaryoperations_BinaryOperation
                       quickstep_types_operations_binaryoperations_BinaryOperationFactory
-                      quickstep_types_operations_binaryoperations_BinaryOperationID
                       quickstep_types_operations_comparisons_Comparison
                       quickstep_types_operations_comparisons_ComparisonFactory
                       quickstep_types_operations_comparisons_ComparisonID

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/strategy/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/strategy/tests/CMakeLists.txt b/query_optimizer/strategy/tests/CMakeLists.txt
index 97675f0..1a60344 100644
--- a/query_optimizer/strategy/tests/CMakeLists.txt
+++ b/query_optimizer/strategy/tests/CMakeLists.txt
@@ -74,7 +74,6 @@ target_link_libraries(quickstep_queryoptimizer_strategy_tests
                       quickstep_types_TypeID
                       quickstep_types_operations_binaryoperations_BinaryOperation
                       quickstep_types_operations_binaryoperations_BinaryOperationFactory
-                      quickstep_types_operations_binaryoperations_BinaryOperationID
                       quickstep_types_operations_comparisons_Comparison
                       quickstep_types_operations_comparisons_ComparisonFactory
                       quickstep_types_operations_comparisons_ComparisonID

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/CMakeLists.txt b/query_optimizer/tests/CMakeLists.txt
index 5ef1d0a..4357c6a 100644
--- a/query_optimizer/tests/CMakeLists.txt
+++ b/query_optimizer/tests/CMakeLists.txt
@@ -51,7 +51,6 @@ target_link_libraries(quickstep_queryoptimizer_tests_OptimizerTest
                       quickstep_types_TypeID
                       quickstep_types_operations_binaryoperations_BinaryOperation
                       quickstep_types_operations_binaryoperations_BinaryOperationFactory
-                      quickstep_types_operations_binaryoperations_BinaryOperationID
                       quickstep_types_operations_comparisons_Comparison
                       quickstep_types_operations_comparisons_ComparisonFactory
                       quickstep_types_operations_comparisons_ComparisonID

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/query_optimizer/tests/OptimizerTest.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/OptimizerTest.cpp b/query_optimizer/tests/OptimizerTest.cpp
index 7eb7a11..36436c0 100644
--- a/query_optimizer/tests/OptimizerTest.cpp
+++ b/query_optimizer/tests/OptimizerTest.cpp
@@ -44,7 +44,6 @@
 #include "types/TypeID.hpp"
 #include "types/operations/binary_operations/BinaryOperation.hpp"
 #include "types/operations/binary_operations/BinaryOperationFactory.hpp"
-#include "types/operations/binary_operations/BinaryOperationID.hpp"
 #include "types/operations/comparisons/Comparison.hpp"
 #include "types/operations/comparisons/ComparisonFactory.hpp"
 #include "types/operations/comparisons/ComparisonID.hpp"

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/relational_operators/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/relational_operators/CMakeLists.txt b/relational_operators/CMakeLists.txt
index 1693ec2..8ba00b0 100644
--- a/relational_operators/CMakeLists.txt
+++ b/relational_operators/CMakeLists.txt
@@ -663,7 +663,6 @@ target_link_libraries(AggregationOperator_unittest
                       quickstep_types_TypedValue
                       quickstep_types_containers_Tuple
                       quickstep_types_operations_binaryoperations_BinaryOperationFactory
-                      quickstep_types_operations_binaryoperations_BinaryOperationID
                       quickstep_types_operations_comparisons_ComparisonFactory
                       quickstep_types_operations_comparisons_ComparisonID
                       quickstep_utility_Macros

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/storage/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/storage/CMakeLists.txt b/storage/CMakeLists.txt
index 8b68150..7789881 100644
--- a/storage/CMakeLists.txt
+++ b/storage/CMakeLists.txt
@@ -863,7 +863,6 @@ target_link_libraries(quickstep_storage_SMAIndexSubBlock
                       quickstep_types_TypedValue
                       quickstep_types_operations_binaryoperations_BinaryOperation
                       quickstep_types_operations_binaryoperations_BinaryOperationFactory
-                      quickstep_types_operations_binaryoperations_BinaryOperationID
                       quickstep_types_operations_comparisons_Comparison
                       quickstep_types_operations_comparisons_ComparisonFactory
                       quickstep_types_operations_comparisons_ComparisonID

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/storage/SMAIndexSubBlock.cpp
----------------------------------------------------------------------
diff --git a/storage/SMAIndexSubBlock.cpp b/storage/SMAIndexSubBlock.cpp
index 3b3b879..fda8c30 100644
--- a/storage/SMAIndexSubBlock.cpp
+++ b/storage/SMAIndexSubBlock.cpp
@@ -46,7 +46,6 @@
 #include "types/TypedValue.hpp"
 #include "types/operations/binary_operations/BinaryOperation.hpp"
 #include "types/operations/binary_operations/BinaryOperationFactory.hpp"
-#include "types/operations/binary_operations/BinaryOperationID.hpp"
 #include "types/operations/comparisons/Comparison.hpp"
 #include "types/operations/comparisons/ComparisonFactory.hpp"
 #include "types/operations/comparisons/ComparisonID.hpp"
@@ -360,8 +359,8 @@ SMAIndexSubBlock::SMAIndexSubBlock(const TupleStorageSubBlock &tuple_store,
       if (add_operations_.elementIsNullAt(attr_typeid)) {
         add_operations_.replaceElement(attr_typeid,
           BinaryOperationFactory::GetBinaryOperation(BinaryOperationID::kAdd)
-              .makeUncheckedBinaryOperatorForTypes(TypeFactory::GetType(attr_typeid),
-                                                   TypeFactory::GetType(attr_sum_typeid)));
+              .makeUncheckedBinaryOperator(TypeFactory::GetType(attr_typeid),
+                                           TypeFactory::GetType(attr_sum_typeid)));
       }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/types/CMakeLists.txt b/types/CMakeLists.txt
index 1fac11a..0c7ee07 100644
--- a/types/CMakeLists.txt
+++ b/types/CMakeLists.txt
@@ -49,7 +49,6 @@ add_library(quickstep_types_NullType ../empty_src.cpp NullType.hpp)
 add_library(quickstep_types_NumericSuperType ../empty_src.cpp NumericSuperType.hpp)
 add_library(quickstep_types_NumericTypeUnifier ../empty_src.cpp NumericTypeUnifier.hpp)
 add_library(quickstep_types_Type Type.cpp Type.hpp)
-add_library(quickstep_types_TypeConcept ../empty_src.cpp TypeConcept.hpp)
 add_library(quickstep_types_TypeErrors ../empty_src.cpp TypeErrors.hpp)
 add_library(quickstep_types_TypeFactory TypeFactory.cpp TypeFactory.hpp)
 add_library(quickstep_types_TypeID TypeID.cpp TypeID.hpp)
@@ -167,8 +166,6 @@ target_link_libraries(quickstep_types_Type
                       quickstep_types_TypeID
                       quickstep_types_TypedValue
                       quickstep_utility_Macros)
-target_link_libraries(quickstep_types_TypeConcept
-                      glog)
 target_link_libraries(quickstep_types_TypeFactory
                       glog
                       quickstep_types_CharType
@@ -204,7 +201,8 @@ target_link_libraries(quickstep_types_TypeUtil
                       quickstep_types_Type_proto
                       quickstep_types_VarCharType
                       quickstep_types_YearMonthIntervalType
-                      quickstep_utility_Macros)
+                      quickstep_utility_Macros
+                      quickstep_utility_TemplateUtil)
 target_link_libraries(quickstep_types_TypedValue
                       farmhash
                       glog

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/NumericSuperType.hpp
----------------------------------------------------------------------
diff --git a/types/NumericSuperType.hpp b/types/NumericSuperType.hpp
index ceb24b6..77f028a 100644
--- a/types/NumericSuperType.hpp
+++ b/types/NumericSuperType.hpp
@@ -55,7 +55,7 @@ class NumericSuperType : public TypeConcept<type_id, false, kNativeEmbedded, Cpp
   }
 
  protected:
-  NumericSuperType(const bool nullable)
+  explicit NumericSuperType(const bool nullable)
       : TypeConcept<type_id, false, kNativeEmbedded, CppType>(
             Type::kNumeric, type_id, nullable, sizeof(CppType), sizeof(CppType)) {
   }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/Type.hpp
----------------------------------------------------------------------
diff --git a/types/Type.hpp b/types/Type.hpp
index afc46eb..066b2b5 100644
--- a/types/Type.hpp
+++ b/types/Type.hpp
@@ -485,7 +485,7 @@ class TypeConcept : public Type {
 
  protected:
   template <typename ...ArgTypes>
-  TypeConcept(ArgTypes &&...args)
+  explicit TypeConcept(ArgTypes &&...args)
       : Type(std::forward<ArgTypes>(args)...) {}
 
  private:

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/TypeUtil.hpp
----------------------------------------------------------------------
diff --git a/types/TypeUtil.hpp b/types/TypeUtil.hpp
index fe55952..6c58ef1 100644
--- a/types/TypeUtil.hpp
+++ b/types/TypeUtil.hpp
@@ -138,7 +138,6 @@ inline auto InvokeOnTypeID(const TypeID type_id,
         std::integral_constant<TypeID, type_id>, FunctorT>::Invoke(functor)
 
   switch (type_id) {
-
     REGISTER_TYPE_ID(kInt);
     REGISTER_TYPE_ID(kLong);
     REGISTER_TYPE_ID(kFloat);
@@ -150,7 +149,6 @@ inline auto InvokeOnTypeID(const TypeID type_id,
     REGISTER_TYPE_ID(kChar);
     REGISTER_TYPE_ID(kVarChar);
     REGISTER_TYPE_ID(kNullType);
-
     default:
       FATAL_ERROR("Unrecognized TypeID in InvokeOnTypeID()");
   }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/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/4005df6e/types/containers/ColumnVector.hpp
----------------------------------------------------------------------
diff --git a/types/containers/ColumnVector.hpp b/types/containers/ColumnVector.hpp
index f0a2cd5..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.
@@ -400,6 +402,8 @@ class NativeColumnVector : public ColumnVector {
  **/
 class IndirectColumnVector : public ColumnVector {
  public:
+  static constexpr bool kNative = false;
+
   /**
    * @brief Constructor.
    *
@@ -494,7 +498,7 @@ 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));
   }
@@ -505,6 +509,10 @@ class IndirectColumnVector : public ColumnVector {
     values_.emplace_back(type_.makeNullValue());
   }
 
+  inline void fillWithNulls() {
+    fillWithValue(type_.makeNullValue());
+  }
+
   /**
    * @brief Fill this entire ColumnVector with copies of value.
    *

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/operations/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/types/operations/CMakeLists.txt b/types/operations/CMakeLists.txt
index 6d38d80..baaaf55 100644
--- a/types/operations/CMakeLists.txt
+++ b/types/operations/CMakeLists.txt
@@ -25,12 +25,41 @@ 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_BinaryOperation
+                      quickstep_types_operations_binaryoperations_BinaryOperationWrapper
+                      quickstep_types_operations_unaryoperations_ArithmeticUnaryOperations
+                      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
@@ -46,6 +75,8 @@ target_link_libraries(quickstep_types_operations_Operation_proto
 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

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/operations/Operation.hpp
----------------------------------------------------------------------
diff --git a/types/operations/Operation.hpp b/types/operations/Operation.hpp
index ad7c868..6da0f4c 100644
--- a/types/operations/Operation.hpp
+++ b/types/operations/Operation.hpp
@@ -23,6 +23,7 @@
 #include <string>
 #include <vector>
 
+#include "types/operations/OperationSignature.hpp"
 #include "utility/Macros.hpp"
 
 namespace quickstep {
@@ -31,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.
@@ -87,6 +91,10 @@ class Operation {
     return "NoShortName";
   }
 
+  virtual std::vector<OperationSignaturePtr> getSignatures() const {
+    return {};
+  }
+
   /**
    * @brief Determine whether this Operation is exactly the same as another.
    * @note Because all exact operations are singletons, a simple pointer
@@ -101,7 +109,7 @@ class Operation {
   }
 
  protected:
-  Operation(const OperationSuperTypeID super_type_id)
+  explicit Operation(const OperationSuperTypeID super_type_id)
       : super_type_id_(super_type_id) {
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/operations/Operation.proto
----------------------------------------------------------------------
diff --git a/types/operations/Operation.proto b/types/operations/Operation.proto
index 006b07c..da2a282 100644
--- a/types/operations/Operation.proto
+++ b/types/operations/Operation.proto
@@ -44,15 +44,3 @@ message OperationSignature {
   repeated TypeID argument_type_ids = 2;
   required uint32 num_static_arguments = 3;
 }
-
-message BinaryOperation {
-  enum BinaryOperationID {
-    ADD = 0;
-    SUBTRACT = 1;
-    MULTIPLY = 2;
-    DIVIDE = 3;
-    MODULO = 4;
-  }
-
-  required BinaryOperationID operation_id = 1;
-}

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/operations/OperationFactory.cpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationFactory.cpp b/types/operations/OperationFactory.cpp
new file mode 100644
index 0000000..5743cfc
--- /dev/null
+++ b/types/operations/OperationFactory.cpp
@@ -0,0 +1,358 @@
+/**
+ * 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/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>();
+}
+
+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_indices = 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_indices.full_match_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_indices.non_static_match_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 = "Cannot resolve function " + operation_name;
+  return nullptr;
+}
+
+OperationFactory::ResolveStatus OperationFactory::resolveOperationWithFullTypeMatch(
+    const FullSignatureIndex &full_match_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 = full_match_index.lower_bound(
+      std::make_pair(&argument_type_ids, max_num_static_arguments));
+
+  if (it != full_match_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 &non_static_match_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 = non_static_match_index.lower_bound(
+      std::make_pair(&argument_type_ids, max_num_static_arguments));
+  while (it != non_static_match_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 (TypeUtil::IsParameterized(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);
+
+    OperationSecondaryIndices &indices =
+        primary_index_[std::make_pair(op_sig->getName(), op_sig->getArity())];
+    const SignatureReference sig_ref =
+        std::make_pair(&op_sig->getArgumentTypeIDs(),
+                       op_sig->getNumStaticArguments());
+    indices.full_match_index.emplace(sig_ref, op_sig);
+    indices.non_static_match_index.emplace(sig_ref, op_sig);
+    indices.signatures.emplace(op_sig);
+  }
+}
+
+
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/types/operations/OperationFactory.hpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationFactory.hpp b/types/operations/OperationFactory.hpp
new file mode 100644
index 0000000..5a73cbd
--- /dev/null
+++ b/types/operations/OperationFactory.hpp
@@ -0,0 +1,205 @@
+/**
+ * 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 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 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);
+  }
+
+  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 SignatureReference = std::pair<const std::vector<TypeID>*, std::size_t>;
+
+  struct FullSignatureLess {
+    inline bool operator()(const SignatureReference &lhs,
+                           const SignatureReference &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 FullSignatureIndex = std::map<SignatureReference,
+                                      OperationSignaturePtr,
+                                      FullSignatureLess>;
+
+  struct PartialSignatureLess {
+    inline bool operator()(const SignatureReference &lhs,
+                           const SignatureReference &rhs) const {
+      const std::size_t l_arity = lhs.first->size() - lhs.second;
+      const std::size_t r_arity = rhs.first->size() - rhs.second;
+      int cmp_code = static_cast<int>(l_arity) - static_cast<int>(r_arity);
+      if (cmp_code != 0) {
+        return cmp_code < 0;
+      }
+      for (std::size_t i = 0; i < l_arity; ++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<SignatureReference,
+                                         OperationSignaturePtr,
+                                         PartialSignatureLess>;
+
+  struct OperationSecondaryIndices {
+    std::set<OperationSignaturePtr> signatures;
+    FullSignatureIndex full_match_index;
+    PartialSignatureIndex non_static_match_index;
+  };
+
+  enum class ResolveStatus {
+    kSuccess = 0,
+    kError,
+    kNotFound
+  };
+
+  ResolveStatus resolveOperationWithFullTypeMatch(
+      const FullSignatureIndex &full_match_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 &non_static_match_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>,
+                     OperationSecondaryIndices> 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/4005df6e/types/operations/OperationSignature.hpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationSignature.hpp b/types/operations/OperationSignature.hpp
index 7020e50..b326aef 100644
--- a/types/operations/OperationSignature.hpp
+++ b/types/operations/OperationSignature.hpp
@@ -86,7 +86,7 @@ class OperationSignature {
     }
     cmp_code = static_cast<int>(num_static_arguments_ - r.num_static_arguments_);
     if (cmp_code != 0) {
-      return cmp_code < 0;
+      return cmp_code > 0;
     }
     for (std::size_t i = 0; i < getArity(); ++i) {
       const auto l_tid =

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/4005df6e/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_