Back to home page

EIC code displayed by LXR

 
 

    


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 // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // Helpers for integers
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 // We want all integer types to be allowed as fields. Some integers
0091 // may have the same width as others, but different type (e.g. long and long long
0092 // may both be 64-bit, but different types). Auxiliar int_traits to allow this to work
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 // Traits
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 // std::optional<T> and boost::optional<T>. To avoid dependencies,
0511 // this is achieved through a "concept"
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()),  // T should be default constructible
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     // Verify that the field is present
0569     if (ctx.is_current_field_absent())
0570     {
0571         ctx.add_field_absent_error();
0572         return;
0573     }
0574 
0575     // Perform the check
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     // Check nullability
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 }  // namespace detail
0598 }  // namespace mysql
0599 }  // namespace boost
0600 
0601 #endif