1use crate::constant::{ColumnFlags, ColumnType};
7use crate::error::{Error, Result, eyre};
8use crate::protocol::BinaryRowPayload;
9use crate::protocol::command::{ColumnDefinition, ColumnDefinitionTail};
10use crate::protocol::primitive::*;
11use crate::value::{Time8, Time12, Timestamp4, Timestamp7, Timestamp11, Value};
12use simdutf8::basic::from_utf8;
13use zerocopy::FromBytes;
14
15const BINARY_CHARSET: u16 = 63;
17
18pub trait FromRawValue<'buf>: Sized {
23 fn from_null() -> Result<Self> {
24 Err(Error::BadUsageError(format!(
25 "Cannot decode MySQL type NULL to {}",
26 std::any::type_name::<Self>()
27 )))
28 }
29
30 fn from_i8(_v: i8) -> Result<Self> {
31 Err(Error::BadUsageError(format!(
32 "Cannot decode MySQL type TINYINT (i8) to {}",
33 std::any::type_name::<Self>()
34 )))
35 }
36
37 fn from_i16(_v: i16) -> Result<Self> {
38 Err(Error::BadUsageError(format!(
39 "Cannot decode MySQL type SMALLINT (i16) to {}",
40 std::any::type_name::<Self>()
41 )))
42 }
43
44 fn from_i32(_v: i32) -> Result<Self> {
45 Err(Error::BadUsageError(format!(
46 "Cannot decode MySQL type INT (i32) to {}",
47 std::any::type_name::<Self>()
48 )))
49 }
50
51 fn from_i64(_v: i64) -> Result<Self> {
52 Err(Error::BadUsageError(format!(
53 "Cannot decode MySQL type BIGINT (i64) to {}",
54 std::any::type_name::<Self>()
55 )))
56 }
57
58 fn from_u8(_v: u8) -> Result<Self> {
59 Err(Error::BadUsageError(format!(
60 "Cannot decode MySQL type TINYINT UNSIGNED (u8) to {}",
61 std::any::type_name::<Self>()
62 )))
63 }
64
65 fn from_u16(_v: u16) -> Result<Self> {
66 Err(Error::BadUsageError(format!(
67 "Cannot decode MySQL type SMALLINT UNSIGNED (u16) to {}",
68 std::any::type_name::<Self>()
69 )))
70 }
71
72 fn from_u32(_v: u32) -> Result<Self> {
73 Err(Error::BadUsageError(format!(
74 "Cannot decode MySQL type INT UNSIGNED (u32) to {}",
75 std::any::type_name::<Self>()
76 )))
77 }
78
79 fn from_u64(_v: u64) -> Result<Self> {
80 Err(Error::BadUsageError(format!(
81 "Cannot decode MySQL type BIGINT UNSIGNED (u64) to {}",
82 std::any::type_name::<Self>()
83 )))
84 }
85
86 fn from_float(_v: f32) -> Result<Self> {
87 Err(Error::BadUsageError(format!(
88 "Cannot decode MySQL type FLOAT (f32) to {}",
89 std::any::type_name::<Self>()
90 )))
91 }
92
93 fn from_double(_v: f64) -> Result<Self> {
94 Err(Error::BadUsageError(format!(
95 "Cannot decode MySQL type DOUBLE (f64) to {}",
96 std::any::type_name::<Self>()
97 )))
98 }
99
100 fn from_bytes(_v: &'buf [u8]) -> Result<Self> {
101 Err(Error::BadUsageError(format!(
102 "Cannot decode MySQL type BYTES to {}",
103 std::any::type_name::<Self>()
104 )))
105 }
106
107 fn from_str(_v: &'buf [u8]) -> Result<Self> {
108 Err(Error::BadUsageError(format!(
109 "Cannot decode MySQL type STRING to {}",
110 std::any::type_name::<Self>()
111 )))
112 }
113
114 fn from_decimal(_v: &'buf [u8]) -> Result<Self> {
115 Err(Error::BadUsageError(format!(
116 "Cannot decode MySQL type DECIMAL to {}",
117 std::any::type_name::<Self>()
118 )))
119 }
120
121 fn from_date0() -> Result<Self> {
122 Err(Error::BadUsageError(format!(
123 "Cannot decode MySQL type DATE to {}",
124 std::any::type_name::<Self>()
125 )))
126 }
127
128 fn from_date4(_v: &'buf Timestamp4) -> Result<Self> {
129 Err(Error::BadUsageError(format!(
130 "Cannot decode MySQL type DATE to {}",
131 std::any::type_name::<Self>()
132 )))
133 }
134
135 fn from_datetime0() -> Result<Self> {
136 Err(Error::BadUsageError(format!(
137 "Cannot decode MySQL type DATETIME to {}",
138 std::any::type_name::<Self>()
139 )))
140 }
141
142 fn from_datetime4(_v: &'buf Timestamp4) -> Result<Self> {
143 Err(Error::BadUsageError(format!(
144 "Cannot decode MySQL type DATETIME to {}",
145 std::any::type_name::<Self>()
146 )))
147 }
148
149 fn from_datetime7(_v: &'buf Timestamp7) -> Result<Self> {
150 Err(Error::BadUsageError(format!(
151 "Cannot decode MySQL type DATETIME to {}",
152 std::any::type_name::<Self>()
153 )))
154 }
155
156 fn from_datetime11(_v: &'buf Timestamp11) -> Result<Self> {
157 Err(Error::BadUsageError(format!(
158 "Cannot decode MySQL type DATETIME to {}",
159 std::any::type_name::<Self>()
160 )))
161 }
162
163 fn from_time0() -> Result<Self> {
164 Err(Error::BadUsageError(format!(
165 "Cannot decode MySQL type TIME to {}",
166 std::any::type_name::<Self>()
167 )))
168 }
169
170 fn from_time8(_v: &'buf Time8) -> Result<Self> {
171 Err(Error::BadUsageError(format!(
172 "Cannot decode MySQL type TIME to {}",
173 std::any::type_name::<Self>()
174 )))
175 }
176
177 fn from_time12(_v: &'buf Time12) -> Result<Self> {
178 Err(Error::BadUsageError(format!(
179 "Cannot decode MySQL type TIME to {}",
180 std::any::type_name::<Self>()
181 )))
182 }
183}
184
185pub fn parse_value<'buf, T: FromRawValue<'buf>>(
189 col: &ColumnDefinitionTail,
190 is_null: bool,
191 data: &'buf [u8],
192) -> Result<(T, &'buf [u8])> {
193 if is_null {
194 return Ok((T::from_null()?, data));
195 }
196 let is_unsigned = col.flags()?.contains(ColumnFlags::UNSIGNED_FLAG);
197 let is_binary_charset = col.charset() == BINARY_CHARSET;
198
199 match col.column_type()? {
200 ColumnType::MYSQL_TYPE_NULL => Ok((T::from_null()?, data)),
201
202 ColumnType::MYSQL_TYPE_TINY => {
204 let (val, rest) = read_int_1(data)?;
205 let out = if is_unsigned {
206 T::from_u8(val)?
207 } else {
208 T::from_i8(val as i8)?
209 };
210 Ok((out, rest))
211 }
212
213 ColumnType::MYSQL_TYPE_SHORT | ColumnType::MYSQL_TYPE_YEAR => {
214 let (val, rest) = read_int_2(data)?;
215 let out = if is_unsigned {
216 T::from_u16(val)?
217 } else {
218 T::from_i16(val as i16)?
219 };
220 Ok((out, rest))
221 }
222
223 ColumnType::MYSQL_TYPE_INT24 | ColumnType::MYSQL_TYPE_LONG => {
224 let (val, rest) = read_int_4(data)?;
225 let out = if is_unsigned {
226 T::from_u32(val)?
227 } else {
228 T::from_i32(val as i32)?
229 };
230 Ok((out, rest))
231 }
232
233 ColumnType::MYSQL_TYPE_LONGLONG => {
234 let (val, rest) = read_int_8(data)?;
235 let out = if is_unsigned {
236 T::from_u64(val)?
237 } else {
238 T::from_i64(val as i64)?
239 };
240 Ok((out, rest))
241 }
242
243 ColumnType::MYSQL_TYPE_FLOAT => {
245 let (val, rest) = read_int_4(data)?;
246 Ok((T::from_float(f32::from_bits(val))?, rest))
247 }
248
249 ColumnType::MYSQL_TYPE_DOUBLE => {
250 let (val, rest) = read_int_8(data)?;
251 Ok((T::from_double(f64::from_bits(val))?, rest))
252 }
253
254 ColumnType::MYSQL_TYPE_DATE | ColumnType::MYSQL_TYPE_NEWDATE => {
256 let (len, mut rest) = read_int_1(data)?;
257 match len {
258 0 => Ok((T::from_date0()?, rest)),
259 4 => {
260 let ts = Timestamp4::ref_from_bytes(&rest[..4])?;
261 rest = &rest[4..];
262 Ok((T::from_date4(ts)?, rest))
263 }
264 _ => Err(Error::LibraryBug(eyre!("invalid date length: {}", len))),
265 }
266 }
267
268 ColumnType::MYSQL_TYPE_DATETIME
270 | ColumnType::MYSQL_TYPE_TIMESTAMP
271 | ColumnType::MYSQL_TYPE_TIMESTAMP2
272 | ColumnType::MYSQL_TYPE_DATETIME2 => {
273 let (len, rest) = read_int_1(data)?;
274 match len {
275 0 => Ok((T::from_datetime0()?, rest)),
276 4 => {
277 let (chunk, tail) = rest
278 .split_first_chunk::<4>()
279 .ok_or_else(|| Error::LibraryBug(eyre!("truncated datetime4")))?;
280 let ts = Timestamp4::ref_from_bytes(chunk)?;
281 Ok((T::from_datetime4(ts)?, tail))
282 }
283 7 => {
284 let (chunk, tail) = rest
285 .split_first_chunk::<7>()
286 .ok_or_else(|| Error::LibraryBug(eyre!("truncated datetime7")))?;
287 let ts = Timestamp7::ref_from_bytes(chunk)?;
288 Ok((T::from_datetime7(ts)?, tail))
289 }
290 11 => {
291 let (chunk, tail) = rest
292 .split_first_chunk::<11>()
293 .ok_or_else(|| Error::LibraryBug(eyre!("truncated datetime11")))?;
294 let ts = Timestamp11::ref_from_bytes(chunk)?;
295 Ok((T::from_datetime11(ts)?, tail))
296 }
297 _ => Err(Error::LibraryBug(eyre!("invalid datetime length: {}", len))),
298 }
299 }
300
301 ColumnType::MYSQL_TYPE_TIME | ColumnType::MYSQL_TYPE_TIME2 => {
303 let (len, rest) = read_int_1(data)?;
304 match len {
305 0 => Ok((T::from_time0()?, rest)),
306 8 => {
307 let (chunk, tail) = rest
308 .split_first_chunk::<8>()
309 .ok_or_else(|| Error::LibraryBug(eyre!("truncated time8")))?;
310 let time = Time8::ref_from_bytes(chunk)?;
311 Ok((T::from_time8(time)?, tail))
312 }
313 12 => {
314 let (chunk, tail) = rest
315 .split_first_chunk::<12>()
316 .ok_or_else(|| Error::LibraryBug(eyre!("truncated time12")))?;
317 let time = Time12::ref_from_bytes(chunk)?;
318 Ok((T::from_time12(time)?, tail))
319 }
320 _ => Err(Error::LibraryBug(eyre!("invalid time length: {}", len))),
321 }
322 }
323
324 ColumnType::MYSQL_TYPE_DECIMAL | ColumnType::MYSQL_TYPE_NEWDECIMAL => {
326 let (bytes, rest) = read_string_lenenc(data)?;
327 Ok((T::from_decimal(bytes)?, rest))
328 }
329
330 ColumnType::MYSQL_TYPE_VARCHAR
332 | ColumnType::MYSQL_TYPE_VAR_STRING
333 | ColumnType::MYSQL_TYPE_STRING
334 | ColumnType::MYSQL_TYPE_BLOB
335 | ColumnType::MYSQL_TYPE_TINY_BLOB
336 | ColumnType::MYSQL_TYPE_MEDIUM_BLOB
337 | ColumnType::MYSQL_TYPE_LONG_BLOB
338 | ColumnType::MYSQL_TYPE_GEOMETRY
339 | ColumnType::MYSQL_TYPE_JSON
340 | ColumnType::MYSQL_TYPE_ENUM
341 | ColumnType::MYSQL_TYPE_SET
342 | ColumnType::MYSQL_TYPE_BIT
343 | ColumnType::MYSQL_TYPE_TYPED_ARRAY => {
344 let (bytes, rest) = read_string_lenenc(data)?;
345 let out = if is_binary_charset {
346 T::from_bytes(bytes)?
347 } else {
348 T::from_str(bytes)?
349 };
350 Ok((out, rest))
351 }
352 }
353}
354
355pub fn skip_value<'buf>(
359 col: &ColumnDefinitionTail,
360 is_null: bool,
361 data: &'buf [u8],
362) -> Result<((), &'buf [u8])> {
363 if is_null {
364 return Ok(((), data));
365 }
366
367 match col.column_type()? {
368 ColumnType::MYSQL_TYPE_NULL => Ok(((), data)),
369
370 ColumnType::MYSQL_TYPE_TINY => Ok(((), &data[1..])),
372 ColumnType::MYSQL_TYPE_SHORT | ColumnType::MYSQL_TYPE_YEAR => Ok(((), &data[2..])),
373 ColumnType::MYSQL_TYPE_INT24
374 | ColumnType::MYSQL_TYPE_LONG
375 | ColumnType::MYSQL_TYPE_FLOAT => Ok(((), &data[4..])),
376 ColumnType::MYSQL_TYPE_LONGLONG | ColumnType::MYSQL_TYPE_DOUBLE => Ok(((), &data[8..])),
377
378 ColumnType::MYSQL_TYPE_DATE
380 | ColumnType::MYSQL_TYPE_NEWDATE
381 | ColumnType::MYSQL_TYPE_DATETIME
382 | ColumnType::MYSQL_TYPE_TIMESTAMP
383 | ColumnType::MYSQL_TYPE_TIMESTAMP2
384 | ColumnType::MYSQL_TYPE_DATETIME2
385 | ColumnType::MYSQL_TYPE_TIME
386 | ColumnType::MYSQL_TYPE_TIME2 => {
387 let (len, rest) = read_int_1(data)?;
388 Ok(((), &rest[len as usize..]))
389 }
390
391 ColumnType::MYSQL_TYPE_DECIMAL
393 | ColumnType::MYSQL_TYPE_NEWDECIMAL
394 | ColumnType::MYSQL_TYPE_VARCHAR
395 | ColumnType::MYSQL_TYPE_VAR_STRING
396 | ColumnType::MYSQL_TYPE_STRING
397 | ColumnType::MYSQL_TYPE_BLOB
398 | ColumnType::MYSQL_TYPE_TINY_BLOB
399 | ColumnType::MYSQL_TYPE_MEDIUM_BLOB
400 | ColumnType::MYSQL_TYPE_LONG_BLOB
401 | ColumnType::MYSQL_TYPE_GEOMETRY
402 | ColumnType::MYSQL_TYPE_JSON
403 | ColumnType::MYSQL_TYPE_ENUM
404 | ColumnType::MYSQL_TYPE_SET
405 | ColumnType::MYSQL_TYPE_BIT
406 | ColumnType::MYSQL_TYPE_TYPED_ARRAY => {
407 let (_, rest) = read_string_lenenc(data)?;
408 Ok(((), rest))
409 }
410 }
411}
412
413pub trait FromRow<'buf>: Sized {
415 fn from_row(cols: &[ColumnDefinition<'_>], row: BinaryRowPayload<'buf>) -> Result<Self>;
416}
417
418impl<'buf, 'value> FromRawValue<'buf> for Value<'value>
423where
424 'buf: 'value,
425{
426 fn from_null() -> Result<Self> {
427 Ok(Value::Null)
428 }
429
430 fn from_i8(v: i8) -> Result<Self> {
431 Ok(Value::SignedInt(v as i64))
432 }
433
434 fn from_i16(v: i16) -> Result<Self> {
435 Ok(Value::SignedInt(v as i64))
436 }
437
438 fn from_i32(v: i32) -> Result<Self> {
439 Ok(Value::SignedInt(v as i64))
440 }
441
442 fn from_i64(v: i64) -> Result<Self> {
443 Ok(Value::SignedInt(v))
444 }
445
446 fn from_u8(v: u8) -> Result<Self> {
447 Ok(Value::UnsignedInt(v as u64))
448 }
449
450 fn from_u16(v: u16) -> Result<Self> {
451 Ok(Value::UnsignedInt(v as u64))
452 }
453
454 fn from_u32(v: u32) -> Result<Self> {
455 Ok(Value::UnsignedInt(v as u64))
456 }
457
458 fn from_u64(v: u64) -> Result<Self> {
459 Ok(Value::UnsignedInt(v))
460 }
461
462 fn from_float(v: f32) -> Result<Self> {
463 Ok(Value::Float(v))
464 }
465
466 fn from_double(v: f64) -> Result<Self> {
467 Ok(Value::Double(v))
468 }
469
470 fn from_bytes(v: &'buf [u8]) -> Result<Self> {
471 Ok(Value::Byte(v))
472 }
473
474 fn from_str(v: &'buf [u8]) -> Result<Self> {
475 Ok(Value::Byte(v))
476 }
477
478 fn from_decimal(v: &'buf [u8]) -> Result<Self> {
479 Ok(Value::Byte(v))
480 }
481
482 fn from_date0() -> Result<Self> {
483 Ok(Value::Date0)
484 }
485
486 fn from_date4(v: &'buf Timestamp4) -> Result<Self> {
487 Ok(Value::Date4(v))
488 }
489
490 fn from_datetime0() -> Result<Self> {
491 Ok(Value::Datetime0)
492 }
493
494 fn from_datetime4(v: &'buf Timestamp4) -> Result<Self> {
495 Ok(Value::Datetime4(v))
496 }
497
498 fn from_datetime7(v: &'buf Timestamp7) -> Result<Self> {
499 Ok(Value::Datetime7(v))
500 }
501
502 fn from_datetime11(v: &'buf Timestamp11) -> Result<Self> {
503 Ok(Value::Datetime11(v))
504 }
505
506 fn from_time0() -> Result<Self> {
507 Ok(Value::Time0)
508 }
509
510 fn from_time8(v: &'buf Time8) -> Result<Self> {
511 Ok(Value::Time8(v))
512 }
513
514 fn from_time12(v: &'buf Time12) -> Result<Self> {
515 Ok(Value::Time12(v))
516 }
517}
518
519impl FromRawValue<'_> for i8 {
524 fn from_i8(v: i8) -> Result<Self> {
525 Ok(v)
526 }
527}
528
529impl FromRawValue<'_> for i16 {
530 fn from_i8(v: i8) -> Result<Self> {
531 Ok(v as i16)
532 }
533
534 fn from_i16(v: i16) -> Result<Self> {
535 Ok(v)
536 }
537}
538
539impl FromRawValue<'_> for i32 {
540 fn from_i8(v: i8) -> Result<Self> {
541 Ok(v as i32)
542 }
543
544 fn from_i16(v: i16) -> Result<Self> {
545 Ok(v as i32)
546 }
547
548 fn from_i32(v: i32) -> Result<Self> {
549 Ok(v)
550 }
551}
552
553impl FromRawValue<'_> for i64 {
554 fn from_i8(v: i8) -> Result<Self> {
555 Ok(v as i64)
556 }
557
558 fn from_i16(v: i16) -> Result<Self> {
559 Ok(v as i64)
560 }
561
562 fn from_i32(v: i32) -> Result<Self> {
563 Ok(v as i64)
564 }
565
566 fn from_i64(v: i64) -> Result<Self> {
567 Ok(v)
568 }
569}
570
571impl FromRawValue<'_> for bool {
572 fn from_i8(v: i8) -> Result<Self> {
573 Ok(v != 0)
574 }
575
576 fn from_u8(v: u8) -> Result<Self> {
577 Ok(v != 0)
578 }
579}
580
581impl FromRawValue<'_> for u8 {
582 fn from_u8(v: u8) -> Result<Self> {
583 Ok(v)
584 }
585}
586
587impl FromRawValue<'_> for u16 {
588 fn from_u8(v: u8) -> Result<Self> {
589 Ok(v as u16)
590 }
591
592 fn from_u16(v: u16) -> Result<Self> {
593 Ok(v)
594 }
595}
596
597impl FromRawValue<'_> for u32 {
598 fn from_u8(v: u8) -> Result<Self> {
599 Ok(v as u32)
600 }
601
602 fn from_u16(v: u16) -> Result<Self> {
603 Ok(v as u32)
604 }
605
606 fn from_u32(v: u32) -> Result<Self> {
607 Ok(v)
608 }
609}
610
611impl FromRawValue<'_> for u64 {
612 fn from_u8(v: u8) -> Result<Self> {
613 Ok(v as u64)
614 }
615
616 fn from_u16(v: u16) -> Result<Self> {
617 Ok(v as u64)
618 }
619
620 fn from_u32(v: u32) -> Result<Self> {
621 Ok(v as u64)
622 }
623
624 fn from_u64(v: u64) -> Result<Self> {
625 Ok(v)
626 }
627}
628
629impl FromRawValue<'_> for f32 {
630 fn from_float(v: f32) -> Result<Self> {
631 Ok(v)
632 }
633}
634
635impl FromRawValue<'_> for f64 {
636 fn from_double(v: f64) -> Result<Self> {
637 Ok(v)
638 }
639
640 fn from_float(v: f32) -> Result<Self> {
641 Ok(v as f64)
642 }
643}
644
645impl<'a> FromRawValue<'a> for &'a [u8] {
646 fn from_bytes(v: &'a [u8]) -> Result<Self> {
647 Ok(v)
648 }
649}
650
651impl FromRawValue<'_> for Vec<u8> {
652 fn from_bytes(v: &[u8]) -> Result<Self> {
653 Ok(v.to_vec())
654 }
655}
656
657impl<'a> FromRawValue<'a> for &'a str {
658 fn from_str(v: &'a [u8]) -> Result<Self> {
659 from_utf8(v).map_err(|e| {
660 Error::BadUsageError(format!("Cannot decode MySQL type STRING to &str: {}", e))
661 })
662 }
663}
664
665impl FromRawValue<'_> for String {
666 fn from_str(v: &[u8]) -> Result<Self> {
667 from_utf8(v).map(|s| s.to_owned()).map_err(|e| {
668 Error::BadUsageError(format!("Cannot decode MySQL type STRING to String: {}", e))
669 })
670 }
671}
672
673impl<'a, T: FromRawValue<'a>> FromRawValue<'a> for Option<T> {
674 fn from_null() -> Result<Self> {
675 Ok(None)
676 }
677
678 fn from_i8(v: i8) -> Result<Self> {
679 T::from_i8(v).map(Some)
680 }
681
682 fn from_i16(v: i16) -> Result<Self> {
683 T::from_i16(v).map(Some)
684 }
685
686 fn from_i32(v: i32) -> Result<Self> {
687 T::from_i32(v).map(Some)
688 }
689
690 fn from_i64(v: i64) -> Result<Self> {
691 T::from_i64(v).map(Some)
692 }
693
694 fn from_u8(v: u8) -> Result<Self> {
695 T::from_u8(v).map(Some)
696 }
697
698 fn from_u16(v: u16) -> Result<Self> {
699 T::from_u16(v).map(Some)
700 }
701
702 fn from_u32(v: u32) -> Result<Self> {
703 T::from_u32(v).map(Some)
704 }
705
706 fn from_u64(v: u64) -> Result<Self> {
707 T::from_u64(v).map(Some)
708 }
709
710 fn from_float(v: f32) -> Result<Self> {
711 T::from_float(v).map(Some)
712 }
713
714 fn from_double(v: f64) -> Result<Self> {
715 T::from_double(v).map(Some)
716 }
717
718 fn from_bytes(v: &'a [u8]) -> Result<Self> {
719 T::from_bytes(v).map(Some)
720 }
721
722 fn from_str(v: &'a [u8]) -> Result<Self> {
723 T::from_str(v).map(Some)
724 }
725
726 fn from_decimal(v: &'a [u8]) -> Result<Self> {
727 T::from_decimal(v).map(Some)
728 }
729
730 fn from_date0() -> Result<Self> {
731 T::from_date0().map(Some)
732 }
733
734 fn from_date4(v: &'a Timestamp4) -> Result<Self> {
735 T::from_date4(v).map(Some)
736 }
737
738 fn from_datetime0() -> Result<Self> {
739 T::from_datetime0().map(Some)
740 }
741
742 fn from_datetime4(v: &'a Timestamp4) -> Result<Self> {
743 T::from_datetime4(v).map(Some)
744 }
745
746 fn from_datetime7(v: &'a Timestamp7) -> Result<Self> {
747 T::from_datetime7(v).map(Some)
748 }
749
750 fn from_datetime11(v: &'a Timestamp11) -> Result<Self> {
751 T::from_datetime11(v).map(Some)
752 }
753
754 fn from_time0() -> Result<Self> {
755 T::from_time0().map(Some)
756 }
757
758 fn from_time8(v: &'a Time8) -> Result<Self> {
759 T::from_time8(v).map(Some)
760 }
761
762 fn from_time12(v: &'a Time12) -> Result<Self> {
763 T::from_time12(v).map(Some)
764 }
765}
766
767macro_rules! impl_from_row_tuple {
772 ($($idx:tt: $T:ident),+) => {
773 impl<'buf, 'value, $($T: FromRawValue<'buf>),+> FromRow<'buf> for ($($T,)+) {
774 #[expect(non_snake_case)]
775 fn from_row(cols: &[ColumnDefinition<'_>], row: BinaryRowPayload<'buf>) -> Result<Self> {
776 let mut data = row.values();
777 let null_bitmap = row.null_bitmap();
778 $(
779 let col = cols.get($idx)
780 .ok_or_else(|| Error::LibraryBug(eyre!(
781 "from_row: column index {} out of bounds (got {} columns)",
782 $idx, cols.len()
783 )))?;
784 let ($T, rest) = parse_value::<$T>(&col.tail, null_bitmap.is_null($idx), data)?;
785 data = rest;
786 )+
787 let _ = data; Ok(($($T,)+))
789 }
790 }
791 };
792}
793
794impl_from_row_tuple!(0: A);
795impl_from_row_tuple!(0: A, 1: B);
796impl_from_row_tuple!(0: A, 1: B, 2: C);
797impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D);
798impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E);
799impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F);
800impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G);
801impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H);
802impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I);
803impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J);
804impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K);
805impl_from_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L);
806
807#[cfg(feature = "with-uuid")]
812impl FromRawValue<'_> for uuid::Uuid {
813 fn from_str(v: &[u8]) -> Result<Self> {
814 let s = from_utf8(v).map_err(|e| {
815 Error::BadUsageError(format!("Cannot decode MySQL STRING to UUID: {}", e))
816 })?;
817 uuid::Uuid::parse_str(s)
818 .map_err(|e| Error::BadUsageError(format!("Cannot parse UUID from '{}': {}", s, e)))
819 }
820
821 fn from_bytes(v: &[u8]) -> Result<Self> {
822 uuid::Uuid::from_slice(v)
823 .map_err(|e| Error::BadUsageError(format!("Cannot decode MySQL BINARY to UUID: {}", e)))
824 }
825}
826
827#[cfg(feature = "with-chrono")]
832const MIDNIGHT: chrono::NaiveTime = chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap();
833
834#[cfg(feature = "with-chrono")]
835impl FromRawValue<'_> for chrono::NaiveDate {
836 fn from_date0() -> Result<Self> {
837 Err(Error::BadUsageError(
838 "Cannot decode zero DATE to chrono::NaiveDate".to_string(),
839 ))
840 }
841
842 fn from_date4(v: &Timestamp4) -> Result<Self> {
843 chrono::NaiveDate::from_ymd_opt(v.year() as i32, v.month as u32, v.day as u32).ok_or_else(
844 || Error::BadUsageError(format!("Invalid date: {}-{}-{}", v.year(), v.month, v.day)),
845 )
846 }
847}
848
849#[cfg(feature = "with-chrono")]
850impl FromRawValue<'_> for chrono::NaiveTime {
851 fn from_time0() -> Result<Self> {
852 Ok(MIDNIGHT)
853 }
854
855 fn from_time8(v: &Time8) -> Result<Self> {
856 if v.is_negative() || v.days() > 0 {
857 return Err(Error::BadUsageError(
858 "Cannot decode TIME with days or negative to chrono::NaiveTime".to_string(),
859 ));
860 }
861 chrono::NaiveTime::from_hms_opt(v.hour as u32, v.minute as u32, v.second as u32).ok_or_else(
862 || {
863 Error::BadUsageError(format!(
864 "Invalid time: {}:{}:{}",
865 v.hour, v.minute, v.second
866 ))
867 },
868 )
869 }
870
871 fn from_time12(v: &Time12) -> Result<Self> {
872 if v.is_negative() || v.days() > 0 {
873 return Err(Error::BadUsageError(
874 "Cannot decode TIME with days or negative to chrono::NaiveTime".to_string(),
875 ));
876 }
877 chrono::NaiveTime::from_hms_micro_opt(
878 v.hour as u32,
879 v.minute as u32,
880 v.second as u32,
881 v.microsecond(),
882 )
883 .ok_or_else(|| {
884 Error::BadUsageError(format!(
885 "Invalid time: {}:{}:{}.{}",
886 v.hour,
887 v.minute,
888 v.second,
889 v.microsecond()
890 ))
891 })
892 }
893}
894
895#[cfg(feature = "with-chrono")]
896impl FromRawValue<'_> for chrono::NaiveDateTime {
897 fn from_datetime0() -> Result<Self> {
898 Err(Error::BadUsageError(
899 "Cannot decode zero DATETIME to chrono::NaiveDateTime".to_string(),
900 ))
901 }
902
903 fn from_datetime4(v: &Timestamp4) -> Result<Self> {
904 let date = chrono::NaiveDate::from_ymd_opt(v.year() as i32, v.month as u32, v.day as u32)
905 .ok_or_else(|| {
906 Error::BadUsageError(format!("Invalid date: {}-{}-{}", v.year(), v.month, v.day))
907 })?;
908 Ok(date.and_time(MIDNIGHT))
909 }
910
911 fn from_datetime7(v: &Timestamp7) -> Result<Self> {
912 let date = chrono::NaiveDate::from_ymd_opt(v.year() as i32, v.month as u32, v.day as u32)
913 .ok_or_else(|| {
914 Error::BadUsageError(format!("Invalid date: {}-{}-{}", v.year(), v.month, v.day))
915 })?;
916 date.and_hms_opt(v.hour as u32, v.minute as u32, v.second as u32)
917 .ok_or_else(|| {
918 Error::BadUsageError(format!(
919 "Invalid time: {}:{}:{}",
920 v.hour, v.minute, v.second
921 ))
922 })
923 }
924
925 fn from_datetime11(v: &Timestamp11) -> Result<Self> {
926 let date = chrono::NaiveDate::from_ymd_opt(v.year() as i32, v.month as u32, v.day as u32)
927 .ok_or_else(|| {
928 Error::BadUsageError(format!("Invalid date: {}-{}-{}", v.year(), v.month, v.day))
929 })?;
930 date.and_hms_micro_opt(
931 v.hour as u32,
932 v.minute as u32,
933 v.second as u32,
934 v.microsecond(),
935 )
936 .ok_or_else(|| {
937 Error::BadUsageError(format!(
938 "Invalid datetime: {}-{}-{} {}:{}:{}.{}",
939 v.year(),
940 v.month,
941 v.day,
942 v.hour,
943 v.minute,
944 v.second,
945 v.microsecond()
946 ))
947 })
948 }
949}
950
951#[cfg(feature = "with-time")]
956impl FromRawValue<'_> for time::Date {
957 fn from_date0() -> Result<Self> {
958 Err(Error::BadUsageError(
959 "Cannot decode zero DATE to time::Date".to_string(),
960 ))
961 }
962
963 fn from_date4(v: &Timestamp4) -> Result<Self> {
964 let month = time::Month::try_from(v.month)
965 .map_err(|e| Error::BadUsageError(format!("Invalid month {}: {}", v.month, e)))?;
966 time::Date::from_calendar_date(v.year() as i32, month, v.day).map_err(|e| {
967 Error::BadUsageError(format!(
968 "Invalid date {}-{}-{}: {}",
969 v.year(),
970 v.month,
971 v.day,
972 e
973 ))
974 })
975 }
976}
977
978#[cfg(feature = "with-time")]
979impl FromRawValue<'_> for time::Time {
980 fn from_time0() -> Result<Self> {
981 Ok(time::Time::MIDNIGHT)
982 }
983
984 fn from_time8(v: &Time8) -> Result<Self> {
985 if v.is_negative() || v.days() > 0 {
986 return Err(Error::BadUsageError(
987 "Cannot decode TIME with days or negative to time::Time".to_string(),
988 ));
989 }
990 time::Time::from_hms(v.hour, v.minute, v.second).map_err(|e| {
991 Error::BadUsageError(format!(
992 "Invalid time {}:{}:{}: {}",
993 v.hour, v.minute, v.second, e
994 ))
995 })
996 }
997
998 fn from_time12(v: &Time12) -> Result<Self> {
999 if v.is_negative() || v.days() > 0 {
1000 return Err(Error::BadUsageError(
1001 "Cannot decode TIME with days or negative to time::Time".to_string(),
1002 ));
1003 }
1004 time::Time::from_hms_micro(v.hour, v.minute, v.second, v.microsecond()).map_err(|e| {
1005 Error::BadUsageError(format!(
1006 "Invalid time {}:{}:{}.{}: {}",
1007 v.hour,
1008 v.minute,
1009 v.second,
1010 v.microsecond(),
1011 e
1012 ))
1013 })
1014 }
1015}
1016
1017#[cfg(feature = "with-time")]
1018impl FromRawValue<'_> for time::PrimitiveDateTime {
1019 fn from_datetime0() -> Result<Self> {
1020 Err(Error::BadUsageError(
1021 "Cannot decode zero DATETIME to time::PrimitiveDateTime".to_string(),
1022 ))
1023 }
1024
1025 fn from_datetime4(v: &Timestamp4) -> Result<Self> {
1026 let month = time::Month::try_from(v.month)
1027 .map_err(|e| Error::BadUsageError(format!("Invalid month {}: {}", v.month, e)))?;
1028 let date = time::Date::from_calendar_date(v.year() as i32, month, v.day).map_err(|e| {
1029 Error::BadUsageError(format!(
1030 "Invalid date {}-{}-{}: {}",
1031 v.year(),
1032 v.month,
1033 v.day,
1034 e
1035 ))
1036 })?;
1037 Ok(time::PrimitiveDateTime::new(date, time::Time::MIDNIGHT))
1038 }
1039
1040 fn from_datetime7(v: &Timestamp7) -> Result<Self> {
1041 let month = time::Month::try_from(v.month)
1042 .map_err(|e| Error::BadUsageError(format!("Invalid month {}: {}", v.month, e)))?;
1043 let date = time::Date::from_calendar_date(v.year() as i32, month, v.day).map_err(|e| {
1044 Error::BadUsageError(format!(
1045 "Invalid date {}-{}-{}: {}",
1046 v.year(),
1047 v.month,
1048 v.day,
1049 e
1050 ))
1051 })?;
1052 let time = time::Time::from_hms(v.hour, v.minute, v.second).map_err(|e| {
1053 Error::BadUsageError(format!(
1054 "Invalid time {}:{}:{}: {}",
1055 v.hour, v.minute, v.second, e
1056 ))
1057 })?;
1058 Ok(time::PrimitiveDateTime::new(date, time))
1059 }
1060
1061 fn from_datetime11(v: &Timestamp11) -> Result<Self> {
1062 let month = time::Month::try_from(v.month)
1063 .map_err(|e| Error::BadUsageError(format!("Invalid month {}: {}", v.month, e)))?;
1064 let date = time::Date::from_calendar_date(v.year() as i32, month, v.day).map_err(|e| {
1065 Error::BadUsageError(format!(
1066 "Invalid date {}-{}-{}: {}",
1067 v.year(),
1068 v.month,
1069 v.day,
1070 e
1071 ))
1072 })?;
1073 let time = time::Time::from_hms_micro(v.hour, v.minute, v.second, v.microsecond())
1074 .map_err(|e| {
1075 Error::BadUsageError(format!(
1076 "Invalid time {}:{}:{}.{}: {}",
1077 v.hour,
1078 v.minute,
1079 v.second,
1080 v.microsecond(),
1081 e
1082 ))
1083 })?;
1084 Ok(time::PrimitiveDateTime::new(date, time))
1085 }
1086}
1087
1088#[cfg(feature = "with-rust-decimal")]
1093impl FromRawValue<'_> for rust_decimal::Decimal {
1094 fn from_decimal(v: &[u8]) -> Result<Self> {
1095 let s = from_utf8(v).map_err(|e| {
1096 Error::BadUsageError(format!("Cannot decode MySQL DECIMAL to string: {}", e))
1097 })?;
1098 s.parse()
1099 .map_err(|e| Error::BadUsageError(format!("Cannot parse Decimal from '{}': {}", s, e)))
1100 }
1101
1102 fn from_str(v: &[u8]) -> Result<Self> {
1103 Self::from_decimal(v)
1104 }
1105}