2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-14 12:52:17 +00:00

deserialize_text_field tests

This commit is contained in:
Ruben Perez
2022-10-05 20:43:11 +02:00
parent ad4f6e0fb1
commit f2dcba3200
12 changed files with 541 additions and 466 deletions

View File

@@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_BINARY_DESERIALIZATION_HPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_BINARY_DESERIALIZATION_HPP
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_BINARY_FIELD_HPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_BINARY_FIELD_HPP
#include <boost/mysql/detail/protocol/serialization.hpp>
#include <boost/mysql/error.hpp>
@@ -26,17 +26,10 @@ inline errc deserialize_binary_field(
field_view& output
);
inline error_code deserialize_binary_row(
deserialization_context& ctx,
const std::vector<metadata>& meta,
const std::uint8_t* buffer_first,
std::vector<field_view>& output
);
} // detail
} // mysql
} // boost
#include <boost/mysql/detail/protocol/impl/binary_deserialization.ipp>
#include <boost/mysql/detail/protocol/impl/deserialize_binary_field.ipp>
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_BINARY_DESERIALIZATION_HPP_ */

View File

@@ -8,11 +8,10 @@
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_ROW_HPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_ROW_HPP
#include <boost/mysql/detail/protocol/resultset_encoding.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/mysql/detail/protocol/capabilities.hpp>
#include <boost/mysql/detail/protocol/serialization.hpp>
#include <boost/mysql/detail/protocol/text_deserialization.hpp>
#include <boost/mysql/detail/protocol/binary_deserialization.hpp>
#include <boost/mysql/detail/protocol/serialization_context.hpp>
#include <boost/mysql/resultset_base.hpp>
#include <boost/mysql/error.hpp>
#include <boost/mysql/field_view.hpp>
@@ -23,6 +22,16 @@ namespace boost {
namespace mysql {
namespace detail {
// Exposed here for the sake of testing
inline void deserialize_row(
resultset_encoding encoding,
deserialization_context& ctx,
const std::vector<metadata>& meta,
const std::uint8_t* buffer_first,
std::vector<field_view>& output,
error_code& err
);
inline bool deserialize_row(
boost::asio::const_buffer read_message,
@@ -32,45 +41,7 @@ inline bool deserialize_row(
std::vector<field_view>& output,
error_code& err,
error_info& info
)
{
assert(result.valid());
// Message type: row, error or eof?
std::uint8_t msg_type = 0;
deserialization_context ctx (read_message, current_capabilities);
err = make_error_code(deserialize(ctx, msg_type));
if (err)
return false;
if (msg_type == eof_packet_header)
{
// end of resultset => this is a ok_packet, not a row
ok_packet ok_pack;
err = deserialize_message(ctx, ok_pack);
if (err)
return false;
result.complete(ok_pack);
output.clear();
return false;
}
else if (msg_type == error_packet_header)
{
// An error occurred during the generation of the rows
err = process_error_packet(ctx, info);
return false;
}
else
{
// An actual row
ctx.rewind(1); // keep the 'message type' byte, as it is part of the actual message
err = result.encoding() == detail::resultset_encoding::text ?
deserialize_text_row(ctx, result.meta(), buffer_first, output) :
deserialize_binary_row(ctx, result.meta(), buffer_first, output);
if (err)
return false;
return true;
}
}
);
inline void offsets_to_string_views(
std::vector<field_view>& fields,
@@ -86,5 +57,7 @@ inline void offsets_to_string_views(
} // mysql
} // boost
#include <boost/mysql/detail/protocol/impl/deserialize_row.ipp>
#endif

View File

@@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_TEXT_DESERIALIZATION_HPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_TEXT_DESERIALIZATION_HPP
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_TEXT_FIELD_HPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_DESERIALIZE_TEXT_FIELD_HPP
#include <boost/mysql/detail/protocol/serialization.hpp>
#include <boost/mysql/error.hpp>
@@ -19,24 +19,17 @@ namespace boost {
namespace mysql {
namespace detail {
inline errc deserialize_text_value(
inline errc deserialize_text_field(
boost::string_view from,
const metadata& meta,
const std::uint8_t* buffer_first,
field_view& output
);
inline error_code deserialize_text_row(
deserialization_context& ctx,
const std::vector<metadata>& meta,
const std::uint8_t* buffer_first,
std::vector<field_view>& output
);
} // detail
} // mysql
} // boost
#include <boost/mysql/detail/protocol/impl/text_deserialization.ipp>
#include <boost/mysql/detail/protocol/impl/deserialize_text_field.ipp>
#endif

View File

@@ -5,15 +5,14 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_BINARY_DESERIALIZATION_IPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_BINARY_DESERIALIZATION_IPP
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_BINARY_FIELD_IPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_BINARY_FIELD_IPP
#pragma once
#include <boost/mysql/detail/auxiliar/string_view_offset.hpp>
#include <boost/mysql/detail/protocol/binary_deserialization.hpp>
#include <boost/mysql/detail/protocol/deserialize_binary_field.hpp>
#include <boost/mysql/detail/protocol/serialization.hpp>
#include <boost/mysql/detail/protocol/null_bitmap_traits.hpp>
#include <boost/mysql/detail/protocol/constants.hpp>
#include <boost/mysql/detail/protocol/date.hpp>
#include <boost/mysql/detail/protocol/bit_deserialization.hpp>
@@ -369,53 +368,4 @@ inline boost::mysql::errc boost::mysql::detail::deserialize_binary_field(
}
}
inline boost::mysql::error_code boost::mysql::detail::deserialize_binary_row(
deserialization_context& ctx,
const std::vector<metadata>& meta,
const std::uint8_t* buffer_first,
std::vector<field_view>& output
)
{
std::size_t old_size = output.size();
// Skip packet header (it is not part of the message in the binary
// protocol but it is in the text protocol, so we include it for homogeneity)
// The caller will have checked we have this byte already for us
assert(ctx.enough_size(1));
ctx.advance(1);
// Number of fields
auto num_fields = meta.size();
output.resize(old_size + num_fields);
// Null bitmap
null_bitmap_traits null_bitmap (binary_row_null_bitmap_offset, num_fields);
const std::uint8_t* null_bitmap_begin = ctx.first();
if (!ctx.enough_size(null_bitmap.byte_count()))
return make_error_code(errc::incomplete_message);
ctx.advance(null_bitmap.byte_count());
// Actual values
for (std::vector<field_view>::size_type i = 0; i < output.size(); ++i)
{
if (null_bitmap.is_null(null_bitmap_begin, i))
{
output[old_size + i] = field_view(nullptr);
}
else
{
auto err = deserialize_binary_field(ctx, meta[i], buffer_first, output[old_size + i]);
if (err != errc::ok)
return make_error_code(err);
}
}
// Check for remaining bytes
if (!ctx.empty())
return make_error_code(errc::extra_bytes);
return error_code();
}
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_BINARY_DESERIALIZATION_IPP_ */

View File

@@ -0,0 +1,177 @@
//
// Copyright (c) 2019-2022 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_ROW_IPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_ROW_IPP
#pragma once
#include <boost/mysql/detail/protocol/deserialize_row.hpp>
#include <boost/mysql/detail/protocol/deserialize_text_field.hpp>
#include <boost/mysql/detail/protocol/null_bitmap_traits.hpp>
#include <boost/mysql/detail/protocol/deserialize_binary_field.hpp>
#include <boost/mysql/detail/protocol/serialization.hpp>
namespace boost {
namespace mysql {
namespace detail {
inline bool is_next_field_null(
const deserialization_context& ctx
)
{
if (!ctx.enough_size(1))
return false;
return *ctx.first() == 0xfb;
}
inline error_code deserialize_text_row(
deserialization_context& ctx,
const std::vector<metadata>& fields,
const std::uint8_t* buffer_first,
std::vector<field_view>& output
)
{
std::size_t old_size = output.size();
output.resize(old_size + fields.size());
for (std::vector<field_view>::size_type i = 0; i < fields.size(); ++i)
{
if (is_next_field_null(ctx))
{
ctx.advance(1);
output[old_size + i] = field_view(nullptr);
}
else
{
string_lenenc value_str;
errc err = deserialize(ctx, value_str);
if (err != errc::ok)
return make_error_code(err);
err = deserialize_text_field(value_str.value, fields[i], buffer_first, output[old_size + i]);
if (err != errc::ok)
return make_error_code(err);
}
}
if (!ctx.empty())
return make_error_code(errc::extra_bytes);
return error_code();
}
inline error_code deserialize_binary_row(
deserialization_context& ctx,
const std::vector<metadata>& meta,
const std::uint8_t* buffer_first,
std::vector<field_view>& output
)
{
std::size_t old_size = output.size();
// Skip packet header (it is not part of the message in the binary
// protocol but it is in the text protocol, so we include it for homogeneity)
// The caller will have checked we have this byte already for us
assert(ctx.enough_size(1));
ctx.advance(1);
// Number of fields
auto num_fields = meta.size();
output.resize(old_size + num_fields);
// Null bitmap
null_bitmap_traits null_bitmap (binary_row_null_bitmap_offset, num_fields);
const std::uint8_t* null_bitmap_begin = ctx.first();
if (!ctx.enough_size(null_bitmap.byte_count()))
return make_error_code(errc::incomplete_message);
ctx.advance(null_bitmap.byte_count());
// Actual values
for (std::vector<field_view>::size_type i = 0; i < output.size(); ++i)
{
if (null_bitmap.is_null(null_bitmap_begin, i))
{
output[old_size + i] = field_view(nullptr);
}
else
{
auto err = deserialize_binary_field(ctx, meta[i], buffer_first, output[old_size + i]);
if (err != errc::ok)
return make_error_code(err);
}
}
// Check for remaining bytes
if (!ctx.empty())
return make_error_code(errc::extra_bytes);
return error_code();
}
} // detail
} // mysql
} // boost
void boost::mysql::detail::deserialize_row(
resultset_encoding encoding,
deserialization_context& ctx,
const std::vector<metadata>& meta,
const std::uint8_t* buffer_first,
std::vector<field_view>& output,
error_code& err
)
{
err = encoding == detail::resultset_encoding::text ?
deserialize_text_row(ctx, meta, buffer_first, output) :
deserialize_binary_row(ctx, meta, buffer_first, output);
}
bool boost::mysql::detail::deserialize_row(
boost::asio::const_buffer read_message,
capabilities current_capabilities,
const std::uint8_t* buffer_first, // to store strings as offsets and allow buffer reallocation
resultset_base& result,
std::vector<field_view>& output,
error_code& err,
error_info& info
)
{
assert(result.valid());
// Message type: row, error or eof?
std::uint8_t msg_type = 0;
deserialization_context ctx (read_message, current_capabilities);
err = make_error_code(deserialize(ctx, msg_type));
if (err)
return false;
if (msg_type == eof_packet_header)
{
// end of resultset => this is a ok_packet, not a row
ok_packet ok_pack;
err = deserialize_message(ctx, ok_pack);
if (err)
return false;
result.complete(ok_pack);
output.clear(); // TODO: this is wrong
return false;
}
else if (msg_type == error_packet_header)
{
// An error occurred during the generation of the rows
err = process_error_packet(ctx, info);
return false;
}
else
{
// An actual row
ctx.rewind(1); // keep the 'message type' byte, as it is part of the actual message
deserialize_row(result.encoding(), ctx, result.meta(), buffer_first, output, err);
if (err)
return false;
return true;
}
}
#endif

View File

@@ -5,12 +5,12 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_TEXT_DESERIALIZATION_IPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_TEXT_DESERIALIZATION_IPP
#ifndef BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_TEXT_FIELD_IPP
#define BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_DESERIALIZE_TEXT_FIELD_IPP
#pragma once
#include <boost/mysql/detail/protocol/text_deserialization.hpp>
#include <boost/mysql/detail/protocol/deserialize_text_field.hpp>
#include <boost/mysql/detail/protocol/constants.hpp>
#include <boost/mysql/detail/protocol/date.hpp>
#include <boost/mysql/detail/protocol/bit_deserialization.hpp>
@@ -296,20 +296,11 @@ inline errc deserialize_text_value_time(
return errc::ok;
}
inline bool is_next_field_null(
const deserialization_context& ctx
)
{
if (!ctx.enough_size(1))
return false;
return *ctx.first() == 0xfb;
}
} // detail
} // mysql
} // boost
inline boost::mysql::errc boost::mysql::detail::deserialize_text_value(
inline boost::mysql::errc boost::mysql::detail::deserialize_text_field(
boost::string_view from,
const metadata& meta,
const std::uint8_t* buffer_first,
@@ -358,38 +349,6 @@ inline boost::mysql::errc boost::mysql::detail::deserialize_text_value(
}
boost::mysql::error_code boost::mysql::detail::deserialize_text_row(
deserialization_context& ctx,
const std::vector<metadata>& fields,
const std::uint8_t* buffer_first,
std::vector<field_view>& output
)
{
std::size_t old_size = output.size();
output.resize(old_size + fields.size());
for (std::vector<field_view>::size_type i = 0; i < fields.size(); ++i)
{
if (is_next_field_null(ctx))
{
ctx.advance(1);
output[old_size + i] = field_view(nullptr);
}
else
{
string_lenenc value_str;
errc err = deserialize(ctx, value_str);
if (err != errc::ok)
return make_error_code(err);
err = deserialize_text_value(value_str.value, fields[i], buffer_first, output[old_size + i]);
if (err != errc::ok)
return make_error_code(err);
}
}
if (!ctx.empty())
return make_error_code(errc::extra_bytes);
return error_code();
}
#ifdef BOOST_MSVC
#pragma warning( pop )
#endif

View File

@@ -8,6 +8,7 @@
#ifndef BOOST_MYSQL_FIELD_VIEW_HPP
#define BOOST_MYSQL_FIELD_VIEW_HPP
#include <boost/config/detail/suffix.hpp>
#include <boost/mysql/detail/auxiliar/string_view_offset.hpp>
#include <boost/mysql/detail/auxiliar/field_impl.hpp>
#include <boost/mysql/datetime_types.hpp>
@@ -182,6 +183,10 @@ private:
BOOST_CXX14_CONSTEXPR date get_date() const noexcept { return date(date::duration(date_));}
BOOST_CXX14_CONSTEXPR datetime get_datetime() const noexcept { return datetime(datetime::duration(datetime_)); }
BOOST_CXX14_CONSTEXPR time get_time() const noexcept { return time(time_); }
BOOST_CXX14_CONSTEXPR detail::string_view_offset get_sv_offset() const noexcept
{
return detail::string_view_offset(sv_offset.offset, sv_offset.size);
}
};
internal_kind ikind_ { internal_kind::null };

View File

@@ -214,7 +214,7 @@ BOOST_CXX14_CONSTEXPR inline boost::mysql::field_kind boost::mysql::field_view::
case internal_kind::time: return field_kind::time;
case internal_kind::field_ptr: return repr_.field_ptr->kind();
// sv_offset values must be converted via offset_to_string_view before calling any other fn
default: assert(false); return field_kind::null;
default: return field_kind::null;
}
}
@@ -350,6 +350,13 @@ BOOST_CXX14_CONSTEXPR bool boost::mysql::field_view::operator==(
const field_view& rhs
) const noexcept
{
// Make operator== work for types not representable by field_kind
if (ikind_ == internal_kind::sv_offset)
{
return rhs.ikind_ == internal_kind::sv_offset &&
repr_.get_sv_offset() == rhs.repr_.get_sv_offset();
}
auto k = kind(), rhs_k = rhs.kind();
switch (k)
{
@@ -401,6 +408,10 @@ inline std::ostream& boost::mysql::operator<<(
const field_view& value
)
{
// Make operator<< work for detail::string_view_offset types
if (value.ikind_ == field_view::internal_kind::sv_offset)
return os << "<sv_offset>";
switch (value.kind())
{
case field_kind::null: return os << "<NULL>";

View File

@@ -37,11 +37,11 @@ add_executable(
unit/detail/auxiliar/static_string.cpp
unit/detail/auxiliar/rows_iterator.cpp
unit/detail/auxiliar/field_type_traits.cpp
# unit/detail/protocol/capabilities.cpp
unit/detail/protocol/capabilities.cpp
# unit/detail/protocol/date.cpp
# unit/detail/protocol/null_bitmap_traits.cpp
# unit/detail/protocol/serialization_test.cpp
# unit/detail/protocol/text_deserialization_value.cpp
unit/detail/protocol/null_bitmap_traits.cpp
unit/detail/protocol/serialization_test.cpp
unit/detail/protocol/deserialize_text_field.cpp
# unit/detail/protocol/text_deserialization_error.cpp
# unit/detail/protocol/binary_deserialization_value.cpp
# unit/detail/protocol/binary_deserialization_error.cpp

View File

@@ -7,10 +7,14 @@
// Test deserialize_text_value(), just positive cases
#include <boost/mysql/detail/protocol/text_deserialization.hpp>
#include <boost/mysql/detail/protocol/deserialize_text_field.hpp>
#include <boost/mysql/detail/auxiliar/stringize.hpp>
#include "boost/mysql/detail/auxiliar/string_view_offset.hpp"
#include "boost/mysql/field_view.hpp"
#include "test_common.hpp"
#include <boost/test/data/monomorphic/collection.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test_suite.hpp>
using namespace boost::mysql::detail;
using namespace boost::mysql::test;
@@ -22,7 +26,12 @@ using boost::mysql::errc;
namespace
{
struct text_value_sample
BOOST_AUTO_TEST_SUITE(test_deserialize_text_field)
// Success cases
BOOST_AUTO_TEST_SUITE(success)
struct success_sample
{
std::string name;
std::string from;
@@ -32,7 +41,7 @@ struct text_value_sample
std::uint16_t flags;
template <class T>
text_value_sample(
success_sample(
std::string&& name,
std::string&& from,
T&& expected_value,
@@ -50,7 +59,7 @@ struct text_value_sample
}
};
std::ostream& operator<<(std::ostream& os, const text_value_sample& input)
std::ostream& operator<<(std::ostream& os, const success_sample& input)
{
return os << "(input=" << input.from
<< ", type=" << to_string(input.type)
@@ -58,7 +67,7 @@ std::ostream& operator<<(std::ostream& os, const text_value_sample& input)
<< ")";
}
void add_string_samples(std::vector<text_value_sample>& output)
void add_string_samples(std::vector<success_sample>& output)
{
output.emplace_back("varchar_non_empty", "string", "string", protocol_field_type::var_string);
output.emplace_back("varchar_empty", "", "", protocol_field_type::var_string);
@@ -88,7 +97,7 @@ void add_int_samples_helper(
std::string zerofill_s,
std::uint64_t zerofill_b,
protocol_field_type type,
std::vector<text_value_sample>& output
std::vector<success_sample>& output
)
{
output.emplace_back("signed", "20", std::int64_t(20), type);
@@ -103,7 +112,7 @@ void add_int_samples_helper(
zerofill_b, type, column_flags::unsigned_ | column_flags::zerofill);
}
void add_int_samples(std::vector<text_value_sample>& output)
void add_int_samples(std::vector<success_sample>& output)
{
add_int_samples_helper(
"127", 127,
@@ -162,7 +171,7 @@ void add_int_samples(std::vector<text_value_sample>& output)
}
// bit
void add_bit_types(std::vector<text_value_sample>& output)
void add_bit_types(std::vector<success_sample>& output)
{
output.emplace_back("bit_8", "\x12", std::uint64_t(0x12),
protocol_field_type::bit, column_flags::unsigned_);
@@ -185,7 +194,7 @@ void add_bit_types(std::vector<text_value_sample>& output)
template <class T>
void add_float_samples(
protocol_field_type type,
std::vector<text_value_sample>& output
std::vector<success_sample>& output
)
{
output.emplace_back("zero", "0", T(0.0), type);
@@ -203,7 +212,7 @@ void add_float_samples(
output.emplace_back("negative_exponent_negative_fractional", "-3.45e-20", T(-3.45e-20), type);
}
void add_date_samples(std::vector<text_value_sample>& output)
void add_date_samples(std::vector<success_sample>& output)
{
output.emplace_back("regular_date", "2019-02-28", makedate(2019, 2, 28), protocol_field_type::date);
output.emplace_back("leap_year", "1788-02-29", makedate(1788, 2, 29), protocol_field_type::date);
@@ -218,7 +227,7 @@ void add_date_samples(std::vector<text_value_sample>& output)
void add_datetime_samples(
protocol_field_type type,
std::vector<text_value_sample>& output
std::vector<success_sample>& output
)
{
output.emplace_back("0_decimals_date", "2010-02-15 00:00:00", makedt(2010, 2, 15), type);
@@ -264,7 +273,8 @@ void add_datetime_samples(
// not a real case, we cap decimals to 6
output.emplace_back("7_decimals", "2010-02-15 02:05:30.002395", makedt(2010, 2, 15, 2, 5, 30, 2395), type, 0, 7);
// Generate all invalid date casuistic for all decimals
// Generate all invalid date casuistic for all decimals.
// These are accepted by MySQL depending on the configuration
constexpr struct
{
const char* name;
@@ -294,7 +304,7 @@ void add_datetime_samples(
}
}
void add_time_samples(std::vector<text_value_sample>& output)
void add_time_samples(std::vector<success_sample>& output)
{
output.emplace_back("0_decimals_positive_h", "01:00:00", maket(1, 0, 0), protocol_field_type::time);
output.emplace_back("0_decimals_positive_hm", "12:03:00", maket(12, 3, 0), protocol_field_type::time);
@@ -365,9 +375,9 @@ void add_time_samples(std::vector<text_value_sample>& output)
output.emplace_back("7_decimals", "14:51:23.501717", maket(14, 51, 23, 501717), protocol_field_type::time, 0, 7);
}
std::vector<text_value_sample> make_all_samples()
std::vector<success_sample> make_all_samples()
{
std::vector<text_value_sample> res;
std::vector<success_sample> res;
add_string_samples(res);
add_int_samples(res);
add_bit_types(res);
@@ -380,17 +390,291 @@ std::vector<text_value_sample> make_all_samples()
return res;
}
BOOST_DATA_TEST_CASE(test_deserialize_text_value_ok, data::make(make_all_samples()))
BOOST_DATA_TEST_CASE(ok, data::make(make_all_samples()))
{
column_definition_packet coldef {};
coldef.type = sample.type;
coldef.decimals = static_cast<std::uint8_t>(sample.decimals);
coldef.flags = sample.flags;
boost::mysql::metadata meta (coldef);
boost::mysql::metadata meta (coldef, false);
const std::uint8_t* buffer_first = reinterpret_cast<const std::uint8_t*>(sample.from.data());
field_view actual_value;
auto err = deserialize_text_value(sample.from, meta, actual_value);
auto err = deserialize_text_field(
sample.from,
meta,
buffer_first,
actual_value
);
BOOST_TEST(err == errc::ok);
// Strings are representd as string view offsets
if (sample.expected.is_string())
{
field_view expected_offset (string_view_offset(0, sample.expected.get_string().size()));
BOOST_TEST(actual_value == expected_offset);
actual_value.offset_to_string_view(buffer_first);
}
BOOST_TEST(actual_value == sample.expected);
}
BOOST_AUTO_TEST_SUITE_END()
//
// Error cases
//
BOOST_AUTO_TEST_SUITE(errors)
struct error_sample
{
std::string name;
boost::string_view from;
protocol_field_type type;
std::uint16_t flags;
unsigned decimals;
errc expected_err;
error_sample(std::string&& name, boost::string_view from, protocol_field_type type,
std::uint16_t flags=0, unsigned decimals=0, errc expected_err=errc::protocol_value_error) :
name(std::move(name)),
from(from),
type(type),
flags(flags),
decimals(decimals),
expected_err(expected_err)
{
}
};
std::ostream& operator<<(std::ostream& os, const error_sample& input)
{
return os << "(input=" << input.from
<< ", type=" << to_string(input.type)
<< ", name=" << input.name
<< ")";
}
void add_int_samples(
protocol_field_type t,
std::vector<error_sample>& output
)
{
output.emplace_back("signed_blank", "", t);
output.emplace_back("signed_non_number", "abtrf", t);
output.emplace_back("signed_hex", "0x01", t);
output.emplace_back("signed_fractional", "1.1", t);
output.emplace_back("signed_exp", "2e10", t);
output.emplace_back("signed_lt_min", "-9223372036854775809", t);
output.emplace_back("signed_gt_max", "9223372036854775808", t);
output.emplace_back("unsigned_blank", "", t, column_flags::unsigned_);
output.emplace_back("unsigned_non_number", "abtrf", t, column_flags::unsigned_);
output.emplace_back("unsigned_hex", "0x01", t, column_flags::unsigned_);
output.emplace_back("unsigned_fractional", "1.1", t, column_flags::unsigned_);
output.emplace_back("unsigned_exp", "2e10", t, column_flags::unsigned_);
output.emplace_back("unsigned_lt_min", "-18446744073709551616", t, column_flags::unsigned_);
output.emplace_back("unsigned_gt_max", "18446744073709551616", t, column_flags::unsigned_);
}
void add_bit_samples(
std::vector<error_sample>& output
)
{
output.emplace_back("bit_string_view_too_short", "", protocol_field_type::bit, column_flags::unsigned_);
output.emplace_back("bit_string_view_too_long", "123456789", protocol_field_type::bit, column_flags::unsigned_);
}
void add_float_samples(
protocol_field_type t,
boost::string_view lt_min,
boost::string_view gt_max,
std::vector<error_sample>& output
)
{
output.emplace_back("blank", "", t);
output.emplace_back("non_number", "abtrf", t);
output.emplace_back("lt_min", lt_min, t);
output.emplace_back("gt_max", gt_max, t);
output.emplace_back("inf", "inf", t); // inf values not allowed by SQL std
output.emplace_back("minus_inf", "-inf", t);
output.emplace_back("nan", "nan", t); // nan values not allowed by SQL std
output.emplace_back("minus_nan", "-nan", t);
}
void add_date_samples(std::vector<error_sample>& output)
{
output.emplace_back("empty", "", protocol_field_type::date);
output.emplace_back("too_short", "2020-05-2", protocol_field_type::date);
output.emplace_back("too_long", "02020-05-02", protocol_field_type::date);
output.emplace_back("bad_delimiter", "2020:05:02", protocol_field_type::date);
output.emplace_back("too_many_groups", "20-20-05-2", protocol_field_type::date);
output.emplace_back("too_few_groups", "2020-00005", protocol_field_type::date);
output.emplace_back("incomplete_year", "999-05-005", protocol_field_type::date);
output.emplace_back("hex", "ffff-ff-ff", protocol_field_type::date);
output.emplace_back("null_value", makesv("2020-05-\02"), protocol_field_type::date);
output.emplace_back("long_year", "10000-05-2", protocol_field_type::date);
output.emplace_back("long_month", "2010-005-2", protocol_field_type::date);
output.emplace_back("long_day", "2010-5-002", protocol_field_type::date);
output.emplace_back("negative_year", "-001-05-02", protocol_field_type::date);
output.emplace_back("invalid_month", "2010-13-02", protocol_field_type::date);
output.emplace_back("invalid_month_max","2010-99-02", protocol_field_type::date);
output.emplace_back("negative_month", "2010--5-02", protocol_field_type::date);
output.emplace_back("invalid_day", "2010-05-32", protocol_field_type::date);
output.emplace_back("invalid_day_max", "2010-05-99", protocol_field_type::date);
output.emplace_back("negative_day", "2010-05--2", protocol_field_type::date);
}
void add_datetime_samples(
protocol_field_type t,
std::vector<error_sample>& output
)
{
output.emplace_back("empty", "", t);
output.emplace_back("too_short_0", "2020-05-02 23:01:0", t, 0, 0);
output.emplace_back("too_short_1", "2020-05-02 23:01:0.1", t, 0, 1);
output.emplace_back("too_short_2", "2020-05-02 23:01:00.1", t, 0, 2);
output.emplace_back("too_short_3", "2020-05-02 23:01:00.11", t, 0, 3);
output.emplace_back("too_short_4", "2020-05-02 23:01:00.111", t, 0, 4);
output.emplace_back("too_short_5", "2020-05-02 23:01:00.1111", t, 0, 5);
output.emplace_back("too_short_6", "2020-05-02 23:01:00.11111", t, 0, 6);
output.emplace_back("too_long_0", "2020-05-02 23:01:00.8", t, 0, 0);
output.emplace_back("too_long_1", "2020-05-02 23:01:00.98", t, 0, 1);
output.emplace_back("too_long_2", "2020-05-02 23:01:00.998", t, 0, 2);
output.emplace_back("too_long_3", "2020-05-02 23:01:00.9998", t, 0, 3);
output.emplace_back("too_long_4", "2020-05-02 23:01:00.99998", t, 0, 4);
output.emplace_back("too_long_5", "2020-05-02 23:01:00.999998", t, 0, 5);
output.emplace_back("too_long_6", "2020-05-02 23:01:00.9999998", t, 0, 6);
output.emplace_back("no_decimals_1", "2020-05-02 23:01:00 ", t, 0, 1);
output.emplace_back("no_decimals_2", "2020-05-02 23:01:00 ", t, 0, 2);
output.emplace_back("no_decimals_3", "2020-05-02 23:01:00 ", t, 0, 3);
output.emplace_back("no_decimals_4", "2020-05-02 23:01:00 ", t, 0, 4);
output.emplace_back("no_decimals_5", "2020-05-02 23:01:00 ", t, 0, 5);
output.emplace_back("no_decimals_6", "2020-05-02 23:01:00 ", t, 0, 6);
output.emplace_back("trailing_0", "2020-05-02 23:01:0p", t, 0, 0);
output.emplace_back("trailing_1", "2020-05-02 23:01:00.p", t, 0, 1);
output.emplace_back("trailing_2", "2020-05-02 23:01:00.1p", t, 0, 2);
output.emplace_back("trailing_3", "2020-05-02 23:01:00.12p", t, 0, 3);
output.emplace_back("trailing_4", "2020-05-02 23:01:00.123p", t, 0, 4);
output.emplace_back("trailing_5", "2020-05-02 23:01:00.1234p", t, 0, 5);
output.emplace_back("trailing_6", "2020-05-02 23:01:00.12345p", t, 0, 6);
output.emplace_back("bad_delimiter", "2020-05-02 23-01-00", t);
output.emplace_back("missing_1gp_0", "2020-05-02 23:01: ", t);
output.emplace_back("missing_2gp_0", "2020-05-02 23: ", t);
output.emplace_back("missing_3gp_0", "2020-05-02 ", t);
output.emplace_back("missing_1gp_1", "2020-05-02 23:01:.9 ", t);
output.emplace_back("missing_2gp_1", "2020-05-02 23:.9 ", t);
output.emplace_back("missing_3gp_1", "2020-05-02.9 ", t);
output.emplace_back("invalid_year", "10000-05-02 24:20:20.1", t, 0, 2);
output.emplace_back("negative_year", "-100-05-02 24:20:20", t);
output.emplace_back("invalid_month", "2020-13-02 24:20:20", t);
output.emplace_back("negative_month", "2020--5-02 24:20:20", t);
output.emplace_back("invalid_day", "2020-05-32 24:20:20", t);
output.emplace_back("negative_day", "2020-05--2 24:20:20", t);
output.emplace_back("invalid_hour", "2020-05-02 24:20:20", t);
output.emplace_back("negative_hour", "2020-05-02 -2:20:20", t);
output.emplace_back("invalid_min", "2020-05-02 22:60:20", t);
output.emplace_back("negative_min", "2020-05-02 22:-1:20", t);
output.emplace_back("invalid_sec", "2020-05-02 22:06:60", t);
output.emplace_back("negative_sec", "2020-05-02 22:06:-1", t);
output.emplace_back("negative_micro_2", "2020-05-02 22:06:01.-1", t, 0, 2);
output.emplace_back("negative_micro_3", "2020-05-02 22:06:01.-12", t, 0, 3);
output.emplace_back("negative_micro_4", "2020-05-02 22:06:01.-123", t, 0, 4);
output.emplace_back("negative_micro_5", "2020-05-02 22:06:01.-1234", t, 0, 5);
output.emplace_back("negative_micro_6", "2020-05-02 22:06:01.-12345", t, 0, 6);
}
void add_time_samples(std::vector<error_sample>& output)
{
output.emplace_back("empty", "", protocol_field_type::time);
output.emplace_back("not_numbers", "abjkjdb67", protocol_field_type::time);
output.emplace_back("too_short_0", "1:20:20", protocol_field_type::time);
output.emplace_back("too_short_1", "1:20:20.1", protocol_field_type::time, 0, 1);
output.emplace_back("too_short_2", "01:20:20.1", protocol_field_type::time, 0, 2);
output.emplace_back("too_short_3", "01:20:20.12", protocol_field_type::time, 0, 3);
output.emplace_back("too_short_4", "01:20:20.123", protocol_field_type::time, 0, 4);
output.emplace_back("too_short_5", "01:20:20.1234", protocol_field_type::time, 0, 5);
output.emplace_back("too_short_6", "01:20:20.12345", protocol_field_type::time, 0, 6);
output.emplace_back("too_long_0", "-9999:40:40", protocol_field_type::time, 0, 0);
output.emplace_back("too_long_1", "-9999:40:40.1", protocol_field_type::time, 0, 1);
output.emplace_back("too_long_2", "-9999:40:40.12", protocol_field_type::time, 0, 2);
output.emplace_back("too_long_3", "-9999:40:40.123", protocol_field_type::time, 0, 3);
output.emplace_back("too_long_4", "-9999:40:40.1234", protocol_field_type::time, 0, 4);
output.emplace_back("too_long_5", "-9999:40:40.12345", protocol_field_type::time, 0, 5);
output.emplace_back("too_long_6", "-9999:40:40.123456", protocol_field_type::time, 0, 6);
output.emplace_back("extra_long", "-99999999:40:40.12345678", protocol_field_type::time, 0, 6);
output.emplace_back("extra_long2", "99999999999:40:40", protocol_field_type::time, 0, 6);
output.emplace_back("decimals_0", "01:20:20.1", protocol_field_type::time, 0, 0);
output.emplace_back("no_decimals_1", "01:20:20 ", protocol_field_type::time, 0, 1);
output.emplace_back("no_decimals_2", "01:20:20 ", protocol_field_type::time, 0, 2);
output.emplace_back("no_decimals_3", "01:20:20 ", protocol_field_type::time, 0, 3);
output.emplace_back("no_decimals_4", "01:20:20 ", protocol_field_type::time, 0, 4);
output.emplace_back("no_decimals_5", "01:20:20 ", protocol_field_type::time, 0, 5);
output.emplace_back("no_decimals_6", "01:20:20 ", protocol_field_type::time, 0, 6);
output.emplace_back("bad_delimiter", "01-20-20", protocol_field_type::time);
output.emplace_back("missing_1gp_0", "23:01: ", protocol_field_type::time);
output.emplace_back("missing_2gp_0", "23: ", protocol_field_type::time);
output.emplace_back("missing_1gp_1", "23:01:.9 ", protocol_field_type::time, 0, 1);
output.emplace_back("missing_2gp_1", "23:.9 ", protocol_field_type::time, 0, 1);
output.emplace_back("invalid_min", "22:60:20", protocol_field_type::time);
output.emplace_back("negative_min", "22:-1:20", protocol_field_type::time);
output.emplace_back("invalid_sec", "22:06:60", protocol_field_type::time);
output.emplace_back("negative_sec", "22:06:-1", protocol_field_type::time);
output.emplace_back("invalid_micro_1", "22:06:01.99", protocol_field_type::time, 0, 1);
output.emplace_back("invalid_micro_2", "22:06:01.999", protocol_field_type::time, 0, 2);
output.emplace_back("invalid_micro_3", "22:06:01.9999", protocol_field_type::time, 0, 3);
output.emplace_back("invalid_micro_4", "22:06:01.99999", protocol_field_type::time, 0, 4);
output.emplace_back("invalid_micro_5", "22:06:01.999999", protocol_field_type::time, 0, 5);
output.emplace_back("invalid_micro_6", "22:06:01.9999999", protocol_field_type::time, 0, 6);
output.emplace_back("negative_micro", "22:06:01.-1", protocol_field_type::time, 0, 2);
output.emplace_back("lt_min", "-900:00:00.00", protocol_field_type::time, 0, 2);
output.emplace_back("gt_max", "900:00:00.00", protocol_field_type::time, 0, 2);
output.emplace_back("invalid_sign", "x670:00:00.00", protocol_field_type::time, 0, 2);
output.emplace_back("null_char", makesv("20:00:\00.00"), protocol_field_type::time, 0, 2);
output.emplace_back("trailing_0", "22:06:01k", protocol_field_type::time, 0, 0);
output.emplace_back("trailing_1", "22:06:01.1k", protocol_field_type::time, 0, 1);
output.emplace_back("trailing_2", "22:06:01.12k", protocol_field_type::time, 0, 2);
output.emplace_back("trailing_3", "22:06:01.123k", protocol_field_type::time, 0, 3);
output.emplace_back("trailing_4", "22:06:01.1234k", protocol_field_type::time, 0, 4);
output.emplace_back("trailing_5", "22:06:01.12345k", protocol_field_type::time, 0, 5);
output.emplace_back("trailing_6", "22:06:01.123456k", protocol_field_type::time, 0, 6);
output.emplace_back("double_sign", "--22:06:01.123456", protocol_field_type::time, 0, 6);
}
std::vector<error_sample> make_all_samples()
{
std::vector<error_sample> res;
add_int_samples(protocol_field_type::tiny, res);
add_int_samples(protocol_field_type::short_, res);
add_int_samples(protocol_field_type::int24, res);
add_int_samples(protocol_field_type::long_, res);
add_int_samples(protocol_field_type::longlong, res);
add_int_samples(protocol_field_type::year, res);
add_bit_samples(res);
add_float_samples(protocol_field_type::float_, "-2e90", "2e90", res);
add_float_samples(protocol_field_type::double_, "-2e9999", "2e9999", res);
add_date_samples(res);
add_datetime_samples(protocol_field_type::datetime, res);
add_datetime_samples(protocol_field_type::timestamp, res);
add_time_samples(res);
return res;
}
BOOST_DATA_TEST_CASE(error, data::make(make_all_samples()))
{
column_definition_packet coldef {};
coldef.type = sample.type;
coldef.decimals = static_cast<std::uint8_t>(sample.decimals);
coldef.flags = sample.flags;
boost::mysql::metadata meta (coldef, false);
auto buffer_first = reinterpret_cast<const std::uint8_t*>(sample.from.data());
field_view actual_value;
auto err = deserialize_text_field(sample.from, meta, buffer_first, actual_value);
BOOST_TEST(err == sample.expected_err);
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
} // anon namespace

View File

@@ -9,6 +9,7 @@
#define BOOST_MYSQL_TEST_UNIT_DETAIL_PROTOCOL_SERIALIZATION_TEST_SAMPLES_PREPARED_STATEMENT_MESSAGES_HPP
#include <boost/mysql/detail/protocol/prepared_statement_messages.hpp>
#include <boost/mysql/field_view.hpp>
#include "../serialization_test.hpp"
#include <forward_list>
#include <array>
@@ -79,7 +80,7 @@ serialization_sample make_stmt_execute_sample(
const serialization_test_spec com_stmt_execute_packet_spec {
serialization_test_type::serialization, {
make_stmt_execute_sample(1, 0x80, 1, 1, // stmt ID, flags, itercount, new params
make_values(std::uint64_t(0xabffffabacadae)), {
make_field_views(std::uint64_t(0xabffffabacadae)), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x80, 0xae, 0xad,
0xac, 0xab, 0xff, 0xff, 0xab, 0x00
@@ -87,7 +88,7 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"uint64_t"
),
make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params
make_values(std::int64_t(-0xabffffabacadae)), {
make_field_views(std::int64_t(-0xabffffabacadae)), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x52, 0x52,
0x53, 0x54, 0x00, 0x00, 0x54, 0xff
@@ -95,7 +96,7 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"int64_t"
),
make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params
make_values(boost::string_view("test")), {
make_field_views(boost::string_view("test")), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x0f, 0x00, 0x04, 0x74,
0x65, 0x73, 0x74
@@ -103,7 +104,7 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"string_view"
),
make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params
make_values(3.14e20f), {
make_field_views(3.14e20f), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x01, 0x2d,
0x88, 0x61
@@ -111,7 +112,7 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"float"
),
make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params
make_values(2.1e214), {
make_field_views(2.1e214), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x56, 0xc0,
0xee, 0xa6, 0x95, 0x30, 0x6f, 0x6c
@@ -119,7 +120,7 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"double"
),
make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params
make_values(makedate(2010, 9, 3)), {
make_field_views(makedate(2010, 9, 3)), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x04, 0xda,
0x07, 0x09, 0x03
@@ -127,7 +128,7 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"date"
),
make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params
make_values(makedt(2010, 9, 3, 10, 30, 59, 231800)), {
make_field_views(makedt(2010, 9, 3, 10, 30, 59, 231800)), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x0b, 0xda,
0x07, 0x09, 0x03, 0x0a, 0x1e, 0x3b, 0x78, 0x89,
@@ -136,7 +137,7 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"datetime"
),
make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params
make_values(maket(230, 30, 59, 231800)), {
make_field_views(maket(230, 30, 59, 231800)), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x0c, 0x00,
0x09, 0x00, 0x00, 0x00, 0x0e, 0x1e, 0x3b, 0x78,
@@ -145,14 +146,14 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"time"
),
make_stmt_execute_sample(1, 0, 1, 1, // stmt ID, flags, itercount, new params
make_values(nullptr), {
make_field_views(nullptr), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x01, 0x06, 0x00
},
"null"
),
make_stmt_execute_sample(2, 0, 1, 1,
make_values(
make_field_views(
std::uint64_t(0xabffffabacadae),
std::int64_t(-0xabffffabacadae),
boost::string_view("test"),
@@ -178,7 +179,7 @@ const serialization_test_spec com_stmt_execute_packet_spec {
"several_params"
),
make_stmt_execute_sample<1, std::forward_list<field_view>>(1, 0x80, 1, 1,
make_values(std::uint64_t(0xabffff)), {
make_field_views(std::uint64_t(0xabffff)), {
0x17, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x80, 0xff, 0xff,
0xab, 0x00, 0x00, 0x00, 0x00, 0x00

View File

@@ -1,271 +0,0 @@
//
// Copyright (c) 2019-2022 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test deserialize_text_value(), only error cases
#include <boost/mysql/detail/protocol/text_deserialization.hpp>
#include "test_common.hpp"
#include <boost/test/data/monomorphic/collection.hpp>
#include <boost/test/data/test_case.hpp>
using namespace boost::mysql::detail;
using namespace boost::mysql::test;
using namespace boost::unit_test;
using boost::mysql::field_view;
using boost::mysql::error_code;
using boost::mysql::errc;
namespace
{
struct text_value_err_sample
{
std::string name;
boost::string_view from;
protocol_field_type type;
std::uint16_t flags;
unsigned decimals;
errc expected_err;
text_value_err_sample(std::string&& name, boost::string_view from, protocol_field_type type,
std::uint16_t flags=0, unsigned decimals=0, errc expected_err=errc::protocol_value_error) :
name(std::move(name)),
from(from),
type(type),
flags(flags),
decimals(decimals),
expected_err(expected_err)
{
}
};
std::ostream& operator<<(std::ostream& os, const text_value_err_sample& input)
{
return os << "(input=" << input.from
<< ", type=" << to_string(input.type)
<< ", name=" << input.name
<< ")";
}
void add_int_samples(
protocol_field_type t,
std::vector<text_value_err_sample>& output
)
{
output.emplace_back("signed_blank", "", t);
output.emplace_back("signed_non_number", "abtrf", t);
output.emplace_back("signed_hex", "0x01", t);
output.emplace_back("signed_fractional", "1.1", t);
output.emplace_back("signed_exp", "2e10", t);
output.emplace_back("signed_lt_min", "-9223372036854775809", t);
output.emplace_back("signed_gt_max", "9223372036854775808", t);
output.emplace_back("unsigned_blank", "", t, column_flags::unsigned_);
output.emplace_back("unsigned_non_number", "abtrf", t, column_flags::unsigned_);
output.emplace_back("unsigned_hex", "0x01", t, column_flags::unsigned_);
output.emplace_back("unsigned_fractional", "1.1", t, column_flags::unsigned_);
output.emplace_back("unsigned_exp", "2e10", t, column_flags::unsigned_);
output.emplace_back("unsigned_lt_min", "-18446744073709551616", t, column_flags::unsigned_);
output.emplace_back("unsigned_gt_max", "18446744073709551616", t, column_flags::unsigned_);
}
void add_bit_samples(
std::vector<text_value_err_sample>& output
)
{
output.emplace_back("bit_string_view_too_short", "", protocol_field_type::bit, column_flags::unsigned_);
output.emplace_back("bit_string_view_too_long", "123456789", protocol_field_type::bit, column_flags::unsigned_);
}
void add_float_samples(
protocol_field_type t,
boost::string_view lt_min,
boost::string_view gt_max,
std::vector<text_value_err_sample>& output
)
{
output.emplace_back("blank", "", t);
output.emplace_back("non_number", "abtrf", t);
output.emplace_back("lt_min", lt_min, t);
output.emplace_back("gt_max", gt_max, t);
output.emplace_back("inf", "inf", t); // inf values not allowed by SQL std
output.emplace_back("minus_inf", "-inf", t);
output.emplace_back("nan", "nan", t); // nan values not allowed by SQL std
output.emplace_back("minus_nan", "-nan", t);
}
void add_date_samples(std::vector<text_value_err_sample>& output)
{
output.emplace_back("empty", "", protocol_field_type::date);
output.emplace_back("too_short", "2020-05-2", protocol_field_type::date);
output.emplace_back("too_long", "02020-05-02", protocol_field_type::date);
output.emplace_back("bad_delimiter", "2020:05:02", protocol_field_type::date);
output.emplace_back("too_many_groups", "20-20-05-2", protocol_field_type::date);
output.emplace_back("too_few_groups", "2020-00005", protocol_field_type::date);
output.emplace_back("incomplete_year", "999-05-005", protocol_field_type::date);
output.emplace_back("hex", "ffff-ff-ff", protocol_field_type::date);
output.emplace_back("null_value", makesv("2020-05-\02"), protocol_field_type::date);
output.emplace_back("long_year", "10000-05-2", protocol_field_type::date);
output.emplace_back("long_month", "2010-005-2", protocol_field_type::date);
output.emplace_back("long_day", "2010-5-002", protocol_field_type::date);
output.emplace_back("negative_year", "-001-05-02", protocol_field_type::date);
output.emplace_back("invalid_month", "2010-13-02", protocol_field_type::date);
output.emplace_back("invalid_month_max","2010-99-02", protocol_field_type::date);
output.emplace_back("negative_month", "2010--5-02", protocol_field_type::date);
output.emplace_back("invalid_day", "2010-05-32", protocol_field_type::date);
output.emplace_back("invalid_day_max", "2010-05-99", protocol_field_type::date);
output.emplace_back("negative_day", "2010-05--2", protocol_field_type::date);
}
void add_datetime_samples(
protocol_field_type t,
std::vector<text_value_err_sample>& output
)
{
output.emplace_back("empty", "", t);
output.emplace_back("too_short_0", "2020-05-02 23:01:0", t, 0, 0);
output.emplace_back("too_short_1", "2020-05-02 23:01:0.1", t, 0, 1);
output.emplace_back("too_short_2", "2020-05-02 23:01:00.1", t, 0, 2);
output.emplace_back("too_short_3", "2020-05-02 23:01:00.11", t, 0, 3);
output.emplace_back("too_short_4", "2020-05-02 23:01:00.111", t, 0, 4);
output.emplace_back("too_short_5", "2020-05-02 23:01:00.1111", t, 0, 5);
output.emplace_back("too_short_6", "2020-05-02 23:01:00.11111", t, 0, 6);
output.emplace_back("too_long_0", "2020-05-02 23:01:00.8", t, 0, 0);
output.emplace_back("too_long_1", "2020-05-02 23:01:00.98", t, 0, 1);
output.emplace_back("too_long_2", "2020-05-02 23:01:00.998", t, 0, 2);
output.emplace_back("too_long_3", "2020-05-02 23:01:00.9998", t, 0, 3);
output.emplace_back("too_long_4", "2020-05-02 23:01:00.99998", t, 0, 4);
output.emplace_back("too_long_5", "2020-05-02 23:01:00.999998", t, 0, 5);
output.emplace_back("too_long_6", "2020-05-02 23:01:00.9999998", t, 0, 6);
output.emplace_back("no_decimals_1", "2020-05-02 23:01:00 ", t, 0, 1);
output.emplace_back("no_decimals_2", "2020-05-02 23:01:00 ", t, 0, 2);
output.emplace_back("no_decimals_3", "2020-05-02 23:01:00 ", t, 0, 3);
output.emplace_back("no_decimals_4", "2020-05-02 23:01:00 ", t, 0, 4);
output.emplace_back("no_decimals_5", "2020-05-02 23:01:00 ", t, 0, 5);
output.emplace_back("no_decimals_6", "2020-05-02 23:01:00 ", t, 0, 6);
output.emplace_back("trailing_0", "2020-05-02 23:01:0p", t, 0, 0);
output.emplace_back("trailing_1", "2020-05-02 23:01:00.p", t, 0, 1);
output.emplace_back("trailing_2", "2020-05-02 23:01:00.1p", t, 0, 2);
output.emplace_back("trailing_3", "2020-05-02 23:01:00.12p", t, 0, 3);
output.emplace_back("trailing_4", "2020-05-02 23:01:00.123p", t, 0, 4);
output.emplace_back("trailing_5", "2020-05-02 23:01:00.1234p", t, 0, 5);
output.emplace_back("trailing_6", "2020-05-02 23:01:00.12345p", t, 0, 6);
output.emplace_back("bad_delimiter", "2020-05-02 23-01-00", t);
output.emplace_back("missing_1gp_0", "2020-05-02 23:01: ", t);
output.emplace_back("missing_2gp_0", "2020-05-02 23: ", t);
output.emplace_back("missing_3gp_0", "2020-05-02 ", t);
output.emplace_back("missing_1gp_1", "2020-05-02 23:01:.9 ", t);
output.emplace_back("missing_2gp_1", "2020-05-02 23:.9 ", t);
output.emplace_back("missing_3gp_1", "2020-05-02.9 ", t);
output.emplace_back("invalid_year", "10000-05-02 24:20:20.1", t, 0, 2);
output.emplace_back("negative_year", "-100-05-02 24:20:20", t);
output.emplace_back("invalid_month", "2020-13-02 24:20:20", t);
output.emplace_back("negative_month", "2020--5-02 24:20:20", t);
output.emplace_back("invalid_day", "2020-05-32 24:20:20", t);
output.emplace_back("negative_day", "2020-05--2 24:20:20", t);
output.emplace_back("invalid_hour", "2020-05-02 24:20:20", t);
output.emplace_back("negative_hour", "2020-05-02 -2:20:20", t);
output.emplace_back("invalid_min", "2020-05-02 22:60:20", t);
output.emplace_back("negative_min", "2020-05-02 22:-1:20", t);
output.emplace_back("invalid_sec", "2020-05-02 22:06:60", t);
output.emplace_back("negative_sec", "2020-05-02 22:06:-1", t);
output.emplace_back("negative_micro_2", "2020-05-02 22:06:01.-1", t, 0, 2);
output.emplace_back("negative_micro_3", "2020-05-02 22:06:01.-12", t, 0, 3);
output.emplace_back("negative_micro_4", "2020-05-02 22:06:01.-123", t, 0, 4);
output.emplace_back("negative_micro_5", "2020-05-02 22:06:01.-1234", t, 0, 5);
output.emplace_back("negative_micro_6", "2020-05-02 22:06:01.-12345", t, 0, 6);
}
void add_time_samples(std::vector<text_value_err_sample>& output)
{
output.emplace_back("empty", "", protocol_field_type::time);
output.emplace_back("not_numbers", "abjkjdb67", protocol_field_type::time);
output.emplace_back("too_short_0", "1:20:20", protocol_field_type::time);
output.emplace_back("too_short_1", "1:20:20.1", protocol_field_type::time, 0, 1);
output.emplace_back("too_short_2", "01:20:20.1", protocol_field_type::time, 0, 2);
output.emplace_back("too_short_3", "01:20:20.12", protocol_field_type::time, 0, 3);
output.emplace_back("too_short_4", "01:20:20.123", protocol_field_type::time, 0, 4);
output.emplace_back("too_short_5", "01:20:20.1234", protocol_field_type::time, 0, 5);
output.emplace_back("too_short_6", "01:20:20.12345", protocol_field_type::time, 0, 6);
output.emplace_back("too_long_0", "-9999:40:40", protocol_field_type::time, 0, 0);
output.emplace_back("too_long_1", "-9999:40:40.1", protocol_field_type::time, 0, 1);
output.emplace_back("too_long_2", "-9999:40:40.12", protocol_field_type::time, 0, 2);
output.emplace_back("too_long_3", "-9999:40:40.123", protocol_field_type::time, 0, 3);
output.emplace_back("too_long_4", "-9999:40:40.1234", protocol_field_type::time, 0, 4);
output.emplace_back("too_long_5", "-9999:40:40.12345", protocol_field_type::time, 0, 5);
output.emplace_back("too_long_6", "-9999:40:40.123456", protocol_field_type::time, 0, 6);
output.emplace_back("extra_long", "-99999999:40:40.12345678", protocol_field_type::time, 0, 6);
output.emplace_back("extra_long2", "99999999999:40:40", protocol_field_type::time, 0, 6);
output.emplace_back("decimals_0", "01:20:20.1", protocol_field_type::time, 0, 0);
output.emplace_back("no_decimals_1", "01:20:20 ", protocol_field_type::time, 0, 1);
output.emplace_back("no_decimals_2", "01:20:20 ", protocol_field_type::time, 0, 2);
output.emplace_back("no_decimals_3", "01:20:20 ", protocol_field_type::time, 0, 3);
output.emplace_back("no_decimals_4", "01:20:20 ", protocol_field_type::time, 0, 4);
output.emplace_back("no_decimals_5", "01:20:20 ", protocol_field_type::time, 0, 5);
output.emplace_back("no_decimals_6", "01:20:20 ", protocol_field_type::time, 0, 6);
output.emplace_back("bad_delimiter", "01-20-20", protocol_field_type::time);
output.emplace_back("missing_1gp_0", "23:01: ", protocol_field_type::time);
output.emplace_back("missing_2gp_0", "23: ", protocol_field_type::time);
output.emplace_back("missing_1gp_1", "23:01:.9 ", protocol_field_type::time, 0, 1);
output.emplace_back("missing_2gp_1", "23:.9 ", protocol_field_type::time, 0, 1);
output.emplace_back("invalid_min", "22:60:20", protocol_field_type::time);
output.emplace_back("negative_min", "22:-1:20", protocol_field_type::time);
output.emplace_back("invalid_sec", "22:06:60", protocol_field_type::time);
output.emplace_back("negative_sec", "22:06:-1", protocol_field_type::time);
output.emplace_back("invalid_micro_1", "22:06:01.99", protocol_field_type::time, 0, 1);
output.emplace_back("invalid_micro_2", "22:06:01.999", protocol_field_type::time, 0, 2);
output.emplace_back("invalid_micro_3", "22:06:01.9999", protocol_field_type::time, 0, 3);
output.emplace_back("invalid_micro_4", "22:06:01.99999", protocol_field_type::time, 0, 4);
output.emplace_back("invalid_micro_5", "22:06:01.999999", protocol_field_type::time, 0, 5);
output.emplace_back("invalid_micro_6", "22:06:01.9999999", protocol_field_type::time, 0, 6);
output.emplace_back("negative_micro", "22:06:01.-1", protocol_field_type::time, 0, 2);
output.emplace_back("lt_min", "-900:00:00.00", protocol_field_type::time, 0, 2);
output.emplace_back("gt_max", "900:00:00.00", protocol_field_type::time, 0, 2);
output.emplace_back("invalid_sign", "x670:00:00.00", protocol_field_type::time, 0, 2);
output.emplace_back("null_char", makesv("20:00:\00.00"), protocol_field_type::time, 0, 2);
output.emplace_back("trailing_0", "22:06:01k", protocol_field_type::time, 0, 0);
output.emplace_back("trailing_1", "22:06:01.1k", protocol_field_type::time, 0, 1);
output.emplace_back("trailing_2", "22:06:01.12k", protocol_field_type::time, 0, 2);
output.emplace_back("trailing_3", "22:06:01.123k", protocol_field_type::time, 0, 3);
output.emplace_back("trailing_4", "22:06:01.1234k", protocol_field_type::time, 0, 4);
output.emplace_back("trailing_5", "22:06:01.12345k", protocol_field_type::time, 0, 5);
output.emplace_back("trailing_6", "22:06:01.123456k", protocol_field_type::time, 0, 6);
output.emplace_back("double_sign", "--22:06:01.123456", protocol_field_type::time, 0, 6);
}
std::vector<text_value_err_sample> make_all_samples()
{
std::vector<text_value_err_sample> res;
add_int_samples(protocol_field_type::tiny, res);
add_int_samples(protocol_field_type::short_, res);
add_int_samples(protocol_field_type::int24, res);
add_int_samples(protocol_field_type::long_, res);
add_int_samples(protocol_field_type::longlong, res);
add_int_samples(protocol_field_type::year, res);
add_bit_samples(res);
add_float_samples(protocol_field_type::float_, "-2e90", "2e90", res);
add_float_samples(protocol_field_type::double_, "-2e9999", "2e9999", res);
add_date_samples(res);
add_datetime_samples(protocol_field_type::datetime, res);
add_datetime_samples(protocol_field_type::timestamp, res);
add_time_samples(res);
return res;
}
BOOST_DATA_TEST_CASE(test_deserialize_text_value_error, data::make(make_all_samples()))
{
column_definition_packet coldef {};
coldef.type = sample.type;
coldef.decimals = static_cast<std::uint8_t>(sample.decimals);
coldef.flags = sample.flags;
boost::mysql::metadata meta (coldef);
field_view actual_value;
auto err = deserialize_text_value(sample.from, meta, actual_value);
auto expected = sample.expected_err;
BOOST_TEST(expected == err);
}
} // anon namespace