File indexing completed on 2025-01-18 09:42:38
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MYSQL_DETAIL_TYPING_READABLE_FIELD_TRAITS_HPP
0009 #define BOOST_MYSQL_DETAIL_TYPING_READABLE_FIELD_TRAITS_HPP
0010
0011 #include <boost/mysql/client_errc.hpp>
0012 #include <boost/mysql/date.hpp>
0013 #include <boost/mysql/datetime.hpp>
0014 #include <boost/mysql/diagnostics.hpp>
0015 #include <boost/mysql/error_code.hpp>
0016 #include <boost/mysql/field_kind.hpp>
0017 #include <boost/mysql/field_view.hpp>
0018 #include <boost/mysql/metadata.hpp>
0019 #include <boost/mysql/metadata_collection_view.hpp>
0020 #include <boost/mysql/string_view.hpp>
0021 #include <boost/mysql/time.hpp>
0022
0023 #include <boost/mysql/detail/config.hpp>
0024 #include <boost/mysql/detail/typing/meta_check_context.hpp>
0025 #include <boost/mysql/detail/typing/pos_map.hpp>
0026 #include <boost/mysql/detail/void_t.hpp>
0027
0028 #include <cstdint>
0029 #include <limits>
0030 #include <string>
0031 #include <type_traits>
0032
0033 namespace boost {
0034 namespace mysql {
0035 namespace detail {
0036
0037
0038 template <class SignedInt>
0039 error_code parse_signed_int(field_view input, SignedInt& output)
0040 {
0041 using unsigned_t = typename std::make_unsigned<SignedInt>::type;
0042 using limits_t = std::numeric_limits<SignedInt>;
0043
0044 auto kind = input.kind();
0045 if (kind == field_kind::int64)
0046 {
0047 auto v = input.get_int64();
0048 if (v < (limits_t::min)() || v > (limits_t::max)())
0049 {
0050 return client_errc::static_row_parsing_error;
0051 }
0052 output = static_cast<SignedInt>(v);
0053 return error_code();
0054 }
0055 else if (kind == field_kind::uint64)
0056 {
0057 auto v = input.get_uint64();
0058 if (v > static_cast<unsigned_t>((limits_t::max)()))
0059 {
0060 return client_errc::static_row_parsing_error;
0061 }
0062 output = static_cast<SignedInt>(v);
0063 return error_code();
0064 }
0065 else
0066 {
0067 return client_errc::static_row_parsing_error;
0068 }
0069 }
0070
0071 template <class UnsignedInt>
0072 error_code parse_unsigned_int(field_view input, UnsignedInt& output)
0073 {
0074 if (input.kind() != field_kind::uint64)
0075 {
0076 return client_errc::static_row_parsing_error;
0077 }
0078 auto v = input.get_uint64();
0079 if (v > (std::numeric_limits<UnsignedInt>::max)())
0080 {
0081 return client_errc::static_row_parsing_error;
0082 }
0083 output = static_cast<UnsignedInt>(v);
0084 return error_code();
0085 }
0086
0087
0088
0089
0090 template <class T, bool is_signed = std::is_signed<T>::value, std::size_t width = sizeof(T)>
0091 struct int_traits
0092 {
0093 static constexpr bool is_supported = false;
0094 };
0095
0096 template <class T>
0097 struct int_traits<T, true, 1>
0098 {
0099 static constexpr bool is_supported = true;
0100 static constexpr const char* type_name = "int8_t";
0101 static bool meta_check(meta_check_context& ctx)
0102 {
0103 switch (ctx.current_meta().type())
0104 {
0105 case column_type::tinyint: return !ctx.current_meta().is_unsigned();
0106 default: return false;
0107 }
0108 }
0109 static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
0110 };
0111
0112 template <class T>
0113 struct int_traits<T, false, 1>
0114 {
0115 static constexpr bool is_supported = true;
0116 static constexpr const char* type_name = "uint8_t";
0117 static bool meta_check(meta_check_context& ctx)
0118 {
0119 switch (ctx.current_meta().type())
0120 {
0121 case column_type::tinyint: return ctx.current_meta().is_unsigned();
0122 default: return false;
0123 }
0124 }
0125 static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
0126 };
0127
0128 template <class T>
0129 struct int_traits<T, true, 2>
0130 {
0131 static constexpr bool is_supported = true;
0132 static constexpr const char* type_name = "int16_t";
0133 static bool meta_check(meta_check_context& ctx)
0134 {
0135 switch (ctx.current_meta().type())
0136 {
0137 case column_type::tinyint: return true;
0138 case column_type::smallint:
0139 case column_type::year: return !ctx.current_meta().is_unsigned();
0140 default: return false;
0141 }
0142 }
0143 static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
0144 };
0145
0146 template <class T>
0147 struct int_traits<T, false, 2>
0148 {
0149 static constexpr bool is_supported = true;
0150 static constexpr const char* type_name = "uint16_t";
0151 static bool meta_check(meta_check_context& ctx)
0152 {
0153 switch (ctx.current_meta().type())
0154 {
0155 case column_type::tinyint:
0156 case column_type::smallint:
0157 case column_type::year: return ctx.current_meta().is_unsigned();
0158 default: return false;
0159 }
0160 }
0161 static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
0162 };
0163
0164 template <class T>
0165 struct int_traits<T, true, 4>
0166 {
0167 static constexpr bool is_supported = true;
0168 static constexpr const char* type_name = "int32_t";
0169 static bool meta_check(meta_check_context& ctx)
0170 {
0171 switch (ctx.current_meta().type())
0172 {
0173 case column_type::tinyint:
0174 case column_type::smallint:
0175 case column_type::year:
0176 case column_type::mediumint: return true;
0177 case column_type::int_: return !ctx.current_meta().is_unsigned();
0178 default: return false;
0179 }
0180 }
0181 static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
0182 };
0183
0184 template <class T>
0185 struct int_traits<T, false, 4>
0186 {
0187 static constexpr bool is_supported = true;
0188 static constexpr const char* type_name = "uint32_t";
0189 static bool meta_check(meta_check_context& ctx)
0190 {
0191 switch (ctx.current_meta().type())
0192 {
0193 case column_type::tinyint:
0194 case column_type::smallint:
0195 case column_type::year:
0196 case column_type::mediumint:
0197 case column_type::int_: return ctx.current_meta().is_unsigned();
0198 default: return false;
0199 }
0200 }
0201 static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
0202 };
0203
0204 template <class T>
0205 struct int_traits<T, true, 8>
0206 {
0207 static constexpr bool is_supported = true;
0208 static constexpr const char* type_name = "int64_t";
0209 static bool meta_check(meta_check_context& ctx)
0210 {
0211 switch (ctx.current_meta().type())
0212 {
0213 case column_type::tinyint:
0214 case column_type::smallint:
0215 case column_type::year:
0216 case column_type::mediumint:
0217 case column_type::int_: return true;
0218 case column_type::bigint: return !ctx.current_meta().is_unsigned();
0219 default: return false;
0220 }
0221 }
0222 static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
0223 };
0224
0225 template <class T>
0226 struct int_traits<T, false, 8>
0227 {
0228 static constexpr bool is_supported = true;
0229 static constexpr const char* type_name = "uint64_t";
0230 static bool meta_check(meta_check_context& ctx)
0231 {
0232 switch (ctx.current_meta().type())
0233 {
0234 case column_type::tinyint:
0235 case column_type::smallint:
0236 case column_type::year:
0237 case column_type::mediumint:
0238 case column_type::int_:
0239 case column_type::bigint: return ctx.current_meta().is_unsigned();
0240 case column_type::bit: return true;
0241 default: return false;
0242 }
0243 }
0244 static error_code parse(field_view input, std::uint64_t& output)
0245 {
0246 return parse_unsigned_int(input, output);
0247 }
0248 };
0249
0250
0251 template <typename T, class EnableIf = void>
0252 struct readable_field_traits
0253 {
0254 static constexpr bool is_supported = false;
0255 };
0256
0257 template <>
0258 struct readable_field_traits<char, void> : int_traits<char>
0259 {
0260 };
0261
0262 template <>
0263 struct readable_field_traits<signed char, void> : int_traits<signed char>
0264 {
0265 };
0266
0267 template <>
0268 struct readable_field_traits<unsigned char, void> : int_traits<unsigned char>
0269 {
0270 };
0271
0272 template <>
0273 struct readable_field_traits<short, void> : int_traits<short>
0274 {
0275 };
0276
0277 template <>
0278 struct readable_field_traits<unsigned short, void> : int_traits<unsigned short>
0279 {
0280 };
0281
0282 template <>
0283 struct readable_field_traits<int, void> : int_traits<int>
0284 {
0285 };
0286
0287 template <>
0288 struct readable_field_traits<unsigned int, void> : int_traits<unsigned int>
0289 {
0290 };
0291
0292 template <>
0293 struct readable_field_traits<long, void> : int_traits<long>
0294 {
0295 };
0296
0297 template <>
0298 struct readable_field_traits<unsigned long, void> : int_traits<unsigned long>
0299 {
0300 };
0301
0302 template <>
0303 struct readable_field_traits<long long, void> : int_traits<long long>
0304 {
0305 };
0306
0307 template <>
0308 struct readable_field_traits<unsigned long long, void> : int_traits<unsigned long long>
0309 {
0310 };
0311
0312 template <>
0313 struct readable_field_traits<bool, void>
0314 {
0315 static constexpr bool is_supported = true;
0316 static constexpr const char* type_name = "bool";
0317 static bool meta_check(meta_check_context& ctx)
0318 {
0319 return ctx.current_meta().type() == column_type::tinyint && !ctx.current_meta().is_unsigned();
0320 }
0321 static error_code parse(field_view input, bool& output)
0322 {
0323 if (input.kind() != field_kind::int64)
0324 {
0325 return client_errc::static_row_parsing_error;
0326 }
0327 output = input.get_int64() != 0;
0328 return error_code();
0329 }
0330 };
0331
0332 template <>
0333 struct readable_field_traits<float, void>
0334 {
0335 static constexpr bool is_supported = true;
0336 static constexpr const char* type_name = "float";
0337 static bool meta_check(meta_check_context& ctx)
0338 {
0339 return ctx.current_meta().type() == column_type::float_;
0340 }
0341 static error_code parse(field_view input, float& output)
0342 {
0343 if (input.kind() != field_kind::float_)
0344 {
0345 return client_errc::static_row_parsing_error;
0346 }
0347 output = input.get_float();
0348 return error_code();
0349 }
0350 };
0351
0352 template <>
0353 struct readable_field_traits<double, void>
0354 {
0355 static constexpr bool is_supported = true;
0356 static constexpr const char* type_name = "double";
0357 static bool meta_check(meta_check_context& ctx)
0358 {
0359 switch (ctx.current_meta().type())
0360 {
0361 case column_type::float_:
0362 case column_type::double_: return true;
0363 default: return false;
0364 }
0365 }
0366 static error_code parse(field_view input, double& output)
0367 {
0368 auto kind = input.kind();
0369 if (kind == field_kind::float_)
0370 {
0371 output = input.get_float();
0372 return error_code();
0373 }
0374 else if (kind == field_kind::double_)
0375 {
0376 output = input.get_double();
0377 return error_code();
0378 }
0379 else
0380 {
0381 return client_errc::static_row_parsing_error;
0382 }
0383 }
0384 };
0385
0386 template <class Allocator>
0387 struct readable_field_traits<std::basic_string<char, std::char_traits<char>, Allocator>, void>
0388 {
0389 static constexpr bool is_supported = true;
0390 static constexpr const char* type_name = "string";
0391 static bool meta_check(meta_check_context& ctx)
0392 {
0393 switch (ctx.current_meta().type())
0394 {
0395 case column_type::decimal:
0396 case column_type::char_:
0397 case column_type::varchar:
0398 case column_type::text:
0399 case column_type::enum_:
0400 case column_type::set:
0401 case column_type::json: return true;
0402 default: return false;
0403 }
0404 }
0405 static error_code parse(
0406 field_view input,
0407 std::basic_string<char, std::char_traits<char>, Allocator>& output
0408 )
0409 {
0410 if (input.kind() != field_kind::string)
0411 {
0412 return client_errc::static_row_parsing_error;
0413 }
0414 output = input.get_string();
0415 return error_code();
0416 }
0417 };
0418
0419 template <class Allocator>
0420 struct readable_field_traits<std::vector<unsigned char, Allocator>, void>
0421 {
0422 static constexpr bool is_supported = true;
0423 static constexpr const char* type_name = "blob";
0424 static bool meta_check(meta_check_context& ctx)
0425 {
0426 switch (ctx.current_meta().type())
0427 {
0428 case column_type::binary:
0429 case column_type::varbinary:
0430 case column_type::blob:
0431 case column_type::geometry:
0432 case column_type::unknown: return true;
0433 default: return false;
0434 }
0435 }
0436 static error_code parse(field_view input, std::vector<unsigned char, Allocator>& output)
0437 {
0438 if (input.kind() != field_kind::blob)
0439 {
0440 return client_errc::static_row_parsing_error;
0441 }
0442 auto view = input.get_blob();
0443 output.assign(view.begin(), view.end());
0444 return error_code();
0445 }
0446 };
0447
0448 template <>
0449 struct readable_field_traits<date, void>
0450 {
0451 static constexpr bool is_supported = true;
0452 static constexpr const char* type_name = "date";
0453 static bool meta_check(meta_check_context& ctx) { return ctx.current_meta().type() == column_type::date; }
0454 static error_code parse(field_view input, date& output)
0455 {
0456 if (input.kind() != field_kind::date)
0457 {
0458 return client_errc::static_row_parsing_error;
0459 }
0460 output = input.get_date();
0461 return error_code();
0462 }
0463 };
0464
0465 template <>
0466 struct readable_field_traits<datetime, void>
0467 {
0468 static constexpr bool is_supported = true;
0469 static constexpr const char* type_name = "datetime";
0470 static bool meta_check(meta_check_context& ctx)
0471 {
0472 switch (ctx.current_meta().type())
0473 {
0474 case column_type::datetime:
0475 case column_type::timestamp: return true;
0476 default: return false;
0477 }
0478 }
0479 static error_code parse(field_view input, datetime& output)
0480 {
0481 if (input.kind() != field_kind::datetime)
0482 {
0483 return client_errc::static_row_parsing_error;
0484 }
0485 output = input.get_datetime();
0486 return error_code();
0487 }
0488 };
0489
0490 template <>
0491 struct readable_field_traits<time, void>
0492 {
0493 static constexpr bool is_supported = true;
0494 static constexpr const char* type_name = "time";
0495 static bool meta_check(meta_check_context& ctx) { return ctx.current_meta().type() == column_type::time; }
0496 static error_code parse(field_view input, time& output)
0497 {
0498 if (input.kind() != field_kind::time)
0499 {
0500 return client_errc::static_row_parsing_error;
0501 }
0502 output = input.get_time();
0503 return error_code();
0504 }
0505 };
0506
0507
0508
0509 template <class T, class = void>
0510 struct is_readable_optional : std::false_type
0511 {
0512 };
0513
0514 template <class T>
0515 struct is_readable_optional<
0516 T,
0517 void_t<
0518 typename std::enable_if<
0519 std::is_same<decltype(std::declval<T&>().value()), typename T::value_type&>::value>::type,
0520 decltype(std::declval<T&>().emplace()),
0521 decltype(std::declval<T&>().reset())>> : std::true_type
0522 {
0523 };
0524
0525 template <class T>
0526 struct readable_field_traits<
0527 T,
0528 typename std::enable_if<
0529 is_readable_optional<T>::value && readable_field_traits<typename T::value_type>::is_supported>::type>
0530 {
0531 using value_type = typename T::value_type;
0532 static constexpr bool is_supported = true;
0533 static constexpr const char* type_name = readable_field_traits<value_type>::type_name;
0534 static bool meta_check(meta_check_context& ctx)
0535 {
0536 ctx.set_nullability_checked();
0537 return readable_field_traits<value_type>::meta_check(ctx);
0538 }
0539 static error_code parse(field_view input, T& output)
0540 {
0541 if (input.is_null())
0542 {
0543 output.reset();
0544 return error_code();
0545 }
0546 else
0547 {
0548 output.emplace();
0549 return readable_field_traits<value_type>::parse(input, output.value());
0550 }
0551 }
0552 };
0553
0554 template <class T>
0555 struct is_readable_field
0556 {
0557 static constexpr bool value = readable_field_traits<T>::is_supported;
0558 };
0559
0560 template <typename ReadableField>
0561 void meta_check_field_impl(meta_check_context& ctx)
0562 {
0563 using traits_t = readable_field_traits<ReadableField>;
0564
0565
0566 if (ctx.is_current_field_absent())
0567 {
0568 ctx.add_field_absent_error();
0569 return;
0570 }
0571
0572
0573 bool ok = traits_t::meta_check(ctx);
0574 if (!ok)
0575 {
0576 ctx.add_type_mismatch_error(traits_t::type_name);
0577 }
0578
0579
0580 if (!ctx.nullability_checked() && !ctx.current_meta().is_not_null())
0581 {
0582 ctx.add_nullability_error();
0583 }
0584 }
0585
0586 template <typename ReadableField>
0587 void meta_check_field(meta_check_context& ctx)
0588 {
0589 static_assert(is_readable_field<ReadableField>::value, "Should be a ReadableField");
0590 meta_check_field_impl<ReadableField>(ctx);
0591 ctx.advance();
0592 }
0593
0594 struct meta_check_field_fn
0595 {
0596 meta_check_context ctx;
0597
0598 template <class T>
0599 void operator()(T)
0600 {
0601 meta_check_field<typename T::type>(ctx);
0602 }
0603 };
0604
0605 template <typename ReadableFieldList>
0606 error_code meta_check_field_type_list(
0607 span<const std::size_t> field_map,
0608 name_table_t name_table,
0609 metadata_collection_view meta,
0610 diagnostics& diag
0611 )
0612 {
0613 meta_check_field_fn fn{meta_check_context(field_map, name_table, meta)};
0614 boost::mp11::mp_for_each<ReadableFieldList>(fn);
0615 return fn.ctx.check_errors(diag);
0616 }
0617
0618 }
0619 }
0620 }
0621
0622 #endif