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