| 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 | |
| 10 | using namespace duckdb; |
| 11 | using namespace std; |
| 12 | |
| 13 | template <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 | |
| 19 | static 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 |
| 25 | static 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 | |
| 38 | template <class SRC> |
| 39 | static 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 | |
| 88 | template <class OP> |
| 89 | static 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 | |
| 128 | static 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 | |
| 166 | static 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 | |
| 183 | static 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 | |
| 196 | static 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 | |
| 218 | static 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 | |
| 232 | void 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 | |
| 297 | void 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 | |