1//===--------------------------------------------------------------------===//
2// cast_operators.cpp
3// Description: This file contains the implementation of the different casts
4//===--------------------------------------------------------------------===//
5#include "duckdb/common/operator/cast_operators.hpp"
6#include "duckdb/common/types/chunk_collection.hpp"
7#include "duckdb/common/vector_operations/unary_executor.hpp"
8#include "duckdb/common/vector_operations/vector_operations.hpp"
9
10using namespace duckdb;
11using namespace std;
12
13template <class SRC, class OP> static void string_cast(Vector &source, Vector &result, idx_t count) {
14 assert(result.type == TypeId::VARCHAR);
15 UnaryExecutor::Execute<SRC, string_t, true>(source, result, count,
16 [&](SRC input) { return OP::template Operation<SRC>(input, result); });
17}
18
19static NotImplementedException UnimplementedCast(SQLType source_type, SQLType target_type) {
20 return NotImplementedException("Unimplemented type for cast (%s -> %s)", SQLTypeToString(source_type).c_str(),
21 SQLTypeToString(target_type).c_str());
22}
23
24// NULL cast only works if all values in source are NULL, otherwise an unimplemented cast exception is thrown
25static void null_cast(Vector &source, Vector &result, SQLType source_type, SQLType target_type, idx_t count) {
26 if (VectorOperations::HasNotNull(source, count)) {
27 throw UnimplementedCast(source_type, target_type);
28 }
29 if (source.vector_type == VectorType::CONSTANT_VECTOR) {
30 result.vector_type = VectorType::CONSTANT_VECTOR;
31 ConstantVector::SetNull(result, true);
32 } else {
33 result.vector_type = VectorType::FLAT_VECTOR;
34 FlatVector::Nullmask(result).set();
35 }
36}
37
38template <class SRC>
39static void numeric_cast_switch(Vector &source, Vector &result, SQLType source_type, SQLType target_type, idx_t count) {
40 // now switch on the result type
41 switch (target_type.id) {
42 case SQLTypeId::BOOLEAN:
43 assert(result.type == TypeId::BOOL);
44 UnaryExecutor::Execute<SRC, bool, duckdb::Cast, true>(source, result, count);
45 break;
46 case SQLTypeId::TINYINT:
47 assert(result.type == TypeId::INT8);
48 UnaryExecutor::Execute<SRC, int8_t, duckdb::Cast, true>(source, result, count);
49 break;
50 case SQLTypeId::SMALLINT:
51 assert(result.type == TypeId::INT16);
52 UnaryExecutor::Execute<SRC, int16_t, duckdb::Cast, true>(source, result, count);
53 break;
54 case SQLTypeId::INTEGER:
55 assert(result.type == TypeId::INT32);
56 UnaryExecutor::Execute<SRC, int32_t, duckdb::Cast, true>(source, result, count);
57 break;
58 case SQLTypeId::BIGINT:
59 assert(result.type == TypeId::INT64);
60 UnaryExecutor::Execute<SRC, int64_t, duckdb::Cast, true>(source, result, count);
61 break;
62 case SQLTypeId::FLOAT:
63 assert(result.type == TypeId::FLOAT);
64 UnaryExecutor::Execute<SRC, float, duckdb::Cast, true>(source, result, count);
65 break;
66 case SQLTypeId::DECIMAL:
67 case SQLTypeId::DOUBLE:
68 assert(result.type == TypeId::DOUBLE);
69 UnaryExecutor::Execute<SRC, double, duckdb::Cast, true>(source, result, count);
70 break;
71 case SQLTypeId::VARCHAR: {
72 string_cast<SRC, duckdb::StringCast>(source, result, count);
73 break;
74 }
75 case SQLTypeId::LIST: {
76 assert(result.type == TypeId::LIST);
77 auto list_child = make_unique<ChunkCollection>();
78 ListVector::SetEntry(result, move(list_child));
79 null_cast(source, result, source_type, target_type, count);
80 break;
81 }
82 default:
83 null_cast(source, result, source_type, target_type, count);
84 break;
85 }
86}
87
88template <class OP>
89static void string_cast_numric_switch(Vector &source, Vector &result, SQLType source_type, SQLType target_type,
90 idx_t count) {
91 // now switch on the result type
92 switch (target_type.id) {
93 case SQLTypeId::BOOLEAN:
94 assert(result.type == TypeId::BOOL);
95 UnaryExecutor::Execute<string_t, bool, OP, true>(source, result, count);
96 break;
97 case SQLTypeId::TINYINT:
98 assert(result.type == TypeId::INT8);
99 UnaryExecutor::Execute<string_t, int8_t, OP, true>(source, result, count);
100 break;
101 case SQLTypeId::SMALLINT:
102 assert(result.type == TypeId::INT16);
103 UnaryExecutor::Execute<string_t, int16_t, OP, true>(source, result, count);
104 break;
105 case SQLTypeId::INTEGER:
106 assert(result.type == TypeId::INT32);
107 UnaryExecutor::Execute<string_t, int32_t, OP, true>(source, result, count);
108 break;
109 case SQLTypeId::BIGINT:
110 assert(result.type == TypeId::INT64);
111 UnaryExecutor::Execute<string_t, int64_t, OP, true>(source, result, count);
112 break;
113 case SQLTypeId::FLOAT:
114 assert(result.type == TypeId::FLOAT);
115 UnaryExecutor::Execute<string_t, float, OP, true>(source, result, count);
116 break;
117 case SQLTypeId::DECIMAL:
118 case SQLTypeId::DOUBLE:
119 assert(result.type == TypeId::DOUBLE);
120 UnaryExecutor::Execute<string_t, double, OP, true>(source, result, count);
121 break;
122 default:
123 null_cast(source, result, source_type, target_type, count);
124 break;
125 }
126}
127
128static void string_cast_switch(Vector &source, Vector &result, SQLType source_type, SQLType target_type, idx_t count,
129 bool strict = false) {
130 // now switch on the result type
131 switch (target_type.id) {
132 case SQLTypeId::DATE:
133 assert(result.type == TypeId::INT32);
134 if (strict) {
135 UnaryExecutor::Execute<string_t, date_t, duckdb::StrictCastToDate, true>(source, result, count);
136 } else {
137 UnaryExecutor::Execute<string_t, date_t, duckdb::CastToDate, true>(source, result, count);
138 }
139 break;
140 case SQLTypeId::TIME:
141 assert(result.type == TypeId::INT32);
142 if (strict) {
143 UnaryExecutor::Execute<string_t, dtime_t, duckdb::StrictCastToTime, true>(source, result, count);
144 } else {
145 UnaryExecutor::Execute<string_t, dtime_t, duckdb::CastToTime, true>(source, result, count);
146 }
147 break;
148 case SQLTypeId::TIMESTAMP:
149 assert(result.type == TypeId::INT64);
150 UnaryExecutor::Execute<string_t, timestamp_t, duckdb::CastToTimestamp, true>(source, result, count);
151 break;
152 case SQLTypeId::BLOB:
153 assert(result.type == TypeId::VARCHAR);
154 string_cast<string_t, duckdb::CastToBlob>(source, result, count);
155 break;
156 default:
157 if (strict) {
158 string_cast_numric_switch<duckdb::StrictCast>(source, result, source_type, target_type, count);
159 } else {
160 string_cast_numric_switch<duckdb::Cast>(source, result, source_type, target_type, count);
161 }
162 break;
163 }
164}
165
166static void date_cast_switch(Vector &source, Vector &result, SQLType source_type, SQLType target_type, idx_t count) {
167 // now switch on the result type
168 switch (target_type.id) {
169 case SQLTypeId::VARCHAR:
170 // date to varchar
171 string_cast<date_t, duckdb::CastFromDate>(source, result, count);
172 break;
173 case SQLTypeId::TIMESTAMP:
174 // date to timestamp
175 UnaryExecutor::Execute<date_t, timestamp_t, duckdb::CastDateToTimestamp, true>(source, result, count);
176 break;
177 default:
178 null_cast(source, result, source_type, target_type, count);
179 break;
180 }
181}
182
183static void time_cast_switch(Vector &source, Vector &result, SQLType source_type, SQLType target_type, idx_t count) {
184 // now switch on the result type
185 switch (target_type.id) {
186 case SQLTypeId::VARCHAR:
187 // time to varchar
188 string_cast<dtime_t, duckdb::CastFromTime>(source, result, count);
189 break;
190 default:
191 null_cast(source, result, source_type, target_type, count);
192 break;
193 }
194}
195
196static void timestamp_cast_switch(Vector &source, Vector &result, SQLType source_type, SQLType target_type,
197 idx_t count) {
198 // now switch on the result type
199 switch (target_type.id) {
200 case SQLTypeId::VARCHAR:
201 // timestamp to varchar
202 string_cast<timestamp_t, duckdb::CastFromTimestamp>(source, result, count);
203 break;
204 case SQLTypeId::DATE:
205 // timestamp to date
206 UnaryExecutor::Execute<timestamp_t, date_t, duckdb::CastTimestampToDate, true>(source, result, count);
207 break;
208 case SQLTypeId::TIME:
209 // timestamp to time
210 UnaryExecutor::Execute<timestamp_t, dtime_t, duckdb::CastTimestampToTime, true>(source, result, count);
211 break;
212 default:
213 null_cast(source, result, source_type, target_type, count);
214 break;
215 }
216}
217
218static void blob_cast_switch(Vector &source, Vector &result, SQLType source_type, SQLType target_type,
219 idx_t count) {
220 // now switch on the result type
221 switch (target_type.id) {
222 case SQLTypeId::VARCHAR:
223 // blob to varchar
224 string_cast<string_t, duckdb::CastFromBlob>(source, result, count);
225 break;
226 default:
227 null_cast(source, result, source_type, target_type, count);
228 break;
229 }
230}
231
232void VectorOperations::Cast(Vector &source, Vector &result, SQLType source_type, SQLType target_type, idx_t count,
233 bool strict) {
234 assert(source_type != target_type);
235 // first switch on source type
236 switch (source_type.id) {
237 case SQLTypeId::BOOLEAN:
238 assert(source.type == TypeId::BOOL);
239 numeric_cast_switch<bool>(source, result, source_type, target_type, count);
240 break;
241 case SQLTypeId::TINYINT:
242 assert(source.type == TypeId::INT8);
243 numeric_cast_switch<int8_t>(source, result, source_type, target_type, count);
244 break;
245 case SQLTypeId::SMALLINT:
246 assert(source.type == TypeId::INT16);
247 numeric_cast_switch<int16_t>(source, result, source_type, target_type, count);
248 break;
249 case SQLTypeId::INTEGER:
250 assert(source.type == TypeId::INT32);
251 numeric_cast_switch<int32_t>(source, result, source_type, target_type, count);
252 break;
253 case SQLTypeId::BIGINT:
254 assert(source.type == TypeId::INT64);
255 numeric_cast_switch<int64_t>(source, result, source_type, target_type, count);
256 break;
257 case SQLTypeId::FLOAT:
258 assert(source.type == TypeId::FLOAT);
259 numeric_cast_switch<float>(source, result, source_type, target_type, count);
260 break;
261 case SQLTypeId::DECIMAL:
262 case SQLTypeId::DOUBLE:
263 assert(source.type == TypeId::DOUBLE);
264 numeric_cast_switch<double>(source, result, source_type, target_type, count);
265 break;
266 case SQLTypeId::DATE:
267 assert(source.type == TypeId::INT32);
268 date_cast_switch(source, result, source_type, target_type, count);
269 break;
270 case SQLTypeId::TIME:
271 assert(source.type == TypeId::INT32);
272 time_cast_switch(source, result, source_type, target_type, count);
273 break;
274 case SQLTypeId::TIMESTAMP:
275 assert(source.type == TypeId::INT64);
276 timestamp_cast_switch(source, result, source_type, target_type, count);
277 break;
278 case SQLTypeId::VARCHAR:
279 assert(source.type == TypeId::VARCHAR);
280 string_cast_switch(source, result, source_type, target_type, count, strict);
281 break;
282 case SQLTypeId::BLOB:
283 assert(source.type == TypeId::VARCHAR);
284 blob_cast_switch(source, result, source_type, target_type, count);
285 break;
286 case SQLTypeId::SQLNULL: {
287 // cast a NULL to another type, just copy the properties and change the type
288 result.vector_type = VectorType::CONSTANT_VECTOR;
289 ConstantVector::SetNull(result, true);
290 break;
291 }
292 default:
293 throw UnimplementedCast(source_type, target_type);
294 }
295}
296
297void VectorOperations::Cast(Vector &source, Vector &result, idx_t count, bool strict) {
298 return VectorOperations::Cast(source, result, SQLTypeFromInternalType(source.type),
299 SQLTypeFromInternalType(result.type), count, strict);
300}
301