mysql_common/packets/
session_state_change.rs

1use std::{borrow::Cow, io};
2
3use crate::{
4    constants::SessionStateType,
5    io::ParseBuf,
6    misc::raw::{bytes::EofBytes, int::LenEnc, RawBytes},
7    proto::{MyDeserialize, MySerialize},
8};
9
10// Copyright (c) 2017 Anatoly Ikorsky
11//
12// Licensed under the Apache License, Version 2.0
13// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
14// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
15// option. All files in the project carrying such notice may not be copied,
16// modified, or distributed except according to those terms.
17
18/// Represents a parsed change in a session state (part of MySql's Ok packet).
19///
20/// See [MySql docs][1].
21///
22/// [1]: https://dev.mysql.com/doc/c-api/5.7/en/mysql-session-track-get-first.html
23#[derive(Clone, Eq, PartialEq, Debug)]
24pub enum SessionStateChange<'a> {
25    IsTracked(bool),
26    Schema(Schema<'a>),
27    SystemVariables(Vec<SystemVariable<'a>>),
28    Gtids(Gtids<'a>),
29    TransactionCharacteristics(TransactionCharacteristics<'a>),
30    TransactionState(TransactionState<'a>),
31    Unsupported(Unsupported<'a>),
32}
33
34impl SessionStateChange<'_> {
35    pub fn into_owned(self) -> SessionStateChange<'static> {
36        match self {
37            SessionStateChange::SystemVariables(x) => SessionStateChange::SystemVariables(
38                x.into_iter().map(SystemVariable::into_owned).collect(),
39            ),
40            SessionStateChange::Schema(schema) => SessionStateChange::Schema(schema.into_owned()),
41            SessionStateChange::IsTracked(x) => SessionStateChange::IsTracked(x),
42            SessionStateChange::Gtids(x) => SessionStateChange::Gtids(x.into_owned()),
43            SessionStateChange::TransactionCharacteristics(x) => {
44                SessionStateChange::TransactionCharacteristics(x.into_owned())
45            }
46            SessionStateChange::TransactionState(x) => {
47                SessionStateChange::TransactionState(x.into_owned())
48            }
49            SessionStateChange::Unsupported(x) => SessionStateChange::Unsupported(x.into_owned()),
50        }
51    }
52}
53
54impl<'de> MyDeserialize<'de> for SessionStateChange<'de> {
55    const SIZE: Option<usize> = None;
56    type Ctx = SessionStateType;
57
58    fn deserialize(ty: SessionStateType, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
59        match ty {
60            SessionStateType::SESSION_TRACK_SYSTEM_VARIABLES => {
61                let mut vars = Vec::new();
62                while !buf.is_empty() {
63                    vars.push(buf.parse_unchecked(())?);
64                }
65                Ok(SessionStateChange::SystemVariables(vars))
66            }
67            SessionStateType::SESSION_TRACK_SCHEMA => {
68                buf.parse_unchecked(()).map(SessionStateChange::Schema)
69            }
70            SessionStateType::SESSION_TRACK_STATE_CHANGE => {
71                let is_tracked: RawBytes<'_, LenEnc> = buf.parse_unchecked(())?;
72                Ok(SessionStateChange::IsTracked(is_tracked.as_bytes() == b"1"))
73            }
74            // Layout isn't specified in the documentation
75            SessionStateType::SESSION_TRACK_GTIDS => {
76                Ok(SessionStateChange::Gtids(buf.parse_unchecked(())?))
77            }
78            SessionStateType::SESSION_TRACK_TRANSACTION_CHARACTERISTICS => Ok(
79                SessionStateChange::TransactionCharacteristics(buf.parse_unchecked(())?),
80            ),
81            SessionStateType::SESSION_TRACK_TRANSACTION_STATE => buf
82                .parse_unchecked(())
83                .map(SessionStateChange::TransactionState),
84        }
85    }
86}
87
88impl MySerialize for SessionStateChange<'_> {
89    fn serialize(&self, buf: &mut Vec<u8>) {
90        match self {
91            SessionStateChange::SystemVariables(vars) => {
92                for var in vars {
93                    var.serialize(&mut *buf);
94                }
95            }
96            SessionStateChange::Schema(schema) => schema.serialize(buf),
97            SessionStateChange::IsTracked(is_tracked) => {
98                if *is_tracked {
99                    b"\x011".serialize(buf);
100                } else {
101                    b"\x010".serialize(buf);
102                }
103            }
104            SessionStateChange::Gtids(x) => x.serialize(buf),
105            SessionStateChange::TransactionCharacteristics(x) => x.serialize(buf),
106            SessionStateChange::TransactionState(x) => x.serialize(buf),
107            SessionStateChange::Unsupported(x) => x.serialize(buf),
108        }
109    }
110}
111
112/// This tracker type indicates that GTIDs are available and contains the GTID string.
113///
114/// The GTID string is in the standard format for specifying a set of GTID values.
115#[derive(Debug, Clone, PartialEq, Eq, Hash)]
116pub struct Gtids<'a>(RawBytes<'a, EofBytes>);
117
118impl<'a> Gtids<'a> {
119    pub fn new(gtid_set: impl Into<Cow<'a, [u8]>>) -> Self {
120        Self(RawBytes::new(gtid_set))
121    }
122
123    /// Returns a raw GTID string.
124    pub fn as_bytes(&self) -> &[u8] {
125        self.0.as_bytes()
126    }
127
128    /// Returns a GTID string (lossy converted).
129    pub fn as_str(&self) -> Cow<'_, str> {
130        self.0.as_str()
131    }
132
133    /// Returns a `'static` version of self.
134    pub fn into_owned(self) -> Gtids<'static> {
135        Gtids(self.0.into_owned())
136    }
137}
138
139impl<'de> MyDeserialize<'de> for Gtids<'de> {
140    const SIZE: Option<usize> = None;
141    type Ctx = ();
142
143    fn deserialize((): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
144        buf.parse_unchecked(()).map(Self)
145    }
146}
147
148impl MySerialize for Gtids<'_> {
149    fn serialize(&self, buf: &mut Vec<u8>) {
150        self.0.serialize(buf);
151    }
152}
153
154/// This tracker type indicates that the default schema has been set.
155///
156/// The value contains the new default schema name.
157#[derive(Debug, Clone, PartialEq, Eq, Hash)]
158pub struct Schema<'a>(RawBytes<'a, LenEnc>);
159
160impl<'a> Schema<'a> {
161    pub fn new(schema_name: impl Into<Cow<'a, [u8]>>) -> Self {
162        Self(RawBytes::new(schema_name))
163    }
164
165    /// Returns a raw schema name.
166    pub fn as_bytes(&self) -> &[u8] {
167        self.0.as_bytes()
168    }
169
170    /// Returns schema name (lossy converted).
171    pub fn as_str(&self) -> Cow<'_, str> {
172        self.0.as_str()
173    }
174
175    /// Returns a `'static` version of `self`.
176    pub fn into_owned(self) -> Schema<'static> {
177        Schema(self.0.into_owned())
178    }
179}
180
181impl<'de> MyDeserialize<'de> for Schema<'de> {
182    const SIZE: Option<usize> = None;
183    type Ctx = ();
184
185    fn deserialize((): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
186        buf.parse_unchecked(()).map(Self)
187    }
188}
189
190impl MySerialize for Schema<'_> {
191    fn serialize(&self, buf: &mut Vec<u8>) {
192        self.0.serialize(buf);
193    }
194}
195
196/// This tracker type indicates that one or more tracked session
197/// system variables have been assigned a value.
198#[derive(Debug, Clone, PartialEq, Eq, Hash)]
199pub struct SystemVariable<'a> {
200    name: RawBytes<'a, LenEnc>,
201    value: RawBytes<'a, LenEnc>,
202}
203
204impl<'a> SystemVariable<'a> {
205    pub fn new(name: impl Into<Cow<'a, [u8]>>, value: impl Into<Cow<'a, [u8]>>) -> Self {
206        Self {
207            name: RawBytes::new(name),
208            value: RawBytes::new(value),
209        }
210    }
211
212    /// Returns a raw name.
213    pub fn name_bytes(&self) -> &[u8] {
214        self.name.as_bytes()
215    }
216
217    /// Returns a name (lossy converted).
218    pub fn name_str(&self) -> Cow<'_, str> {
219        self.name.as_str()
220    }
221
222    /// Returns a raw value.
223    pub fn value_bytes(&self) -> &[u8] {
224        self.value.as_bytes()
225    }
226
227    /// Returns a value (lossy converted).
228    pub fn value_str(&self) -> Cow<'_, str> {
229        self.value.as_str()
230    }
231
232    /// Returns a `'static` version of `self`.
233    pub fn into_owned(self) -> SystemVariable<'static> {
234        SystemVariable {
235            name: self.name.into_owned(),
236            value: self.value.into_owned(),
237        }
238    }
239}
240
241impl<'de> MyDeserialize<'de> for SystemVariable<'de> {
242    const SIZE: Option<usize> = None;
243    type Ctx = ();
244
245    fn deserialize((): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
246        Ok(Self {
247            name: buf.parse_unchecked(())?,
248            value: buf.parse_unchecked(())?,
249        })
250    }
251}
252
253impl MySerialize for SystemVariable<'_> {
254    fn serialize(&self, buf: &mut Vec<u8>) {
255        self.name.serialize(&mut *buf);
256        self.value.serialize(buf);
257    }
258}
259
260/// This tracker type indicates that transaction characteristics are available.
261///
262/// The characteristics tracker data string may be empty,
263/// or it may contain one or more SQL statements, each terminated by a semicolon.
264#[derive(Debug, Clone, PartialEq, Eq, Hash)]
265pub struct TransactionCharacteristics<'a>(RawBytes<'a, LenEnc>);
266
267impl<'a> TransactionCharacteristics<'a> {
268    pub fn new(value: impl Into<Cow<'a, [u8]>>) -> Self {
269        Self(RawBytes::new(value))
270    }
271
272    /// Returns a raw value.
273    pub fn as_bytes(&self) -> &[u8] {
274        self.0.as_bytes()
275    }
276
277    /// Returns a value (lossy converted).
278    pub fn as_str(&self) -> Cow<'_, str> {
279        self.0.as_str()
280    }
281
282    /// Returns a `'static` version of `self`.
283    pub fn into_owned(self) -> TransactionCharacteristics<'static> {
284        TransactionCharacteristics(self.0.into_owned())
285    }
286}
287
288impl<'de> MyDeserialize<'de> for TransactionCharacteristics<'de> {
289    const SIZE: Option<usize> = None;
290    type Ctx = ();
291
292    fn deserialize((): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
293        buf.parse_unchecked(()).map(Self)
294    }
295}
296
297impl MySerialize for TransactionCharacteristics<'_> {
298    fn serialize(&self, buf: &mut Vec<u8>) {
299        self.0.serialize(buf);
300    }
301}
302
303/// This tracker type indicates that transaction state information is available.
304///
305/// Value is a string containing ASCII characters, each of which indicates some aspect
306/// of the transaction state.
307#[derive(Debug, Clone, PartialEq, Eq, Hash)]
308pub struct TransactionState<'a>(RawBytes<'a, LenEnc>);
309
310impl<'a> TransactionState<'a> {
311    pub fn new(value: impl Into<Cow<'a, [u8]>>) -> Self {
312        Self(RawBytes::new(value))
313    }
314
315    /// Returns a raw value.
316    pub fn as_bytes(&self) -> &[u8] {
317        self.0.as_bytes()
318    }
319
320    /// Returns a value (lossy converted).
321    pub fn as_str(&self) -> Cow<'_, str> {
322        self.0.as_str()
323    }
324
325    /// Returns a `'static` version of `self`.
326    pub fn into_owned(self) -> TransactionState<'static> {
327        TransactionState(self.0.into_owned())
328    }
329}
330
331impl<'de> MyDeserialize<'de> for TransactionState<'de> {
332    const SIZE: Option<usize> = None;
333    type Ctx = ();
334
335    fn deserialize((): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
336        buf.parse_unchecked(()).map(Self)
337    }
338}
339
340impl MySerialize for TransactionState<'_> {
341    fn serialize(&self, buf: &mut Vec<u8>) {
342        self.0.serialize(buf);
343    }
344}
345
346/// This tracker type is unknown/unsupported.
347#[derive(Debug, Clone, PartialEq, Eq, Hash)]
348pub struct Unsupported<'a>(RawBytes<'a, LenEnc>);
349
350impl<'a> Unsupported<'a> {
351    pub fn new(value: impl Into<Cow<'a, [u8]>>) -> Self {
352        Self(RawBytes::new(value))
353    }
354
355    /// Returns a value as a slice of bytes.
356    pub fn as_bytes(&self) -> &[u8] {
357        self.0.as_bytes()
358    }
359
360    /// Returns a value as a string (lossy converted).
361    pub fn as_str(&self) -> Cow<'_, str> {
362        self.0.as_str()
363    }
364
365    /// Returns a `'static` version of `self`.
366    pub fn into_owned(self) -> Unsupported<'static> {
367        Unsupported(self.0.into_owned())
368    }
369}
370
371impl<'de> MyDeserialize<'de> for Unsupported<'de> {
372    const SIZE: Option<usize> = None;
373    type Ctx = ();
374
375    fn deserialize((): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
376        buf.parse_unchecked(()).map(Self)
377    }
378}
379
380impl MySerialize for Unsupported<'_> {
381    fn serialize(&self, buf: &mut Vec<u8>) {
382        self.0.serialize(buf);
383    }
384}