1//
2// Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7
8#include <boost/mysql/blob_view.hpp>
9#include <boost/mysql/column_type.hpp>
10#include <boost/mysql/date.hpp>
11#include <boost/mysql/datetime.hpp>
12#include <boost/mysql/metadata.hpp>
13
14#include <boost/mysql/impl/internal/protocol/deserialize_binary_field.hpp>
15#include <boost/mysql/impl/internal/protocol/serialization.hpp>
16
17#include <boost/test/unit_test.hpp>
18
19#include <cstddef>
20
21#include "operators.hpp"
22#include "serialization_test.hpp"
23#include "test_common/create_basic.hpp"
24#include "test_unit/create_meta.hpp"
25
26using namespace boost::mysql;
27using namespace boost::mysql::test;
28using detail::deserialize_errc;
29
30namespace {
31
32BOOST_AUTO_TEST_SUITE(test_deserialize_binary_field)
33
34BOOST_AUTO_TEST_SUITE(success)
35
36struct success_sample
37{
38 std::string name;
39 deserialization_buffer from;
40 field_view expected;
41 metadata meta;
42
43 template <class T>
44 success_sample(std::string name, std::vector<std::uint8_t> from, T&& expected_value, metadata meta)
45 : name(std::move(name)),
46 from(std::move(from)),
47 expected(std::forward<T>(expected_value)),
48 meta(std::move(meta))
49 {
50 }
51};
52
53void add_string_samples(std::vector<success_sample>& output)
54{
55 output.push_back(
56 x: success_sample("varchar", {0x04, 0x74, 0x65, 0x73, 0x74}, "test", create_meta(type: column_type::varchar))
57 );
58 output.push_back(
59 x: success_sample("char", {0x04, 0x74, 0x65, 0x73, 0x74}, "test", create_meta(type: column_type::char_))
60 );
61 output.push_back(
62 x: success_sample("text", {0x04, 0x74, 0x65, 0x73, 0x74}, "test", create_meta(type: column_type::text))
63 );
64 output.push_back(
65 x: success_sample("enum", {0x04, 0x74, 0x65, 0x73, 0x74}, "test", create_meta(type: column_type::enum_))
66 );
67 output.push_back(
68 x: success_sample("set", {0x04, 0x74, 0x65, 0x73, 0x74}, "test", create_meta(type: column_type::set))
69 );
70 output.push_back(x: success_sample("decimal", {0x02, 0x31, 0x30}, "10", create_meta(type: column_type::decimal)));
71 output.push_back(x: success_sample("json", {0x02, 0x7b, 0x7d}, "{}", create_meta(type: column_type::json)));
72}
73
74void add_blob_samples(std::vector<success_sample>& output)
75{
76 static constexpr std::uint8_t buff[] = {0x01, 0x00, 0x73, 0x74};
77
78 output.push_back(x: success_sample(
79 "varbinary",
80 {0x04, 0x01, 0x00, 0x73, 0x74},
81 blob_view(buff),
82 create_meta(type: column_type::varbinary)
83 ));
84 output.push_back(x: success_sample(
85 "binary",
86 {0x04, 0x01, 0x00, 0x73, 0x74},
87 blob_view(buff),
88 create_meta(type: column_type::binary)
89 ));
90 output.push_back(x: success_sample(
91 "blob",
92 {0x04, 0x01, 0x00, 0x73, 0x74},
93 blob_view(buff),
94 create_meta(type: column_type::blob)
95 ));
96 output.push_back(x: success_sample(
97 "geometry",
98 {0x04, 0x01, 0x00, 0x73, 0x74},
99 blob_view(buff),
100 create_meta(type: column_type::geometry)
101 ));
102
103 // Anything we don't know what it is, we interpret as a blob
104 output.push_back(x: success_sample(
105 "unknown_protocol_type",
106 {0x04, 0x01, 0x00, 0x73, 0x74},
107 blob_view(buff),
108 create_meta(type: column_type::unknown)
109 ));
110}
111
112// Note: these employ regular integer deserialization functions, which have
113// already been tested
114void add_int_samples(std::vector<success_sample>& output)
115{
116 output.push_back(x: success_sample(
117 "tinyint_unsigned",
118 {0x14},
119 std::uint64_t(20),
120 meta_builder().type(v: column_type::tinyint).unsigned_flag(v: true).build()
121 ));
122 output.push_back(
123 x: success_sample("tinyint_signed", {0xec}, std::int64_t(-20), create_meta(type: column_type::tinyint))
124 );
125
126 output.push_back(x: success_sample(
127 "smallint_unsigned",
128 {0x14, 0x00},
129 std::uint64_t(20),
130 meta_builder().type(v: column_type::smallint).unsigned_flag(v: true).build()
131 ));
132 output.push_back(
133 x: success_sample("smallint_signed", {0xec, 0xff}, std::int64_t(-20), create_meta(type: column_type::smallint))
134 );
135
136 output.push_back(x: success_sample(
137 "mediumint_unsigned",
138 {0x14, 0x00, 0x00, 0x00},
139 std::uint64_t(20),
140 meta_builder().type(v: column_type::mediumint).unsigned_flag(v: true).build()
141 ));
142 output.push_back(x: success_sample(
143 "mediumint_signed",
144 {0xec, 0xff, 0xff, 0xff},
145 std::int64_t(-20),
146 create_meta(type: column_type::mediumint)
147 ));
148
149 output.push_back(x: success_sample(
150 "int_unsigned",
151 {0x14, 0x00, 0x00, 0x00},
152 std::uint64_t(20),
153 meta_builder().type(v: column_type::int_).unsigned_flag(v: true).build()
154 ));
155 output.push_back(x: success_sample(
156 "int_signed",
157 {0xec, 0xff, 0xff, 0xff},
158 std::int64_t(-20),
159 create_meta(type: column_type::int_)
160 ));
161
162 output.push_back(x: success_sample(
163 "bigint_unsigned",
164 {0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
165 std::uint64_t(20),
166 meta_builder().type(v: column_type::bigint).unsigned_flag(v: true).build()
167 ));
168 output.push_back(x: success_sample(
169 "bigint_signed",
170 {0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
171 std::int64_t(-20),
172 create_meta(type: column_type::bigint)
173 ));
174
175 output.push_back(x: success_sample(
176 "year",
177 {0xe3, 0x07},
178 std::uint64_t(2019),
179 meta_builder().type(v: column_type::year).unsigned_flag(v: true).build()
180 ));
181}
182
183// bit
184void add_bit_types(std::vector<success_sample>& output)
185{
186 auto meta = meta_builder().type(v: column_type::bit).unsigned_flag(v: true).build();
187
188 output.push_back(x: success_sample("bit_8", {0x01, 0x12}, std::uint64_t(0x12), meta));
189 output.push_back(x: success_sample("bit_16", {0x02, 0x12, 0x34}, std::uint64_t(0x1234), meta));
190 output.push_back(x: success_sample("bit_24", {0x03, 0x12, 0x34, 0x56}, std::uint64_t(0x123456), meta));
191 output.push_back(x: success_sample("bit_32", {0x04, 0x12, 0x34, 0x56, 0x78}, std::uint64_t(0x12345678), meta)
192 );
193 output.push_back(
194 x: success_sample("bit_40", {0x05, 0x12, 0x34, 0x56, 0x78, 0x9a}, std::uint64_t(0x123456789a), meta)
195 );
196 output.push_back(x: success_sample(
197 "bit_48",
198 {0x06, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc},
199 std::uint64_t(0x123456789abc),
200 meta
201 ));
202 output.push_back(x: success_sample(
203 "bit_56",
204 {0x07, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde},
205 std::uint64_t(0x123456789abcde),
206 meta
207 ));
208 output.push_back(x: success_sample(
209 "bit_64",
210 {0x08, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
211 std::uint64_t(0x123456789abcdef0),
212 meta
213 ));
214}
215
216void add_float_samples(std::vector<success_sample>& output)
217{
218 auto meta = create_meta(type: column_type::float_);
219 output.push_back(x: success_sample("fractional_negative", {0x66, 0x66, 0x86, 0xc0}, -4.2f, meta));
220 output.push_back(x: success_sample("fractional_positive", {0x66, 0x66, 0x86, 0x40}, 4.2f, meta));
221 output.push_back(
222 x: success_sample("positive_exp_positive_fractional", {0x01, 0x2d, 0x88, 0x61}, 3.14e20f, meta)
223 );
224 output.push_back(x: success_sample("zero", {0x00, 0x00, 0x00, 0x00}, 0.0f, meta));
225}
226
227void add_double_samples(std::vector<success_sample>& output)
228{
229 auto meta = create_meta(type: column_type::double_);
230 output.push_back(
231 x: success_sample("fractional_negative", {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0xc0}, -4.2, meta)
232 );
233 output.push_back(
234 x: success_sample("fractional_positive", {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40}, 4.2, meta)
235 );
236 output.push_back(x: success_sample(
237 "positive_exp_positive_fractional",
238 {0xce, 0x46, 0x3c, 0x76, 0x9c, 0x68, 0x90, 0x69},
239 3.14e200,
240 meta
241 ));
242 output.push_back(x: success_sample("zero", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0.0, meta));
243}
244
245void add_date_samples(std::vector<success_sample>& output)
246{
247 auto meta = create_meta(type: column_type::date);
248 output.push_back(x: success_sample("regular", {0x04, 0xda, 0x07, 0x03, 0x1c}, date(2010u, 3u, 28u), meta));
249 output.push_back(x: success_sample("min", {0x04, 0x00, 0x00, 0x01, 0x01}, date(0u, 1u, 1u), meta));
250 output.push_back(x: success_sample("max", {0x04, 0x0f, 0x27, 0x0c, 0x1f}, date(9999u, 12u, 31u), meta));
251 output.push_back(x: success_sample("empty", {0x00}, date(), meta));
252 output.push_back(x: success_sample("zero", {0x04, 0x00, 0x00, 0x00, 0x00}, date(), meta));
253 output.push_back(x: success_sample("zero_month", {0x04, 0xda, 0x07, 0x00, 0x01}, date(2010u, 0u, 1u), meta));
254 output.push_back(x: success_sample("zero_day", {0x04, 0xda, 0x07, 0x01, 0x00}, date(2010u, 1u, 0u), meta));
255 output.push_back(
256 x: success_sample("zero_month_day", {0x04, 0xda, 0x07, 0x00, 0x00}, date(2010u, 0u, 0u), meta)
257 );
258 output.push_back(
259 x: success_sample("invalid_date", {0x04, 0xda, 0x07, 0x0b, 0x1f}, date(2010u, 11u, 31u), meta)
260 );
261}
262
263void add_datetime_samples(column_type type, std::vector<success_sample>& output)
264{
265 auto meta = create_meta(type);
266 output.push_back(
267 x: success_sample("only_date", {0x04, 0xda, 0x07, 0x01, 0x01}, datetime(2010u, 1u, 1u), meta)
268 );
269 output.push_back(x: success_sample(
270 "date_h",
271 {0x07, 0xda, 0x07, 0x01, 0x01, 0x14, 0x00, 0x00},
272 datetime(2010u, 1u, 1u, 20u, 0u, 0u, 0u),
273 meta
274 ));
275 output.push_back(x: success_sample(
276 "date_m",
277 {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x00},
278 datetime(2010u, 1u, 1u, 0u, 1u, 0u, 0u),
279 meta
280 ));
281 output.push_back(x: success_sample(
282 "date_hm",
283 {0x07, 0xda, 0x07, 0x01, 0x01, 0x03, 0x02, 0x00},
284 datetime(2010u, 1u, 1u, 3u, 2u, 0u, 0u),
285 meta
286 ));
287 output.push_back(x: success_sample(
288 "date_s",
289 {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x01},
290 datetime(2010u, 1u, 1u, 0u, 0u, 1u, 0u),
291 meta
292 ));
293 output.push_back(x: success_sample(
294 "date_ms",
295 {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x3b, 0x01},
296 datetime(2010u, 1u, 1u, 0u, 59u, 1u, 0u),
297 meta
298 ));
299 output.push_back(x: success_sample(
300 "date_hs",
301 {0x07, 0xda, 0x07, 0x01, 0x01, 0x05, 0x00, 0x01},
302 datetime(2010u, 1u, 1u, 5u, 0u, 1u, 0u),
303 meta
304 ));
305 output.push_back(x: success_sample(
306 "date_hms",
307 {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b},
308 datetime(2010u, 1u, 1u, 23u, 1u, 59u, 0u),
309 meta
310 ));
311 output.push_back(x: success_sample(
312 "date_u",
313 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x78, 0xd4, 0x03, 0x00},
314 datetime(2010u, 1u, 1u, 0u, 0u, 0u, 251000u),
315 meta
316 ));
317 output.push_back(x: success_sample(
318 "date_hu",
319 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x00, 0x00, 0x56, 0xc3, 0x0e, 0x00},
320 datetime(2010u, 1u, 1u, 23u, 0u, 0u, 967510u),
321 meta
322 ));
323 output.push_back(x: success_sample(
324 "date_mu",
325 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x00, 0x56, 0xc3, 0x0e, 0x00},
326 datetime(2010u, 1u, 1u, 0u, 1u, 0u, 967510u),
327 meta
328 ));
329 output.push_back(x: success_sample(
330 "date_hmu",
331 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x00, 0x56, 0xc3, 0x0e, 0x00},
332 datetime(2010u, 1u, 1u, 23u, 1u, 0u, 967510u),
333 meta
334 ));
335 output.push_back(x: success_sample(
336 "date_su",
337 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
338 datetime(2010u, 1u, 1u, 0u, 0u, 59u, 967510u),
339 meta
340 ));
341 output.push_back(x: success_sample(
342 "date_msu",
343 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
344 datetime(2010u, 1u, 1u, 0u, 1u, 59u, 967510u),
345 meta
346 ));
347 output.push_back(x: success_sample(
348 "date_hsu",
349 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x00, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
350 datetime(2010u, 1u, 1u, 23u, 0u, 59u, 967510u),
351 meta
352 ));
353 output.push_back(x: success_sample(
354 "date_hmsu",
355 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
356 datetime(2010u, 1u, 1u, 23u, 1u, 59u, 967510u),
357 meta
358 ));
359
360 // Invalid datetimes (because their date is invalid)
361 output.push_back(x: success_sample("empty", {0x00}, datetime(), meta));
362 output.push_back(x: success_sample("only_date_zeros", {0x04, 0x00, 0x00, 0x00, 0x00}, datetime(), meta));
363 output.push_back(x: success_sample(
364 "only_date_invalid_date",
365 {0x04, 0xda, 0x07, 0x0b, 0x1f},
366 datetime(2010u, 11u, 31u),
367 meta
368 ));
369 output.push_back(
370 x: success_sample("only_date_zero_month", {0x04, 0xda, 0x07, 0x00, 0x01}, datetime(2010u, 0u, 1u), meta)
371 );
372 output.push_back(
373 x: success_sample("only_date_zero_day", {0x04, 0xda, 0x07, 0x01, 0x00}, datetime(2010u, 1u, 0u), meta)
374 );
375 output.push_back(x: success_sample(
376 "only_date_zero_month_day",
377 {0x04, 0xda, 0x07, 0x00, 0x00},
378 datetime(2010u, 0u, 0u),
379 meta
380 ));
381
382 output.push_back(
383 x: success_sample("date_hms_zeros", {0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, datetime(), meta)
384 );
385 output.push_back(x: success_sample(
386 "date_hms_invalid_date",
387 {0x07, 0xda, 0x07, 0x0b, 0x1f, 0x17, 0x01, 0x3b},
388 datetime(2010u, 11u, 31u, 23u, 1u, 59u),
389 meta
390 ));
391 output.push_back(x: success_sample(
392 "date_hms_zero_month",
393 {0x07, 0xda, 0x07, 0x00, 0x01, 0x17, 0x01, 0x3b},
394 datetime(2010u, 0u, 1u, 23u, 1u, 59u),
395 meta
396 ));
397 output.push_back(x: success_sample(
398 "date_hms_zero_day",
399 {0x07, 0xda, 0x07, 0x01, 0x00, 0x17, 0x01, 0x3b},
400 datetime(2010u, 1u, 0u, 23u, 1u, 59u),
401 meta
402 ));
403 output.push_back(x: success_sample(
404 "date_hms_zero_month_day",
405 {0x07, 0xda, 0x07, 0x00, 0x00, 0x17, 0x01, 0x3b},
406 datetime(2010u, 0u, 0u, 23u, 1u, 59u),
407 meta
408 ));
409
410 output.push_back(x: success_sample(
411 "date_hmsu_zeros",
412 {0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
413 datetime(),
414 meta
415 ));
416 output.push_back(x: success_sample(
417 "date_hmsu_invalid_date",
418 {0x0b, 0xda, 0x07, 0x0b, 0x1f, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
419 datetime(2010u, 11u, 31u, 23u, 1u, 59u, 967510u),
420 meta
421 ));
422 output.push_back(x: success_sample(
423 "date_hmsu_zero_month",
424 {0x0b, 0xda, 0x07, 0x00, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
425 datetime(2010u, 0u, 1u, 23u, 1u, 59u, 967510u),
426 meta
427 ));
428 output.push_back(x: success_sample(
429 "date_hmsu_zero_day",
430 {0x0b, 0xda, 0x07, 0x01, 0x00, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
431 datetime(2010u, 1u, 0u, 23u, 1u, 59u, 967510u),
432 meta
433 ));
434 output.push_back(x: success_sample(
435 "date_hmsu_zero_month_day",
436 {0x0b, 0xda, 0x07, 0x00, 0x00, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
437 datetime(2010u, 0u, 0u, 23u, 1u, 59u, 967510u),
438 meta
439 ));
440}
441
442void add_time_samples(std::vector<success_sample>& output)
443{
444 auto meta = create_meta(type: column_type::time);
445 output.push_back(x: success_sample("zero", {0x00}, maket(hours: 0, mins: 0, secs: 0), meta));
446 output.push_back(x: success_sample(
447 "positive_d",
448 {0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
449 maket(hours: 48, mins: 0, secs: 0, micros: 0),
450 meta
451 ));
452 output.push_back(x: success_sample(
453 "positive_h",
454 {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00},
455 maket(hours: 21, mins: 0, secs: 0, micros: 0),
456 meta
457 ));
458 output.push_back(x: success_sample(
459 "positive_m",
460 {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00},
461 maket(hours: 0, mins: 40, secs: 0),
462 meta
463 ));
464 output.push_back(x: success_sample(
465 "positive_s",
466 {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15},
467 maket(hours: 0, mins: 0, secs: 21),
468 meta
469 ));
470 output.push_back(x: success_sample(
471 "positive_u",
472 {0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00},
473 maket(hours: 0, mins: 0, secs: 0, micros: 321000),
474 meta
475 ));
476 output.push_back(x: success_sample(
477 "positive_hmsu",
478 {0x0c, 0x00, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00},
479 maket(hours: 838, mins: 59, secs: 58, micros: 999000),
480 meta
481 ));
482 output.push_back(x: success_sample(
483 "negative_d",
484 {0x08, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
485 -maket(hours: 48, mins: 0, secs: 0, micros: 0),
486 meta
487 ));
488 output.push_back(x: success_sample(
489 "negative_h",
490 {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00},
491 -maket(hours: 21, mins: 0, secs: 0, micros: 0),
492 meta
493 ));
494 output.push_back(x: success_sample(
495 "negative_m",
496 {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00},
497 -maket(hours: 0, mins: 40, secs: 0),
498 meta
499 ));
500 output.push_back(x: success_sample(
501 "negative_s",
502 {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15},
503 -maket(hours: 0, mins: 0, secs: 21),
504 meta
505 ));
506 output.push_back(x: success_sample(
507 "negative_u",
508 {0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00},
509 -maket(hours: 0, mins: 0, secs: 0, micros: 321000),
510 meta
511 ));
512 output.push_back(x: success_sample(
513 "negative_hmsu",
514 {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00},
515 -maket(hours: 838, mins: 59, secs: 58, micros: 999000),
516 meta
517 ));
518 output.push_back(x: success_sample(
519 "negative_sign_not_one",
520 {0x0c, 0x03, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00},
521 -maket(hours: 838, mins: 59, secs: 58, micros: 999000),
522 meta
523 ));
524}
525
526std::vector<success_sample> make_all_samples()
527{
528 std::vector<success_sample> res;
529 add_string_samples(output&: res);
530 add_blob_samples(output&: res);
531 add_int_samples(output&: res);
532 add_bit_types(output&: res);
533 add_float_samples(output&: res);
534 add_double_samples(output&: res);
535 add_date_samples(output&: res);
536 add_datetime_samples(type: column_type::datetime, output&: res);
537 add_datetime_samples(type: column_type::timestamp, output&: res);
538 add_time_samples(output&: res);
539 return res;
540}
541
542BOOST_AUTO_TEST_CASE(success)
543{
544 for (const auto& tc : make_all_samples())
545 {
546 BOOST_TEST_CONTEXT("type=" << tc.meta.type() << ", name=" << tc.name)
547 {
548 const auto& buffer = tc.from;
549 detail::deserialization_context ctx(buffer);
550
551 field_view actual_value;
552 auto err = deserialize_binary_field(ctx, meta: tc.meta, output&: actual_value);
553
554 BOOST_TEST(err == deserialize_errc::ok);
555 BOOST_TEST(actual_value == tc.expected);
556 BOOST_TEST(ctx.first() == buffer.data() + buffer.size()); // all bytes consumed
557 }
558 }
559}
560
561BOOST_AUTO_TEST_SUITE_END()
562
563BOOST_AUTO_TEST_SUITE(error)
564
565struct error_sample
566{
567 std::string name;
568 deserialization_buffer from;
569 metadata meta;
570 deserialize_errc expected_err;
571
572 error_sample(
573 std::string&& name,
574 deserialization_buffer&& from,
575 metadata meta,
576 deserialize_errc expected_err = deserialize_errc::protocol_value_error
577 )
578 : name(std::move(name)), from(std::move(from)), meta(std::move(meta)), expected_err(expected_err)
579 {
580 }
581};
582
583void add_int_samples(column_type type, std::size_t num_bytes, std::vector<error_sample>& output)
584{
585 output.emplace_back(args: error_sample(
586 "signed_not_enough_space",
587 deserialization_buffer(num_bytes, 0x0a),
588 create_meta(type),
589 deserialize_errc::incomplete_message
590 ));
591 output.emplace_back(args: error_sample(
592 "unsigned_not_enough_space",
593 deserialization_buffer(num_bytes, 0x0a),
594 meta_builder().type(v: type).unsigned_flag(v: true).build(),
595 deserialize_errc::incomplete_message
596 ));
597}
598
599void add_bit_samples(std::vector<error_sample>& output)
600{
601 auto meta = meta_builder().type(v: column_type::bit).unsigned_flag(v: true).build();
602
603 output.emplace_back(args: error_sample(
604 "bit_error_deserializing_string_view",
605 {0x01},
606 meta,
607 deserialize_errc::incomplete_message
608 ));
609 output.emplace_back(args: error_sample("bit_string_view_too_short", {0x00}, meta));
610 output.emplace_back(args: error_sample(
611 "bit_string_view_too_long",
612 {0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09},
613 meta
614 ));
615}
616
617void add_float_samples(std::vector<error_sample>& output)
618{
619 auto meta = create_meta(type: column_type::float_);
620
621 output.push_back(
622 x: error_sample("not_enough_space", {0x01, 0x02, 0x03}, meta, deserialize_errc::incomplete_message)
623 );
624 output.push_back(x: error_sample("inf", {0x00, 0x00, 0x80, 0x7f}, meta));
625 output.push_back(x: error_sample("minus_inf", {0x00, 0x00, 0x80, 0xff}, meta));
626 output.push_back(x: error_sample("nan", {0xff, 0xff, 0xff, 0x7f}, meta));
627 output.push_back(x: error_sample("minus_nan", {0xff, 0xff, 0xff, 0xff}, meta));
628}
629
630void add_double_samples(std::vector<error_sample>& output)
631{
632 auto meta = create_meta(type: column_type::double_);
633
634 output.push_back(x: error_sample(
635 "not_enough_space",
636 {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07},
637 meta,
638 deserialize_errc::incomplete_message
639 ));
640 output.push_back(x: error_sample("inf", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f}, meta));
641 output.push_back(x: error_sample("minus_inf", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff}, meta));
642 output.push_back(x: error_sample("nan", {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, meta));
643 output.push_back(x: error_sample("minus_nan", {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, meta));
644}
645
646// Based on correct, regular date {0x04, 0xda, 0x07, 0x03, 0x1c}
647void add_date_samples(std::vector<error_sample>& output)
648{
649 auto meta = create_meta(type: column_type::date);
650
651 output.push_back(x: error_sample("empty", {}, meta, deserialize_errc::incomplete_message));
652 output.push_back(x: error_sample("incomplete_year", {0x04, 0xda}, meta, deserialize_errc::incomplete_message)
653 );
654 output.push_back(
655 x: error_sample("no_month_day", {0x04, 0xda, 0x07}, meta, deserialize_errc::incomplete_message)
656 );
657 output.push_back(
658 x: error_sample("no_day", {0x04, 0xda, 0x07, 0x03}, meta, deserialize_errc::incomplete_message)
659 );
660 output.push_back(x: error_sample(
661 "invalid_year",
662 {0x04, 0x10, 0x27, 0x03, 0x1c}, // year 10000
663 meta
664 ));
665 output.push_back(x: error_sample("invalid_year_max", {0x04, 0xff, 0xff, 0x03, 0x1c}, meta));
666 output.push_back(x: error_sample("invalid_month", {0x04, 0xda, 0x07, 13, 0x1c}, meta));
667 output.push_back(x: error_sample("invalid_month_max", {0x04, 0xda, 0x07, 0xff, 0x1c}, meta));
668 output.push_back(x: error_sample("invalid_day", {0x04, 0xda, 0x07, 0x03, 32}, meta));
669 output.push_back(x: error_sample("invalid_day_max", {0x04, 0xda, 0x07, 0x03, 0xff}, meta));
670 output.push_back(x: error_sample("protocol_max", {0xff, 0xff, 0xff, 0xff, 0xff}, meta));
671}
672
673// Based on correct datetime {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e,
674// 0x00}
675void add_datetime_samples(column_type type, std::vector<error_sample>& output)
676{
677 auto meta = create_meta(type);
678
679 output.push_back(x: error_sample("empty", {}, meta, deserialize_errc::incomplete_message));
680 output.push_back(
681 x: error_sample("incomplete_date", {0x04, 0xda, 0x07, 0x01}, meta, deserialize_errc::incomplete_message)
682 );
683 output.push_back(x: error_sample(
684 "no_hours_mins_secs",
685 {0x07, 0xda, 0x07, 0x01, 0x01},
686 meta,
687 deserialize_errc::incomplete_message
688 ));
689 output.push_back(x: error_sample(
690 "no_mins_secs",
691 {0x07, 0xda, 0x07, 0x01, 0x01, 0x17},
692 meta,
693 deserialize_errc::incomplete_message
694 ));
695 output.push_back(x: error_sample(
696 "no_secs",
697 {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01},
698 meta,
699 deserialize_errc::incomplete_message
700 ));
701 output.push_back(x: error_sample(
702 "incomplete_micros",
703 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e},
704 meta,
705 deserialize_errc::incomplete_message
706 ));
707 output.push_back(x: error_sample("invalid_year_d", {0x04, 0x10, 0x27, 0x01, 0x01}, meta)); // year 10000
708 output.push_back(x: error_sample("invalid_year_hms", {0x07, 0x10, 0x27, 0x01, 0x01, 0x17, 0x01, 0x3b}, meta)
709 );
710 output.push_back(x: error_sample(
711 "invalid_year_hmsu",
712 {0x0b, 0x10, 0x27, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
713 meta
714 ));
715 output.push_back(x: error_sample(
716 "invalid_year_max_hmsu",
717 {0x0b, 0xff, 0xff, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
718 meta
719 ));
720 output.push_back(x: error_sample("invalid_hour_hms", {0x07, 0xda, 0x07, 0x01, 0x01, 24, 0x01, 0x3b}, meta));
721 output.push_back(x: error_sample(
722 "invalid_hour_hmsu",
723 {0x0b, 0xda, 0x07, 0x01, 0x01, 24, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
724 meta
725 ));
726 output.push_back(x: error_sample(
727 "invalid_hour_max_hmsu",
728 {0x0b, 0xda, 0x07, 0x01, 0x01, 0xff, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
729 meta
730 ));
731 output.push_back(x: error_sample("invalid_min_hms", {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 60, 0x3b}, meta));
732 output.push_back(x: error_sample(
733 "invalid_min_hmsu",
734 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 60, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
735 meta
736 ));
737 output.push_back(x: error_sample(
738 "invalid_min_max_hmsu",
739 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0xff, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
740 meta
741 ));
742 output.push_back(x: error_sample("invalid_sec_hms", {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 60}, meta));
743 output.push_back(x: error_sample(
744 "invalid_sec_hmsu",
745 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 60, 0x56, 0xc3, 0x0e, 0x00},
746 meta
747 ));
748 output.push_back(x: error_sample(
749 "invalid_sec_max_hmsu",
750 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0xff, 0x56, 0xc3, 0x0e, 0x00},
751 meta
752 ));
753 output.push_back(x: error_sample(
754 "invalid_micro_hmsu",
755 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x40, 0x42, 0xf4, 0x00},
756 meta
757 )); // 1M
758 output.push_back(x: error_sample(
759 "invalid_micro_max_hmsu",
760 {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0xff, 0xff, 0xff, 0xff},
761 meta
762 ));
763 output.push_back(x: error_sample(
764 "invalid_hour_invalid_date",
765 {0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
766 meta
767 ));
768 output.push_back(x: error_sample(
769 "invalid_min_invalid_date",
770 {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x3b, 0x56, 0xc3, 0x0e, 0x00},
771 meta
772 ));
773 output.push_back(x: error_sample(
774 "invalid_sec_invalid_date",
775 {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0x01, 0xff, 0x56, 0xc3, 0x0e, 0x00},
776 meta
777 ));
778 output.push_back(x: error_sample(
779 "invalid_micro_invalid_date",
780 {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0x01, 0x3b, 0xff, 0xff, 0xff, 0xff},
781 meta
782 ));
783 output.push_back(x: error_sample(
784 "protocol_max",
785 {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
786 meta
787 ));
788}
789
790void add_time_samples(std::vector<error_sample>& output)
791{
792 auto meta = create_meta(type: column_type::time);
793
794 output.push_back(x: error_sample("empty", {}, meta, deserialize_errc::incomplete_message));
795 output.push_back(
796 x: error_sample("no_sign_days_hours_mins_secs", {0x08}, meta, deserialize_errc::incomplete_message)
797 );
798 output.push_back(
799 x: error_sample("no_days_hours_mins_secs", {0x08, 0x01}, meta, deserialize_errc::incomplete_message)
800 );
801 output.push_back(x: error_sample(
802 "no_hours_mins_secs",
803 {0x08, 0x01, 0x22, 0x00, 0x00, 0x00},
804 meta,
805 deserialize_errc::incomplete_message
806 ));
807 output.push_back(x: error_sample(
808 "no_mins_secs",
809 {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16},
810 meta,
811 deserialize_errc::incomplete_message
812 ));
813 output.push_back(x: error_sample(
814 "no_secs",
815 {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b},
816 meta,
817 deserialize_errc::incomplete_message
818 ));
819 output.push_back(x: error_sample(
820 "no_micros",
821 {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a},
822 meta,
823 deserialize_errc::incomplete_message
824 ));
825
826 std::pair<const char*, std::vector<std::uint8_t>> out_of_range_cases[]{
827 {"invalid_days", {0x08, 0x00, 35, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a} },
828 {"invalid_days_max", {0x08, 0x00, 0xff, 0xff, 0xff, 0xff, 0x16, 0x3b, 0x3a} },
829 {"invalid_hours", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 24, 0x3b, 0x3a} },
830 {"invalid_hours_max", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0xff, 0x3b, 0x3a} },
831 {"invalid_mins", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 60, 0x3a} },
832 {"invalid_mins_max", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0xff, 0x3a} },
833 {"invalid_secs", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 60} },
834 {"invalid_secs_max", {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0xff} },
835 {"invalid_micros", {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x40, 0x42, 0xf4, 0x00}},
836 {"invalid_micros_max",
837 {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0xff, 0xff, 0xff, 0xff} },
838 };
839
840 for (auto& c : out_of_range_cases)
841 {
842 // Positive
843 c.second[1] = 0x00;
844 output.emplace_back(args: c.first + std::string("_positive"), args: deserialization_buffer(c.second), args&: meta);
845
846 // Negative
847 c.second[1] = 0x01;
848 output.emplace_back(args: c.first + std::string("_negative"), args: deserialization_buffer(c.second), args&: meta);
849 }
850}
851
852std::vector<error_sample> make_all_samples()
853{
854 std::vector<error_sample> res;
855 add_int_samples(type: column_type::tinyint, num_bytes: 0, output&: res);
856 add_int_samples(type: column_type::smallint, num_bytes: 1, output&: res);
857 add_int_samples(type: column_type::mediumint, num_bytes: 3, output&: res);
858 add_int_samples(type: column_type::int_, num_bytes: 3, output&: res);
859 add_int_samples(type: column_type::bigint, num_bytes: 7, output&: res);
860 add_int_samples(type: column_type::year, num_bytes: 1, output&: res);
861 add_bit_samples(output&: res);
862 add_float_samples(output&: res);
863 add_double_samples(output&: res);
864 add_date_samples(output&: res);
865 add_datetime_samples(type: column_type::datetime, output&: res);
866 add_datetime_samples(type: column_type::timestamp, output&: res);
867 add_time_samples(output&: res);
868 return res;
869}
870
871BOOST_AUTO_TEST_CASE(error)
872{
873 for (const auto& tc : make_all_samples())
874 {
875 BOOST_TEST_CONTEXT("type=" << tc.meta.type() << ", name=" << tc.name)
876 {
877 detail::deserialization_context ctx(tc.from);
878
879 field_view actual_value;
880 auto err = deserialize_binary_field(ctx, meta: tc.meta, output&: actual_value);
881
882 BOOST_TEST(err == tc.expected_err);
883 }
884 }
885}
886
887BOOST_AUTO_TEST_SUITE_END()
888
889BOOST_AUTO_TEST_SUITE_END()
890
891} // namespace
892

source code of boost/libs/mysql/test/unit/test/protocol/deserialize_binary_field.cpp