sqlx_mysql/protocol/statement/
row.rs1use bytes::{Buf, Bytes};
2
3use crate::error::Error;
4use crate::io::MySqlBufExt;
5use crate::io::{BufExt, ProtocolDecode};
6use crate::protocol::text::ColumnType;
7use crate::protocol::Row;
8use crate::MySqlColumn;
9
10#[derive(Debug)]
14pub(crate) struct BinaryRow(pub(crate) Row);
15
16impl<'de> ProtocolDecode<'de, &'de [MySqlColumn]> for BinaryRow {
17 fn decode_with(mut buf: Bytes, columns: &'de [MySqlColumn]) -> Result<Self, Error> {
18 let header = buf.get_u8();
19 if header != 0 {
20 return Err(err_protocol!(
21 "exepcted 0x00 (ROW) but found 0x{:02x}",
22 header
23 ));
24 }
25
26 let storage = buf.clone();
27 let offset = buf.len();
28
29 let null_bitmap_len = (columns.len() + 9) / 8;
30 let null_bitmap = buf.get_bytes(null_bitmap_len);
31
32 let mut values = Vec::with_capacity(columns.len());
33
34 for (column_idx, column) in columns.iter().enumerate() {
35 let column_null_idx = column_idx + 2;
37
38 let byte_idx = column_null_idx / 8;
39 let bit_idx = column_null_idx % 8;
40
41 let is_null = null_bitmap[byte_idx] & (1u8 << bit_idx) != 0;
42
43 if is_null {
44 values.push(None);
45 continue;
46 }
47
48 let type_info = &column.type_info;
50
51 let size: usize = match type_info.r#type {
55 ColumnType::LongLong => 8,
57 ColumnType::Long | ColumnType::Int24 => 4,
58 ColumnType::Short | ColumnType::Year => 2,
59 ColumnType::Tiny => 1,
60 ColumnType::Float => 4,
61 ColumnType::Double => 8,
62
63 ColumnType::String
66 | ColumnType::VarChar
67 | ColumnType::VarString
68 | ColumnType::Enum
69 | ColumnType::Set
70 | ColumnType::LongBlob
71 | ColumnType::MediumBlob
72 | ColumnType::Blob
73 | ColumnType::TinyBlob
74 | ColumnType::Geometry
75 | ColumnType::Bit
76 | ColumnType::Decimal
77 | ColumnType::Json
78 | ColumnType::NewDecimal => {
79 let size = buf.get_uint_lenenc();
80 usize::try_from(size)
81 .map_err(|_| err_protocol!("BLOB length out of range: {size}"))?
82 }
83
84 ColumnType::Time
87 | ColumnType::Timestamp
88 | ColumnType::Date
89 | ColumnType::Datetime => {
90 buf[0] as usize + 1
92 }
93
94 ColumnType::Null => unreachable!(),
96 };
97
98 let offset = offset - buf.len();
99
100 values.push(Some(offset..(offset + size)));
101
102 buf.advance(size);
103 }
104
105 Ok(BinaryRow(Row { values, storage }))
106 }
107}