| 1 | #include "duckdb/function/cast/default_casts.hpp" |
| 2 | #include "duckdb/function/cast/vector_cast_helpers.hpp" |
| 3 | #include "duckdb/common/pair.hpp" |
| 4 | #include "duckdb/common/vector.hpp" |
| 5 | #include "duckdb/function/scalar/nested_functions.hpp" |
| 6 | #include "duckdb/function/cast/bound_cast_data.hpp" |
| 7 | |
| 8 | namespace duckdb { |
| 9 | |
| 10 | template <class T> |
| 11 | bool StringEnumCastLoop(const string_t *source_data, ValidityMask &source_mask, const LogicalType &source_type, |
| 12 | T *result_data, ValidityMask &result_mask, const LogicalType &result_type, idx_t count, |
| 13 | string *error_message, const SelectionVector *sel) { |
| 14 | bool all_converted = true; |
| 15 | for (idx_t i = 0; i < count; i++) { |
| 16 | idx_t source_idx = i; |
| 17 | if (sel) { |
| 18 | source_idx = sel->get_index(idx: i); |
| 19 | } |
| 20 | if (source_mask.RowIsValid(row_idx: source_idx)) { |
| 21 | auto pos = EnumType::GetPos(type: result_type, key: source_data[source_idx]); |
| 22 | if (pos == -1) { |
| 23 | result_data[i] = |
| 24 | HandleVectorCastError::Operation<T>(CastExceptionText<string_t, T>(source_data[source_idx]), |
| 25 | result_mask, i, error_message, all_converted); |
| 26 | } else { |
| 27 | result_data[i] = pos; |
| 28 | } |
| 29 | } else { |
| 30 | result_mask.SetInvalid(i); |
| 31 | } |
| 32 | } |
| 33 | return all_converted; |
| 34 | } |
| 35 | |
| 36 | template <class T> |
| 37 | bool StringEnumCast(Vector &source, Vector &result, idx_t count, CastParameters ¶meters) { |
| 38 | D_ASSERT(source.GetType().id() == LogicalTypeId::VARCHAR); |
| 39 | auto enum_name = EnumType::GetTypeName(type: result.GetType()); |
| 40 | switch (source.GetVectorType()) { |
| 41 | case VectorType::CONSTANT_VECTOR: { |
| 42 | result.SetVectorType(VectorType::CONSTANT_VECTOR); |
| 43 | |
| 44 | auto source_data = ConstantVector::GetData<string_t>(vector&: source); |
| 45 | auto source_mask = ConstantVector::Validity(vector&: source); |
| 46 | auto result_data = ConstantVector::GetData<T>(result); |
| 47 | auto &result_mask = ConstantVector::Validity(vector&: result); |
| 48 | |
| 49 | return StringEnumCastLoop(source_data, source_mask, source.GetType(), result_data, result_mask, |
| 50 | result.GetType(), 1, parameters.error_message, nullptr); |
| 51 | } |
| 52 | default: { |
| 53 | UnifiedVectorFormat vdata; |
| 54 | source.ToUnifiedFormat(count, data&: vdata); |
| 55 | |
| 56 | result.SetVectorType(VectorType::FLAT_VECTOR); |
| 57 | |
| 58 | auto source_data = UnifiedVectorFormat::GetData<string_t>(format: vdata); |
| 59 | auto source_sel = vdata.sel; |
| 60 | auto source_mask = vdata.validity; |
| 61 | auto result_data = FlatVector::GetData<T>(result); |
| 62 | auto &result_mask = FlatVector::Validity(vector&: result); |
| 63 | |
| 64 | return StringEnumCastLoop(source_data, source_mask, source.GetType(), result_data, result_mask, |
| 65 | result.GetType(), count, parameters.error_message, source_sel); |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | static BoundCastInfo VectorStringCastNumericSwitch(BindCastInput &input, const LogicalType &source, |
| 71 | const LogicalType &target) { |
| 72 | // now switch on the result type |
| 73 | switch (target.id()) { |
| 74 | case LogicalTypeId::ENUM: { |
| 75 | switch (target.InternalType()) { |
| 76 | case PhysicalType::UINT8: |
| 77 | return StringEnumCast<uint8_t>; |
| 78 | case PhysicalType::UINT16: |
| 79 | return StringEnumCast<uint16_t>; |
| 80 | case PhysicalType::UINT32: |
| 81 | return StringEnumCast<uint32_t>; |
| 82 | default: |
| 83 | throw InternalException("ENUM can only have unsigned integers (except UINT64) as physical types" ); |
| 84 | } |
| 85 | } |
| 86 | case LogicalTypeId::BOOLEAN: |
| 87 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, bool, duckdb::TryCast>); |
| 88 | case LogicalTypeId::TINYINT: |
| 89 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, int8_t, duckdb::TryCast>); |
| 90 | case LogicalTypeId::SMALLINT: |
| 91 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, int16_t, duckdb::TryCast>); |
| 92 | case LogicalTypeId::INTEGER: |
| 93 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, int32_t, duckdb::TryCast>); |
| 94 | case LogicalTypeId::BIGINT: |
| 95 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, int64_t, duckdb::TryCast>); |
| 96 | case LogicalTypeId::UTINYINT: |
| 97 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, uint8_t, duckdb::TryCast>); |
| 98 | case LogicalTypeId::USMALLINT: |
| 99 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, uint16_t, duckdb::TryCast>); |
| 100 | case LogicalTypeId::UINTEGER: |
| 101 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, uint32_t, duckdb::TryCast>); |
| 102 | case LogicalTypeId::UBIGINT: |
| 103 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, uint64_t, duckdb::TryCast>); |
| 104 | case LogicalTypeId::HUGEINT: |
| 105 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, hugeint_t, duckdb::TryCast>); |
| 106 | case LogicalTypeId::FLOAT: |
| 107 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, float, duckdb::TryCast>); |
| 108 | case LogicalTypeId::DOUBLE: |
| 109 | return BoundCastInfo(&VectorCastHelpers::TryCastStrictLoop<string_t, double, duckdb::TryCast>); |
| 110 | case LogicalTypeId::INTERVAL: |
| 111 | return BoundCastInfo(&VectorCastHelpers::TryCastErrorLoop<string_t, interval_t, duckdb::TryCastErrorMessage>); |
| 112 | case LogicalTypeId::DECIMAL: |
| 113 | return BoundCastInfo(&VectorCastHelpers::ToDecimalCast<string_t>); |
| 114 | default: |
| 115 | return DefaultCasts::TryVectorNullCast; |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | //===--------------------------------------------------------------------===// |
| 120 | // string -> list casting |
| 121 | //===--------------------------------------------------------------------===// |
| 122 | bool VectorStringToList::StringToNestedTypeCastLoop(const string_t *source_data, ValidityMask &source_mask, |
| 123 | Vector &result, ValidityMask &result_mask, idx_t count, |
| 124 | CastParameters ¶meters, const SelectionVector *sel) { |
| 125 | idx_t total_list_size = 0; |
| 126 | for (idx_t i = 0; i < count; i++) { |
| 127 | idx_t idx = i; |
| 128 | if (sel) { |
| 129 | idx = sel->get_index(idx: i); |
| 130 | } |
| 131 | if (!source_mask.RowIsValid(row_idx: idx)) { |
| 132 | continue; |
| 133 | } |
| 134 | total_list_size += VectorStringToList::CountPartsList(input: source_data[idx]); |
| 135 | } |
| 136 | |
| 137 | Vector varchar_vector(LogicalType::VARCHAR, total_list_size); |
| 138 | |
| 139 | ListVector::Reserve(vec&: result, required_capacity: total_list_size); |
| 140 | ListVector::SetListSize(vec&: result, size: total_list_size); |
| 141 | |
| 142 | auto list_data = ListVector::GetData(v&: result); |
| 143 | auto child_data = FlatVector::GetData<string_t>(vector&: varchar_vector); |
| 144 | |
| 145 | bool all_converted = true; |
| 146 | idx_t total = 0; |
| 147 | for (idx_t i = 0; i < count; i++) { |
| 148 | idx_t idx = i; |
| 149 | if (sel) { |
| 150 | idx = sel->get_index(idx: i); |
| 151 | } |
| 152 | if (!source_mask.RowIsValid(row_idx: idx)) { |
| 153 | result_mask.SetInvalid(i); |
| 154 | continue; |
| 155 | } |
| 156 | |
| 157 | list_data[i].offset = total; |
| 158 | if (!VectorStringToList::SplitStringList(input: source_data[idx], child_data, child_start&: total, child&: varchar_vector)) { |
| 159 | string text = "Type VARCHAR with value '" + source_data[idx].GetString() + |
| 160 | "' can't be cast to the destination type LIST" ; |
| 161 | HandleVectorCastError::Operation<string_t>(error_message: text, mask&: result_mask, idx, error_message_ptr: parameters.error_message, all_converted); |
| 162 | } |
| 163 | list_data[i].length = total - list_data[i].offset; // length is the amount of parts coming from this string |
| 164 | } |
| 165 | D_ASSERT(total_list_size == total); |
| 166 | |
| 167 | auto &result_child = ListVector::GetEntry(vector&: result); |
| 168 | auto &cast_data = parameters.cast_data->Cast<ListBoundCastData>(); |
| 169 | CastParameters child_parameters(parameters, cast_data.child_cast_info.cast_data, parameters.local_state); |
| 170 | return cast_data.child_cast_info.function(varchar_vector, result_child, total_list_size, child_parameters) && |
| 171 | all_converted; |
| 172 | } |
| 173 | |
| 174 | static LogicalType InitVarcharStructType(const LogicalType &target) { |
| 175 | child_list_t<LogicalType> child_types; |
| 176 | for (auto &child : StructType::GetChildTypes(type: target)) { |
| 177 | child_types.push_back(x: make_pair(x: child.first, y: LogicalType::VARCHAR)); |
| 178 | } |
| 179 | |
| 180 | return LogicalType::STRUCT(children: child_types); |
| 181 | } |
| 182 | |
| 183 | //===--------------------------------------------------------------------===// |
| 184 | // string -> struct casting |
| 185 | //===--------------------------------------------------------------------===// |
| 186 | bool VectorStringToStruct::StringToNestedTypeCastLoop(const string_t *source_data, ValidityMask &source_mask, |
| 187 | Vector &result, ValidityMask &result_mask, idx_t count, |
| 188 | CastParameters ¶meters, const SelectionVector *sel) { |
| 189 | auto varchar_struct_type = InitVarcharStructType(target: result.GetType()); |
| 190 | Vector varchar_vector(varchar_struct_type, count); |
| 191 | auto &child_vectors = StructVector::GetEntries(vector&: varchar_vector); |
| 192 | auto &result_children = StructVector::GetEntries(vector&: result); |
| 193 | |
| 194 | string_map_t<idx_t> child_names; |
| 195 | vector<ValidityMask *> child_masks; |
| 196 | for (idx_t child_idx = 0; child_idx < result_children.size(); child_idx++) { |
| 197 | child_names.insert(x: {StructType::GetChildName(type: result.GetType(), index: child_idx), child_idx}); |
| 198 | child_masks.emplace_back(args: &FlatVector::Validity(vector&: *child_vectors[child_idx])); |
| 199 | child_masks[child_idx]->SetAllInvalid(count); |
| 200 | } |
| 201 | |
| 202 | bool all_converted = true; |
| 203 | for (idx_t i = 0; i < count; i++) { |
| 204 | idx_t idx = i; |
| 205 | if (sel) { |
| 206 | idx = sel->get_index(idx: i); |
| 207 | } |
| 208 | if (!source_mask.RowIsValid(row_idx: idx)) { |
| 209 | result_mask.SetInvalid(i); |
| 210 | continue; |
| 211 | } |
| 212 | if (!VectorStringToStruct::SplitStruct(input: source_data[idx], varchar_vectors&: child_vectors, row_idx&: i, child_names, child_masks)) { |
| 213 | string text = "Type VARCHAR with value '" + source_data[idx].GetString() + |
| 214 | "' can't be cast to the destination type STRUCT" ; |
| 215 | for (auto &child_mask : child_masks) { |
| 216 | child_mask->SetInvalid(idx); // some values may have already been found and set valid |
| 217 | } |
| 218 | HandleVectorCastError::Operation<string_t>(error_message: text, mask&: result_mask, idx, error_message_ptr: parameters.error_message, all_converted); |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | auto &cast_data = parameters.cast_data->Cast<StructBoundCastData>(); |
| 223 | auto &lstate = parameters.local_state->Cast<StructCastLocalState>(); |
| 224 | D_ASSERT(cast_data.child_cast_info.size() == result_children.size()); |
| 225 | |
| 226 | for (idx_t child_idx = 0; child_idx < result_children.size(); child_idx++) { |
| 227 | auto &child_varchar_vector = *child_vectors[child_idx]; |
| 228 | auto &result_child_vector = *result_children[child_idx]; |
| 229 | auto &child_cast_info = cast_data.child_cast_info[child_idx]; |
| 230 | CastParameters child_parameters(parameters, child_cast_info.cast_data, lstate.local_states[child_idx]); |
| 231 | if (!child_cast_info.function(child_varchar_vector, result_child_vector, count, child_parameters)) { |
| 232 | all_converted = false; |
| 233 | } |
| 234 | } |
| 235 | return all_converted; |
| 236 | } |
| 237 | |
| 238 | //===--------------------------------------------------------------------===// |
| 239 | // string -> map casting |
| 240 | //===--------------------------------------------------------------------===// |
| 241 | unique_ptr<FunctionLocalState> InitMapCastLocalState(CastLocalStateParameters ¶meters) { |
| 242 | auto &cast_data = parameters.cast_data->Cast<MapBoundCastData>(); |
| 243 | auto result = make_uniq<MapCastLocalState>(); |
| 244 | |
| 245 | if (cast_data.key_cast.init_local_state) { |
| 246 | CastLocalStateParameters child_params(parameters, cast_data.key_cast.cast_data); |
| 247 | result->key_state = cast_data.key_cast.init_local_state(child_params); |
| 248 | } |
| 249 | if (cast_data.value_cast.init_local_state) { |
| 250 | CastLocalStateParameters child_params(parameters, cast_data.value_cast.cast_data); |
| 251 | result->value_state = cast_data.value_cast.init_local_state(child_params); |
| 252 | } |
| 253 | return std::move(result); |
| 254 | } |
| 255 | |
| 256 | bool VectorStringToMap::StringToNestedTypeCastLoop(const string_t *source_data, ValidityMask &source_mask, |
| 257 | Vector &result, ValidityMask &result_mask, idx_t count, |
| 258 | CastParameters ¶meters, const SelectionVector *sel) { |
| 259 | idx_t total_elements = 0; |
| 260 | for (idx_t i = 0; i < count; i++) { |
| 261 | idx_t idx = i; |
| 262 | if (sel) { |
| 263 | idx = sel->get_index(idx: i); |
| 264 | } |
| 265 | if (!source_mask.RowIsValid(row_idx: idx)) { |
| 266 | continue; |
| 267 | } |
| 268 | total_elements += (VectorStringToMap::CountPartsMap(input: source_data[idx]) + 1) / 2; |
| 269 | } |
| 270 | |
| 271 | Vector varchar_key_vector(LogicalType::VARCHAR, total_elements); |
| 272 | Vector varchar_val_vector(LogicalType::VARCHAR, total_elements); |
| 273 | auto child_key_data = FlatVector::GetData<string_t>(vector&: varchar_key_vector); |
| 274 | auto child_val_data = FlatVector::GetData<string_t>(vector&: varchar_val_vector); |
| 275 | |
| 276 | ListVector::Reserve(vec&: result, required_capacity: total_elements); |
| 277 | ListVector::SetListSize(vec&: result, size: total_elements); |
| 278 | auto list_data = ListVector::GetData(v&: result); |
| 279 | |
| 280 | bool all_converted = true; |
| 281 | idx_t total = 0; |
| 282 | for (idx_t i = 0; i < count; i++) { |
| 283 | idx_t idx = i; |
| 284 | if (sel) { |
| 285 | idx = sel->get_index(idx: i); |
| 286 | } |
| 287 | if (!source_mask.RowIsValid(row_idx: idx)) { |
| 288 | result_mask.SetInvalid(idx); |
| 289 | continue; |
| 290 | } |
| 291 | |
| 292 | list_data[i].offset = total; |
| 293 | if (!VectorStringToMap::SplitStringMap(input: source_data[idx], child_key_data, child_val_data, child_start&: total, |
| 294 | varchar_key&: varchar_key_vector, varchar_val&: varchar_val_vector)) { |
| 295 | string text = "Type VARCHAR with value '" + source_data[idx].GetString() + |
| 296 | "' can't be cast to the destination type MAP" ; |
| 297 | FlatVector::SetNull(vector&: result, idx, is_null: true); |
| 298 | HandleVectorCastError::Operation<string_t>(error_message: text, mask&: result_mask, idx, error_message_ptr: parameters.error_message, all_converted); |
| 299 | } |
| 300 | list_data[i].length = total - list_data[i].offset; |
| 301 | } |
| 302 | D_ASSERT(total_elements == total); |
| 303 | |
| 304 | auto &result_key_child = MapVector::GetKeys(vector&: result); |
| 305 | auto &result_val_child = MapVector::GetValues(vector&: result); |
| 306 | auto &cast_data = parameters.cast_data->Cast<MapBoundCastData>(); |
| 307 | auto &lstate = parameters.local_state->Cast<MapCastLocalState>(); |
| 308 | |
| 309 | CastParameters key_params(parameters, cast_data.key_cast.cast_data, lstate.key_state); |
| 310 | if (!cast_data.key_cast.function(varchar_key_vector, result_key_child, total_elements, key_params)) { |
| 311 | all_converted = false; |
| 312 | } |
| 313 | CastParameters val_params(parameters, cast_data.value_cast.cast_data, lstate.value_state); |
| 314 | if (!cast_data.value_cast.function(varchar_val_vector, result_val_child, total_elements, val_params)) { |
| 315 | all_converted = false; |
| 316 | } |
| 317 | |
| 318 | auto &key_validity = FlatVector::Validity(vector&: result_key_child); |
| 319 | if (!all_converted) { |
| 320 | for (idx_t row_idx = 0; row_idx < count; row_idx++) { |
| 321 | if (!result_mask.RowIsValid(row_idx)) { |
| 322 | continue; |
| 323 | } |
| 324 | auto list = list_data[row_idx]; |
| 325 | for (idx_t list_idx = 0; list_idx < list.length; list_idx++) { |
| 326 | auto idx = list.offset + list_idx; |
| 327 | if (!key_validity.RowIsValid(row_idx: idx)) { |
| 328 | result_mask.SetInvalid(row_idx); |
| 329 | } |
| 330 | } |
| 331 | } |
| 332 | } |
| 333 | MapVector::MapConversionVerify(vector&: result, count); |
| 334 | return all_converted; |
| 335 | } |
| 336 | |
| 337 | template <class T> |
| 338 | bool StringToNestedTypeCast(Vector &source, Vector &result, idx_t count, CastParameters ¶meters) { |
| 339 | D_ASSERT(source.GetType().id() == LogicalTypeId::VARCHAR); |
| 340 | |
| 341 | switch (source.GetVectorType()) { |
| 342 | case VectorType::CONSTANT_VECTOR: { |
| 343 | auto source_data = ConstantVector::GetData<string_t>(vector&: source); |
| 344 | auto &source_mask = ConstantVector::Validity(vector&: source); |
| 345 | auto &result_mask = FlatVector::Validity(vector&: result); |
| 346 | auto ret = T::StringToNestedTypeCastLoop(source_data, source_mask, result, result_mask, 1, parameters, nullptr); |
| 347 | result.SetVectorType(VectorType::CONSTANT_VECTOR); |
| 348 | return ret; |
| 349 | } |
| 350 | default: { |
| 351 | UnifiedVectorFormat unified_source; |
| 352 | |
| 353 | source.ToUnifiedFormat(count, data&: unified_source); |
| 354 | auto source_sel = unified_source.sel; |
| 355 | auto source_data = UnifiedVectorFormat::GetData<string_t>(format: unified_source); |
| 356 | auto &source_mask = unified_source.validity; |
| 357 | auto &result_mask = FlatVector::Validity(vector&: result); |
| 358 | |
| 359 | return T::StringToNestedTypeCastLoop(source_data, source_mask, result, result_mask, count, parameters, |
| 360 | source_sel); |
| 361 | } |
| 362 | } |
| 363 | } |
| 364 | |
| 365 | BoundCastInfo DefaultCasts::StringCastSwitch(BindCastInput &input, const LogicalType &source, |
| 366 | const LogicalType &target) { |
| 367 | switch (target.id()) { |
| 368 | case LogicalTypeId::DATE: |
| 369 | return BoundCastInfo(&VectorCastHelpers::TryCastErrorLoop<string_t, date_t, duckdb::TryCastErrorMessage>); |
| 370 | case LogicalTypeId::TIME: |
| 371 | case LogicalTypeId::TIME_TZ: |
| 372 | return BoundCastInfo(&VectorCastHelpers::TryCastErrorLoop<string_t, dtime_t, duckdb::TryCastErrorMessage>); |
| 373 | case LogicalTypeId::TIMESTAMP: |
| 374 | case LogicalTypeId::TIMESTAMP_TZ: |
| 375 | return BoundCastInfo(&VectorCastHelpers::TryCastErrorLoop<string_t, timestamp_t, duckdb::TryCastErrorMessage>); |
| 376 | case LogicalTypeId::TIMESTAMP_NS: |
| 377 | return BoundCastInfo( |
| 378 | &VectorCastHelpers::TryCastStrictLoop<string_t, timestamp_t, duckdb::TryCastToTimestampNS>); |
| 379 | case LogicalTypeId::TIMESTAMP_SEC: |
| 380 | return BoundCastInfo( |
| 381 | &VectorCastHelpers::TryCastStrictLoop<string_t, timestamp_t, duckdb::TryCastToTimestampSec>); |
| 382 | case LogicalTypeId::TIMESTAMP_MS: |
| 383 | return BoundCastInfo( |
| 384 | &VectorCastHelpers::TryCastStrictLoop<string_t, timestamp_t, duckdb::TryCastToTimestampMS>); |
| 385 | case LogicalTypeId::BLOB: |
| 386 | return BoundCastInfo(&VectorCastHelpers::TryCastStringLoop<string_t, string_t, duckdb::TryCastToBlob>); |
| 387 | case LogicalTypeId::BIT: |
| 388 | return BoundCastInfo(&VectorCastHelpers::TryCastStringLoop<string_t, string_t, duckdb::TryCastToBit>); |
| 389 | case LogicalTypeId::UUID: |
| 390 | return BoundCastInfo(&VectorCastHelpers::TryCastStringLoop<string_t, hugeint_t, duckdb::TryCastToUUID>); |
| 391 | case LogicalTypeId::SQLNULL: |
| 392 | return &DefaultCasts::TryVectorNullCast; |
| 393 | case LogicalTypeId::VARCHAR: |
| 394 | return &DefaultCasts::ReinterpretCast; |
| 395 | case LogicalTypeId::LIST: |
| 396 | // the second argument allows for a secondary casting function to be passed in the CastParameters |
| 397 | return BoundCastInfo( |
| 398 | &StringToNestedTypeCast<VectorStringToList>, |
| 399 | ListBoundCastData::BindListToListCast(input, source: LogicalType::LIST(child: LogicalType::VARCHAR), target), |
| 400 | ListBoundCastData::InitListLocalState); |
| 401 | case LogicalTypeId::STRUCT: |
| 402 | return BoundCastInfo(&StringToNestedTypeCast<VectorStringToStruct>, |
| 403 | StructBoundCastData::BindStructToStructCast(input, source: InitVarcharStructType(target), target), |
| 404 | StructBoundCastData::InitStructCastLocalState); |
| 405 | case LogicalTypeId::MAP: |
| 406 | return BoundCastInfo(&StringToNestedTypeCast<VectorStringToMap>, |
| 407 | MapBoundCastData::BindMapToMapCast( |
| 408 | input, source: LogicalType::MAP(key: LogicalType::VARCHAR, value: LogicalType::VARCHAR), target), |
| 409 | InitMapCastLocalState); |
| 410 | default: |
| 411 | return VectorStringCastNumericSwitch(input, source, target); |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | } // namespace duckdb |
| 416 | |