Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:41

0001 //
0002 // Copyright (c) 2019-2023 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_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_BINARY_FIELD_IPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_BINARY_FIELD_IPP
0010 
0011 #pragma once
0012 
0013 #include <boost/mysql/field_kind.hpp>
0014 #include <boost/mysql/field_view.hpp>
0015 #include <boost/mysql/metadata.hpp>
0016 
0017 #include <boost/mysql/detail/config.hpp>
0018 #include <boost/mysql/detail/datetime.hpp>
0019 
0020 #include <boost/mysql/impl/internal/protocol/bit_deserialization.hpp>
0021 #include <boost/mysql/impl/internal/protocol/constants.hpp>
0022 #include <boost/mysql/impl/internal/protocol/deserialize_binary_field.hpp>
0023 #include <boost/mysql/impl/internal/protocol/serialization.hpp>
0024 
0025 #include <cmath>
0026 #include <cstddef>
0027 
0028 namespace boost {
0029 namespace mysql {
0030 namespace detail {
0031 
0032 // strings
0033 BOOST_MYSQL_STATIC_OR_INLINE
0034 deserialize_errc deserialize_binary_field_string(
0035     deserialization_context& ctx,
0036     field_view& output,
0037     bool is_blob
0038 ) noexcept
0039 {
0040     string_lenenc deser;
0041     auto err = deserialize(ctx, deser);
0042     if (err != deserialize_errc::ok)
0043         return err;
0044     if (is_blob)
0045     {
0046         output = field_view(
0047             blob_view(reinterpret_cast<const unsigned char*>(deser.value.data()), deser.value.size())
0048         );
0049     }
0050     else
0051     {
0052         output = field_view(deser.value);
0053     }
0054     return deserialize_errc::ok;
0055 }
0056 
0057 // ints
0058 template <class TargetType, class DeserializableType>
0059 BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
0060 deserialize_binary_field_int_impl(deserialization_context& ctx, field_view& output) noexcept
0061 {
0062     DeserializableType deser;
0063     auto err = deserialize(ctx, deser);
0064     if (err != deserialize_errc::ok)
0065         return err;
0066     output = field_view(static_cast<TargetType>(deser));
0067     return deserialize_errc::ok;
0068 }
0069 
0070 template <class DeserializableTypeUnsigned, class DeserializableTypeSigned>
0071 BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
0072 deserialize_binary_field_int(const metadata& meta, deserialization_context& ctx, field_view& output) noexcept
0073 {
0074     return meta.is_unsigned()
0075                ? deserialize_binary_field_int_impl<std::uint64_t, DeserializableTypeUnsigned>(ctx, output)
0076                : deserialize_binary_field_int_impl<std::int64_t, DeserializableTypeSigned>(ctx, output);
0077 }
0078 
0079 // Bits. These come as a binary value between 1 and 8 bytes,
0080 // packed in a string
0081 BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
0082 deserialize_binary_field_bit(deserialization_context& ctx, field_view& output) noexcept
0083 {
0084     string_lenenc buffer;
0085     auto err = deserialize(ctx, buffer);
0086     if (err != deserialize_errc::ok)
0087         return err;
0088     return boost::mysql::detail::deserialize_bit(buffer.value, output);
0089 }
0090 
0091 // Floats
0092 template <class T>
0093 BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
0094 deserialize_binary_field_float(deserialization_context& ctx, field_view& output) noexcept
0095 {
0096     // Size check
0097     if (!ctx.enough_size(sizeof(T)))
0098         return deserialize_errc::incomplete_message;
0099 
0100     // Endianness conversion. Boost.Endian support for floats start at 1.71
0101     T v = boost::endian::endian_load<T, sizeof(T), boost::endian::order::little>(ctx.first());
0102 
0103     // Nans and infs not allowed in SQL
0104     if (std::isnan(v) || std::isinf(v))
0105         return deserialize_errc::protocol_value_error;
0106 
0107     // Done
0108     ctx.advance(sizeof(T));
0109     output = field_view(v);
0110     return deserialize_errc::ok;
0111 }
0112 
0113 // Time types
0114 BOOST_MYSQL_STATIC_OR_INLINE
0115 deserialize_errc deserialize_binary_ymd(deserialization_context& ctx, boost::mysql::date& output)
0116 {
0117     using namespace boost::mysql::detail;
0118 
0119     std::uint16_t year;
0120     std::uint8_t month;
0121     std::uint8_t day;
0122 
0123     // Deserialize
0124     auto err = deserialize(ctx, year, month, day);
0125     if (err != deserialize_errc::ok)
0126         return err;
0127 
0128     // Range check
0129     if (year > max_year || month > max_month || day > max_day)
0130     {
0131         return deserialize_errc::protocol_value_error;
0132     }
0133 
0134     output = boost::mysql::date(year, month, day);
0135 
0136     return deserialize_errc::ok;
0137 }
0138 
0139 BOOST_MYSQL_STATIC_OR_INLINE
0140 deserialize_errc deserialize_binary_field_date(deserialization_context& ctx, field_view& output) noexcept
0141 {
0142     using namespace boost::mysql::detail::binc;
0143 
0144     // Deserialize length
0145     std::uint8_t length;
0146     auto err = deserialize(ctx, length);
0147     if (err != deserialize_errc::ok)
0148         return err;
0149 
0150     // Check for zero dates
0151     if (length < date_sz)
0152     {
0153         output = field_view(boost::mysql::date());
0154         return deserialize_errc::ok;
0155     }
0156 
0157     // Deserialize rest of fields
0158     boost::mysql::date d;
0159     err = deserialize_binary_ymd(ctx, d);
0160     if (err != deserialize_errc::ok)
0161         return err;
0162     output = field_view(d);
0163     return deserialize_errc::ok;
0164 }
0165 
0166 BOOST_MYSQL_STATIC_OR_INLINE
0167 deserialize_errc deserialize_binary_field_datetime(deserialization_context& ctx, field_view& output) noexcept
0168 {
0169     using namespace binc;
0170 
0171     // Deserialize length
0172     std::uint8_t length;
0173     auto err = deserialize(ctx, length);
0174     if (err != deserialize_errc::ok)
0175         return err;
0176 
0177     // If the DATETIME does not contain some of the values below,
0178     // they are supposed to be zero
0179     boost::mysql::date d{};
0180     std::uint8_t hours = 0;
0181     std::uint8_t minutes = 0;
0182     std::uint8_t seconds = 0;
0183     std::uint32_t micros = 0;
0184 
0185     // Date part
0186     if (length >= datetime_d_sz)
0187     {
0188         err = deserialize_binary_ymd(ctx, d);
0189         if (err != deserialize_errc::ok)
0190             return err;
0191     }
0192 
0193     // Hours, minutes, seconds
0194     if (length >= datetime_dhms_sz)
0195     {
0196         err = deserialize(ctx, hours, minutes, seconds);
0197         if (err != deserialize_errc::ok)
0198             return err;
0199     }
0200 
0201     // Microseconds
0202     if (length >= datetime_dhmsu_sz)
0203     {
0204         err = deserialize(ctx, micros);
0205         if (err != deserialize_errc::ok)
0206             return err;
0207     }
0208 
0209     // Validity check. deserialize_binary_ymd already does it for date
0210     if (hours > max_hour || minutes > max_min || seconds > max_sec || micros > max_micro)
0211     {
0212         return deserialize_errc::protocol_value_error;
0213     }
0214 
0215     // Compose the final datetime
0216     boost::mysql::datetime dt(d.year(), d.month(), d.day(), hours, minutes, seconds, micros);
0217     output = field_view(dt);
0218     return deserialize_errc::ok;
0219 }
0220 
0221 BOOST_MYSQL_STATIC_OR_INLINE
0222 deserialize_errc deserialize_binary_field_time(deserialization_context& ctx, field_view& output) noexcept
0223 {
0224     using namespace boost::mysql::detail;
0225     using namespace boost::mysql::detail::binc;
0226 
0227     // Deserialize length
0228     std::uint8_t length;
0229     auto err = deserialize(ctx, length);
0230     if (err != deserialize_errc::ok)
0231         return err;
0232 
0233     // If the TIME contains no value for these fields, they are zero
0234     std::uint8_t is_negative = 0;
0235     std::uint32_t num_days = 0;
0236     std::uint8_t hours = 0;
0237     std::uint8_t minutes = 0;
0238     std::uint8_t seconds = 0;
0239     std::uint32_t microseconds = 0;
0240 
0241     // Sign, days, hours, minutes, seconds
0242     if (length >= time_dhms_sz)
0243     {
0244         err = deserialize(ctx, is_negative, num_days, hours, minutes, seconds);
0245         if (err != deserialize_errc::ok)
0246             return err;
0247     }
0248 
0249     // Microseconds
0250     if (length >= time_dhmsu_sz)
0251     {
0252         err = deserialize(ctx, microseconds);
0253         if (err != deserialize_errc::ok)
0254             return err;
0255     }
0256 
0257     // Range check
0258     if (num_days > time_max_days || hours > max_hour || minutes > max_min || seconds > max_sec ||
0259         microseconds > max_micro)
0260     {
0261         return deserialize_errc::protocol_value_error;
0262     }
0263 
0264     // Compose the final time
0265     output = field_view(boost::mysql::time(
0266         (is_negative ? -1 : 1) *
0267         (boost::mysql::days(num_days) + std::chrono::hours(hours) + std::chrono::minutes(minutes) +
0268          std::chrono::seconds(seconds) + std::chrono::microseconds(microseconds))
0269     ));
0270     return deserialize_errc::ok;
0271 }
0272 
0273 }  // namespace detail
0274 }  // namespace mysql
0275 }  // namespace boost
0276 
0277 boost::mysql::detail::deserialize_errc boost::mysql::detail::deserialize_binary_field(
0278     deserialization_context& ctx,
0279     const metadata& meta,
0280     field_view& output
0281 )
0282 {
0283     switch (meta.type())
0284     {
0285     case column_type::tinyint:
0286         return deserialize_binary_field_int<std::uint8_t, std::int8_t>(meta, ctx, output);
0287     case column_type::smallint:
0288     case column_type::year:
0289         return deserialize_binary_field_int<std::uint16_t, std::int16_t>(meta, ctx, output);
0290     case column_type::mediumint:
0291     case column_type::int_:
0292         return deserialize_binary_field_int<std::uint32_t, std::int32_t>(meta, ctx, output);
0293     case column_type::bigint:
0294         return deserialize_binary_field_int<std::uint64_t, std::int64_t>(meta, ctx, output);
0295     case column_type::bit: return deserialize_binary_field_bit(ctx, output);
0296     case column_type::float_: return deserialize_binary_field_float<float>(ctx, output);
0297     case column_type::double_: return deserialize_binary_field_float<double>(ctx, output);
0298     case column_type::timestamp:
0299     case column_type::datetime: return deserialize_binary_field_datetime(ctx, output);
0300     case column_type::date: return deserialize_binary_field_date(ctx, output);
0301     case column_type::time: return deserialize_binary_field_time(ctx, output);
0302     // True string types
0303     case column_type::char_:
0304     case column_type::varchar:
0305     case column_type::text:
0306     case column_type::enum_:
0307     case column_type::set:
0308     case column_type::decimal:
0309     case column_type::json: return deserialize_binary_field_string(ctx, output, false);
0310     // Blobs and anything else
0311     case column_type::binary:
0312     case column_type::varbinary:
0313     case column_type::blob:
0314     case column_type::geometry:
0315     default: return deserialize_binary_field_string(ctx, output, true);
0316     }
0317 }
0318 
0319 #endif