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);
419
420// ============================================================================
421// Slice and Vec implementations
422// ============================================================================
423
424impl<T: TypedParam> Params for [T] {
425    fn len(&self) -> usize {
426        <[T]>::len(self)
427    }
428
429    fn encode_null_bitmap(&self, out: &mut Vec<u8>) {
430        let num_bytes = self.len().div_ceil(8);
431        let start_len = out.len();
432        out.resize(start_len + num_bytes, 0);
433
434        for (idx, item) in self.iter().enumerate() {
435            if item.is_null() {
436                let byte_pos = start_len + (idx >> 3);
437                let bit_offset = idx & 7;
438                out[byte_pos] |= 1 << bit_offset;
439            }
440        }
441    }
442
443    fn encode_types(&self, out: &mut Vec<u8>) {
444        for _ in self {
445            T::encode_type(out);
446        }
447    }
448
449    fn encode_values(&self, out: &mut Vec<u8>) -> Result<()> {
450        for item in self {
451            if !item.is_null() {
452                item.encode_value(out)?;
453            }
454        }
455        Ok(())
456    }
457
458    fn encode_values_for_bulk(&self, out: &mut Vec<u8>) -> Result<()> {
459        for item in self {
460            if item.is_null() {
461                out.push(ParamIndicator::Null as u8);
462            } else {
463                out.push(ParamIndicator::None as u8);
464                item.encode_value(out)?;
465            }
466        }
467        Ok(())
468    }
469}
470
471impl<T: TypedParam> Params for &[T] {
472    fn len(&self) -> usize {
473        <[T]>::len(self)
474    }
475
476    fn encode_null_bitmap(&self, out: &mut Vec<u8>) {
477        <[T] as Params>::encode_null_bitmap(self, out)
478    }
479
480    fn encode_types(&self, out: &mut Vec<u8>) {
481        <[T] as Params>::encode_types(self, out)
482    }
483
484    fn encode_values(&self, out: &mut Vec<u8>) -> Result<()> {
485        <[T] as Params>::encode_values(self, out)
486    }
487
488    fn encode_values_for_bulk(&self, out: &mut Vec<u8>) -> Result<()> {
489        <[T] as Params>::encode_values_for_bulk(self, out)
490    }
491}
492
493impl<T: TypedParam> Params for Vec<T> {
494    fn len(&self) -> usize {
495        self.as_slice().len()
496    }
497
498    fn encode_null_bitmap(&self, out: &mut Vec<u8>) {
499        self.as_slice().encode_null_bitmap(out)
500    }
501
502    fn encode_types(&self, out: &mut Vec<u8>) {
503        self.as_slice().encode_types(out)
504    }
505
506    fn encode_values(&self, out: &mut Vec<u8>) -> Result<()> {
507        self.as_slice().encode_values(out)
508    }
509
510    fn encode_values_for_bulk(&self, out: &mut Vec<u8>) -> Result<()> {
511        self.as_slice().encode_values_for_bulk(out)
512    }
513}
514
515impl<T: TypedParam> Params for &Vec<T> {
516    fn len(&self) -> usize {
517        self.as_slice().len()
518    }
519
520    fn encode_null_bitmap(&self, out: &mut Vec<u8>) {
521        self.as_slice().encode_null_bitmap(out)
522    }
523
524    fn encode_types(&self, out: &mut Vec<u8>) {
525        self.as_slice().encode_types(out)
526    }
527
528    fn encode_values(&self, out: &mut Vec<u8>) -> Result<()> {
529        self.as_slice().encode_values(out)
530    }
531
532    fn encode_values_for_bulk(&self, out: &mut Vec<u8>) -> Result<()> {
533        self.as_slice().encode_values_for_bulk(out)
534    }
535}
536
537// ============================================================================
538// UUID support
539// ============================================================================
540
541#[cfg(feature = "with-uuid")]
542impl TypedParam for uuid::Uuid {
543    fn encode_type(out: &mut Vec<u8>) {
544        out.push(ColumnType::MYSQL_TYPE_VAR_STRING as u8);
545        out.push(0x00);
546    }
547
548    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
549        let s = self.as_hyphenated().to_string();
550        write_string_lenenc(out, &s);
551        Ok(())
552    }
553}
554
555#[cfg(feature = "with-uuid")]
556impl TypedParam for &uuid::Uuid {
557    fn encode_type(out: &mut Vec<u8>) {
558        out.push(ColumnType::MYSQL_TYPE_VAR_STRING as u8);
559        out.push(0x00);
560    }
561
562    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
563        let s = self.as_hyphenated().to_string();
564        write_string_lenenc(out, &s);
565        Ok(())
566    }
567}
568
569// ============================================================================
570// chrono support
571// ============================================================================
572
573#[cfg(feature = "with-chrono")]
574use chrono::{Datelike, Timelike};
575
576#[cfg(feature = "with-chrono")]
577impl TypedParam for chrono::NaiveDate {
578    fn encode_type(out: &mut Vec<u8>) {
579        out.push(ColumnType::MYSQL_TYPE_DATE as u8);
580        out.push(0x00);
581    }
582
583    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
584        out.push(4); // length
585        write_int_2(out, u16::try_from(self.year()).unwrap_or(0));
586        out.push(self.month() as u8);
587        out.push(self.day() as u8);
588        Ok(())
589    }
590}
591
592#[cfg(feature = "with-chrono")]
593impl TypedParam for chrono::NaiveTime {
594    fn encode_type(out: &mut Vec<u8>) {
595        out.push(ColumnType::MYSQL_TYPE_TIME as u8);
596        out.push(0x00);
597    }
598
599    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
600        let micros = self.nanosecond() / 1000;
601        if micros > 0 {
602            out.push(12); // length
603            out.push(0); // is_negative
604            write_int_4(out, 0); // days
605            out.push(self.hour() as u8);
606            out.push(self.minute() as u8);
607            out.push(self.second() as u8);
608            write_int_4(out, micros);
609        } else {
610            out.push(8); // length
611            out.push(0); // is_negative
612            write_int_4(out, 0); // days
613            out.push(self.hour() as u8);
614            out.push(self.minute() as u8);
615            out.push(self.second() as u8);
616        }
617        Ok(())
618    }
619}
620
621#[cfg(feature = "with-chrono")]
622impl TypedParam for chrono::NaiveDateTime {
623    fn encode_type(out: &mut Vec<u8>) {
624        out.push(ColumnType::MYSQL_TYPE_DATETIME as u8);
625        out.push(0x00);
626    }
627
628    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
629        let micros = self.and_utc().timestamp_subsec_micros();
630        if micros > 0 {
631            out.push(11); // length
632            write_int_2(out, u16::try_from(self.year()).unwrap_or(0));
633            out.push(self.month() as u8);
634            out.push(self.day() as u8);
635            out.push(self.hour() as u8);
636            out.push(self.minute() as u8);
637            out.push(self.second() as u8);
638            write_int_4(out, micros);
639        } else {
640            out.push(7); // length
641            write_int_2(out, u16::try_from(self.year()).unwrap_or(0));
642            out.push(self.month() as u8);
643            out.push(self.day() as u8);
644            out.push(self.hour() as u8);
645            out.push(self.minute() as u8);
646            out.push(self.second() as u8);
647        }
648        Ok(())
649    }
650}
651
652// ============================================================================
653// time crate support
654// ============================================================================
655
656#[cfg(feature = "with-time")]
657impl TypedParam for time::Date {
658    fn encode_type(out: &mut Vec<u8>) {
659        out.push(ColumnType::MYSQL_TYPE_DATE as u8);
660        out.push(0x00);
661    }
662
663    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
664        out.push(4); // length
665        write_int_2(out, u16::try_from(self.year()).unwrap_or(0));
666        out.push(self.month() as u8);
667        out.push(self.day());
668        Ok(())
669    }
670}
671
672#[cfg(feature = "with-time")]
673impl TypedParam for time::Time {
674    fn encode_type(out: &mut Vec<u8>) {
675        out.push(ColumnType::MYSQL_TYPE_TIME as u8);
676        out.push(0x00);
677    }
678
679    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
680        let micros = self.microsecond();
681        if micros > 0 {
682            out.push(12); // length
683            out.push(0); // is_negative
684            write_int_4(out, 0); // days
685            out.push(self.hour());
686            out.push(self.minute());
687            out.push(self.second());
688            write_int_4(out, micros);
689        } else {
690            out.push(8); // length
691            out.push(0); // is_negative
692            write_int_4(out, 0); // days
693            out.push(self.hour());
694            out.push(self.minute());
695            out.push(self.second());
696        }
697        Ok(())
698    }
699}
700
701#[cfg(feature = "with-time")]
702impl TypedParam for time::PrimitiveDateTime {
703    fn encode_type(out: &mut Vec<u8>) {
704        out.push(ColumnType::MYSQL_TYPE_DATETIME as u8);
705        out.push(0x00);
706    }
707
708    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
709        let micros = self.microsecond();
710        if micros > 0 {
711            out.push(11); // length
712            write_int_2(out, u16::try_from(self.year()).unwrap_or(0));
713            out.push(self.month() as u8);
714            out.push(self.day());
715            out.push(self.hour());
716            out.push(self.minute());
717            out.push(self.second());
718            write_int_4(out, micros);
719        } else {
720            out.push(7); // length
721            write_int_2(out, u16::try_from(self.year()).unwrap_or(0));
722            out.push(self.month() as u8);
723            out.push(self.day());
724            out.push(self.hour());
725            out.push(self.minute());
726            out.push(self.second());
727        }
728        Ok(())
729    }
730}
731
732// ============================================================================
733// rust_decimal support
734// ============================================================================
735
736#[cfg(feature = "with-rust-decimal")]
737impl TypedParam for rust_decimal::Decimal {
738    fn encode_type(out: &mut Vec<u8>) {
739        out.push(ColumnType::MYSQL_TYPE_NEWDECIMAL as u8);
740        out.push(0x00);
741    }
742
743    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
744        let s = self.to_string();
745        write_string_lenenc(out, &s);
746        Ok(())
747    }
748}
749
750#[cfg(feature = "with-rust-decimal")]
751impl TypedParam for &rust_decimal::Decimal {
752    fn encode_type(out: &mut Vec<u8>) {
753        out.push(ColumnType::MYSQL_TYPE_NEWDECIMAL as u8);
754        out.push(0x00);
755    }
756
757    fn encode_value(&self, out: &mut Vec<u8>) -> Result<()> {
758        let s = self.to_string();
759        write_string_lenenc(out, &s);
760        Ok(())
761    }
762}