zero_mysql/protocol/trait/
param.rs

1use auto_impl::auto_impl;
2
3use crate::constant::ColumnType;
4use crate::error::Result;
5use crate::protocol::primitive::*;
6
7/// Parameter indicator for COM_STMT_BULK_EXECUTE
8///
9/// See: https://mariadb.com/docs/server/reference/clientserver-protocol/3-binary-protocol-prepared-statements/com_stmt_bulk_execute
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[repr(u8)]
12pub enum ParamIndicator {
13    /// Value follows (0)
14    None = 0,
15    /// Value is null (1)
16    Null = 1,
17    /// For INSERT/UPDATE, value is default (2)
18    Default = 2,
19    /// Value is default for insert, ignored for update (3)
20    Ignore = 3,
21}
22
23pub trait Param {
24    fn is_null(&self) -> bool;
25    fn encode_type(&self, out: &mut Vec<u8>);
26    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()>;
27}
28
29pub trait TypedParam {
30    fn is_null(&self) -> bool {
31        false
32    }
33    fn encode_type(out: &mut Vec<u8>);
34    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()>;
35}
36
37impl TypedParam for bool {
38    fn encode_type(out: &mut Vec<u8>) {
39        out.push(ColumnType::MYSQL_TYPE_TINY as u8);
40        out.push(0x00);
41    }
42
43    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
44        write_int_1(out, u8::from(*self));
45        Ok(())
46    }
47}
48
49impl TypedParam for i8 {
50    fn encode_type(out: &mut Vec<u8>) {
51        out.push(ColumnType::MYSQL_TYPE_TINY as u8);
52        out.push(0x00);
53    }
54
55    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
56        write_int_1(out, *self as u8);
57        Ok(())
58    }
59}
60
61impl TypedParam for i16 {
62    fn encode_type(out: &mut Vec<u8>) {
63        out.push(ColumnType::MYSQL_TYPE_SHORT as u8);
64        out.push(0x00);
65    }
66
67    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
68        write_int_2(out, *self as u16);
69        Ok(())
70    }
71}
72
73impl TypedParam for i32 {
74    fn encode_type(out: &mut Vec<u8>) {
75        out.push(ColumnType::MYSQL_TYPE_LONG as u8);
76        out.push(0x00);
77    }
78
79    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
80        write_int_4(out, *self as u32);
81        Ok(())
82    }
83}
84
85impl TypedParam for i64 {
86    fn encode_type(out: &mut Vec<u8>) {
87        out.push(ColumnType::MYSQL_TYPE_LONGLONG as u8);
88        out.push(0x00);
89    }
90
91    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
92        write_int_8(out, *self as u64);
93        Ok(())
94    }
95}
96
97impl TypedParam for u8 {
98    fn encode_type(out: &mut Vec<u8>) {
99        out.push(ColumnType::MYSQL_TYPE_TINY as u8);
100        out.push(0x80);
101    }
102
103    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
104        write_int_1(out, *self);
105        Ok(())
106    }
107}
108
109impl TypedParam for u16 {
110    fn encode_type(out: &mut Vec<u8>) {
111        out.push(ColumnType::MYSQL_TYPE_SHORT as u8);
112        out.push(0x80);
113    }
114
115    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
116        write_int_2(out, *self);
117        Ok(())
118    }
119}
120
121impl TypedParam for u32 {
122    fn encode_type(out: &mut Vec<u8>) {
123        out.push(ColumnType::MYSQL_TYPE_LONG as u8);
124        out.push(0x80);
125    }
126
127    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
128        write_int_4(out, *self);
129        Ok(())
130    }
131}
132
133impl TypedParam for u64 {
134    fn encode_type(out: &mut Vec<u8>) {
135        out.push(ColumnType::MYSQL_TYPE_LONGLONG as u8);
136        out.push(0x80);
137    }
138
139    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
140        write_int_8(out, *self);
141        Ok(())
142    }
143}
144
145impl TypedParam for f32 {
146    fn encode_type(out: &mut Vec<u8>) {
147        out.push(ColumnType::MYSQL_TYPE_FLOAT as u8);
148        out.push(0x00);
149    }
150
151    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
152        write_int_4(out, self.to_bits());
153        Ok(())
154    }
155}
156
157impl TypedParam for f64 {
158    fn encode_type(out: &mut Vec<u8>) {
159        out.push(ColumnType::MYSQL_TYPE_DOUBLE as u8);
160        out.push(0x00);
161    }
162
163    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
164        write_int_8(out, self.to_bits());
165        Ok(())
166    }
167}
168
169impl TypedParam for &str {
170    fn encode_type(out: &mut Vec<u8>) {
171        out.push(ColumnType::MYSQL_TYPE_VAR_STRING as u8);
172        out.push(0x00);
173    }
174
175    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
176        write_string_lenenc(out, self);
177        Ok(())
178    }
179}
180
181impl TypedParam for String {
182    fn encode_type(out: &mut Vec<u8>) {
183        out.push(ColumnType::MYSQL_TYPE_VAR_STRING as u8);
184        out.push(0x00);
185    }
186
187    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
188        write_string_lenenc(out, self);
189        Ok(())
190    }
191}
192
193impl TypedParam for &String {
194    fn encode_type(out: &mut Vec<u8>) {
195        out.push(ColumnType::MYSQL_TYPE_VAR_STRING as u8);
196        out.push(0x00);
197    }
198
199    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
200        write_string_lenenc(out, self);
201        Ok(())
202    }
203}
204
205impl TypedParam for &[u8] {
206    fn encode_type(out: &mut Vec<u8>) {
207        out.push(ColumnType::MYSQL_TYPE_BLOB as u8);
208        out.push(0x00);
209    }
210
211    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
212        write_bytes_lenenc(out, self);
213        Ok(())
214    }
215}
216
217impl TypedParam for Vec<u8> {
218    fn encode_type(out: &mut Vec<u8>) {
219        out.push(ColumnType::MYSQL_TYPE_BLOB as u8);
220        out.push(0x00);
221    }
222
223    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
224        write_bytes_lenenc(out, self);
225        Ok(())
226    }
227}
228
229impl TypedParam for &Vec<u8> {
230    fn encode_type(out: &mut Vec<u8>) {
231        out.push(ColumnType::MYSQL_TYPE_BLOB as u8);
232        out.push(0x00);
233    }
234
235    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
236        write_bytes_lenenc(out, self);
237        Ok(())
238    }
239}
240
241impl<T: TypedParam> TypedParam for Option<T> {
242    fn is_null(&self) -> bool {
243        self.is_none()
244    }
245
246    fn encode_type(out: &mut Vec<u8>) {
247        T::encode_type(out);
248    }
249
250    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
251        match self {
252            Some(value) => value.encode_value(out),
253            None => Ok(()),
254        }
255    }
256}
257
258// ============================================================================
259// Params trait - for collections of parameters
260// ============================================================================
261
262/// Trait for parameter binding in prepared statements
263///
264/// This trait is implemented by external libraries to provide a custom parameter serialization.
265pub trait Params {
266    /// Number of parameters
267    fn len(&self) -> usize;
268
269    fn is_empty(&self) -> bool {
270        self.len() == 0
271    }
272
273    /// Write NULL bitmap
274    ///
275    /// The NULL bitmap is (num_params + 7) / 8 bytes long.
276    /// Bit is set to 1 if the parameter is NULL.
277    fn encode_null_bitmap(&self, out: &mut Vec<u8>);
278
279    /// Write parameter types
280    ///
281    /// Each parameter type is 2 bytes:
282    /// - 1 byte: MySQL type (MYSQL_TYPE_*)
283    /// - 1 byte: unsigned flag (0x80 if unsigned, 0x00 otherwise)
284    fn encode_types(&self, out: &mut Vec<u8>);
285
286    /// Write parameter values (binary encoded)
287    ///
288    /// Values are encoded according to MySQL binary protocol.
289    /// NULL parameters should be skipped (they're already in the NULL bitmap).
290    fn encode_values(&self, out: &mut Vec<u8>) -> Result<()>;
291
292    /// Write parameter values for bulk execution (COM_STMT_BULK_EXECUTE)
293    ///
294    /// Format:
295    /// - First: parameter indicators (1 byte per parameter)
296    /// - Then: values (only for parameters with indicator None)
297    ///
298    /// See: https://mariadb.com/docs/server/reference/clientserver-protocol/3-binary-protocol-prepared-statements/com_stmt_bulk_execute
299    fn encode_values_for_bulk(&self, out: &mut Vec<u8>) -> Result<()>;
300}
301
302#[auto_impl(&)]
303pub trait TypedParams {
304    fn len(&self) -> usize;
305    fn is_empty(&self) -> bool {
306        self.len() == 0
307    }
308    fn encode_null_bitmap(&self, out: &mut Vec<u8>);
309    fn encode_types(out: &mut Vec<u8>);
310    fn encode_values(&self, out: &mut Vec<u8>) -> Result<()>;
311    fn encode_values_for_bulk(&self, out: &mut Vec<u8>) -> Result<()>;
312}
313
314impl<T: TypedParams> Params for T {
315    fn len(&self) -> usize {
316        TypedParams::len(self)
317    }
318    fn encode_null_bitmap(&self, out: &mut Vec<u8>) {
319        TypedParams::encode_null_bitmap(self, out)
320    }
321    fn encode_types(&self, out: &mut Vec<u8>) {
322        T::encode_types(out)
323    }
324    fn encode_values(&self, out: &mut Vec<u8>) -> Result<()> {
325        TypedParams::encode_values(self, out)
326    }
327    fn encode_values_for_bulk(&self, out: &mut Vec<u8>) -> Result<()> {
328        TypedParams::encode_values_for_bulk(self, out)
329    }
330}
331
332impl TypedParams for () {
333    fn len(&self) -> usize {
334        0
335    }
336    fn encode_null_bitmap(&self, _out: &mut Vec<u8>) {}
337    fn encode_types(_out: &mut Vec<u8>) {}
338    fn encode_values(&self, _out: &mut Vec<u8>) -> Result<()> {
339        Ok(())
340    }
341    fn encode_values_for_bulk(&self, _out: &mut Vec<u8>) -> Result<()> {
342        Ok(())
343    }
344}
345
346// ============================================================================
347// Tuple implementations for common sizes
348// ============================================================================
349
350macro_rules! impl_params_for_tuple {
351    ($($T:ident : $idx:tt),+) => {
352        impl<$($T: TypedParam),+> TypedParams for ($($T,)+) {
353            fn len(&self) -> usize {
354                let mut count = 0;
355                $(
356                    let _ = &self.$idx;
357                    count += 1;
358                )+
359                count
360            }
361
362            fn encode_null_bitmap(&self, out: &mut Vec<u8>) {
363                let num_bytes = TypedParams::len(self).div_ceil(8);
364                let start_len = out.len();
365                out.resize(start_len + num_bytes, 0);
366
367                $(
368                    if self.$idx.is_null() {
369                        let byte_pos = start_len + ($idx >> 3);
370                        let bit_offset = $idx & 7;
371                        out[byte_pos] |= 1 << bit_offset;
372                    }
373                )+
374            }
375
376            fn encode_types(out: &mut Vec<u8>) {
377                $(
378                    $T::encode_type(out);
379                )+
380            }
381
382            fn encode_values(&self, out: &mut Vec<u8>) -> Result<()> {
383                $(
384                    if !self.$idx.is_null() {
385                        self.$idx.encode_value(out)?;
386                    }
387                )+
388                Ok(())
389            }
390
391            fn encode_values_for_bulk(&self, out: &mut Vec<u8>) -> Result<()> {
392                $(
393                    if self.$idx.is_null() {
394                        out.push(ParamIndicator::Null as u8);
395                    } else {
396                        out.push(ParamIndicator::None as u8);
397                        self.$idx.encode_value(out)?;
398                    }
399                )+
400                Ok(())
401            }
402        }
403    };
404}
405
406// Implement for tuples of size 1-12
407impl_params_for_tuple!(T0: 0);
408impl_params_for_tuple!(T0: 0, T1: 1);
409impl_params_for_tuple!(T0: 0, T1: 1, T2: 2);
410impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3);
411impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4);
412impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5);
413impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6);
414impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7);
415impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8);
416impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9);
417impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10);
418impl_params_for_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11);