zero_mysql/protocol/
response.rs1use crate::constant::ServerStatusFlags;
2use crate::error::{Error, Result, eyre};
3use crate::protocol::primitive::*;
4use zerocopy::byteorder::little_endian::U16 as U16LE;
5use zerocopy::{FromBytes, Immutable, KnownLayout};
6
7#[derive(Debug, Clone, Copy)]
9pub struct OkPayloadBytes<'a>(pub &'a [u8]);
10
11impl<'a> OkPayloadBytes<'a> {
12 pub fn assert_eof(&self) -> Result<()> {
13 if self.0[0] == 0xFE {
14 Ok(())
15 } else {
16 Err(Error::LibraryBug(eyre!(
17 "expected EOF packet header 0xFE, got 0x{:02X}",
18 self.0[0]
19 )))
20 }
21 }
22
23 pub fn bytes(&self) -> &[u8] {
24 self.0
25 }
26}
27
28#[derive(Debug, Clone)]
30pub struct OkPayload {
31 pub affected_rows: u64,
32 pub last_insert_id: u64,
33 pub status_flags: ServerStatusFlags,
34 pub warnings: u16,
35 }
38
39impl TryFrom<OkPayloadBytes<'_>> for OkPayload {
40 type Error = Error;
41
42 fn try_from(bytes: OkPayloadBytes<'_>) -> Result<Self> {
43 let (header, data) = read_int_1(bytes.bytes())?;
44 if header != 0x00 && header != 0xFE {
45 return Err(Error::LibraryBug(eyre!(
46 "expected OK/EOF packet header 0x00 or 0xFE, got 0x{:02X}",
47 header
48 )));
49 }
50
51 let (affected_rows, data) = read_int_lenenc(data)?;
52 let (last_insert_id, data) = read_int_lenenc(data)?;
53 let (status_flags, data) = read_int_2(data)?;
54 let (warnings, _data) = read_int_2(data)?;
55
56 Ok(OkPayload {
59 affected_rows,
60 last_insert_id,
61 status_flags: ServerStatusFlags::from_bits_truncate(status_flags),
62 warnings,
63 })
64 }
65}
66
67#[derive(Debug)]
68pub struct ErrPayloadBytes<'a>(pub &'a [u8]);
69
70#[derive(Debug, Clone, thiserror::Error)]
72#[error("ERROR {} ({}): {}", self.error_code, self.sql_state, self.message)]
73pub struct ErrPayload {
74 pub error_code: u16,
75 pub sql_state: String,
76 pub message: String,
77}
78
79impl TryFrom<ErrPayloadBytes<'_>> for ErrPayload {
80 type Error = Error;
81
82 fn try_from(bytes: ErrPayloadBytes<'_>) -> Result<Self> {
83 let (header, data) = read_int_1(bytes.0)?;
84 debug_assert_eq!(header, 0xFF);
85
86 let (error_code, data) = read_int_2(data)?;
87
88 let (_sql_state_marker, data) = read_string_fix(data, 1)?;
90 let (sql_state, data) = read_string_fix(data, 5)?;
91
92 Ok(ErrPayload {
93 error_code,
94 sql_state: String::from_utf8_lossy(sql_state).to_string(),
95 message: String::from_utf8_lossy(data).to_string(), })
97 }
98}
99
100#[repr(C, packed)]
101#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable)]
102pub struct EofPacket {
103 warnings: U16LE,
104 status_flags: U16LE,
105}
106
107impl EofPacket {
108 pub fn warnings(&self) -> u16 {
109 self.warnings.get()
110 }
111 pub fn status_flags(&self) -> ServerStatusFlags {
113 ServerStatusFlags::from_bits_truncate(self.status_flags.get())
114 }
115}
116
117pub fn read_eof_packet(payload: &[u8]) -> Result<&EofPacket> {
119 let (header, data) = read_int_1(payload)?;
120 if header != 0xFE {
121 return Err(Error::LibraryBug(eyre!(
122 "expected EOF packet header 0xFE, got 0x{:02X}",
123 header
124 )));
125 }
126
127 if data.len() < 4 {
129 return Err(Error::LibraryBug(eyre!(
130 "EOF packet data too short: {} < 4",
131 data.len()
132 )));
133 }
134
135 Ok(EofPacket::ref_from_bytes(&data[..4])?)
137}