mysql_common/binlog/events/
user_var_event.rs

1// Copyright (c) 2021 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use std::{
10    borrow::Cow,
11    cmp::min,
12    io::{self},
13};
14
15use bytes::BufMut;
16use saturating::Saturating as S;
17
18use crate::{
19    binlog::{
20        consts::{BinlogVersion, EventType, UserVarFlags},
21        BinlogCtx, BinlogEvent, BinlogStruct,
22    },
23    constants::{ItemResult, UnknownItemResultType},
24    io::ParseBuf,
25    misc::raw::{bytes::U32Bytes, int::*, RawBytes, RawConst, RawFlags},
26    proto::{MyDeserialize, MySerialize},
27};
28
29use super::BinlogEventHeader;
30
31/// User variable event.
32///
33/// Written every time a statement uses a user variable; precedes other events for the statement.
34/// Indicates the value to use for the user variable in the next statement.
35/// This is written only before a `QUERY_EVENT` and is not used with row-based logging.
36///
37/// # Notes on `BinlogEvent` implementation
38///
39/// * it won't try to read/write anything except `name` and `is_null` if `is_null` is `true`
40#[derive(Debug, Clone, Eq, PartialEq, Hash)]
41pub struct UserVarEvent<'a> {
42    /// User variable name.
43    name: RawBytes<'a, U32Bytes>,
44    /// `true` if value is `NULL`.
45    is_null: bool,
46    /// Type of a value.
47    value_type: RawConst<i8, ItemResult>,
48    /// Character set of a value. Will be `0` if `is_null` is `true`.
49    charset: RawInt<LeU32>,
50    /// Value of a user variable. Will be empty if `is_null` is `true`.
51    value: RawBytes<'a, U32Bytes>,
52    /// Flags of a user variable. Will be `0` if `is_null` is `true`.
53    flags: RawFlags<UserVarFlags, u8>,
54}
55
56impl<'a> UserVarEvent<'a> {
57    /// Returns the raw name of the variable.
58    pub fn name_raw(&'a self) -> &'a [u8] {
59        self.name.as_bytes()
60    }
61
62    /// Returns the name of the variable as a string (lossy converted).
63    pub fn name(&'a self) -> Cow<'a, str> {
64        self.name.as_str()
65    }
66
67    /// This is `true` if the value is null.
68    pub fn is_null(&self) -> bool {
69        self.is_null
70    }
71
72    /// Returns the type of the variable value.
73    pub fn value_type(&self) -> Result<ItemResult, UnknownItemResultType> {
74        self.value_type.get()
75    }
76
77    /// Returns the charset of the variable value (`0` if [`Self::is_null`] is `true`).
78    pub fn charset(&self) -> u32 {
79        self.charset.0
80    }
81
82    /// Returns the value of the variable (empty if [`Self::is_null`] is `true`).
83    pub fn value(&'a self) -> &'a [u8] {
84        self.value.as_bytes()
85    }
86
87    /// Returns the raw flags.
88    pub fn flags_raw(&self) -> u8 {
89        self.flags.0
90    }
91
92    /// Returns the flags (unknown bits are truncated).
93    pub fn flags(&self) -> UserVarFlags {
94        self.flags.get()
95    }
96
97    pub fn into_owned(self) -> UserVarEvent<'static> {
98        UserVarEvent {
99            name: self.name.into_owned(),
100            is_null: self.is_null,
101            value_type: self.value_type,
102            charset: self.charset,
103            value: self.value.into_owned(),
104            flags: self.flags,
105        }
106    }
107}
108
109impl<'de> MyDeserialize<'de> for UserVarEvent<'de> {
110    const SIZE: Option<usize> = None;
111    type Ctx = BinlogCtx<'de>;
112
113    fn deserialize(_ctx: Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
114        let name = buf.parse(())?;
115        let is_null = buf.parse::<RawInt<u8>>(())?.0 != 0;
116
117        if is_null {
118            return Ok(Self {
119                name,
120                is_null,
121                value_type: RawConst::new(ItemResult::STRING_RESULT as i8),
122                charset: RawInt::new(63),
123                value: RawBytes::default(),
124                flags: RawFlags::default(),
125            });
126        }
127
128        let mut sbuf: ParseBuf = buf.parse(5)?;
129        let value_type = sbuf.parse_unchecked(())?;
130        let charset = sbuf.parse_unchecked(())?;
131
132        let value = buf.parse(())?;
133
134        // Old servers may not pack flags here.
135        let flags = if !buf.is_empty() {
136            buf.parse_unchecked(())?
137        } else {
138            Default::default()
139        };
140
141        Ok(Self {
142            name,
143            is_null,
144            value_type,
145            charset,
146            value,
147            flags,
148        })
149    }
150}
151
152impl MySerialize for UserVarEvent<'_> {
153    fn serialize(&self, buf: &mut Vec<u8>) {
154        self.name.serialize(&mut *buf);
155        buf.put_u8(self.is_null as u8);
156        if !self.is_null {
157            self.value_type.serialize(&mut *buf);
158            self.charset.serialize(&mut *buf);
159            self.value.serialize(&mut *buf);
160            self.flags.serialize(&mut *buf);
161        }
162    }
163}
164
165impl<'a> BinlogEvent<'a> for UserVarEvent<'a> {
166    const EVENT_TYPE: EventType = EventType::USER_VAR_EVENT;
167}
168
169impl<'a> BinlogStruct<'a> for UserVarEvent<'a> {
170    fn len(&self, _version: BinlogVersion) -> usize {
171        let mut len = S(0);
172
173        len += S(4);
174        len += S(min(self.name.0.len(), u32::MAX as usize));
175        len += S(1);
176
177        if !self.is_null {
178            len += S(1);
179            len += S(4);
180            len += S(4);
181            len += S(min(self.value.len(), u32::MAX as usize));
182            len += S(1);
183        }
184
185        min(len.0, u32::MAX as usize - BinlogEventHeader::LEN)
186    }
187}