Repository: incubator-quickstep
Updated Branches:
  refs/heads/untyped-agg 140069b95 -> 9ccd5a311


http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/HashTablePool.hpp
----------------------------------------------------------------------
diff --git a/storage/HashTablePool.hpp b/storage/HashTablePool.hpp
index faa0abc..124b4f5 100644
--- a/storage/HashTablePool.hpp
+++ b/storage/HashTablePool.hpp
@@ -20,6 +20,7 @@
 #ifndef QUICKSTEP_STORAGE_HASH_TABLE_POOL_HPP_
 #define QUICKSTEP_STORAGE_HASH_TABLE_POOL_HPP_
 
+#include <algorithm>
 #include <chrono>
 #include <memory>
 #include <utility>
@@ -27,9 +28,7 @@
 
 #include "expressions/aggregation/AggregationHandle.hpp"
 #include "storage/HashTableBase.hpp"
-#include "storage/AggregationHashTable.hpp"
-#include "storage/FastHashTable.hpp"
-#include "storage/FastHashTableFactory.hpp"
+#include "storage/AggregationStateHashTable.hpp"
 #include "threading/SpinMutex.hpp"
 #include "utility/Macros.hpp"
 #include "utility/StringUtil.hpp"
@@ -57,36 +56,6 @@ class HashTablePool {
   /**
    * @brief Constructor.
    *
-   * @param estimated_num_entries The maximum number of entries in a hash 
table.
-   * @param hash_table_impl_type The type of hash table implementation.
-   * @param group_by_types A vector of pointer of types which form the group by
-   *        key.
-   * @param agg_handle The aggregation handle.
-   * @param storage_manager A pointer to the storage manager.
-   *
-   * @note The estimate of number of entries is quite inaccurate at this time.
-   *       If we go by the current estimate, each hash table demands much
-   *       larger space than it actually needs, which causes the system to
-   *       either trigger evictions or worse - run out of memory. To fix this
-   *       issue, we divide the estimate by 100. The division will not affect
-   *       correctness, however it may allocate some hash tables smaller space
-   *       than their requirement, causing them to be resized during build
-   *       phase, which has a performance penalty.
-   **/
-  HashTablePool(const std::size_t estimated_num_entries,
-                const HashTableImplType hash_table_impl_type,
-                const std::vector<const Type *> &group_by_types,
-                AggregationHandle *agg_handle,
-                StorageManager *storage_manager)
-      : 
estimated_num_entries_(reduceEstimatedCardinality(estimated_num_entries)),
-        hash_table_impl_type_(hash_table_impl_type),
-        group_by_types_(group_by_types),
-        agg_handle_(DCHECK_NOTNULL(agg_handle)),
-        storage_manager_(DCHECK_NOTNULL(storage_manager)) {}
-
-  /**
-   * @brief Constructor.
-   *
    * @note This constructor is relevant for HashTables specialized for
    *       aggregation.
    *
@@ -94,52 +63,29 @@ class HashTablePool {
    * @param hash_table_impl_type The type of hash table implementation.
    * @param group_by_types A vector of pointer of types which form the group by
    *        key.
-   * @param payload_sizes The sizes in bytes for the AggregationStates for the
-   *        respective AggregationHandles.
    * @param handles The AggregationHandles in this query.
    * @param storage_manager A pointer to the storage manager.
    **/
   HashTablePool(const std::size_t estimated_num_entries,
                 const HashTableImplType hash_table_impl_type,
                 const std::vector<const Type *> &group_by_types,
-                const std::vector<std::size_t> &payload_sizes,
                 const std::vector<AggregationHandle *> &handles,
                 StorageManager *storage_manager)
       : 
estimated_num_entries_(reduceEstimatedCardinality(estimated_num_entries)),
         hash_table_impl_type_(hash_table_impl_type),
         group_by_types_(group_by_types),
-        payload_sizes_(payload_sizes),
         handles_(handles),
         storage_manager_(DCHECK_NOTNULL(storage_manager)) {}
 
   /**
    * @brief Check out a hash table for insertion.
    *
-   * @return A hash table pointer.
-   **/
-  AggregationStateHashTableBase* getHashTable() {
-    {
-      SpinMutexLock lock(mutex_);
-      if (!hash_tables_.empty()) {
-        std::unique_ptr<AggregationStateHashTableBase> ret_hash_table(
-            std::move(hash_tables_.back()));
-        hash_tables_.pop_back();
-        DCHECK(ret_hash_table != nullptr);
-        return ret_hash_table.release();
-      }
-    }
-    return createNewHashTable();
-  }
-
-  /**
-   * @brief Check out a hash table for insertion.
-   *
    * @note This method is relevant for specialized (for aggregation)
    *       hash table implementation.
    *
    * @return A hash table pointer.
    **/
-  AggregationStateHashTableBase* getHashTableFast() {
+  AggregationStateHashTableBase* getHashTable() {
     {
       SpinMutexLock lock(mutex_);
       if (!hash_tables_.empty()) {
@@ -150,7 +96,7 @@ class HashTablePool {
         return ret_hash_table.release();
       }
     }
-    return createNewHashTableFast();
+    return createNewHashTable();
   }
 
   /**
@@ -174,63 +120,38 @@ class HashTablePool {
    * @param All the hash tables in the pool.
    *
    **/
-  const std::vector<std::unique_ptr<AggregationStateHashTableBase>>*
-      getAllHashTables() {
+  std::vector<std::unique_ptr<AggregationStateHashTableBase>>* 
getAllHashTables() {
     return &hash_tables_;
   }
 
-  AggregationHashTableBase* createNewThreadPrivateHashTable() {
-    agg_hash_tables_.emplace_back(
-        std::unique_ptr<AggregationHashTableBase>(
-            new ThreadPrivateAggregationHashTable(
-               group_by_types_,
-               estimated_num_entries_,
-               handles_,
-               storage_manager_)));
-    return agg_hash_tables_.back().get();
+  // TODO: temporary
+  const HashTableImplType& hash_table_impl_type() const {
+    return hash_table_impl_type_;
   }
 
  private:
   AggregationStateHashTableBase* createNewHashTable() {
-    return agg_handle_->createGroupByHashTable(hash_table_impl_type_,
-                                               group_by_types_,
-                                               estimated_num_entries_,
-                                               storage_manager_);
-  }
-
-  AggregationStateHashTableBase* createNewHashTableFast() {
-    return AggregationStateFastHashTableFactory::CreateResizable(
-                hash_table_impl_type_,
-                group_by_types_,
-                estimated_num_entries_,
-                payload_sizes_,
-                handles_,
-                storage_manager_);
+    return new ThreadPrivateAggregationStateHashTable(
+        group_by_types_,
+        estimated_num_entries_,
+        handles_,
+        storage_manager_);
   }
 
   inline std::size_t reduceEstimatedCardinality(
       const std::size_t original_estimate) const {
-    if (original_estimate < kEstimateReductionFactor) {
-      return original_estimate;
-    } else {
-      DCHECK_GT(kEstimateReductionFactor, 0u);
-      return original_estimate / kEstimateReductionFactor;
-    }
+    DCHECK_GT(kEstimateReductionFactor, 0u);
+    return std::max(16uL,  original_estimate / kEstimateReductionFactor);
   }
 
   static constexpr std::size_t kEstimateReductionFactor = 100;
 
   std::vector<std::unique_ptr<AggregationStateHashTableBase>> hash_tables_;
-  std::vector<std::unique_ptr<AggregationHashTableBase>> agg_hash_tables_;
 
   const std::size_t estimated_num_entries_;
   const HashTableImplType hash_table_impl_type_;
 
   const std::vector<const Type *> group_by_types_;
-
-  std::vector<std::size_t> payload_sizes_;
-
-  AggregationHandle *agg_handle_;
   const std::vector<AggregationHandle *> handles_;
   StorageManager *storage_manager_;
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/HashTableUntypedKeyManager.hpp
----------------------------------------------------------------------
diff --git a/storage/HashTableUntypedKeyManager.hpp 
b/storage/HashTableUntypedKeyManager.hpp
index dffb116..ee32412 100644
--- a/storage/HashTableUntypedKeyManager.hpp
+++ b/storage/HashTableUntypedKeyManager.hpp
@@ -46,10 +46,12 @@ class HashTableUntypedKeyManager {
   HashTableUntypedKeyManager(const std::vector<const Type *> &key_types,
                              const std::size_t key_start_in_bucket)
       : key_types_(key_types),
-        key_hasher_(MakeUntypedKeyHashFunctor(key_types)),
-        key_equality_checker_(MakeUntypedKeyEqualityFunctor(key_types)),
+        key_hasher_(MakeUntypedHashFunctor(key_types)),
+        key_equality_checker_(MakeUntypedEqualityFunctor(key_types)),
         key_start_in_bucket_(key_start_in_bucket),
-        fixed_key_size_(0) {
+        fixed_key_size_(0),
+        is_key_nullable_(false) {
+
     for (const Type *key_type : key_types) {
       key_sizes_.emplace_back(key_type->maximumByteLength());
       key_offsets_.emplace_back(fixed_key_size_);
@@ -57,6 +59,7 @@ class HashTableUntypedKeyManager {
 
       DCHECK(!key_type->isVariableLength());
       fixed_key_size_ += key_type->maximumByteLength();
+      is_key_nullable_ |= key_type->isNullable();
     }
   }
 
@@ -68,6 +71,10 @@ class HashTableUntypedKeyManager {
     return fixed_key_size_;
   }
 
+  inline bool isKeyNullable() const {
+    return is_key_nullable_;
+  }
+
   inline std::size_t hashUntypedKey(const void *key) const {
     return key_hasher_(key);
   }
@@ -77,8 +84,14 @@ class HashTableUntypedKeyManager {
     return key_equality_checker_(key, getUntypedKeyComponent(bucket));
   }
 
-  inline void writeUntypedKeyToBucket(const void *key, void *bucket) {
-    InlineMemcpy(getUntypedKeyComponent(bucket), key, fixed_key_size_);
+  inline void writeUntypedKeyToBucket(const void *key,
+                                      void *bucket) {
+    copyUntypedKey(getUntypedKeyComponent(bucket), key);
+  }
+
+  inline void copyUntypedKey(void *destination,
+                             const void *key) const {
+    InlineMemcpy(destination, key, fixed_key_size_);
   }
 
   template <typename ValueAccessorT>
@@ -125,21 +138,24 @@ class HashTableUntypedKeyManager {
     return static_cast<char *>(bucket) + key_offsets_in_bucket_[component_id];
   }
 
-  inline const UntypedKeyHashFunctor& getUntypedKeyHashFunctor() const {
+  inline const UntypedHashFunctor& getUntypedKeyHashFunctor() const {
     return key_hasher_;
   }
 
-  inline const UntypedKeyEqualityFunctor& getUntypedKeyEqualityFunctor() const 
{
+  inline const UntypedEqualityFunctor& getUntypedKeyEqualityFunctor() const {
     return key_equality_checker_;
   }
 
  private:
   const std::vector<const Type*> &key_types_;
-  const UntypedKeyHashFunctor key_hasher_;
-  const UntypedKeyEqualityFunctor key_equality_checker_;
+  const UntypedHashFunctor key_hasher_;
+  const UntypedEqualityFunctor key_equality_checker_;
+
 
   std::size_t key_start_in_bucket_;
   std::size_t fixed_key_size_;
+  bool is_key_nullable_;
+
   std::vector<std::size_t> key_sizes_;
   std::vector<std::size_t> key_offsets_;
   std::vector<std::size_t> key_offsets_in_bucket_;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/InsertDestination.cpp
----------------------------------------------------------------------
diff --git a/storage/InsertDestination.cpp b/storage/InsertDestination.cpp
index 5e83453..5b77631 100644
--- a/storage/InsertDestination.cpp
+++ b/storage/InsertDestination.cpp
@@ -33,6 +33,7 @@
 #include "query_execution/QueryExecutionMessages.pb.h"
 #include "query_execution/QueryExecutionTypedefs.hpp"
 #include "query_execution/QueryExecutionUtil.hpp"
+#include "storage/AggregationResultIterator.hpp"
 #include "storage/InsertDestination.pb.h"
 #include "storage/StorageBlock.hpp"
 #include "storage/StorageBlockInfo.hpp"
@@ -221,6 +222,23 @@ void InsertDestination::bulkInsertTuples(ValueAccessor 
*accessor, bool always_ma
   });
 }
 
+void InsertDestination::bulkInsertAggregationResults(
+    AggregationResultIterator *results) {
+  results->beginIteration();
+  while (!results->iterationFinished()) {
+    MutableBlockReference output_block = this->getBlockForInsertion();
+    // FIXME(chasseur): Deal with TupleTooLargeForBlock exception.
+    if (output_block->bulkInsertAggregationResults(results) == 0) {
+      // output_block is full.
+      this->returnBlock(std::move(output_block), true);
+    } else {
+      // Bulk insert into output_block was successful. output_block
+      // will be rebuilt when there won't be any more insertions to it.
+      this->returnBlock(std::move(output_block), 
!results->iterationFinished());
+    }
+  }
+}
+
 void InsertDestination::bulkInsertTuplesWithRemappedAttributes(
     const std::vector<attribute_id> &attribute_map,
     ValueAccessor *accessor,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/InsertDestination.hpp
----------------------------------------------------------------------
diff --git a/storage/InsertDestination.hpp b/storage/InsertDestination.hpp
index 408e76b..ca02da3 100644
--- a/storage/InsertDestination.hpp
+++ b/storage/InsertDestination.hpp
@@ -52,6 +52,7 @@ namespace tmb { class MessageBus; }
 
 namespace quickstep {
 
+class AggregationResultIterator;
 class StorageManager;
 class ValueAccessor;
 
@@ -145,6 +146,8 @@ class InsertDestination : public InsertDestinationInterface 
{
 
   void insertTupleInBatch(const Tuple &tuple) override;
 
+  void bulkInsertAggregationResults(AggregationResultIterator *results);
+
   void bulkInsertTuples(ValueAccessor *accessor, bool always_mark_full = 
false) override;
 
   void bulkInsertTuplesWithRemappedAttributes(

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/PackedRowStoreTupleStorageSubBlock.cpp
----------------------------------------------------------------------
diff --git a/storage/PackedRowStoreTupleStorageSubBlock.cpp 
b/storage/PackedRowStoreTupleStorageSubBlock.cpp
index 0ad4a4c..f09fabb 100644
--- a/storage/PackedRowStoreTupleStorageSubBlock.cpp
+++ b/storage/PackedRowStoreTupleStorageSubBlock.cpp
@@ -26,6 +26,7 @@
 #include "catalog/CatalogAttribute.hpp"
 #include "catalog/CatalogRelationSchema.hpp"
 #include "catalog/CatalogTypedefs.hpp"
+#include "storage/AggregationResultIterator.hpp"
 #include "storage/PackedRowStoreValueAccessor.hpp"
 #include "storage/StorageBlockInfo.hpp"
 #include "storage/StorageBlockLayout.pb.h"
@@ -204,6 +205,35 @@ tuple_id 
PackedRowStoreTupleStorageSubBlock::bulkInsertTuples(ValueAccessor *acc
   return header_->num_tuples - original_num_tuples;
 }
 
+tuple_id PackedRowStoreTupleStorageSubBlock::bulkInsertAggregationResults(
+    AggregationResultIterator *results) {
+  const tuple_id original_num_tuples = header_->num_tuples;
+  char *dest_addr = static_cast<char*>(tuple_storage_)
+                        + header_->num_tuples * relation_.getFixedByteLength();
+
+  const std::size_t attrs_total_size = relation_.getMaximumByteLength();
+  const std::size_t key_size = results->getKeySize();
+  const std::size_t results_size = results->getResultsSize();
+  DEBUG_ASSERT(attrs_total_size == key_size + results_size);
+
+  if (results_size  == 0) {
+    while (this->hasSpaceToInsert<false>(1) && results->next()) {
+      results->writeKeyTo(dest_addr);
+      dest_addr += attrs_total_size;
+      ++(header_->num_tuples);
+    }
+  } else {
+    while (this->hasSpaceToInsert<false>(1) && results->next()) {
+      results->writeKeyTo(dest_addr);
+      results->writeResultsTo(dest_addr + key_size);
+      dest_addr += attrs_total_size;
+      ++(header_->num_tuples);
+    }
+  }
+
+  return header_->num_tuples - original_num_tuples;
+}
+
 tuple_id 
PackedRowStoreTupleStorageSubBlock::bulkInsertTuplesWithRemappedAttributes(
     const std::vector<attribute_id> &attribute_map,
     ValueAccessor *accessor) {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/PackedRowStoreTupleStorageSubBlock.hpp
----------------------------------------------------------------------
diff --git a/storage/PackedRowStoreTupleStorageSubBlock.hpp 
b/storage/PackedRowStoreTupleStorageSubBlock.hpp
index 0cd41f4..9e9fe40 100644
--- a/storage/PackedRowStoreTupleStorageSubBlock.hpp
+++ b/storage/PackedRowStoreTupleStorageSubBlock.hpp
@@ -33,6 +33,7 @@
 
 namespace quickstep {
 
+class AggregationResultIterator;
 class CatalogRelationSchema;
 class ComparisonPredicate;
 class TupleStorageSubBlockDescription;
@@ -144,6 +145,8 @@ class PackedRowStoreTupleStorageSubBlock: public 
TupleStorageSubBlock {
 
   tuple_id bulkInsertTuples(ValueAccessor *accessor) override;
 
+  tuple_id bulkInsertAggregationResults(AggregationResultIterator *results) 
override;
+
   tuple_id bulkInsertTuplesWithRemappedAttributes(
       const std::vector<attribute_id> &attribute_map,
       ValueAccessor *accessor) override;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/StorageBlock.cpp
----------------------------------------------------------------------
diff --git a/storage/StorageBlock.cpp b/storage/StorageBlock.cpp
index 4fce131..abb17f1 100644
--- a/storage/StorageBlock.cpp
+++ b/storage/StorageBlock.cpp
@@ -31,6 +31,7 @@
 #include "expressions/aggregation/AggregationHandle.hpp"
 #include "expressions/predicate/Predicate.hpp"
 #include "expressions/scalar/Scalar.hpp"
+#include "storage/AggregationResultIterator.hpp"
 #include "storage/BasicColumnStoreTupleStorageSubBlock.hpp"
 #include "storage/BloomFilterIndexSubBlock.hpp"
 #include "storage/CSBTreeIndexSubBlock.hpp"
@@ -60,6 +61,7 @@
 #include "types/containers/Tuple.hpp"
 #include "types/operations/comparisons/ComparisonUtil.hpp"
 #include "utility/Macros.hpp"
+#include "utility/ScopedBuffer.hpp"
 
 #include "glog/logging.h"
 
@@ -267,6 +269,19 @@ tuple_id StorageBlock::bulkInsertTuples(ValueAccessor 
*accessor) {
   return num_inserted;
 }
 
+tuple_id StorageBlock::bulkInsertAggregationResults(AggregationResultIterator 
*results) {
+  const tuple_id num_inserted = 
tuple_store_->bulkInsertAggregationResults(results);
+  if (num_inserted != 0) {
+    invalidateAllIndexes();
+    dirty_ = true;
+  } else if (tuple_store_->isEmpty()) {
+    if (!results->iterationFinished()) {
+      throw TupleTooLargeForBlock(0);
+    }
+  }
+  return num_inserted;
+}
+
 tuple_id StorageBlock::bulkInsertTuplesWithRemappedAttributes(
     const std::vector<attribute_id> &attribute_map,
     ValueAccessor *accessor) {
@@ -385,7 +400,7 @@ void StorageBlock::selectSimple(const 
std::vector<attribute_id> &selection,
                                                       accessor.get());
 }
 
-AggregationState* StorageBlock::aggregate(
+ScopedBuffer StorageBlock::aggregate(
     const AggregationHandle &handle,
     const std::vector<std::unique_ptr<const Scalar>> &arguments,
     const std::vector<attribute_id> *arguments_as_attributes,
@@ -419,7 +434,6 @@ void StorageBlock::aggregateGroupBy(
     const std::vector<std::unique_ptr<const Scalar>> &group_by,
     const Predicate *predicate,
     AggregationStateHashTableBase *hash_table,
-    AggregationHashTableBase *tp_hash_table,
     std::unique_ptr<TupleIdSequence> *reuse_matches,
     std::vector<std::unique_ptr<ColumnVector>> *reuse_group_by_vectors) const {
   DCHECK_GT(group_by.size(), 0u)
@@ -492,115 +506,9 @@ void StorageBlock::aggregateGroupBy(
      }
   }
 
-  hash_table->upsertValueAccessorCompositeKeyFast(argument_ids,
-                                                  &temp_result,
-                                                  key_ids,
-                                                  true);
-
-  // NOTE: experiments here
-  if (tp_hash_table != nullptr) {
-    if (key_ids.size() == 1) {
-      tp_hash_table->upsertValueAccessor(&temp_result,
-                                         key_ids.front(),
-                                         argument_ids,
-                                         true);
-    } else {
-      tp_hash_table->upsertValueAccessorCompositeKey(&temp_result,
-                                                     key_ids,
-                                                     argument_ids,
-                                                     true);
-    }
-    tp_hash_table->print();
-  }
-}
-
-
-void StorageBlock::aggregateDistinct(
-    const AggregationHandle &handle,
-    const std::vector<std::unique_ptr<const Scalar>> &arguments,
-    const std::vector<attribute_id> *arguments_as_attributes,
-    const std::vector<std::unique_ptr<const Scalar>> &group_by,
-    const Predicate *predicate,
-    AggregationStateHashTableBase *distinctify_hash_table,
-    std::unique_ptr<TupleIdSequence> *reuse_matches,
-    std::vector<std::unique_ptr<ColumnVector>> *reuse_group_by_vectors) const {
-  DCHECK_GT(arguments.size(), 0u)
-      << "Called aggregateDistinct() with zero argument expressions";
-  DCHECK((group_by.size() == 0 || reuse_group_by_vectors != nullptr));
-
-  std::vector<attribute_id> key_ids;
-
-  // An intermediate ValueAccessor that stores the materialized 'arguments' for
-  // this aggregate, as well as the GROUP BY expression values.
-  ColumnVectorsValueAccessor temp_result;
-  {
-    std::unique_ptr<ValueAccessor> accessor;
-    if (predicate) {
-      if (!*reuse_matches) {
-        // If there is a filter predicate that hasn't already been evaluated,
-        // evaluate it now and save the results for other aggregates on this
-        // same block.
-        reuse_matches->reset(getMatchesForPredicate(predicate));
-      }
-
-      // Create a filtered ValueAccessor that only iterates over predicate
-      // matches.
-      accessor.reset(tuple_store_->createValueAccessor(reuse_matches->get()));
-    } else {
-      // Create a ValueAccessor that iterates over all tuples in this block
-      accessor.reset(tuple_store_->createValueAccessor());
-    }
-
-#ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
-    // If all the arguments to this aggregate are plain relation attributes,
-    // aggregate directly on a ValueAccessor from this block to avoid a copy.
-    if ((arguments_as_attributes != nullptr) && 
(!arguments_as_attributes->empty())) {
-      DCHECK_EQ(arguments.size(), arguments_as_attributes->size())
-          << "Mismatch between number of arguments and number of 
attribute_ids";
-      DCHECK_EQ(group_by.size(), 0u);
-      handle.insertValueAccessorIntoDistinctifyHashTable(
-          accessor.get(), *arguments_as_attributes, distinctify_hash_table);
-      return;
-    }
-#endif
-
-    SubBlocksReference sub_blocks_ref(*tuple_store_,
-                                      indices_,
-                                      indices_consistent_);
-    attribute_id attr_id = 0;
-
-    if (!group_by.empty()) {
-      // Put GROUP BY keys into 'temp_result'.
-      if (reuse_group_by_vectors->empty()) {
-        // Compute GROUP BY values from group_by Scalars, and store them in
-        // reuse_group_by_vectors for reuse by other aggregates on this same
-        // block.
-        reuse_group_by_vectors->reserve(group_by.size());
-        for (const std::unique_ptr<const Scalar> &group_by_element : group_by) 
{
-          reuse_group_by_vectors->emplace_back(
-              group_by_element->getAllValues(accessor.get(), &sub_blocks_ref));
-          temp_result.addColumn(reuse_group_by_vectors->back().get(), false);
-          key_ids.push_back(attr_id++);
-        }
-      } else {
-        // Reuse precomputed GROUP BY values from reuse_group_by_vectors.
-        DCHECK_EQ(group_by.size(), reuse_group_by_vectors->size())
-            << "Wrong number of reuse_group_by_vectors";
-        for (const std::unique_ptr<ColumnVector> &reuse_cv : 
*reuse_group_by_vectors) {
-          temp_result.addColumn(reuse_cv.get(), false);
-          key_ids.push_back(attr_id++);
-        }
-      }
-    }
-    // Compute argument vectors and add them to 'temp_result'.
-    for (const std::unique_ptr<const Scalar> &argument : arguments) {
-      temp_result.addColumn(argument->getAllValues(accessor.get(), 
&sub_blocks_ref));
-      key_ids.push_back(attr_id++);
-    }
-  }
-
-  handle.insertValueAccessorIntoDistinctifyHashTable(
-      &temp_result, key_ids, distinctify_hash_table);
+  hash_table->upsertValueAccessorCompositeKey(&temp_result,
+                                              key_ids,
+                                              argument_ids);
 }
 
 // TODO(chasseur): Vectorization for updates.
@@ -1302,14 +1210,17 @@ std::unordered_map<attribute_id, TypedValue>* 
StorageBlock::generateUpdatedValue
   return update_map;
 }
 
-AggregationState* StorageBlock::aggregateHelperColumnVector(
+ScopedBuffer StorageBlock::aggregateHelperColumnVector(
     const AggregationHandle &handle,
     const std::vector<std::unique_ptr<const Scalar>> &arguments,
     const TupleIdSequence *matches) const {
+  ScopedBuffer state = handle.createInitialState();
   if (arguments.empty()) {
     // Special case. This is a nullary aggregate (i.e. COUNT(*)).
-    return handle.accumulateNullary(matches == nullptr ? 
tuple_store_->numTuples()
-                                                       : matches->size());
+    handle.accumulateNullary(
+        state.get(),
+        matches == nullptr ? tuple_store_->numTuples()
+                           : matches->size());
   } else {
     // Set up a ValueAccessor that will be used when materializing argument
     // values below (possibly filtered based on the '*matches' to a filter
@@ -1332,12 +1243,13 @@ AggregationState* 
StorageBlock::aggregateHelperColumnVector(
     }
 
     // Have the AggregationHandle actually do the aggregation.
-    return handle.accumulateColumnVectors(column_vectors);
+    handle.accumulateColumnVectors(state.get(), column_vectors);
   }
+  return state;
 }
 
 #ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
-AggregationState* StorageBlock::aggregateHelperValueAccessor(
+ScopedBuffer StorageBlock::aggregateHelperValueAccessor(
     const AggregationHandle &handle,
     const std::vector<attribute_id> &argument_ids,
     const TupleIdSequence *matches) const {
@@ -1351,9 +1263,11 @@ AggregationState* 
StorageBlock::aggregateHelperValueAccessor(
   }
 
   // Have the AggregationHandle actually do the aggregation.
-  return handle.accumulateValueAccessor(
-      accessor.get(),
-      argument_ids);
+  ScopedBuffer state = handle.createInitialState();
+  handle.accumulateValueAccessor(state.get(),
+                                 accessor.get(),
+                                 argument_ids);
+  return state;
 }
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/StorageBlock.hpp
----------------------------------------------------------------------
diff --git a/storage/StorageBlock.hpp b/storage/StorageBlock.hpp
index 567af33..08d81d0 100644
--- a/storage/StorageBlock.hpp
+++ b/storage/StorageBlock.hpp
@@ -36,11 +36,11 @@
 #include "storage/TupleStorageSubBlock.hpp"
 #include "utility/Macros.hpp"
 #include "utility/PtrVector.hpp"
+#include "utility/ScopedBuffer.hpp"
 
 namespace quickstep {
 
 class AggregationHandle;
-class AggregationState;
 class CatalogRelationSchema;
 class ColumnVector;
 class InsertDestinationInterface;
@@ -282,6 +282,8 @@ class StorageBlock : public StorageBlockBase {
    **/
   tuple_id bulkInsertTuples(ValueAccessor *accessor);
 
+  tuple_id bulkInsertAggregationResults(AggregationResultIterator *results);
+
   /**
    * @brief Insert as many tuples as possible from a ValueAccessor (all of the
    *        tuples accessible or as many as will fit in this StorageBlock) as a
@@ -408,7 +410,7 @@ class StorageBlock : public StorageBlockBase {
    *         AggregationHandle::finalize() can be used to generate a final
    *         result.
    **/
-  AggregationState* aggregate(
+  ScopedBuffer aggregate(
       const AggregationHandle &handle,
       const std::vector<std::unique_ptr<const Scalar>> &arguments,
       const std::vector<attribute_id> *arguments_as_attributes,
@@ -463,55 +465,10 @@ class StorageBlock : public StorageBlockBase {
       const std::vector<std::unique_ptr<const Scalar>> &group_by,
       const Predicate *predicate,
       AggregationStateHashTableBase *hash_table,
-      AggregationHashTableBase *tp_hash_table,
       std::unique_ptr<TupleIdSequence> *reuse_matches,
       std::vector<std::unique_ptr<ColumnVector>> *reuse_group_by_vectors) 
const;
 
   /**
-   * @brief Inserts the GROUP BY expressions and aggregation arguments together
-   *        as keys into the distinctify hash table.
-   *
-   * This is the first step for DISTINCT aggregation. It populates the 
distinctify
-   * hash table so that arguments are distinctified within each GROUP BY group.
-   * Later, a second-round aggregation on the distinctify hash table will be
-   * performed to actually compute the aggregated result for each GROUP BY 
group.
-   *
-   * @param handle Aggregation handle to compute aggregates with.
-   * @param arguments The arguments to the aggregation function as Scalars.
-   * @param arguments_as_attributes If non-NULL, indicates a valid attribute_id
-   *        for each of the elements in arguments, and is used to elide a copy.
-   *        Has no effect if NULL, or if VECTOR_COPY_ELISION_LEVEL is NONE.
-   * @param group_by The list of GROUP BY attributes/expressions.
-   * @param predicate A predicate for selection. \c nullptr indicates that all
-   *        tuples should be aggregated on.
-   * @param distinctify_hash_table Hash table to store the arguments and GROUP
-   *        BY expressions together as hash table key and a bool constant \c 
true
-   *        as hash table value. (So the hash table actually serves as a hash 
set.)
-   * @param reuse_matches This parameter is used to store and reuse tuple-id
-   *        sequence of matches pre-computed in an earlier invocations of
-   *        aggregateGroupBy(). \c reuse_matches is never \c nullptr for ease 
of
-   *        use.  Current invocation of aggregateGroupBy() will reuse
-   *        TupleIdSequence if passed, otherwise computes a TupleIdSequence 
based
-   *        on \c predicate and stores in \c reuse_matches. We use
-   *        std::unique_ptr for each of use, since the caller will not have to
-   *        selective free.
-   * @param reuse_group_by_vectors This parameter is used to store and reuse
-   *        GROUP BY attribute vectors pre-computed in an earlier invocation of
-   *        aggregateGroupBy(). \c reuse_group_by_vectors is never \c nullptr
-   *        for ease of use. Current invocation of aggregateGroupBy() will 
reuse
-   *        ColumnVectors if non-empty, otherwise computes ColumnVectors based
-   *        on \c group_by and stores them in \c reuse_group_by_vectors.
-   */
-  void aggregateDistinct(const AggregationHandle &handle,
-                         const std::vector<std::unique_ptr<const Scalar>> 
&arguments,
-                         const std::vector<attribute_id> 
*arguments_as_attributes,
-                         const std::vector<std::unique_ptr<const Scalar>> 
&group_by,
-                         const Predicate *predicate,
-                         AggregationStateHashTableBase *distinctify_hash_table,
-                         std::unique_ptr<TupleIdSequence> *reuse_matches,
-                         std::vector<std::unique_ptr<ColumnVector>> 
*reuse_group_by_vectors) const;
-
-  /**
    * @brief Perform an UPDATE query over the tuples in this StorageBlock.
    * @warning In some edge cases, calling this method may cause IndexSubBlocks
    *          in this block to become inconsistent (the TupleStorageSubBlock
@@ -635,13 +592,13 @@ class StorageBlock : public StorageBlockBase {
       const tuple_id tuple,
       const std::unordered_map<attribute_id, std::unique_ptr<const Scalar>> 
&assignments) const;
 
-  AggregationState* aggregateHelperColumnVector(
+  ScopedBuffer aggregateHelperColumnVector(
       const AggregationHandle &handle,
       const std::vector<std::unique_ptr<const Scalar>> &arguments,
       const TupleIdSequence *matches) const;
 
 #ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
-  AggregationState* aggregateHelperValueAccessor(
+  ScopedBuffer aggregateHelperValueAccessor(
       const AggregationHandle &handle,
       const std::vector<attribute_id> &argument_ids,
       const TupleIdSequence *matches) const;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/storage/TupleStorageSubBlock.hpp
----------------------------------------------------------------------
diff --git a/storage/TupleStorageSubBlock.hpp b/storage/TupleStorageSubBlock.hpp
index aed6eea..3733165 100644
--- a/storage/TupleStorageSubBlock.hpp
+++ b/storage/TupleStorageSubBlock.hpp
@@ -30,10 +30,13 @@
 #include "types/TypedValue.hpp"
 #include "utility/Macros.hpp"
 
+#include "glog/logging.h"
+
 namespace quickstep {
 
 class CatalogRelationSchema;
 class ComparisonPredicate;
+class AggregationResultIterator;
 class Tuple;
 class TupleStorageSubBlockDescription;
 class ValueAccessor;
@@ -245,6 +248,10 @@ class TupleStorageSubBlock {
    **/
   virtual tuple_id bulkInsertTuples(ValueAccessor *accessor) = 0;
 
+  virtual tuple_id bulkInsertAggregationResults(AggregationResultIterator 
*results) {
+    LOG(FATAL) << "Not implemented\n";
+  }
+
   /**
    * @brief Insert as many tuples as possible from a ValueAccessor (all of the
    *        tuples accessible or as many as will fit in this

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/CharType.hpp
----------------------------------------------------------------------
diff --git a/types/CharType.hpp b/types/CharType.hpp
index c7321f4..8ed903c 100644
--- a/types/CharType.hpp
+++ b/types/CharType.hpp
@@ -22,6 +22,7 @@
 
 #include <cstddef>
 #include <cstdio>
+#include <cstring>
 #include <string>
 
 #include "types/Type.hpp"
@@ -132,6 +133,17 @@ class CharType : public AsciiStringSuperType {
   TypedValue coerceValue(const TypedValue &original_value,
                          const Type &original_type) const override;
 
+  inline std::size_t getHash(const void *value_ptr) const {
+    const char *char_ptr = static_cast<const char *>(value_ptr);
+    return util::Hash(char_ptr, strnlen(char_ptr, length_));
+  }
+
+  inline void copyValue(void *dst, const void *src) const {
+    std::strncpy(static_cast<char *>(dst),
+                 static_cast<const char *>(src),
+                 length_);
+  }
+
  private:
   CharType(const std::size_t length, const bool nullable)
       : AsciiStringSuperType(kChar, nullable, length, length, length) {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/DateType.hpp
----------------------------------------------------------------------
diff --git a/types/DateType.hpp b/types/DateType.hpp
index b83848e..e4f75a7 100644
--- a/types/DateType.hpp
+++ b/types/DateType.hpp
@@ -22,6 +22,7 @@
 
 #include <cstddef>
 #include <cstdio>
+#include <cstring>
 #include <string>
 
 #include "types/DatetimeLit.hpp"
@@ -126,8 +127,18 @@ class DateType : public Type {
     return true;
   }
 
+  void makeZeroValue(void *value_ptr) const override {
+    std::memset(value_ptr, 0, sizeof(cpptype));
+  }
+
   inline std::size_t getHash(const void *value_ptr) const {
-    return DateLit::getHash(reinterpret_cast<const DateLit *>(value_ptr));
+    return DateLit::getHash(static_cast<const DateLit *>(value_ptr));
+  }
+
+  inline void copyValue(void *dst, const void *src) const {
+    return DateLit::copyValue(
+        static_cast<DateLit *>(dst),
+        static_cast<const DateLit *>(src));
   }
 
  private:

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/DatetimeIntervalType.hpp
----------------------------------------------------------------------
diff --git a/types/DatetimeIntervalType.hpp b/types/DatetimeIntervalType.hpp
index 71e2842..d8b7bef 100644
--- a/types/DatetimeIntervalType.hpp
+++ b/types/DatetimeIntervalType.hpp
@@ -23,6 +23,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <cstdio>
+#include <cstring>
 #include <string>
 
 #include "types/IntervalLit.hpp"
@@ -118,8 +119,17 @@ class DatetimeIntervalType : public Type {
     return true;
   }
 
+  void makeZeroValue(void *value_ptr) const override {
+    std::memset(value_ptr, 0, sizeof(cpptype));
+  }
+
   inline std::size_t getHash(const void *value_ptr) const {
-    return *reinterpret_cast<const DatetimeIntervalLit::cpptype *>(value_ptr);
+    return *static_cast<const DatetimeIntervalLit::cpptype *>(value_ptr);
+  }
+
+  inline void copyValue(void *dst, const void *src) const {
+    *static_cast<DatetimeIntervalLit::cpptype *>(dst) =
+        *static_cast<const DatetimeIntervalLit::cpptype *>(src);
   }
 
  private:

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/DatetimeLit.hpp
----------------------------------------------------------------------
diff --git a/types/DatetimeLit.hpp b/types/DatetimeLit.hpp
index c528b1f..d43b4d8 100644
--- a/types/DatetimeLit.hpp
+++ b/types/DatetimeLit.hpp
@@ -105,6 +105,10 @@ struct DateLit {
         | static_cast<std::uint64_t>(date_lit->month) << 8
         | static_cast<std::uint64_t>(date_lit->day);
   }
+
+  static inline void copyValue(DateLit *dst, const DateLit *src) {
+    *dst = *src;
+  }
 };
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/DatetimeType.hpp
----------------------------------------------------------------------
diff --git a/types/DatetimeType.hpp b/types/DatetimeType.hpp
index 974a277..b869aaf 100644
--- a/types/DatetimeType.hpp
+++ b/types/DatetimeType.hpp
@@ -22,6 +22,7 @@
 
 #include <cstddef>
 #include <cstdio>
+#include <cstring>
 #include <string>
 
 #include "types/DatetimeLit.hpp"
@@ -134,8 +135,17 @@ class DatetimeType : public Type {
     return true;
   }
 
+  void makeZeroValue(void *value_ptr) const override {
+    std::memset(value_ptr, 0, sizeof(cpptype));
+  }
+
   inline std::size_t getHash(const void *value_ptr) const {
-    return *reinterpret_cast<const DatetimeLit::cpptype *>(value_ptr);
+    return *static_cast<const DatetimeLit::cpptype *>(value_ptr);
+  }
+
+  inline void copyValue(void *dst, const void *src) const {
+    *static_cast<DatetimeLit::cpptype *>(dst) =
+        *static_cast<const DatetimeLit::cpptype *>(src);
   }
 
  private:

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/NullType.hpp
----------------------------------------------------------------------
diff --git a/types/NullType.hpp b/types/NullType.hpp
index 309c826..90a8852 100644
--- a/types/NullType.hpp
+++ b/types/NullType.hpp
@@ -22,6 +22,7 @@
 
 #include <cstddef>
 #include <cstdio>
+#include <cstring>
 #include <string>
 
 #include "types/Type.hpp"
@@ -107,6 +108,9 @@ class NullType : public Type {
     return true;
   }
 
+  void makeZeroValue(void *value_ptr) const override {
+  }
+
  private:
   // NOTE(chasseur): NullType requires 0 bytes of inherent storage. It does,
   // however, require a bit in NULL bitmaps.

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/NumericSuperType.hpp
----------------------------------------------------------------------
diff --git a/types/NumericSuperType.hpp b/types/NumericSuperType.hpp
index 76dfe33..37fd437 100644
--- a/types/NumericSuperType.hpp
+++ b/types/NumericSuperType.hpp
@@ -21,6 +21,7 @@
 #define QUICKSTEP_TYPES_NUMERIC_SUPER_TYPE_HPP_
 
 #include <cstddef>
+#include <cstring>
 
 #include "types/NullCoercibilityCheckMacro.hpp"
 #include "types/Type.hpp"
@@ -60,8 +61,16 @@ class NumericSuperType : public Type {
     return true;
   }
 
+  void makeZeroValue(void *value_ptr) const override {
+    std::memset(value_ptr, 0, sizeof(cpptype));
+  }
+
   inline std::size_t getHash(const void *value_ptr) const {
-    return *reinterpret_cast<const CppType *>(value_ptr);
+    return *static_cast<const CppType *>(value_ptr);
+  }
+
+  inline void copyValue(void *dst, const void *src) const {
+    *static_cast<CppType *>(dst) = *static_cast<const CppType *>(src);
   }
 
  protected:

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/Type.hpp
----------------------------------------------------------------------
diff --git a/types/Type.hpp b/types/Type.hpp
index 041b6b8..13c0644 100644
--- a/types/Type.hpp
+++ b/types/Type.hpp
@@ -452,6 +452,8 @@ class Type {
 
   virtual bool canCheckEqualityWithMemcmp() const = 0;
 
+  virtual void makeZeroValue(void *value_ptr) const = 0;
+
  protected:
   Type(const SuperTypeID super_type_id,
        const TypeID type_id,
@@ -495,9 +497,10 @@ class AsciiStringSuperType : public Type {
     return false;
   }
 
-  inline std::size_t getHash(const void *value_ptr) const {
-    const char *char_ptr = reinterpret_cast<const char *>(value_ptr);
-    return util::Hash(char_ptr, strnlen(char_ptr, length_));
+  void makeZeroValue(void *value_ptr) const override {
+    if (maximum_byte_length_ > 0) {
+      *static_cast<char *>(value_ptr) = 0;
+    }
   }
 
  protected:

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/TypeFunctors.cpp
----------------------------------------------------------------------
diff --git a/types/TypeFunctors.cpp b/types/TypeFunctors.cpp
index 84fcad2..bf49df8 100644
--- a/types/TypeFunctors.cpp
+++ b/types/TypeFunctors.cpp
@@ -73,8 +73,8 @@ typename Maker::FunctorType MakeHelper(const Type *type) {
   }
 }
 
-struct UntypedKeyHashFunctorMaker {
-  typedef UntypedKeyHashFunctor FunctorType;
+struct UntypedHashFunctorMaker {
+  typedef UntypedHashFunctor FunctorType;
 
   template <typename TypeName>
   static FunctorType MakeFunctor(const TypeName *type) {
@@ -84,22 +84,22 @@ struct UntypedKeyHashFunctorMaker {
   }
 };
 
-UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const Type *type) {
-  return MakeHelper<UntypedKeyHashFunctorMaker>(type);
+UntypedHashFunctor MakeUntypedHashFunctor(const Type *type) {
+  return MakeHelper<UntypedHashFunctorMaker>(type);
 }
 
-UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const std::vector<const Type 
*> &types) {
+UntypedHashFunctor MakeUntypedHashFunctor(const std::vector<const Type *> 
&types) {
   DCHECK_GE(types.size(), 1u);
 
   if (types.size() == 1u) {
-    return MakeUntypedKeyHashFunctor(types.front());
+    return MakeUntypedHashFunctor(types.front());
   }
 
-  std::vector<UntypedKeyHashFunctor> hashers;
+  std::vector<UntypedHashFunctor> hashers;
   std::vector<std::size_t> offsets;
   std::size_t accum_offset = 0;
   for (const Type *type : types) {
-    hashers.emplace_back(MakeUntypedKeyHashFunctor(type));
+    hashers.emplace_back(MakeUntypedHashFunctor(type));
     offsets.emplace_back(accum_offset);
     accum_offset += type->isVariableLength() ? sizeof(void *)
                                              : type->maximumByteLength();
@@ -115,44 +115,44 @@ UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const 
std::vector<const Type *>
   };
 }
 
-struct UntypedKeyEqualityFunctorMaker {
-  typedef UntypedKeyEqualityFunctor FunctorType;
+struct UntypedEqualityFunctorMaker {
+  typedef UntypedEqualityFunctor FunctorType;
 
   template <typename TypeName>
-  static UntypedKeyEqualityFunctor MakeFunctor(const TypeName *type) {
+  static UntypedEqualityFunctor MakeFunctor(const TypeName *type) {
     return STLLiteralEqual<typename TypeName::cpptype>();
   }
 };
 
 template <>
-UntypedKeyEqualityFunctor UntypedKeyEqualityFunctorMaker::MakeFunctor(
+UntypedEqualityFunctor UntypedEqualityFunctorMaker::MakeFunctor(
     const CharType *type) {
   return STLCharEqual(type->getStringLength());
 }
 
 template <>
-UntypedKeyEqualityFunctor UntypedKeyEqualityFunctorMaker::MakeFunctor(
+UntypedEqualityFunctor UntypedEqualityFunctorMaker::MakeFunctor(
     const VarCharType *type) {
   return STLVarCharEqual();
 }
 
-UntypedKeyEqualityFunctor MakeUntypedKeyEqualityFunctor(const Type *type) {
-  return MakeHelper<UntypedKeyEqualityFunctorMaker>(type);
+UntypedEqualityFunctor MakeUntypedEqualityFunctor(const Type *type) {
+  return MakeHelper<UntypedEqualityFunctorMaker>(type);
 }
 
-UntypedKeyEqualityFunctor MakeUntypedKeyEqualityFunctor(const 
std::vector<const Type *> &types) {
+UntypedEqualityFunctor MakeUntypedEqualityFunctor(const std::vector<const Type 
*> &types) {
   DCHECK_GE(types.size(), 1u);
 
   if (types.size() == 1u) {
-    return MakeUntypedKeyEqualityFunctor(types.front());
+    return MakeUntypedEqualityFunctor(types.front());
   }
 
-  std::vector<UntypedKeyEqualityFunctor> equality_checkers;
+  std::vector<UntypedEqualityFunctor> equality_checkers;
   std::vector<std::size_t> offsets;
   std::size_t accum_offset = 0;
   bool can_check_equality_with_memcmp = true;
   for (const Type *type : types) {
-    equality_checkers.emplace_back(MakeUntypedKeyEqualityFunctor(type));
+    equality_checkers.emplace_back(MakeUntypedEqualityFunctor(type));
     offsets.emplace_back(accum_offset);
     accum_offset += type->isVariableLength() ? sizeof(void *)
                                              : type->maximumByteLength();
@@ -160,7 +160,7 @@ UntypedKeyEqualityFunctor 
MakeUntypedKeyEqualityFunctor(const std::vector<const
   }
   if (can_check_equality_with_memcmp) {
     return [accum_offset](const void *left, const void *right) -> bool {
-      return memcmp(left, right, accum_offset);
+      return !std::memcmp(left, right, accum_offset);
     };
   } else {
     return [offsets, equality_checkers](const void *left, const void *right) 
-> bool {
@@ -175,5 +175,19 @@ UntypedKeyEqualityFunctor 
MakeUntypedKeyEqualityFunctor(const std::vector<const
   }
 }
 
+struct UntypedCopyFunctorMaker {
+  typedef UntypedCopyFunctor FunctorType;
+
+  template <typename TypeName>
+  static FunctorType MakeFunctor(const TypeName *type) {
+    return [type](void *dst, const void *src) -> void {
+      type->copyValue(dst, src);
+    };
+  }
+};
+
+UntypedCopyFunctor MakeUntypedCopyFunctor(const Type *type) {
+  return MakeHelper<UntypedCopyFunctorMaker>(type);
+}
 
 }  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/TypeFunctors.hpp
----------------------------------------------------------------------
diff --git a/types/TypeFunctors.hpp b/types/TypeFunctors.hpp
index a8466c5..55f63e1 100644
--- a/types/TypeFunctors.hpp
+++ b/types/TypeFunctors.hpp
@@ -32,13 +32,16 @@ class Type;
  *  @{
  */
 
-typedef std::function<std::size_t (const void *)> UntypedKeyHashFunctor;
-UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const Type *type);
-UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const std::vector<const Type 
*> &types);
+typedef std::function<std::size_t (const void *)> UntypedHashFunctor;
+UntypedHashFunctor MakeUntypedHashFunctor(const Type *type);
+UntypedHashFunctor MakeUntypedHashFunctor(const std::vector<const Type *> 
&types);
 
-typedef std::function<bool (const void *, const void *)> 
UntypedKeyEqualityFunctor;
-UntypedKeyEqualityFunctor MakeUntypedKeyEqualityFunctor(const Type *type);
-UntypedKeyEqualityFunctor MakeUntypedKeyEqualityFunctor(const 
std::vector<const Type *> &types);
+typedef std::function<bool (const void *, const void *)> 
UntypedEqualityFunctor;
+UntypedEqualityFunctor MakeUntypedEqualityFunctor(const Type *type);
+UntypedEqualityFunctor MakeUntypedEqualityFunctor(const std::vector<const Type 
*> &types);
+
+typedef std::function<void (void *, const void *)> UntypedCopyFunctor;
+UntypedCopyFunctor MakeUntypedCopyFunctor(const Type *type);
 
 /** @} */
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/VarCharType.hpp
----------------------------------------------------------------------
diff --git a/types/VarCharType.hpp b/types/VarCharType.hpp
index bb50e92..d35039f 100644
--- a/types/VarCharType.hpp
+++ b/types/VarCharType.hpp
@@ -22,6 +22,7 @@
 
 #include <cstddef>
 #include <cstdio>
+#include <cstring>
 #include <string>
 
 #include "types/Type.hpp"
@@ -30,6 +31,8 @@
 #include "types/TypedValue.hpp"
 #include "utility/Macros.hpp"
 
+#include "glog/logging.h"
+
 namespace quickstep {
 
 /** \addtogroup Types
@@ -135,6 +138,15 @@ class VarCharType : public AsciiStringSuperType {
   TypedValue coerceValue(const TypedValue &original_value,
                          const Type &original_type) const override;
 
+  inline std::size_t getHash(const void *value_ptr) const {
+    LOG(FATAL) << "Not implemented";
+    return 0;
+  }
+
+  inline void copyValue(void *dst, const void *src) const {
+    LOG(FATAL) << "Not implemented";
+  }
+
  private:
   VarCharType(const std::size_t length, const bool nullable)
       : AsciiStringSuperType(kVarChar, nullable, 1, length + 1, length) {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/YearMonthIntervalType.hpp
----------------------------------------------------------------------
diff --git a/types/YearMonthIntervalType.hpp b/types/YearMonthIntervalType.hpp
index 6c54b10..c0f4723 100644
--- a/types/YearMonthIntervalType.hpp
+++ b/types/YearMonthIntervalType.hpp
@@ -22,6 +22,7 @@
 
 #include <cstddef>
 #include <cstdio>
+#include <cstring>
 #include <string>
 
 #include "types/IntervalLit.hpp"
@@ -117,8 +118,17 @@ class YearMonthIntervalType : public Type {
     return true;
   }
 
+  void makeZeroValue(void *value_ptr) const override {
+    std::memset(value_ptr, 0, sizeof(cpptype));
+  }
+
   inline std::size_t getHash(const void *value_ptr) const {
-    return *reinterpret_cast<const YearMonthIntervalLit::cpptype *>(value_ptr);
+    return *static_cast<const YearMonthIntervalLit::cpptype *>(value_ptr);
+  }
+
+  inline void copyValue(void *dst, const void *src) const {
+    *static_cast<YearMonthIntervalLit::cpptype *>(dst) =
+        *static_cast<const YearMonthIntervalLit::cpptype *>(src);
   }
 
  private:

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/operations/binary_operations/ArithmeticBinaryOperators.hpp
----------------------------------------------------------------------
diff --git a/types/operations/binary_operations/ArithmeticBinaryOperators.hpp 
b/types/operations/binary_operations/ArithmeticBinaryOperators.hpp
index 7224a0c..9238d4e 100644
--- a/types/operations/binary_operations/ArithmeticBinaryOperators.hpp
+++ b/types/operations/binary_operations/ArithmeticBinaryOperators.hpp
@@ -172,6 +172,26 @@ class ArithmeticUncheckedBinaryOperator : public 
UncheckedBinaryOperator {
   ArithmeticUncheckedBinaryOperator(const ArithmeticUncheckedBinaryOperator 
&orig) = default;
   ~ArithmeticUncheckedBinaryOperator() = default;
 
+  BinaryOperatorFunctor getFunctor() const override {
+    OpFunctor<LeftCppType, RightCppType> op_functor;
+    return [op_functor](void *result, const void *left, const void *right) {
+      *static_cast<typename ResultType::cpptype *>(result) =
+          op_functor(
+              *static_cast<const LeftCppType *>(left),
+              *static_cast<const RightCppType *>(right));
+    };
+  }
+
+  BinaryOperatorMergeFunctor getMergeFunctor() const override {
+    OpFunctor<LeftCppType, RightCppType> op_functor;
+    return [op_functor](void *left, const void *right) {
+      *static_cast<typename ResultType::cpptype *>(left) =
+          op_functor(
+              *static_cast<const LeftCppType *>(left),
+              *static_cast<const RightCppType *>(right));
+    };
+  }
+
   inline TypedValue applyToTypedValues(const TypedValue &left,
                                        const TypedValue &right) const override 
{
     return applyToTypedValuesInl(left, right);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9ccd5a31/types/operations/binary_operations/BinaryOperation.hpp
----------------------------------------------------------------------
diff --git a/types/operations/binary_operations/BinaryOperation.hpp 
b/types/operations/binary_operations/BinaryOperation.hpp
index 585a1c6..49cc342 100644
--- a/types/operations/binary_operations/BinaryOperation.hpp
+++ b/types/operations/binary_operations/BinaryOperation.hpp
@@ -21,6 +21,7 @@
 #define QUICKSTEP_TYPES_OPERATIONS_BINARY_OPERATIONS_BINARY_OPERATION_HPP_
 
 #include <cstddef>
+#include <functional>
 #include <string>
 #include <type_traits>
 #include <utility>
@@ -44,6 +45,9 @@ class ValueAccessor;
  *  @{
  */
 
+typedef std::function<void (void *, const void *, const void*)> 
BinaryOperatorFunctor;
+typedef std::function<void (void *, const void *)> BinaryOperatorMergeFunctor;
+
 /**
  * @brief A binary operator which can be quickly applied to data items WITHOUT
  *        checking their types.
@@ -56,6 +60,9 @@ class UncheckedBinaryOperator {
   virtual ~UncheckedBinaryOperator() {
   }
 
+  virtual BinaryOperatorFunctor getFunctor() const = 0;
+  virtual BinaryOperatorMergeFunctor getMergeFunctor() const = 0;
+
   /**
    * @brief Apply to two TypedValues without type-checking.
    *

Reply via email to