zero_mysql/
raw.rs

1//! Flexible decoding API for MySQL binary protocol values.
2//!
3//! This module provides traits for decoding MySQL values directly into target types
4//! without intermediate `Value` allocation.
5
6use 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
15/// MySQL binary charset number - indicates binary/non-text data
16const BINARY_CHARSET: u16 = 63;
17
18/// Trait for types that can be decoded from MySQL binary protocol values.
19///
20/// Each method corresponds to a MySQL wire format. Implementations should
21/// return `Err` for unsupported conversions.
22pub 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
185/// Parse a single value from binary data into target type `T`.
186///
187/// Returns the parsed value and remaining bytes.
188pub 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        // Integer types
203        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        // Floating point types
244        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        // DATE types
255        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        // DATETIME/TIMESTAMP types
269        ColumnType::MYSQL_TYPE_DATETIME
270        | ColumnType::MYSQL_TYPE_TIMESTAMP
271        | ColumnType::MYSQL_TYPE_TIMESTAMP2
272        | ColumnType::MYSQL_TYPE_DATETIME2 => {
273            let (len, mut rest) = read_int_1(data)?;
274            match len {
275                0 => Ok((T::from_datetime0()?, rest)),
276                4 => {
277                    let ts = Timestamp4::ref_from_bytes(&rest[..4])?;
278                    rest = &rest[4..];
279                    Ok((T::from_datetime4(ts)?, rest))
280                }
281                7 => {
282                    let ts = Timestamp7::ref_from_bytes(&rest[..7])?;
283                    rest = &rest[7..];
284                    Ok((T::from_datetime7(ts)?, rest))
285                }
286                11 => {
287                    let ts = Timestamp11::ref_from_bytes(&rest[..11])?;
288                    rest = &rest[11..];
289                    Ok((T::from_datetime11(ts)?, rest))
290                }
291                _ => Err(Error::LibraryBug(eyre!("invalid datetime length: {}", len))),
292            }
293        }
294
295        // TIME types
296        ColumnType::MYSQL_TYPE_TIME | ColumnType::MYSQL_TYPE_TIME2 => {
297            let (len, mut rest) = read_int_1(data)?;
298            match len {
299                0 => Ok((T::from_time0()?, rest)),
300                8 => {
301                    let time = Time8::ref_from_bytes(&rest[..8])?;
302                    rest = &rest[8..];
303                    Ok((T::from_time8(time)?, rest))
304                }
305                12 => {
306                    let time = Time12::ref_from_bytes(&rest[..12])?;
307                    rest = &rest[12..];
308                    Ok((T::from_time12(time)?, rest))
309                }
310                _ => Err(Error::LibraryBug(eyre!("invalid time length: {}", len))),
311            }
312        }
313
314        // DECIMAL types
315        ColumnType::MYSQL_TYPE_DECIMAL | ColumnType::MYSQL_TYPE_NEWDECIMAL => {
316            let (bytes, rest) = read_string_lenenc(data)?;
317            Ok((T::from_decimal(bytes)?, rest))
318        }
319
320        // String and BLOB types
321        ColumnType::MYSQL_TYPE_VARCHAR
322        | ColumnType::MYSQL_TYPE_VAR_STRING
323        | ColumnType::MYSQL_TYPE_STRING
324        | ColumnType::MYSQL_TYPE_BLOB
325        | ColumnType::MYSQL_TYPE_TINY_BLOB
326        | ColumnType::MYSQL_TYPE_MEDIUM_BLOB
327        | ColumnType::MYSQL_TYPE_LONG_BLOB
328        | ColumnType::MYSQL_TYPE_GEOMETRY
329        | ColumnType::MYSQL_TYPE_JSON
330        | ColumnType::MYSQL_TYPE_ENUM
331        | ColumnType::MYSQL_TYPE_SET
332        | ColumnType::MYSQL_TYPE_BIT
333        | ColumnType::MYSQL_TYPE_TYPED_ARRAY => {
334            let (bytes, rest) = read_string_lenenc(data)?;
335            let out = if is_binary_charset {
336                T::from_bytes(bytes)?
337            } else {
338                T::from_str(bytes)?
339            };
340            Ok((out, rest))
341        }
342    }
343}
344
345/// Trait for types that can be decoded from a MySQL row.
346pub trait FromRawRow<'buf>: Sized {
347    fn from_raw_row(cols: &[ColumnDefinition<'_>], row: BinaryRowPayload<'buf>) -> Result<Self>;
348}
349
350// ============================================================================
351// FromRawValue implementations for Value<'a>
352// ============================================================================
353
354impl<'buf, 'value> FromRawValue<'buf> for Value<'value>
355where
356    'buf: 'value,
357{
358    fn from_null() -> Result<Self> {
359        Ok(Value::Null)
360    }
361
362    fn from_i8(v: i8) -> Result<Self> {
363        Ok(Value::SignedInt(v as i64))
364    }
365
366    fn from_i16(v: i16) -> Result<Self> {
367        Ok(Value::SignedInt(v as i64))
368    }
369
370    fn from_i32(v: i32) -> Result<Self> {
371        Ok(Value::SignedInt(v as i64))
372    }
373
374    fn from_i64(v: i64) -> Result<Self> {
375        Ok(Value::SignedInt(v))
376    }
377
378    fn from_u8(v: u8) -> Result<Self> {
379        Ok(Value::UnsignedInt(v as u64))
380    }
381
382    fn from_u16(v: u16) -> Result<Self> {
383        Ok(Value::UnsignedInt(v as u64))
384    }
385
386    fn from_u32(v: u32) -> Result<Self> {
387        Ok(Value::UnsignedInt(v as u64))
388    }
389
390    fn from_u64(v: u64) -> Result<Self> {
391        Ok(Value::UnsignedInt(v))
392    }
393
394    fn from_float(v: f32) -> Result<Self> {
395        Ok(Value::Float(v))
396    }
397
398    fn from_double(v: f64) -> Result<Self> {
399        Ok(Value::Double(v))
400    }
401
402    fn from_bytes(v: &'buf [u8]) -> Result<Self> {
403        Ok(Value::Byte(v))
404    }
405
406    fn from_str(v: &'buf [u8]) -> Result<Self> {
407        Ok(Value::Byte(v))
408    }
409
410    fn from_decimal(v: &'buf [u8]) -> Result<Self> {
411        Ok(Value::Byte(v))
412    }
413
414    fn from_date0() -> Result<Self> {
415        Ok(Value::Date0)
416    }
417
418    fn from_date4(v: &'buf Timestamp4) -> Result<Self> {
419        Ok(Value::Date4(v))
420    }
421
422    fn from_datetime0() -> Result<Self> {
423        Ok(Value::Datetime0)
424    }
425
426    fn from_datetime4(v: &'buf Timestamp4) -> Result<Self> {
427        Ok(Value::Datetime4(v))
428    }
429
430    fn from_datetime7(v: &'buf Timestamp7) -> Result<Self> {
431        Ok(Value::Datetime7(v))
432    }
433
434    fn from_datetime11(v: &'buf Timestamp11) -> Result<Self> {
435        Ok(Value::Datetime11(v))
436    }
437
438    fn from_time0() -> Result<Self> {
439        Ok(Value::Time0)
440    }
441
442    fn from_time8(v: &'buf Time8) -> Result<Self> {
443        Ok(Value::Time8(v))
444    }
445
446    fn from_time12(v: &'buf Time12) -> Result<Self> {
447        Ok(Value::Time12(v))
448    }
449}
450
451// ============================================================================
452// FromRawValue implementations for primitive types
453// ============================================================================
454
455impl FromRawValue<'_> for i8 {
456    fn from_i8(v: i8) -> Result<Self> {
457        Ok(v)
458    }
459}
460
461impl FromRawValue<'_> for i16 {
462    fn from_i8(v: i8) -> Result<Self> {
463        Ok(v as i16)
464    }
465
466    fn from_i16(v: i16) -> Result<Self> {
467        Ok(v)
468    }
469}
470
471impl FromRawValue<'_> for i32 {
472    fn from_i8(v: i8) -> Result<Self> {
473        Ok(v as i32)
474    }
475
476    fn from_i16(v: i16) -> Result<Self> {
477        Ok(v as i32)
478    }
479
480    fn from_i32(v: i32) -> Result<Self> {
481        Ok(v)
482    }
483}
484
485impl FromRawValue<'_> for i64 {
486    fn from_i8(v: i8) -> Result<Self> {
487        Ok(v as i64)
488    }
489
490    fn from_i16(v: i16) -> Result<Self> {
491        Ok(v as i64)
492    }
493
494    fn from_i32(v: i32) -> Result<Self> {
495        Ok(v as i64)
496    }
497
498    fn from_i64(v: i64) -> Result<Self> {
499        Ok(v)
500    }
501}
502
503impl FromRawValue<'_> for bool {
504    fn from_i8(v: i8) -> Result<Self> {
505        Ok(v != 0)
506    }
507
508    fn from_u8(v: u8) -> Result<Self> {
509        Ok(v != 0)
510    }
511}
512
513impl FromRawValue<'_> for u8 {
514    fn from_u8(v: u8) -> Result<Self> {
515        Ok(v)
516    }
517}
518
519impl FromRawValue<'_> for u16 {
520    fn from_u8(v: u8) -> Result<Self> {
521        Ok(v as u16)
522    }
523
524    fn from_u16(v: u16) -> Result<Self> {
525        Ok(v)
526    }
527}
528
529impl FromRawValue<'_> for u32 {
530    fn from_u8(v: u8) -> Result<Self> {
531        Ok(v as u32)
532    }
533
534    fn from_u16(v: u16) -> Result<Self> {
535        Ok(v as u32)
536    }
537
538    fn from_u32(v: u32) -> Result<Self> {
539        Ok(v)
540    }
541}
542
543impl FromRawValue<'_> for u64 {
544    fn from_u8(v: u8) -> Result<Self> {
545        Ok(v as u64)
546    }
547
548    fn from_u16(v: u16) -> Result<Self> {
549        Ok(v as u64)
550    }
551
552    fn from_u32(v: u32) -> Result<Self> {
553        Ok(v as u64)
554    }
555
556    fn from_u64(v: u64) -> Result<Self> {
557        Ok(v)
558    }
559}
560
561impl FromRawValue<'_> for f32 {
562    fn from_float(v: f32) -> Result<Self> {
563        Ok(v)
564    }
565}
566
567impl FromRawValue<'_> for f64 {
568    fn from_double(v: f64) -> Result<Self> {
569        Ok(v)
570    }
571
572    fn from_float(v: f32) -> Result<Self> {
573        Ok(v as f64)
574    }
575}
576
577impl<'a> FromRawValue<'a> for &'a [u8] {
578    fn from_bytes(v: &'a [u8]) -> Result<Self> {
579        Ok(v)
580    }
581}
582
583impl FromRawValue<'_> for Vec<u8> {
584    fn from_bytes(v: &[u8]) -> Result<Self> {
585        Ok(v.to_vec())
586    }
587}
588
589impl<'a> FromRawValue<'a> for &'a str {
590    fn from_str(v: &'a [u8]) -> Result<Self> {
591        from_utf8(v).map_err(|e| {
592            Error::BadUsageError(format!("Cannot decode MySQL type STRING to &str: {}", e))
593        })
594    }
595}
596
597impl FromRawValue<'_> for String {
598    fn from_str(v: &[u8]) -> Result<Self> {
599        from_utf8(v).map(|s| s.to_owned()).map_err(|e| {
600            Error::BadUsageError(format!("Cannot decode MySQL type STRING to String: {}", e))
601        })
602    }
603}
604
605impl<'a, T: FromRawValue<'a>> FromRawValue<'a> for Option<T> {
606    fn from_null() -> Result<Self> {
607        Ok(None)
608    }
609
610    fn from_i8(v: i8) -> Result<Self> {
611        T::from_i8(v).map(Some)
612    }
613
614    fn from_i16(v: i16) -> Result<Self> {
615        T::from_i16(v).map(Some)
616    }
617
618    fn from_i32(v: i32) -> Result<Self> {
619        T::from_i32(v).map(Some)
620    }
621
622    fn from_i64(v: i64) -> Result<Self> {
623        T::from_i64(v).map(Some)
624    }
625
626    fn from_u8(v: u8) -> Result<Self> {
627        T::from_u8(v).map(Some)
628    }
629
630    fn from_u16(v: u16) -> Result<Self> {
631        T::from_u16(v).map(Some)
632    }
633
634    fn from_u32(v: u32) -> Result<Self> {
635        T::from_u32(v).map(Some)
636    }
637
638    fn from_u64(v: u64) -> Result<Self> {
639        T::from_u64(v).map(Some)
640    }
641
642    fn from_float(v: f32) -> Result<Self> {
643        T::from_float(v).map(Some)
644    }
645
646    fn from_double(v: f64) -> Result<Self> {
647        T::from_double(v).map(Some)
648    }
649
650    fn from_bytes(v: &'a [u8]) -> Result<Self> {
651        T::from_bytes(v).map(Some)
652    }
653
654    fn from_str(v: &'a [u8]) -> Result<Self> {
655        T::from_str(v).map(Some)
656    }
657
658    fn from_decimal(v: &'a [u8]) -> Result<Self> {
659        T::from_decimal(v).map(Some)
660    }
661
662    fn from_date0() -> Result<Self> {
663        T::from_date0().map(Some)
664    }
665
666    fn from_date4(v: &'a Timestamp4) -> Result<Self> {
667        T::from_date4(v).map(Some)
668    }
669
670    fn from_datetime0() -> Result<Self> {
671        T::from_datetime0().map(Some)
672    }
673
674    fn from_datetime4(v: &'a Timestamp4) -> Result<Self> {
675        T::from_datetime4(v).map(Some)
676    }
677
678    fn from_datetime7(v: &'a Timestamp7) -> Result<Self> {
679        T::from_datetime7(v).map(Some)
680    }
681
682    fn from_datetime11(v: &'a Timestamp11) -> Result<Self> {
683        T::from_datetime11(v).map(Some)
684    }
685
686    fn from_time0() -> Result<Self> {
687        T::from_time0().map(Some)
688    }
689
690    fn from_time8(v: &'a Time8) -> Result<Self> {
691        T::from_time8(v).map(Some)
692    }
693
694    fn from_time12(v: &'a Time12) -> Result<Self> {
695        T::from_time12(v).map(Some)
696    }
697}
698
699// ============================================================================
700// FromRawRow implementations for tuples
701// ============================================================================
702
703macro_rules! impl_from_raw_row_tuple {
704    ($($idx:tt: $T:ident),+) => {
705        impl<'buf, 'value, $($T: FromRawValue<'buf>),+> FromRawRow<'buf> for ($($T,)+) {
706            #[expect(non_snake_case)]
707            fn from_raw_row(cols: &[ColumnDefinition<'_>], row: BinaryRowPayload<'buf>) -> Result<Self> {
708                let mut data = row.values();
709                let null_bitmap = row.null_bitmap();
710                $(
711                    let ($T, rest) = parse_value::<$T>(&cols[$idx].tail, null_bitmap.is_null($idx), data)?;
712                    data = rest;
713                )+
714                let _ = data; // suppress unused warning for last element
715                Ok(($($T,)+))
716            }
717        }
718    };
719}
720
721impl_from_raw_row_tuple!(0: A);
722impl_from_raw_row_tuple!(0: A, 1: B);
723impl_from_raw_row_tuple!(0: A, 1: B, 2: C);
724impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D);
725impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E);
726impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F);
727impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G);
728impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H);
729impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I);
730impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J);
731impl_from_raw_row_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K);
732impl_from_raw_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);