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 | |