sqlx_mysql/
arguments.rs

1use crate::encode::{Encode, IsNull};
2use crate::types::Type;
3use crate::{MySql, MySqlTypeInfo};
4pub(crate) use sqlx_core::arguments::*;
5use sqlx_core::error::BoxDynError;
6use std::ops::Deref;
7
8/// Implementation of [`Arguments`] for MySQL.
9#[derive(Debug, Default, Clone)]
10pub struct MySqlArguments {
11    pub(crate) values: Vec<u8>,
12    pub(crate) types: Vec<MySqlTypeInfo>,
13    pub(crate) null_bitmap: NullBitMap,
14}
15
16impl MySqlArguments {
17    pub(crate) fn add<'q, T>(&mut self, value: T) -> Result<(), BoxDynError>
18    where
19        T: Encode<'q, MySql> + Type<MySql>,
20    {
21        let ty = value.produces().unwrap_or_else(T::type_info);
22
23        let value_length_before_encoding = self.values.len();
24        let is_null = match value.encode(&mut self.values) {
25            Ok(is_null) => is_null,
26            Err(error) => {
27                // reset the value buffer to its previous value if encoding failed so we don't leave a half-encoded value behind
28                self.values.truncate(value_length_before_encoding);
29                return Err(error);
30            }
31        };
32
33        self.types.push(ty);
34        self.null_bitmap.push(is_null);
35
36        Ok(())
37    }
38}
39
40impl<'q> Arguments<'q> for MySqlArguments {
41    type Database = MySql;
42
43    fn reserve(&mut self, len: usize, size: usize) {
44        self.types.reserve(len);
45        self.values.reserve(size);
46    }
47
48    fn add<T>(&mut self, value: T) -> Result<(), BoxDynError>
49    where
50        T: Encode<'q, Self::Database> + Type<Self::Database>,
51    {
52        self.add(value)
53    }
54
55    fn len(&self) -> usize {
56        self.types.len()
57    }
58}
59
60#[derive(Debug, Default, Clone)]
61pub(crate) struct NullBitMap {
62    bytes: Vec<u8>,
63    length: usize,
64}
65
66impl NullBitMap {
67    fn push(&mut self, is_null: IsNull) {
68        let byte_index = self.length / (u8::BITS as usize);
69        let bit_offset = self.length % (u8::BITS as usize);
70
71        if bit_offset == 0 {
72            self.bytes.push(0);
73        }
74
75        self.bytes[byte_index] |= u8::from(is_null.is_null()) << bit_offset;
76        self.length += 1;
77    }
78}
79
80impl Deref for NullBitMap {
81    type Target = [u8];
82
83    fn deref(&self) -> &Self::Target {
84        &self.bytes
85    }
86}
87
88#[cfg(test)]
89mod test {
90    use super::*;
91
92    #[test]
93    fn null_bit_map_should_push_is_null() {
94        let mut bit_map = NullBitMap::default();
95
96        bit_map.push(IsNull::Yes);
97        bit_map.push(IsNull::No);
98        bit_map.push(IsNull::Yes);
99        bit_map.push(IsNull::No);
100        bit_map.push(IsNull::Yes);
101        bit_map.push(IsNull::No);
102        bit_map.push(IsNull::Yes);
103        bit_map.push(IsNull::No);
104        bit_map.push(IsNull::Yes);
105
106        assert_eq!([0b01010101, 0b1].as_slice(), bit_map.deref());
107    }
108}