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
13using namespace duckdb;
14using namespace std;
15
16template <class T>
17static 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
27void 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
173void 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