quickstep-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jianq...@apache.org
Subject incubator-quickstep git commit: Updates to implicit casts
Date Wed, 11 Oct 2017 18:35:02 GMT
Repository: incubator-quickstep
Updated Branches:
  refs/heads/refactor-type 4bf0857c5 -> 8c3996c68


Updates to implicit casts


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

Branch: refs/heads/refactor-type
Commit: 8c3996c686ac22d19e01d5e4e1f7bfb415f8321c
Parents: 4bf0857
Author: Jianqiao Zhu <jianqiao@cs.wisc.edu>
Authored: Wed Oct 11 03:38:40 2017 -0500
Committer: Jianqiao Zhu <jianqiao@cs.wisc.edu>
Committed: Wed Oct 11 03:38:40 2017 -0500

----------------------------------------------------------------------
 query_optimizer/expressions/Cast.cpp          |  16 ++
 query_optimizer/expressions/Cast.hpp          |  19 +-
 query_optimizer/expressions/Expression.hpp    |   5 +
 query_optimizer/expressions/ScalarLiteral.hpp |   8 +-
 query_optimizer/resolver/Resolver.cpp         |  27 ++-
 types/TextType.cpp                            |   9 +
 types/TextType.hpp                            |   2 +
 types/TypeUtil.hpp                            |  27 +++
 types/operations/OperationFactory.cpp         | 218 ++++++++++++++-------
 types/operations/OperationFactory.hpp         |  56 ++++--
 10 files changed, 285 insertions(+), 102 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/expressions/Cast.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/Cast.cpp b/query_optimizer/expressions/Cast.cpp
index 2315f92..7df4159 100644
--- a/query_optimizer/expressions/Cast.cpp
+++ b/query_optimizer/expressions/Cast.cpp
@@ -73,6 +73,22 @@ ExpressionPtr Cast::copyWithNewChildren(
       std::make_shared<const std::vector<TypedValue>>(std::move(meta_type_value)));
 }
 
+TypedValue Cast::getConstantValue() const {
+  DCHECK(isConstant());
+  const Type &source_type = operand_->getValueType();
+  const UnaryOperationPtr cast_operation =
+      OperationFactory::GetCastOperation(source_type.getTypeID());
+
+  std::vector<TypedValue> meta_type_value =
+      { GenericValue::CreateWithLiteral(
+            MetaType::InstanceNonNullable(), &target_type_).toTypedValue() };
+  DCHECK(cast_operation->canApplyTo(source_type, meta_type_value));
+
+  std::unique_ptr<UncheckedUnaryOperator> cast_op(
+      cast_operation->makeUncheckedUnaryOperator(source_type, meta_type_value));
+  return cast_op->applyToTypedValue(operand_->getConstantValue());
+}
+
 std::size_t Cast::computeHash() const {
   return CombineHashes(
       CombineHashes(static_cast<std::size_t>(ExpressionType::kCast),

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/expressions/Cast.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/Cast.hpp b/query_optimizer/expressions/Cast.hpp
index 11be775..5da0e8c 100644
--- a/query_optimizer/expressions/Cast.hpp
+++ b/query_optimizer/expressions/Cast.hpp
@@ -55,13 +55,23 @@ typedef std::shared_ptr<const Cast> CastPtr;
  */
 class Cast : public Scalar {
  public:
-  ExpressionType getExpressionType() const override { return ExpressionType::kCast; }
+  ExpressionType getExpressionType() const override {
+    return ExpressionType::kCast;
+  }
+
+  std::string getName() const override {
+    return "Cast";
+  }
 
-  std::string getName() const override { return "Cast"; }
+  const Type& getValueType() const override {
+    return target_type_;
+  }
 
-  const Type& getValueType() const override { return target_type_; }
+  bool isConstant() const override {
+    return operand_->isConstant();
+  }
 
-  bool isConstant() const override { return operand_->isConstant(); }
+  TypedValue getConstantValue() const override;
 
   /**
    * @return The expression to be coerced.
@@ -78,6 +88,7 @@ class Cast : public Scalar {
   ::quickstep::Scalar* concretize(
       const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map)
const override;
 
+
   bool equals(const ScalarPtr &other) const override;
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/expressions/Expression.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/Expression.hpp b/query_optimizer/expressions/Expression.hpp
index 7127047..fc6fc53 100644
--- a/query_optimizer/expressions/Expression.hpp
+++ b/query_optimizer/expressions/Expression.hpp
@@ -80,6 +80,11 @@ class Expression : public OptimizerTree<Expression> {
    */
   virtual bool isConstant() const = 0;
 
+  virtual TypedValue getConstantValue() const {
+    LOG(FATAL) << "Not implemented";
+  }
+
+
  protected:
   Expression() {}
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/expressions/ScalarLiteral.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/ScalarLiteral.hpp b/query_optimizer/expressions/ScalarLiteral.hpp
index f6a14f4..fc9f69a 100644
--- a/query_optimizer/expressions/ScalarLiteral.hpp
+++ b/query_optimizer/expressions/ScalarLiteral.hpp
@@ -65,7 +65,13 @@ class ScalarLiteral : public Scalar {
 
   const Type& getValueType() const override;
 
-  bool isConstant() const override { return true; }
+  bool isConstant() const override {
+    return true;
+  }
+
+  TypedValue getConstantValue() const override {
+    return value_.toTypedValue();
+  }
 
   /**
    * @return The literal value.

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/resolver/Resolver.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/Resolver.cpp b/query_optimizer/resolver/Resolver.cpp
index b3e8c2c..f06679d 100644
--- a/query_optimizer/resolver/Resolver.cpp
+++ b/query_optimizer/resolver/Resolver.cpp
@@ -2928,24 +2928,37 @@ E::ScalarPtr Resolver::resolveScalarFunction(
     }
   }
 
-  // TODO: add cast if neccessary.
-  (void)coerced_argument_types;
+  // Add cast if neccessary.
+  std::vector<E::ScalarPtr> coerced_arguments;
+  for (std::size_t i = 0; i < op_signature->getNonStaticArity(); ++i) {
+    const auto &argument = resolved_arguments[i];
+    const Type &target_type = *(*coerced_argument_types)[i];
+    if (argument->getValueType().equals(target_type)) {
+      coerced_arguments.emplace_back(argument);
+    } else {
+      coerced_arguments.emplace_back(E::Cast::Create(argument, target_type));
+    }
+  }
 
   const OperationPtr operation = OperationFactory::GetOperation(op_signature);
   switch (operation->getOperationSuperTypeID()) {
-    case Operation::kUnaryOperation:
+    case Operation::kUnaryOperation: {
+      DCHECK_EQ(1u, coerced_arguments.size());
       return E::UnaryExpression::Create(
           op_signature,
           std::static_pointer_cast<const UnaryOperation>(operation),
-          resolved_arguments[0],
+          coerced_arguments[0],
           coerced_static_arguments);
-    case Operation::kBinaryOperation:
+    }
+    case Operation::kBinaryOperation: {
+      DCHECK_EQ(2u, coerced_arguments.size());
       return E::BinaryExpression::Create(
           op_signature,
           std::static_pointer_cast<const BinaryOperation>(operation),
-          resolved_arguments[0],
-          resolved_arguments[1],
+          coerced_arguments[0],
+          coerced_arguments[1],
           coerced_static_arguments);
+    }
     default: {
       const auto operation_id =
          static_cast<std::underlying_type_t<Operation::OperationSuperTypeID>>(

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/TextType.cpp
----------------------------------------------------------------------
diff --git a/types/TextType.cpp b/types/TextType.cpp
index ce5c3a5..b806ea8 100644
--- a/types/TextType.cpp
+++ b/types/TextType.cpp
@@ -22,8 +22,17 @@
 #include <cstddef>
 #include <string>
 
+#include "types/Type.hpp"
+#include "types/TypeID.hpp"
+#include "utility/EqualsAnyConstant.hpp"
+
 namespace quickstep {
 
+bool TextType::isSafelyCoercibleFrom(const Type &original_type) const {
+  return QUICKSTEP_EQUALS_ANY_CONSTANT(original_type.getTypeID(),
+                                       kChar, kVarChar, kText);
+}
+
 bool TextType::checkValuesEqual(const UntypedLiteral *lhs,
                                 const UntypedLiteral *rhs,
                                 const Type &rhs_type) const {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/TextType.hpp
----------------------------------------------------------------------
diff --git a/types/TextType.hpp b/types/TextType.hpp
index a1fc04e..620420e 100644
--- a/types/TextType.hpp
+++ b/types/TextType.hpp
@@ -42,6 +42,8 @@ class TextType final : public TypeSynthesizer<kText> {
     return 32;
   }
 
+  bool isSafelyCoercibleFrom(const Type &original_type) const override;
+
   bool checkValuesEqual(const UntypedLiteral *lhs,
                         const UntypedLiteral *rhs,
                         const Type &rhs_type) const override;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/TypeUtil.hpp
----------------------------------------------------------------------
diff --git a/types/TypeUtil.hpp b/types/TypeUtil.hpp
index ca88456..496844f 100644
--- a/types/TypeUtil.hpp
+++ b/types/TypeUtil.hpp
@@ -41,6 +41,7 @@
 #include "types/VarCharType.hpp"
 #include "types/YearMonthIntervalType.hpp"
 #include "utility/Macros.hpp"
+#include "utility/meta/TypeList.hpp"
 
 #include "glog/logging.h"
 
@@ -50,8 +51,29 @@ namespace quickstep {
  *  @{
  */
 
+namespace internal {
+
+// TODO(refactor-type): Organize selector predicates, refactor the old design.
+template <MemoryLayout layout>
+struct MemoryLayoutSelector {
+  template <typename TypeIDConstant>
+  struct type {
+    static constexpr bool value =
+        TypeIDTrait<TypeIDConstant::value>::kMemoryLayout == layout;
+  };
+};
+
+}  // namespace internal
+
+
 class TypeUtil {
  public:
+  template <MemoryLayout layout>
+  using TypeIDSequenceMemoryLayout =
+      TypeIDSequenceAll::bind_to<meta::TypeList>
+                       ::filter<internal::MemoryLayoutSelector<kCxxInlinePod>::type>
+                       ::as_sequence<TypeID>;
+
   static MemoryLayout GetMemoryLayout(const TypeID type_id) {
     return InvokeOnTypeID(
         type_id,
@@ -60,6 +82,11 @@ class TypeUtil {
     });
   }
 
+  template <MemoryLayout layout>
+  static std::vector<TypeID> GetTypeIDVectorOfMemoryLayout(){
+    return TypeIDSequenceMemoryLayout<layout>::Instantiate<std::vector<TypeID>>();
+  }
+
   static bool IsParameterizedPod(const TypeID type_id) {
     return InvokeOnTypeID(
         type_id,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/operations/OperationFactory.cpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationFactory.cpp b/types/operations/OperationFactory.cpp
index df536ed..af0ddc9 100644
--- a/types/operations/OperationFactory.cpp
+++ b/types/operations/OperationFactory.cpp
@@ -94,6 +94,8 @@ OperationFactory::OperationFactory() {
   registerFunctorPack<ArithmeticBinaryFunctorPack>();
   registerFunctorPack<AsciiStringBinaryFunctorPack>();
   registerFunctorPack<CMathBinaryFunctorPack>();
+
+  initializeTypeIDSafeCoercibility();
 }
 
 bool OperationFactory::HasOperation(const std::string &operation_name,
@@ -207,7 +209,6 @@ OperationSignaturePtr OperationFactory::resolveOperation(
 
   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) {
@@ -215,7 +216,7 @@ OperationSignaturePtr OperationFactory::resolveOperation(
   }
 
   // First, try full exact matching.
-  status = resolveOperationWithFullTypeMatch(secondary_index,
+  status = resolveOperationWithFullTypeMatch(indices_it->second.partial_signature_index,
                                              argument_type_ids,
                                              *argument_types,
                                              *static_arguments,
@@ -231,7 +232,7 @@ OperationSignaturePtr OperationFactory::resolveOperation(
   }
 
   // Otherwise, try partial (non-static arguments) exact matching.
-  status = resolveOperationWithPartialTypeMatch(secondary_index,
+  status = resolveOperationWithPartialTypeMatch(indices_it->second.static_arity_index,
                                                 argument_type_ids,
                                                 *argument_types,
                                                 *static_arguments,
@@ -246,13 +247,13 @@ OperationSignaturePtr OperationFactory::resolveOperation(
     return nullptr;
   }
 
-  // TODO
+  // TODO(refactor-type): More informative error message.
   *message = "Unexpected argument types for function " + operation_name;
   return nullptr;
 }
 
 OperationFactory::ResolveStatus OperationFactory::resolveOperationWithFullTypeMatch(
-    const PartialSignatureIndex &secondary_index,
+    const PartialSignatureIndex &partial_signature_index,
     const std::vector<TypeID> &argument_type_ids,
     const std::vector<const Type*> &argument_types,
     const std::vector<GenericValue> &static_arguments,
@@ -260,10 +261,11 @@ OperationFactory::ResolveStatus OperationFactory::resolveOperationWithFullTypeMa
     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));
+  auto it = partial_signature_index.lower_bound(
+      PartialSignature(&argument_type_ids, max_num_static_arguments));
 
-  if (it != secondary_index.end() && *it->first.first == argument_type_ids) {
+  if (it != partial_signature_index.end() &&
+      *it->first.argument_type_ids == argument_type_ids) {
     const OperationSignaturePtr op_signature = it->second;
     const OperationPtr operation = operations_.at(op_signature);
 
@@ -288,7 +290,7 @@ OperationFactory::ResolveStatus OperationFactory::resolveOperationWithFullTypeMa
 }
 
 OperationFactory::ResolveStatus OperationFactory::resolveOperationWithPartialTypeMatch(
-    const PartialSignatureIndex &secondary_index,
+    const StaticArityIndex &static_arity_index,
     const std::vector<TypeID> &argument_type_ids,
     const std::vector<const Type*> &argument_types,
     const std::vector<GenericValue> &static_arguments,
@@ -300,84 +302,154 @@ OperationFactory::ResolveStatus OperationFactory::resolveOperationWithPartialTyp
   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;
-    }
+  const OperationSignaturePtr *best_match_op_sig = nullptr;
+  const std::vector<TypeID> *best_match_type_ids = nullptr;
+  std::size_t best_match_num_static_arguments = max_num_static_arguments;
 
-    // Coerce static arguments
-    std::vector<GenericValue> coerced_static_args;
+  auto it = static_arity_index.lower_bound(max_num_static_arguments);
+  while (it != static_arity_index.end()) {
+    if (it->first != best_match_num_static_arguments) {
+      if (best_match_op_sig != nullptr) {
+        break;
+      } else {
+        best_match_num_static_arguments = it->first;
+      }
+    }
 
-    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 GenericValue &arg_value =
-          static_arguments.at(i - first_static_argument_position);
-      const TypeID &expected_type_id = expected_type_ids.at(i);
+    const auto &current_type_ids = it->second->getArgumentTypeIDs();
 
-      if (arg_type.getTypeID() == expected_type_id) {
-        coerced_static_args.emplace_back(arg_value);
+    if (canSafelyCoerceTypes(argument_type_ids, current_type_ids)) {
+      if (best_match_type_ids == nullptr) {
+        DCHECK(best_match_op_sig == nullptr);
+        best_match_op_sig = &it->second;
+        best_match_type_ids = &current_type_ids;
       } 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);
+        const bool cur_to_best_safe =
+            canSafelyCoerceTypes(current_type_ids, *best_match_type_ids);
+        const bool best_to_cur_safe =
+            canSafelyCoerceTypes(*best_match_type_ids, current_type_ids);
+        if (cur_to_best_safe == best_to_cur_safe) {
+          *message = "Ambiguous call to overloaded function " +
+                     it->second->getName() + ", candidates: " +
+                     (*best_match_op_sig)->toString() + " v.s. " +
+                     it->second->toString();
+          return ResolveStatus::kError;
         }
-
-        if (expected_type != nullptr && expected_type->isSafelyCoercibleFrom(arg_type))
{
-          coerced_static_args.emplace_back(arg_value.coerce(*expected_type));
-        } else {
-          is_coercible = false;
-          break;
+        if (cur_to_best_safe) {
+          best_match_op_sig = &it->second;
+          best_match_type_ids = &current_type_ids;
         }
       }
     }
 
-    if (is_coercible) {
-      std::vector<const Type*> coerced_arg_types(
-          argument_types.begin(),
-          argument_types.begin() + num_non_static_arguments);
-      for (const auto &value : coerced_static_args) {
-        coerced_arg_types.emplace_back(&value.getType());
-      }
+    ++it;
+  }
 
-      const OperationPtr operation = operations_.at(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<GenericValue>>(std::move(coerced_static_args));
-        *resolved_op_signature = it->second;
-        return ResolveStatus::kSuccess;
-      }
+  if (best_match_op_sig == nullptr) {
+    return ResolveStatus::kNotFound;
+  }
+
+  DCHECK(best_match_type_ids != nullptr);
+  DCHECK_EQ(arity, best_match_type_ids->size());
+  std::vector<const Type*> coerced_arg_types;
+  for (std::size_t i = 0; i < arity; ++i) {
+    const Type &source_type = *argument_types[i];
+    const TypeID target_type_id = (*best_match_type_ids)[i];
+    // TODO(refactor-type): Figure out how to better handle this.
+    if (source_type.getTypeID() == target_type_id) {
+      coerced_arg_types.emplace_back(&source_type);
+    } else if (TypeUtil::GetMemoryLayout(target_type_id) == kCxxInlinePod) {
+      coerced_arg_types.emplace_back(
+          &TypeFactory::GetType(target_type_id, source_type.isNullable()));
+    } else if (target_type_id == kChar && source_type.getTypeID() == kVarChar) {
+      coerced_arg_types.emplace_back(
+          &CharType::Instance(source_type.isNullable(),
+                              source_type.maximumByteLength() - 1));
+    } else if (target_type_id == kVarChar && source_type.getTypeID() == kChar) {
+      coerced_arg_types.emplace_back(
+          &VarCharType::Instance(source_type.isNullable(),
+                                 source_type.maximumByteLength() + 1));
+    } else if (target_type_id == kText) {
+      coerced_arg_types.emplace_back(
+          &TextType::Instance(source_type.isNullable()));
+    } else {
+      LOG(FATAL) << "Unexpected casting";
     }
+  }
 
-    ++it;
+  std::vector<GenericValue> coerced_static_args;
+  for (std::size_t i = arity - best_match_num_static_arguments; i < arity; ++i) {
+    const auto &value = static_arguments[i - first_static_argument_position];
+    if (coerced_arg_types[i]->equals(*argument_types[i])) {
+      coerced_static_args.emplace_back(value);
+    } else {
+      coerced_static_args.emplace_back(value.coerce(*coerced_arg_types[i]));
+    }
+  }
+
+  const OperationPtr operation = operations_.at(*best_match_op_sig);
+  // TODO(refactor-type): Fix.
+  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<GenericValue>>(std::move(coerced_static_args));
+    *resolved_op_signature = *best_match_op_sig;
+    return ResolveStatus::kSuccess;
   }
 
   return ResolveStatus::kNotFound;
 }
 
+bool OperationFactory::canSafelyCoerceTypes(const std::vector<TypeID> &source_type_ids,
+                                            const std::vector<TypeID> &target_type_ids)
const {
+  if (source_type_ids.size() != target_type_ids.size()) {
+    return false;
+  }
+  for (std::size_t i = 0; i < source_type_ids.size(); ++i) {
+    const TypeID source_id = source_type_ids[i];
+    const TypeID target_id = target_type_ids[i];
+    if (source_id != target_id) {
+      const auto it = type_id_safe_coercibility_.find(
+          std::make_pair(source_id, target_id));
+      if (it == type_id_safe_coercibility_.end()) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void OperationFactory::initializeTypeIDSafeCoercibility() {
+  // TODO(refactor-type): Figure out how to better handle this.
+  const std::vector<TypeID> cxx_inline_pod_type_ids =
+      TypeUtil::GetTypeIDVectorOfMemoryLayout<kCxxInlinePod>();
+
+  std::vector<const Type*> cxx_line_pod_types;
+  for (const TypeID tid : cxx_inline_pod_type_ids) {
+    cxx_line_pod_types.emplace_back(&TypeFactory::GetType(tid, true));
+  }
+
+  for (const Type *source_type : cxx_line_pod_types) {
+    for (const Type *target_type : cxx_line_pod_types) {
+      if (target_type->isSafelyCoercibleFrom(*source_type)) {
+        type_id_safe_coercibility_.emplace(
+            std::make_pair(source_type->getTypeID(), target_type->getTypeID()));
+      }
+    }
+  }
+
+  for (const TypeID source_id : std::vector<TypeID>({kChar, kVarChar})) {
+    for (const TypeID target_id : std::vector<TypeID>({kChar, kVarChar, kText})) {
+      type_id_safe_coercibility_.emplace(std::make_pair(source_id, target_id));
+    }
+  }
+  type_id_safe_coercibility_.emplace(std::make_pair(kText, kText));
+}
+
 bool OperationFactory::canApplyOperationTo(
     const OperationPtr operation,
     const std::vector<const Type*> &argument_types,
@@ -444,12 +516,8 @@ void OperationFactory::registerOperationInternal(const OperationPtr &operation)
 
     // 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);
+                                  op_sig->getArity())].addSignature(op_sig);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/operations/OperationFactory.hpp
----------------------------------------------------------------------
diff --git a/types/operations/OperationFactory.hpp b/types/operations/OperationFactory.hpp
index 7fccbc5..f124e9a 100644
--- a/types/operations/OperationFactory.hpp
+++ b/types/operations/OperationFactory.hpp
@@ -134,30 +134,49 @@ class OperationFactory {
 
   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());
+  struct PartialSignature {
+    PartialSignature(const std::vector<TypeID> *argument_type_ids_in,
+                     const std::size_t num_static_arguments_in)
+        : argument_type_ids(argument_type_ids_in),
+          num_static_arguments(num_static_arguments_in) {
+    }
+    inline bool operator<(const PartialSignature &rhs) const {
+      const PartialSignature &lhs = *this;
+      const std::vector<TypeID> &lhs_ids = *lhs.argument_type_ids;
+      const std::vector<TypeID> &rhs_ids = *rhs.argument_type_ids;
+      int cmp_code = static_cast<int>(lhs_ids.size()) - static_cast<int>(rhs_ids.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));
+      for (std::size_t i = 0; i < lhs.argument_type_ids->size(); ++i) {
+        cmp_code = static_cast<int>(lhs_ids[i]) - static_cast<int>(rhs_ids[i]);
         if (cmp_code != 0) {
           return cmp_code < 0;
         }
       }
-      return lhs.second > rhs.second;
+      return lhs.num_static_arguments > rhs.num_static_arguments;
     }
+    const std::vector<TypeID> *argument_type_ids;
+    const std::size_t num_static_arguments;
   };
 
   using PartialSignatureIndex = std::map<PartialSignature,
+                                         OperationSignaturePtr>;
+  using StaticArityIndex = std::multimap<std::size_t,
                                          OperationSignaturePtr,
-                                         PartialSignatureLess>;
+                                         std::greater<std::size_t>>;
+
+  struct SecondaryIndex {
+    inline void addSignature(const OperationSignaturePtr &op_sig) {
+      partial_signature_index.emplace(
+          PartialSignature(&op_sig->getArgumentTypeIDs(),
+                           op_sig->getNumStaticArguments()),
+          op_sig);
+      static_arity_index.emplace(op_sig->getNumStaticArguments(), op_sig);
+    }
+    PartialSignatureIndex partial_signature_index;
+    StaticArityIndex static_arity_index;
+  };
 
   enum class ResolveStatus {
     kSuccess = 0,
@@ -174,7 +193,7 @@ class OperationFactory {
       std::string *message) const;
 
   ResolveStatus resolveOperationWithFullTypeMatch(
-      const PartialSignatureIndex &secondary_index,
+      const PartialSignatureIndex &partial_signature_index,
       const std::vector<TypeID> &argument_type_ids,
       const std::vector<const Type*> &argument_types,
       const std::vector<GenericValue> &static_arguments,
@@ -183,7 +202,7 @@ class OperationFactory {
       std::string *message) const;
 
   ResolveStatus resolveOperationWithPartialTypeMatch(
-      const PartialSignatureIndex &secondary_index,
+      const StaticArityIndex &static_arity_index,
       const std::vector<TypeID> &argument_type_ids,
       const std::vector<const Type*> &argument_types,
       const std::vector<GenericValue> &static_arguments,
@@ -192,6 +211,11 @@ class OperationFactory {
       OperationSignaturePtr *resolved_op_signature,
       std::string *message) const;
 
+  bool canSafelyCoerceTypes(const std::vector<TypeID> &source_type_ids,
+                            const std::vector<TypeID> &target_type_ids) const;
+
+  void initializeTypeIDSafeCoercibility();
+
   bool canApplyOperationTo(const OperationPtr operation,
                            const std::vector<const Type*> &argument_types,
                            const std::vector<GenericValue> &static_arguments,
@@ -203,7 +227,9 @@ class OperationFactory {
                      OperationSignatureEqual> operations_;
 
   std::unordered_map<std::pair<std::string, std::size_t>,
-                     PartialSignatureIndex> primary_index_;
+                     SecondaryIndex> primary_index_;
+
+  std::unordered_set<std::pair<TypeID, TypeID>> type_id_safe_coercibility_;
 
   DISALLOW_COPY_AND_ASSIGN(OperationFactory);
 };


Mime
View raw message