| 1 | //===--------------------------------------------------------------------===// |
| 2 | // copy.cpp |
| 3 | // Description: This file contains the implementation of the different copy |
| 4 | // functions |
| 5 | //===--------------------------------------------------------------------===// |
| 6 | |
| 7 | #include "duckdb/common/exception.hpp" |
| 8 | #include "duckdb/common/types/null_value.hpp" |
| 9 | #include "duckdb/common/types/chunk_collection.hpp" |
| 10 | |
| 11 | #include "duckdb/common/vector_operations/vector_operations.hpp" |
| 12 | |
| 13 | using namespace duckdb; |
| 14 | using namespace std; |
| 15 | |
| 16 | template <class T> |
| 17 | static void TemplatedCopy(Vector &source, const SelectionVector &sel, Vector &target, idx_t source_offset, |
| 18 | idx_t target_offset, idx_t copy_count) { |
| 19 | auto ldata = FlatVector::GetData<T>(source); |
| 20 | auto tdata = FlatVector::GetData<T>(target); |
| 21 | for (idx_t i = 0; i < copy_count; i++) { |
| 22 | auto source_idx = sel.get_index(source_offset + i); |
| 23 | tdata[target_offset + i] = ldata[source_idx]; |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | void VectorOperations::Copy(Vector &source, Vector &target, const SelectionVector &sel, idx_t source_count, |
| 28 | idx_t source_offset, idx_t target_offset) { |
| 29 | assert(source_offset <= source_count); |
| 30 | assert(target.vector_type == VectorType::FLAT_VECTOR); |
| 31 | assert(source.type == target.type); |
| 32 | switch (source.vector_type) { |
| 33 | case VectorType::DICTIONARY_VECTOR: { |
| 34 | // dictionary vector: merge selection vectors |
| 35 | auto &child = DictionaryVector::Child(source); |
| 36 | auto &dict_sel = DictionaryVector::SelVector(source); |
| 37 | // merge the selection vectors and verify the child |
| 38 | auto new_buffer = dict_sel.Slice(sel, source_count); |
| 39 | SelectionVector merged_sel(new_buffer); |
| 40 | VectorOperations::Copy(child, target, merged_sel, source_count, source_offset, target_offset); |
| 41 | return; |
| 42 | } |
| 43 | case VectorType::SEQUENCE_VECTOR: { |
| 44 | int64_t start, increment; |
| 45 | Vector seq(source.type); |
| 46 | SequenceVector::GetSequence(source, start, increment); |
| 47 | VectorOperations::GenerateSequence(seq, source_count, sel, start, increment); |
| 48 | VectorOperations::Copy(seq, target, sel, source_count, source_offset, target_offset); |
| 49 | return; |
| 50 | } |
| 51 | case VectorType::CONSTANT_VECTOR: |
| 52 | case VectorType::FLAT_VECTOR: |
| 53 | break; |
| 54 | default: |
| 55 | throw NotImplementedException("FIXME unimplemented vector type for VectorOperations::Copy" ); |
| 56 | } |
| 57 | |
| 58 | idx_t copy_count = source_count - source_offset; |
| 59 | assert(target_offset + copy_count <= STANDARD_VECTOR_SIZE); |
| 60 | if (copy_count == 0) { |
| 61 | return; |
| 62 | } |
| 63 | |
| 64 | // first copy the nullmask |
| 65 | auto &tmask = FlatVector::Nullmask(target); |
| 66 | if (source.vector_type == VectorType::CONSTANT_VECTOR) { |
| 67 | if (ConstantVector::IsNull(source)) { |
| 68 | for (idx_t i = 0; i < copy_count; i++) { |
| 69 | tmask[target_offset + i] = true; |
| 70 | } |
| 71 | } |
| 72 | } else { |
| 73 | auto &smask = FlatVector::Nullmask(source); |
| 74 | for (idx_t i = 0; i < copy_count; i++) { |
| 75 | auto idx = sel.get_index(source_offset + i); |
| 76 | tmask[target_offset + i] = smask[idx]; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | // now copy over the data |
| 81 | switch (source.type) { |
| 82 | case TypeId::BOOL: |
| 83 | case TypeId::INT8: |
| 84 | TemplatedCopy<int8_t>(source, sel, target, source_offset, target_offset, copy_count); |
| 85 | break; |
| 86 | case TypeId::INT16: |
| 87 | TemplatedCopy<int16_t>(source, sel, target, source_offset, target_offset, copy_count); |
| 88 | break; |
| 89 | case TypeId::INT32: |
| 90 | TemplatedCopy<int32_t>(source, sel, target, source_offset, target_offset, copy_count); |
| 91 | break; |
| 92 | case TypeId::INT64: |
| 93 | TemplatedCopy<int64_t>(source, sel, target, source_offset, target_offset, copy_count); |
| 94 | break; |
| 95 | case TypeId::POINTER: |
| 96 | TemplatedCopy<uintptr_t>(source, sel, target, source_offset, target_offset, copy_count); |
| 97 | break; |
| 98 | case TypeId::FLOAT: |
| 99 | TemplatedCopy<float>(source, sel, target, source_offset, target_offset, copy_count); |
| 100 | break; |
| 101 | case TypeId::DOUBLE: |
| 102 | TemplatedCopy<double>(source, sel, target, source_offset, target_offset, copy_count); |
| 103 | break; |
| 104 | case TypeId::VARCHAR: { |
| 105 | auto ldata = FlatVector::GetData<string_t>(source); |
| 106 | auto tdata = FlatVector::GetData<string_t>(target); |
| 107 | for (idx_t i = 0; i < copy_count; i++) { |
| 108 | auto source_idx = sel.get_index(source_offset + i); |
| 109 | auto target_idx = target_offset + i; |
| 110 | if (!tmask[target_idx]) { |
| 111 | tdata[target_idx] = StringVector::AddBlob(target, ldata[source_idx]); |
| 112 | } |
| 113 | } |
| 114 | break; |
| 115 | } |
| 116 | case TypeId::STRUCT: { |
| 117 | if (StructVector::HasEntries(target)) { |
| 118 | // target already has entries: append to them |
| 119 | auto &source_children = StructVector::GetEntries(source); |
| 120 | auto &target_children = StructVector::GetEntries(target); |
| 121 | assert(source_children.size() == target_children.size()); |
| 122 | for (idx_t i = 0; i < source_children.size(); i++) { |
| 123 | assert(target_children[i].first == target_children[i].first); |
| 124 | VectorOperations::Copy(*source_children[i].second, *target_children[i].second, sel, source_count, |
| 125 | source_offset, target_offset); |
| 126 | } |
| 127 | } else { |
| 128 | assert(target_offset == 0); |
| 129 | // target has no entries: create new entries for the target |
| 130 | auto &source_children = StructVector::GetEntries(source); |
| 131 | for (auto &child : source_children) { |
| 132 | auto child_copy = make_unique<Vector>(child.second->type); |
| 133 | |
| 134 | VectorOperations::Copy(*child.second, *child_copy, sel, source_count, source_offset, target_offset); |
| 135 | StructVector::AddEntry(target, child.first, move(child_copy)); |
| 136 | } |
| 137 | } |
| 138 | break; |
| 139 | } |
| 140 | case TypeId::LIST: { |
| 141 | assert(target.type == TypeId::LIST); |
| 142 | if (ListVector::HasEntry(source)) { |
| 143 | // if the source has list offsets, we need to append them to the target |
| 144 | if (!ListVector::HasEntry(target)) { |
| 145 | auto new_target_child = make_unique<ChunkCollection>(); |
| 146 | ListVector::SetEntry(target, move(new_target_child)); |
| 147 | } |
| 148 | auto &source_child = ListVector::GetEntry(source); |
| 149 | auto &target_child = ListVector::GetEntry(target); |
| 150 | idx_t old_target_child_len = target_child.count; |
| 151 | |
| 152 | // append to list itself |
| 153 | target_child.Append(source_child); |
| 154 | // now write the list offsets |
| 155 | auto ldata = FlatVector::GetData<list_entry_t>(source); |
| 156 | auto tdata = FlatVector::GetData<list_entry_t>(target); |
| 157 | for (idx_t i = 0; i < copy_count; i++) { |
| 158 | auto source_idx = sel.get_index(source_offset + i); |
| 159 | auto &source_entry = ldata[source_idx]; |
| 160 | auto &target_entry = tdata[target_offset + i]; |
| 161 | |
| 162 | target_entry.length = source_entry.length; |
| 163 | target_entry.offset = old_target_child_len + source_entry.offset; |
| 164 | } |
| 165 | } |
| 166 | break; |
| 167 | } |
| 168 | default: |
| 169 | throw NotImplementedException("Unimplemented type for copy!" ); |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | void VectorOperations::Copy(Vector &source, Vector &target, idx_t source_count, idx_t source_offset, |
| 174 | idx_t target_offset) { |
| 175 | switch (source.vector_type) { |
| 176 | case VectorType::DICTIONARY_VECTOR: { |
| 177 | // dictionary: continue into child with selection vector |
| 178 | auto &child = DictionaryVector::Child(source); |
| 179 | auto &dict_sel = DictionaryVector::SelVector(source); |
| 180 | VectorOperations::Copy(child, target, dict_sel, source_count, source_offset, target_offset); |
| 181 | break; |
| 182 | } |
| 183 | case VectorType::CONSTANT_VECTOR: |
| 184 | VectorOperations::Copy(source, target, ConstantVector::ZeroSelectionVector, source_count, source_offset, |
| 185 | target_offset); |
| 186 | break; |
| 187 | default: |
| 188 | source.Normalify(source_count); |
| 189 | VectorOperations::Copy(source, target, FlatVector::IncrementalSelectionVector, source_count, source_offset, |
| 190 | target_offset); |
| 191 | break; |
| 192 | } |
| 193 | } |
| 194 | |