Optimized the code for inserting SplitRow and PackedRow stores.
diff --git a/storage/PackedRowStoreTupleStorageSubBlock.cpp b/storage/PackedRowStoreTupleStorageSubBlock.cpp
index 1328826..0e15bb5 100644
--- a/storage/PackedRowStoreTupleStorageSubBlock.cpp
+++ b/storage/PackedRowStoreTupleStorageSubBlock.cpp
@@ -143,46 +143,72 @@
   InvokeOnAnyValueAccessor(
       accessor,
       [&](auto *accessor) -> void {  // NOLINT(build/c++11)
+
+    const std::size_t num_attrs = relation_.size();
+    // We keep track of the total size of a tuple in the case that we do a
+    // 'fast path' insertion later in the code.
+    std::size_t attrs_total_size = 0;
+    // Create a vector containing the maximum sizes of the to-be extracted
+    // attributes.
+    // NOTE(Marc): This is an optimization so that we need not use an iterator
+    // object in the following inner loops.
+    std::vector<std::size_t> attrs_max_size;
+    for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
+         attr_it != relation_.end();
+         ++attr_it) {
+      attrs_max_size.push_back(attr_it->getType().maximumByteLength());
+      attrs_total_size += attrs_max_size.back();
+    }
+
     if (num_nullable_attrs != 0) {
+      // Index i of null_attr_idxs is an index greater than 0 if the i-th
+      // attribute of this relation is nullable, -1 otherwise.
+      std::vector<int> null_attr_idxs;
+      for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
+           attr_it != relation_.end(); ++attr_it) {
+        null_attr_idxs.push_back(
+            relation_.getNullableAttributeIndex(attr_it->getID()));
+      }
+
       while (this->hasSpaceToInsert<true>(1) && accessor->next()) {
-        attribute_id accessor_attr_id = 0;
-        for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-             attr_it != relation_.end();
-             ++attr_it) {
-          const std::size_t attr_size = attr_it->getType().maximumByteLength();
-          const int nullable_idx = relation_.getNullableAttributeIndex(
-              attr_it->getID());
-          if (nullable_idx != -1) {
+        for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+          // If this attribute is nullable, check for a returned null value.
+          if (null_attr_idxs[curr_attr] != -1) {
             const void *attr_value
-                = accessor->template getUntypedValue<true>(accessor_attr_id);
+                = accessor->template getUntypedValue<true>(curr_attr);
             if (attr_value == nullptr) {
-              null_bitmap_->setBit(header_->num_tuples * num_nullable_attrs + nullable_idx,
+              null_bitmap_->setBit(header_->num_tuples * num_nullable_attrs + null_attr_idxs[curr_attr],
                                    true);
             } else {
-              memcpy(dest_addr, attr_value, attr_size);
+              memcpy(dest_addr, attr_value, attrs_max_size[curr_attr]);
             }
           } else {
             memcpy(dest_addr,
-                   accessor->template getUntypedValue<false>(accessor_attr_id),
-                   attr_size);
+                   accessor->template getUntypedValue<false>(curr_attr),
+                   attrs_max_size[curr_attr]);
           }
-          ++accessor_attr_id;
-          dest_addr += attr_size;
+          dest_addr += attrs_max_size[curr_attr];
         }
         ++(header_->num_tuples);
       }
     } else {
+      // If the accessor is from a packed row store, we can optimize the
+      // memcpy by avoiding iterating over each attribute.
+      const bool fast_copy =
+          (accessor->getImplementationType() ==
+              ValueAccessor::Implementation::kCompressedPackedRowStore);
       while (this->hasSpaceToInsert<false>(1) && accessor->next()) {
-        attribute_id accessor_attr_id = 0;
-        for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-             attr_it != relation_.end();
-             ++attr_it) {
-          const std::size_t attr_size = attr_it->getType().maximumByteLength();
+        if (fast_copy) {
           memcpy(dest_addr,
-                 accessor->template getUntypedValue<false>(accessor_attr_id),
-                 attr_size);
-          ++accessor_attr_id;
-          dest_addr += attr_size;
+                 accessor->template getUntypedValue<false>(0),
+                 attrs_total_size);
+        } else {
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            memcpy(dest_addr,
+                   accessor->template getUntypedValue<false>(curr_attr),
+                   attrs_max_size[curr_attr]);
+            dest_addr += attrs_max_size[curr_attr];
+          }
         }
         ++(header_->num_tuples);
       }
@@ -205,46 +231,57 @@
   InvokeOnAnyValueAccessor(
       accessor,
       [&](auto *accessor) -> void {  // NOLINT(build/c++11)
+
+    const std::size_t num_attrs = relation_.size();
+    // Create a vector containing the maximum sizes of the to-be extracted
+    // attributes.
+    // NOTE(Marc): This is an optimization so that we need not use an iterator
+    // object in the following inner loops.
+    std::vector<std::size_t> attrs_max_size;
+    for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
+         attr_it != relation_.end();
+         ++attr_it) {
+      attrs_max_size.push_back(attr_it->getType().maximumByteLength());
+    }
+
     if (num_nullable_attrs != 0) {
+      // Index i of null_attr_idxs is an index greater than 0 if the i-th
+      // attribute of this relation is nullable, -1 otherwise.
+      std::vector<int> null_attr_idxs;
+      for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
+           attr_it != relation_.end(); ++attr_it) {
+        null_attr_idxs.push_back(
+            relation_.getNullableAttributeIndex(attr_it->getID()));
+      }
+
       while (this->hasSpaceToInsert<true>(1) && accessor->next()) {
-        std::vector<attribute_id>::const_iterator attribute_map_it = attribute_map.begin();
-        for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-             attr_it != relation_.end();
-             ++attr_it) {
-          const std::size_t attr_size = attr_it->getType().maximumByteLength();
-          const int nullable_idx = relation_.getNullableAttributeIndex(
-              attr_it->getID());
-          if (nullable_idx != -1) {
+        for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+          // If this attribute is nullable, check for a returned null value.
+          if (null_attr_idxs[curr_attr] != -1) {
             const void *attr_value
-                = accessor->template getUntypedValue<true>(*attribute_map_it);
+                = accessor->template getUntypedValue<true>(attribute_map[curr_attr]);
             if (attr_value == nullptr) {
-              null_bitmap_->setBit(header_->num_tuples * num_nullable_attrs + nullable_idx,
+              null_bitmap_->setBit(header_->num_tuples * num_nullable_attrs + null_attr_idxs[curr_attr],
                                    true);
             } else {
-              memcpy(dest_addr, attr_value, attr_size);
+              memcpy(dest_addr, attr_value, attrs_max_size[curr_attr]);
             }
           } else {
             memcpy(dest_addr,
-                   accessor->template getUntypedValue<false>(*attribute_map_it),
-                   attr_size);
+                   accessor->template getUntypedValue<false>(attribute_map[curr_attr]),
+                   attrs_max_size[curr_attr]);
           }
-          ++attribute_map_it;
-          dest_addr += attr_size;
+          dest_addr += attrs_max_size[curr_attr];
         }
         ++(header_->num_tuples);
       }
     } else {
       while (this->hasSpaceToInsert<false>(1) && accessor->next()) {
-        std::vector<attribute_id>::const_iterator attribute_map_it = attribute_map.begin();
-        for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-             attr_it != relation_.end();
-             ++attr_it) {
-          const std::size_t attr_size = attr_it->getType().maximumByteLength();
+        for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
           memcpy(dest_addr,
-                 accessor->template getUntypedValue<false>(*attribute_map_it),
-                 attr_size);
-          ++attribute_map_it;
-          dest_addr += attr_size;
+                 accessor->template getUntypedValue<false>(attribute_map[curr_attr]),
+                 attrs_max_size[curr_attr]);
+          dest_addr += attrs_max_size[curr_attr];
         }
         ++(header_->num_tuples);
       }
diff --git a/storage/SplitRowStoreTupleStorageSubBlock.cpp b/storage/SplitRowStoreTupleStorageSubBlock.cpp
index 6c70d0f..9f31a94 100644
--- a/storage/SplitRowStoreTupleStorageSubBlock.cpp
+++ b/storage/SplitRowStoreTupleStorageSubBlock.cpp
@@ -198,6 +198,33 @@
   InvokeOnAnyValueAccessor(
       accessor,
       [&](auto *accessor) -> void {  // NOLINT(build/c++11)
+
+    const std::size_t num_attrs = relation_.size();
+    // Create a vector containing the maximum sizes, null attributes, and 
+    // variable length attributes of the to-be extracted attributes.
+    // NOTE(Marc): This is an optimization so that we need not use an iterator
+    // object in the following inner loops.
+    std::vector<std::size_t> attrs_max_size;
+    std::vector<int> fixlen_attr_offsets;
+    std::vector<int> null_attr_idxs;
+    std::vector<int> varlen_attr_idxs;
+    for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
+         attr_it != relation_.end();
+         ++attr_it) {
+      attrs_max_size.push_back(attr_it->getType().maximumByteLength());
+      null_attr_idxs.push_back(
+            relation_.getNullableAttributeIndex(attr_it->getID()));
+      varlen_attr_idxs.push_back(
+            relation_.getVariableLengthAttributeIndex(attr_it->getID()));
+      // Get the fixed length offset, or set to -1 if not applicable.
+      if (varlen_attr_idxs.back() == -1) {
+        fixlen_attr_offsets.push_back(
+            relation_.getFixedLengthAttributeOffset(attr_it->getID()));
+      } else {
+        fixlen_attr_offsets.push_back(-1);
+      }
+    }
+
     if (relation_.hasNullableAttributes()) {
       if (relation_.isVariableLength()) {
         while (accessor->next()) {
@@ -227,30 +254,26 @@
           std::uint32_t current_variable_position
               = tuple_storage_bytes_ - header_->variable_length_bytes_allocated;
 
-          attribute_id accessor_attr_id = 0;
-          for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-               attr_it != relation_.end();
-               ++attr_it, ++accessor_attr_id) {
-            const int nullable_idx = relation_.getNullableAttributeIndex(attr_it->getID());
-            const int variable_idx = relation_.getVariableLengthAttributeIndex(attr_it->getID());
-            TypedValue attr_value(accessor->getTypedValue(accessor_attr_id));
-            if ((nullable_idx != -1) && (attr_value.isNull())) {
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            TypedValue attr_value(accessor->getTypedValue(curr_attr));
+            if ((null_attr_idxs[curr_attr] != -1) && attr_value.isNull()) {
               // Set null bit and move on.
-              tuple_null_bitmap.setBit(nullable_idx, true);
+              tuple_null_bitmap.setBit(null_attr_idxs[curr_attr], true);
               continue;
             }
-            if (variable_idx != -1) {
+            if (varlen_attr_idxs[curr_attr] != -1) {
+              // The attribute is variable length.
               // Write offset and size into the slot, then copy the actual
               // value into the variable-length storage region.
               const std::size_t attr_size = attr_value.getDataSize();
-              variable_length_info_array[variable_idx << 1] = current_variable_position;
-              variable_length_info_array[(variable_idx << 1) + 1] = attr_size;
+              variable_length_info_array[varlen_attr_idxs[curr_attr] << 1] = current_variable_position;
+              variable_length_info_array[(varlen_attr_idxs[curr_attr] << 1) + 1] = attr_size;
               attr_value.copyInto(static_cast<char*>(tuple_storage_) + current_variable_position);
               current_variable_position += attr_size;
             } else {
               // Copy fixed-length value directly into the slot.
               attr_value.copyInto(fixed_length_attr_storage
-                                  + relation_.getFixedLengthAttributeOffset(attr_it->getID()));
+                                  + fixlen_attr_offsets[curr_attr]);
             }
           }
           // Update occupancy bitmap and header.
@@ -261,7 +284,7 @@
           }
         }
       } else {
-        // Same as above, but skip variable-length checks.
+        // Has nullable attributes but no varlen attributes. Skip variable-length checks.
         while (accessor->next()) {
           pos = this->isPacked() ? header_->num_tuples
                                  : occupancy_bitmap_->firstZero(pos);
@@ -274,28 +297,23 @@
                                             relation_.numNullableAttributes());
           tuple_null_bitmap.clear();
           char *fixed_length_attr_storage = static_cast<char*>(tuple_slot) + per_tuple_null_bitmap_bytes_;
-
-          attribute_id accessor_attr_id = 0;
-          for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-               attr_it != relation_.end();
-               ++attr_it, ++accessor_attr_id) {
-            const int nullable_idx = relation_.getNullableAttributeIndex(attr_it->getID());
-            if (nullable_idx != -1) {
-              const void *attr_value = accessor->template getUntypedValue<true>(accessor_attr_id);
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            if (null_attr_idxs[curr_attr] != -1) {
+              const void *attr_value = accessor->template getUntypedValue<true>(curr_attr);
               if (attr_value == nullptr) {
-                tuple_null_bitmap.setBit(nullable_idx, true);
+                tuple_null_bitmap.setBit(null_attr_idxs[curr_attr], true);
               } else {
                 std::memcpy(fixed_length_attr_storage
-                                + relation_.getFixedLengthAttributeOffset(attr_it->getID()),
+                                + fixlen_attr_offsets[curr_attr],
                             attr_value,
-                            attr_it->getType().maximumByteLength());
+                            attrs_max_size[curr_attr]);
               }
             } else {
-              const void *attr_value = accessor->template getUntypedValue<false>(accessor_attr_id);
-              std::memcpy(fixed_length_attr_storage
-                              + relation_.getFixedLengthAttributeOffset(attr_it->getID()),
-                          attr_value,
-                          attr_it->getType().maximumByteLength());
+              const void *attr_value = accessor->template getUntypedValue<false>(curr_attr);
+              std::memcpy(
+                  fixed_length_attr_storage + fixlen_attr_offsets[curr_attr],
+                  attr_value, 
+                  attrs_max_size[curr_attr]);
             }
           }
           occupancy_bitmap_->setBit(pos, true);
@@ -326,21 +344,20 @@
           std::uint32_t current_variable_position
               = tuple_storage_bytes_ - header_->variable_length_bytes_allocated;
 
-          attribute_id accessor_attr_id = 0;
-          for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-               attr_it != relation_.end();
-               ++attr_it, ++accessor_attr_id) {
-            const int variable_idx = relation_.getVariableLengthAttributeIndex(attr_it->getID());
-            TypedValue attr_value(accessor->getTypedValue(accessor_attr_id));
-            if (variable_idx != -1) {
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            TypedValue attr_value(accessor->getTypedValue(curr_attr));
+            if (varlen_attr_idxs[curr_attr] != -1) {
+              // The attribute is variable length.
+              // Write offset and size into the slot, then copy the actual
+              // value into the variable-length storage region.
               const std::size_t attr_size = attr_value.getDataSize();
-              variable_length_info_array[variable_idx << 1] = current_variable_position;
-              variable_length_info_array[(variable_idx << 1) + 1] = attr_size;
+              variable_length_info_array[varlen_attr_idxs[curr_attr] << 1] = current_variable_position;
+              variable_length_info_array[(varlen_attr_idxs[curr_attr] << 1) + 1] = attr_size;
               attr_value.copyInto(static_cast<char*>(tuple_storage_) + current_variable_position);
               current_variable_position += attr_size;
             } else {
-              attr_value.copyInto(fixed_length_attr_storage
-                                  + relation_.getFixedLengthAttributeOffset(attr_it->getID()));
+              // Copy fixed-length value directly into the slot.
+              attr_value.copyInto(fixed_length_attr_storage + fixlen_attr_offsets[curr_attr]);
             }
           }
           occupancy_bitmap_->setBit(pos, true);
@@ -361,15 +378,12 @@
           void *tuple_slot = static_cast<char*>(tuple_storage_) + pos * tuple_slot_bytes_;
           char *fixed_length_attr_storage = static_cast<char*>(tuple_slot) + per_tuple_null_bitmap_bytes_;
 
-          attribute_id accessor_attr_id = 0;
-          for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-               attr_it != relation_.end();
-               ++attr_it, ++accessor_attr_id) {
-            const void *attr_value = accessor->template getUntypedValue<false>(accessor_attr_id);
-            std::memcpy(fixed_length_attr_storage
-                            + relation_.getFixedLengthAttributeOffset(attr_it->getID()),
-                        attr_value,
-                        attr_it->getType().maximumByteLength());
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            const void *attr_value = accessor->template getUntypedValue<false>(curr_attr);
+            std::memcpy(
+                fixed_length_attr_storage + fixlen_attr_offsets[curr_attr],
+                attr_value, 
+                attrs_max_size[curr_attr]);
           }
           occupancy_bitmap_->setBit(pos, true);
           ++(header_->num_tuples);
@@ -387,13 +401,39 @@
 tuple_id SplitRowStoreTupleStorageSubBlock::bulkInsertTuplesWithRemappedAttributes(
     const std::vector<attribute_id> &attribute_map,
     ValueAccessor *accessor) {
-  DEBUG_ASSERT(attribute_map.size() == relation_.size());
+  DCHECK_EQ(attribute_map.size(), relation_.size());
   const tuple_id original_num_tuples = header_->num_tuples;
   tuple_id pos = 0;
 
   InvokeOnAnyValueAccessor(
       accessor,
       [&](auto *accessor) -> void {  // NOLINT(build/c++11)
+        const std::size_t num_attrs = relation_.size();
+    // Create a vector containing the maximum sizes, null attributes, and 
+    // variable length attributes of the to-be extracted attributes.
+    // NOTE(Marc): This is an optimization so that we need not use an iterator
+    // object in the following inner loops.
+    std::vector<std::size_t> attrs_max_size;
+    std::vector<int> fixlen_attr_offsets;
+    std::vector<int> null_attr_idxs;
+    std::vector<int> varlen_attr_idxs;
+    for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
+         attr_it != relation_.end();
+         ++attr_it) {
+      attrs_max_size.push_back(attr_it->getType().maximumByteLength());
+      null_attr_idxs.push_back(
+            relation_.getNullableAttributeIndex(attr_it->getID()));
+      varlen_attr_idxs.push_back(
+            relation_.getVariableLengthAttributeIndex(attr_it->getID()));
+      // Get the fixed length offset, or set to -1 if not applicable.
+      if (varlen_attr_idxs.back() == -1) {
+        fixlen_attr_offsets.push_back(
+            relation_.getFixedLengthAttributeOffset(attr_it->getID()));
+      } else {
+        fixlen_attr_offsets.push_back(-1);
+      }
+    }
+
     if (relation_.hasNullableAttributes()) {
       if (relation_.isVariableLength()) {
         while (accessor->next()) {
@@ -418,26 +458,26 @@
           std::uint32_t current_variable_position
               = tuple_storage_bytes_ - header_->variable_length_bytes_allocated;
 
-          std::vector<attribute_id>::const_iterator attr_map_it = attribute_map.begin();
-          for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-               attr_it != relation_.end();
-               ++attr_it, ++attr_map_it) {
-            const int nullable_idx = relation_.getNullableAttributeIndex(attr_it->getID());
-            const int variable_idx = relation_.getVariableLengthAttributeIndex(attr_it->getID());
-            TypedValue attr_value(accessor->getTypedValue(*attr_map_it));
-            if ((nullable_idx != -1) && (attr_value.isNull())) {
-              tuple_null_bitmap.setBit(nullable_idx, true);
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            TypedValue attr_value(accessor->getTypedValue(attribute_map[curr_attr]));
+            if ((null_attr_idxs[curr_attr] != -1) && attr_value.isNull()) {
+              // Set null bit and move on.
+              tuple_null_bitmap.setBit(null_attr_idxs[curr_attr], true);
               continue;
             }
-            if (variable_idx != -1) {
+            if (varlen_attr_idxs[curr_attr] != -1) {
+              // The attribute is variable length.
+              // Write offset and size into the slot, then copy the actual
+              // value into the variable-length storage region.
               const std::size_t attr_size = attr_value.getDataSize();
-              variable_length_info_array[variable_idx << 1] = current_variable_position;
-              variable_length_info_array[(variable_idx << 1) + 1] = attr_size;
+              variable_length_info_array[varlen_attr_idxs[curr_attr] << 1] = current_variable_position;
+              variable_length_info_array[(varlen_attr_idxs[curr_attr] << 1) + 1] = attr_size;
               attr_value.copyInto(static_cast<char*>(tuple_storage_) + current_variable_position);
               current_variable_position += attr_size;
             } else {
+              // Copy fixed-length value directly into the slot.
               attr_value.copyInto(fixed_length_attr_storage
-                                  + relation_.getFixedLengthAttributeOffset(attr_it->getID()));
+                                  + fixlen_attr_offsets[curr_attr]);
             }
           }
           occupancy_bitmap_->setBit(pos, true);
@@ -460,27 +500,23 @@
           tuple_null_bitmap.clear();
           char *fixed_length_attr_storage = static_cast<char*>(tuple_slot) + per_tuple_null_bitmap_bytes_;
 
-          std::vector<attribute_id>::const_iterator attr_map_it = attribute_map.begin();
-          for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-               attr_it != relation_.end();
-               ++attr_it, ++attr_map_it) {
-            const int nullable_idx = relation_.getNullableAttributeIndex(attr_it->getID());
-            if (nullable_idx != -1) {
-              const void *attr_value = accessor->template getUntypedValue<true>(*attr_map_it);
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            if (null_attr_idxs[curr_attr] != -1) {
+              const void *attr_value = accessor->template getUntypedValue<true>(attribute_map[curr_attr]);
               if (attr_value == nullptr) {
-                tuple_null_bitmap.setBit(nullable_idx, true);
+                tuple_null_bitmap.setBit(null_attr_idxs[curr_attr], true);
               } else {
                 std::memcpy(fixed_length_attr_storage
-                                + relation_.getFixedLengthAttributeOffset(attr_it->getID()),
+                                + fixlen_attr_offsets[curr_attr],
                             attr_value,
-                            attr_it->getType().maximumByteLength());
+                            attrs_max_size[curr_attr]);
               }
             } else {
-              const void *attr_value = accessor->template getUntypedValue<false>(*attr_map_it);
-              std::memcpy(fixed_length_attr_storage
-                              + relation_.getFixedLengthAttributeOffset(attr_it->getID()),
-                          attr_value,
-                          attr_it->getType().maximumByteLength());
+              const void *attr_value = accessor->template getUntypedValue<false>(attribute_map[curr_attr]);
+              std::memcpy(
+                  fixed_length_attr_storage + fixlen_attr_offsets[curr_attr],
+                  attr_value, 
+                  attrs_max_size[curr_attr]);
             }
           }
           occupancy_bitmap_->setBit(pos, true);
@@ -511,21 +547,20 @@
           std::uint32_t current_variable_position
               = tuple_storage_bytes_ - header_->variable_length_bytes_allocated;
 
-          std::vector<attribute_id>::const_iterator attr_map_it = attribute_map.begin();
-          for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-               attr_it != relation_.end();
-               ++attr_it, ++attr_map_it) {
-            const int variable_idx = relation_.getVariableLengthAttributeIndex(attr_it->getID());
-            TypedValue attr_value(accessor->getTypedValue(*attr_map_it));
-            if (variable_idx != -1) {
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            TypedValue attr_value(accessor->getTypedValue(attribute_map[curr_attr]));
+            if (varlen_attr_idxs[curr_attr] != -1) {
+              // The attribute is variable length.
+              // Write offset and size into the slot, then copy the actual
+              // value into the variable-length storage region.
               const std::size_t attr_size = attr_value.getDataSize();
-              variable_length_info_array[variable_idx << 1] = current_variable_position;
-              variable_length_info_array[(variable_idx << 1) + 1] = attr_size;
+              variable_length_info_array[varlen_attr_idxs[curr_attr] << 1] = current_variable_position;
+              variable_length_info_array[(varlen_attr_idxs[curr_attr] << 1) + 1] = attr_size;
               attr_value.copyInto(static_cast<char*>(tuple_storage_) + current_variable_position);
               current_variable_position += attr_size;
             } else {
-              attr_value.copyInto(fixed_length_attr_storage
-                                  + relation_.getFixedLengthAttributeOffset(attr_it->getID()));
+              // Copy fixed-length value directly into the slot.
+              attr_value.copyInto(fixed_length_attr_storage + fixlen_attr_offsets[curr_attr]);
             }
           }
           occupancy_bitmap_->setBit(pos, true);
@@ -545,15 +580,12 @@
           void *tuple_slot = static_cast<char*>(tuple_storage_) + pos * tuple_slot_bytes_;
           char *fixed_length_attr_storage = static_cast<char*>(tuple_slot) + per_tuple_null_bitmap_bytes_;
 
-          std::vector<attribute_id>::const_iterator attr_map_it = attribute_map.begin();
-          for (CatalogRelationSchema::const_iterator attr_it = relation_.begin();
-               attr_it != relation_.end();
-               ++attr_it, ++attr_map_it) {
-            const void *attr_value = accessor->template getUntypedValue<false>(*attr_map_it);
-            std::memcpy(fixed_length_attr_storage
-                            + relation_.getFixedLengthAttributeOffset(attr_it->getID()),
-                        attr_value,
-                        attr_it->getType().maximumByteLength());
+          for (std::size_t curr_attr = 0; curr_attr < num_attrs; ++curr_attr) {
+            const void *attr_value = accessor->template getUntypedValue<false>(attribute_map[curr_attr]);
+            std::memcpy(
+                fixed_length_attr_storage + fixlen_attr_offsets[curr_attr],
+                attr_value, 
+                attrs_max_size[curr_attr]);
           }
           occupancy_bitmap_->setBit(pos, true);
           ++(header_->num_tuples);