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.
89use std::{
10 borrow::Cow,
11 cmp::min,
12 io::{self},
13};
1415use bytes::BufMut;
16use saturating::Saturating as S;
1718use 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};
2829use super::BinlogEventHeader;
3031/// 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.
43name: RawBytes<'a, U32Bytes>,
44/// `true` if value is `NULL`.
45is_null: bool,
46/// Type of a value.
47value_type: RawConst<i8, ItemResult>,
48/// Character set of a value. Will be `0` if `is_null` is `true`.
49charset: RawInt<LeU32>,
50/// Value of a user variable. Will be empty if `is_null` is `true`.
51value: RawBytes<'a, U32Bytes>,
52/// Flags of a user variable. Will be `0` if `is_null` is `true`.
53flags: RawFlags<UserVarFlags, u8>,
54}
5556impl<'a> UserVarEvent<'a> {
57/// Returns the raw name of the variable.
58pub fn name_raw(&'a self) -> &'a [u8] {
59self.name.as_bytes()
60 }
6162/// Returns the name of the variable as a string (lossy converted).
63pub fn name(&'a self) -> Cow<'a, str> {
64self.name.as_str()
65 }
6667/// This is `true` if the value is null.
68pub fn is_null(&self) -> bool {
69self.is_null
70 }
7172/// Returns the type of the variable value.
73pub fn value_type(&self) -> Result<ItemResult, UnknownItemResultType> {
74self.value_type.get()
75 }
7677/// Returns the charset of the variable value (`0` if [`Self::is_null`] is `true`).
78pub fn charset(&self) -> u32 {
79self.charset.0
80}
8182/// Returns the value of the variable (empty if [`Self::is_null`] is `true`).
83pub fn value(&'a self) -> &'a [u8] {
84self.value.as_bytes()
85 }
8687/// Returns the raw flags.
88pub fn flags_raw(&self) -> u8 {
89self.flags.0
90}
9192/// Returns the flags (unknown bits are truncated).
93pub fn flags(&self) -> UserVarFlags {
94self.flags.get()
95 }
9697pub 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}
108109impl<'de> MyDeserialize<'de> for UserVarEvent<'de> {
110const SIZE: Option<usize> = None;
111type Ctx = BinlogCtx<'de>;
112113fn deserialize(_ctx: Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
114let name = buf.parse(())?;
115let is_null = buf.parse::<RawInt<u8>>(())?.0 != 0;
116117if is_null {
118return 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 }
127128let mut sbuf: ParseBuf = buf.parse(5)?;
129let value_type = sbuf.parse_unchecked(())?;
130let charset = sbuf.parse_unchecked(())?;
131132let value = buf.parse(())?;
133134// Old servers may not pack flags here.
135let flags = if !buf.is_empty() {
136 buf.parse_unchecked(())?
137} else {
138 Default::default()
139 };
140141Ok(Self {
142 name,
143 is_null,
144 value_type,
145 charset,
146 value,
147 flags,
148 })
149 }
150}
151152impl MySerialize for UserVarEvent<'_> {
153fn serialize(&self, buf: &mut Vec<u8>) {
154self.name.serialize(&mut *buf);
155 buf.put_u8(self.is_null as u8);
156if !self.is_null {
157self.value_type.serialize(&mut *buf);
158self.charset.serialize(&mut *buf);
159self.value.serialize(&mut *buf);
160self.flags.serialize(&mut *buf);
161 }
162 }
163}
164165impl<'a> BinlogEvent<'a> for UserVarEvent<'a> {
166const EVENT_TYPE: EventType = EventType::USER_VAR_EVENT;
167}
168169impl<'a> BinlogStruct<'a> for UserVarEvent<'a> {
170fn len(&self, _version: BinlogVersion) -> usize {
171let mut len = S(0);
172173 len += S(4);
174 len += S(min(self.name.0.len(), u32::MAX as usize));
175 len += S(1);
176177if !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 }
184185 min(len.0, u32::MAX as usize - BinlogEventHeader::LEN)
186 }
187}