rbdc_mysql/protocol/statement/
row.rs1use bytes::{Buf, Bytes};
2
3use crate::io::MySqlBufExt;
4use crate::protocol::text::ColumnType;
5use crate::protocol::Row;
6use crate::result_set::MySqlColumn;
7use rbdc::io::{BufExt, Decode};
8use rbdc::{err_protocol, Error};
9
10#[derive(Debug)]
14pub struct BinaryRow(pub Row);
15
16impl<'de> Decode<'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 if buf.len() < null_bitmap_len {
31 return Err(err_protocol!(
32 "binary row: null-bitmap length {} exceeds remaining {} bytes",
33 null_bitmap_len,
34 buf.len()
35 ));
36 }
37 let null_bitmap = buf.get_bytes(null_bitmap_len);
38
39 let mut values = Vec::with_capacity(columns.len());
40
41 for (column_idx, column) in columns.iter().enumerate() {
42 let column_null_idx = column_idx + 2;
44 let is_null =
45 null_bitmap[column_null_idx / 8] & (1 << (column_null_idx % 8) as u8) != 0;
46
47 if is_null {
48 values.push(None);
49 continue;
50 }
51
52 let type_info = &column.type_info;
54
55 let size: usize = match type_info.r#type {
56 ColumnType::String
57 | ColumnType::VarChar
58 | ColumnType::VarString
59 | ColumnType::Enum
60 | ColumnType::Set
61 | ColumnType::LongBlob
62 | ColumnType::MediumBlob
63 | ColumnType::Blob
64 | ColumnType::TinyBlob
65 | ColumnType::Geometry
66 | ColumnType::Bit
67 | ColumnType::Decimal
68 | ColumnType::Json
69 | ColumnType::NewDecimal => buf.get_uint_lenenc() as usize,
70
71 ColumnType::LongLong => 8,
72 ColumnType::Long | ColumnType::Int24 => 4,
73 ColumnType::Short | ColumnType::Year => 2,
74 ColumnType::Tiny => 1,
75 ColumnType::Float => 4,
76 ColumnType::Double => 8,
77
78 ColumnType::Time
79 | ColumnType::Timestamp
80 | ColumnType::Date
81 | ColumnType::Datetime => {
82 if buf.is_empty() { return Err(err_protocol!("binary row: expected temporal length byte, found empty buffer")); }
84 buf[0] as usize + 1
85 }
86
87 ColumnType::Null => unreachable!(),
89 };
90
91 if size > buf.len() {
92 return Err(err_protocol!(
93 "binary row column length {} exceeds remaining {} bytes",
94 size,
95 buf.len()
96 ));
97 }
98
99 let offset = offset - buf.len();
100
101 values.push(Some(offset..(offset + size)));
102
103 buf.advance(size);
104 }
105 Ok(BinaryRow(Row::from((values, storage.to_vec()))))
106 }
107}