Skip to main content

diesel/mysql_like/types/
mod.rs

1//! MySQL and Mariadb shared types
2
3pub(super) mod date_and_time;
4mod enum_;
5#[cfg(feature = "serde_json")]
6mod json;
7mod numeric;
8mod primitives;
9
10use self::primitives::{decimal_to_integer, f32_to_i64, f64_to_i64, narrow};
11use crate::deserialize::{self, FromSql};
12use crate::mysql_like::MysqlLikeBackend;
13use crate::mysql_like::NumericRepresentation;
14use crate::mysql_like::{MysqlType, MysqlValue};
15use crate::query_builder::QueryId;
16use crate::serialize::{self, IsNull, Output, ToSql};
17use crate::sql_types::ops::*;
18use crate::sql_types::*;
19use crate::sql_types::{self};
20use byteorder::{NativeEndian, WriteBytesExt};
21
22impl<DB: MysqlLikeBackend> ToSql<TinyInt, DB> for i8 {
23    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
24        out.write_i8(*self).map(|_| IsNull::No).map_err(Into::into)
25    }
26}
27
28impl<DB: MysqlLikeBackend> FromSql<TinyInt, DB> for i8 {
29    fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
30        match value.numeric_value()? {
31            NumericRepresentation::Tiny(x) => Ok(x),
32            NumericRepresentation::UnsignedTiny(x) => narrow(x),
33            NumericRepresentation::Small(x) => narrow(x),
34            NumericRepresentation::UnsignedSmall(x) => narrow(x),
35            NumericRepresentation::Medium(x) => narrow(x),
36            NumericRepresentation::UnsignedMedium(x) => narrow(x),
37            NumericRepresentation::Big(x) => narrow(x),
38            NumericRepresentation::UnsignedBig(x) => narrow(x),
39            NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
40            NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
41            NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
42        }
43    }
44}
45
46/// Represents the MySQL unsigned type.
47#[derive(#[automatically_derived]
impl<ST: ::core::fmt::Debug + 'static> ::core::fmt::Debug for Unsigned<ST> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Unsigned",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl<ST: ::core::clone::Clone + 'static> ::core::clone::Clone for Unsigned<ST>
    {
    #[inline]
    fn clone(&self) -> Unsigned<ST> {
        Unsigned(::core::clone::Clone::clone(&self.0))
    }
}Clone, #[automatically_derived]
impl<ST: ::core::marker::Copy + 'static> ::core::marker::Copy for Unsigned<ST>
    {
}Copy, #[automatically_derived]
impl<ST: ::core::default::Default + 'static> ::core::default::Default for
    Unsigned<ST> {
    #[inline]
    fn default() -> Unsigned<ST> {
        Unsigned(::core::default::Default::default())
    }
}Default, const _: () =
    {
        use diesel;
        impl<ST: 'static> diesel::sql_types::SqlType for Unsigned<ST> {
            type IsNull = diesel::sql_types::is_nullable::NotNull;
            const IS_ARRAY: bool = false;
        }
        impl<ST: 'static> diesel::sql_types::SingleValue for Unsigned<ST> {}
    };SqlType, const _: () =
    {
        use diesel;
        #[allow(non_camel_case_types)]
        impl<ST: 'static + diesel::query_builder::QueryId>
            diesel::query_builder::QueryId for Unsigned<ST> {
            type QueryId =
                Unsigned<<ST as diesel::query_builder::QueryId>::QueryId>;
            const HAS_STATIC_QUERY_ID: bool =
                <ST as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID &&
                    true;
            const IS_WINDOW_FUNCTION: bool =
                <ST as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION ||
                    false;
        }
    };QueryId)]
48pub struct Unsigned<ST: 'static>(ST);
49
50impl<T> Add for Unsigned<T>
51where
52    T: Add,
53{
54    type Rhs = Unsigned<T::Rhs>;
55    type Output = Unsigned<T::Output>;
56}
57
58impl<T> Sub for Unsigned<T>
59where
60    T: Sub,
61{
62    type Rhs = Unsigned<T::Rhs>;
63    type Output = Unsigned<T::Output>;
64}
65
66impl<T> Mul for Unsigned<T>
67where
68    T: Mul,
69{
70    type Rhs = Unsigned<T::Rhs>;
71    type Output = Unsigned<T::Output>;
72}
73
74impl<T> Div for Unsigned<T>
75where
76    T: Div,
77{
78    type Rhs = Unsigned<T::Rhs>;
79    type Output = Unsigned<T::Output>;
80}
81
82impl<DB: MysqlLikeBackend> ToSql<Unsigned<TinyInt>, DB> for u8 {
83    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
84        out.write_u8(*self)?;
85        Ok(IsNull::No)
86    }
87}
88
89impl<DB: MysqlLikeBackend> FromSql<Unsigned<TinyInt>, DB> for u8 {
90    fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
91        match value.numeric_value()? {
92            NumericRepresentation::Tiny(x) => narrow(x),
93            NumericRepresentation::UnsignedTiny(x) => Ok(x),
94            NumericRepresentation::Small(x) => narrow(x),
95            NumericRepresentation::UnsignedSmall(x) => narrow(x),
96            NumericRepresentation::Medium(x) => narrow(x),
97            NumericRepresentation::UnsignedMedium(x) => narrow(x),
98            NumericRepresentation::Big(x) => narrow(x),
99            NumericRepresentation::UnsignedBig(x) => narrow(x),
100            NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
101            NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
102            NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
103        }
104    }
105}
106
107impl<DB: MysqlLikeBackend> ToSql<Unsigned<SmallInt>, DB> for u16 {
108    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
109        out.write_u16::<NativeEndian>(*self)?;
110        Ok(IsNull::No)
111    }
112}
113
114impl<DB: MysqlLikeBackend> FromSql<Unsigned<SmallInt>, DB> for u16 {
115    fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
116        match value.numeric_value()? {
117            NumericRepresentation::Tiny(x) => narrow(x),
118            NumericRepresentation::UnsignedTiny(x) => Ok(x.into()),
119            NumericRepresentation::Small(x) => narrow(x),
120            NumericRepresentation::UnsignedSmall(x) => Ok(x),
121            NumericRepresentation::Medium(x) => narrow(x),
122            NumericRepresentation::UnsignedMedium(x) => narrow(x),
123            NumericRepresentation::Big(x) => narrow(x),
124            NumericRepresentation::UnsignedBig(x) => narrow(x),
125            NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
126            NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
127            NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
128        }
129    }
130}
131
132impl<DB: MysqlLikeBackend> ToSql<Unsigned<Integer>, DB> for u32 {
133    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
134        out.write_u32::<NativeEndian>(*self)?;
135        Ok(IsNull::No)
136    }
137}
138
139impl<DB: MysqlLikeBackend> FromSql<Unsigned<Integer>, DB> for u32 {
140    fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
141        match value.numeric_value()? {
142            NumericRepresentation::Tiny(x) => narrow(x),
143            NumericRepresentation::UnsignedTiny(x) => Ok(x.into()),
144            NumericRepresentation::Small(x) => narrow(x),
145            NumericRepresentation::UnsignedSmall(x) => Ok(x.into()),
146            NumericRepresentation::Medium(x) => narrow(x),
147            NumericRepresentation::UnsignedMedium(x) => Ok(x),
148            NumericRepresentation::Big(x) => narrow(x),
149            NumericRepresentation::UnsignedBig(x) => narrow(x),
150            NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
151            NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
152            NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
153        }
154    }
155}
156
157impl<DB: MysqlLikeBackend> ToSql<Unsigned<BigInt>, DB> for u64 {
158    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
159        out.write_u64::<NativeEndian>(*self)?;
160        Ok(IsNull::No)
161    }
162}
163
164impl<DB: MysqlLikeBackend> FromSql<Unsigned<BigInt>, DB> for u64 {
165    fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
166        // No signed type covers the whole unsigned range, unlike the narrower widths.
167        match value.numeric_value()? {
168            NumericRepresentation::Tiny(x) => narrow(x),
169            NumericRepresentation::UnsignedTiny(x) => Ok(x.into()),
170            NumericRepresentation::Small(x) => narrow(x),
171            NumericRepresentation::UnsignedSmall(x) => Ok(x.into()),
172            NumericRepresentation::Medium(x) => narrow(x),
173            NumericRepresentation::UnsignedMedium(x) => Ok(x.into()),
174            NumericRepresentation::Big(x) => narrow(x),
175            NumericRepresentation::UnsignedBig(x) => Ok(x),
176            NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
177            NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
178            NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
179        }
180    }
181}
182
183impl<DB: MysqlLikeBackend> ToSql<Bool, DB> for bool {
184    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
185        let int_value = i32::from(*self);
186        <i32 as ToSql<Integer, DB>>::to_sql(&int_value, &mut out.reborrow())
187    }
188}
189
190impl<DB: MysqlLikeBackend> FromSql<Bool, DB> for bool {
191    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
192        Ok(bytes.as_bytes().iter().any(|x| *x != 0))
193    }
194}
195
196impl<DB: MysqlLikeBackend> ToSql<sql_types::SmallInt, DB> for i16 {
197    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
198        out.write_i16::<NativeEndian>(*self)
199            .map(|_| IsNull::No)
200            .map_err(|e| Box::new(e) as Box<_>)
201    }
202}
203
204impl<DB: MysqlLikeBackend> ToSql<sql_types::Integer, DB> for i32 {
205    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
206        out.write_i32::<NativeEndian>(*self)
207            .map(|_| IsNull::No)
208            .map_err(|e| Box::new(e) as Box<_>)
209    }
210}
211
212impl<DB: MysqlLikeBackend> ToSql<sql_types::BigInt, DB> for i64 {
213    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
214        out.write_i64::<NativeEndian>(*self)
215            .map(|_| IsNull::No)
216            .map_err(|e| Box::new(e) as Box<_>)
217    }
218}
219
220impl<DB: MysqlLikeBackend> ToSql<sql_types::Double, DB> for f64 {
221    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
222        out.write_f64::<NativeEndian>(*self)
223            .map(|_| IsNull::No)
224            .map_err(|e| Box::new(e) as Box<_>)
225    }
226}
227
228impl<DB: MysqlLikeBackend> ToSql<sql_types::Float, DB> for f32 {
229    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
230        out.write_f32::<NativeEndian>(*self)
231            .map(|_| IsNull::No)
232            .map_err(|e| Box::new(e) as Box<_>)
233    }
234}
235
236impl<DB: MysqlLikeBackend> HasSqlType<Unsigned<TinyInt>> for DB {
237    fn metadata(_lookup: &mut ()) -> MysqlType {
238        MysqlType::UnsignedTiny
239    }
240}
241
242impl<DB: MysqlLikeBackend> HasSqlType<Unsigned<SmallInt>> for DB {
243    fn metadata(_lookup: &mut ()) -> MysqlType {
244        MysqlType::UnsignedShort
245    }
246}
247
248impl<DB: MysqlLikeBackend> HasSqlType<Unsigned<Integer>> for DB {
249    fn metadata(_lookup: &mut ()) -> MysqlType {
250        MysqlType::UnsignedLong
251    }
252}
253
254impl<DB: MysqlLikeBackend> HasSqlType<Unsigned<BigInt>> for DB {
255    fn metadata(_lookup: &mut ()) -> MysqlType {
256        MysqlType::UnsignedLongLong
257    }
258}
259
260/// Represents the MySQL datetime type.
261///
262/// ### [`ToSql`] impls
263///
264/// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
265/// - [`time::PrimitiveDateTime`] with `feature = "time"`
266/// - [`time::OffsetDateTime`] with `feature = "time"`
267///
268/// ### [`FromSql`] impls
269///
270/// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
271/// - [`time::PrimitiveDateTime`] with `feature = "time"`
272/// - [`time::OffsetDateTime`] with `feature = "time"`
273///
274/// [`ToSql`]: crate::serialize::ToSql
275/// [`FromSql`]: crate::deserialize::FromSql
276#[cfg_attr(
277    feature = "chrono",
278    doc = " [`chrono::NaiveDateTime`]: chrono::naive::NaiveDateTime"
279)]
280#[cfg_attr(
281    not(feature = "chrono"),
282    doc = " [`chrono::NaiveDateTime`]: https://docs.rs/chrono/0.4.19/chrono/naive/struct.NaiveDateTime.html"
283)]
284#[cfg_attr(
285    feature = "time",
286    doc = " [`time::PrimitiveDateTime`]: time::PrimitiveDateTime"
287)]
288#[cfg_attr(
289    not(feature = "time"),
290    doc = " [`time::PrimitiveDateTime`]: https://docs.rs/time/0.3.9/time/struct.PrimitiveDateTime.html"
291)]
292#[cfg_attr(
293    feature = "time",
294    doc = " [`time::OffsetDateTime`]: time::OffsetDateTime"
295)]
296#[cfg_attr(
297    not(feature = "time"),
298    doc = " [`time::OffsetDateTime`]: https://docs.rs/time/0.3.9/time/struct.OffsetDateTime.html"
299)]
300#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Datetime {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Datetime")
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Datetime { }
#[automatically_derived]
impl ::core::clone::Clone for Datetime {
    #[inline]
    fn clone(&self) -> Datetime { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Datetime { }Copy, #[automatically_derived]
impl ::core::default::Default for Datetime {
    #[inline]
    fn default() -> Datetime { Datetime {} }
}Default, const _: () =
    {
        use diesel;
        #[allow(non_camel_case_types)]
        impl diesel::query_builder::QueryId for Datetime {
            type QueryId = Datetime<>;
            const HAS_STATIC_QUERY_ID: bool = true;
            const IS_WINDOW_FUNCTION: bool = false;
        }
    };QueryId, const _: () =
    {
        use diesel;
        impl diesel::sql_types::SqlType for Datetime {
            type IsNull = diesel::sql_types::is_nullable::NotNull;
            const IS_ARRAY: bool = false;
        }
        impl diesel::sql_types::SingleValue for Datetime {}
        impl diesel::sql_types::HasSqlType<Datetime> for diesel::mysql::Mysql
            {
            fn metadata(_: &mut ()) -> diesel::mysql::MysqlType {
                diesel::mysql::MysqlType::DateTime
            }
        }
        impl diesel::sql_types::HasSqlType<Datetime> for
            diesel::mariadb::Mariadb {
            fn metadata(_: &mut ()) -> diesel::mariadb::MariadbType {
                diesel::mariadb::MariadbType::DateTime
            }
        }
    };SqlType)]
301#[diesel(mysql_type(name = "DateTime"))]
302#[diesel(mariadb_type(name = "DateTime"))]
303pub struct Datetime;
304
305#[cfg(all(test, any(feature = "mysql", feature = "mariadb")))]
306mod tests {
307    use super::*;
308
309    #[cfg(feature = "mysql")]
310    type DB = crate::mysql::Mysql;
311    #[cfg(feature = "mariadb")]
312    type DB = crate::mariadb::Mariadb;
313
314    #[diesel_test_helper::test]
315    fn empty_tiny_buffer_is_an_error() {
316        let empty = MysqlValue::new_internal(&[], MysqlType::Tiny);
317        assert!(<i8 as FromSql<TinyInt, DB>>::from_sql(empty).is_err());
318
319        let empty = MysqlValue::new_internal(&[], MysqlType::UnsignedTiny);
320        assert!(<u8 as FromSql<Unsigned<TinyInt>, DB>>::from_sql(empty).is_err());
321    }
322
323    #[diesel_test_helper::test]
324    fn tiny_buffers_keep_their_signedness() {
325        let signed = MysqlValue::new_internal(&[0xFF], MysqlType::Tiny);
326        assert_eq!(<i8 as FromSql<TinyInt, DB>>::from_sql(signed).unwrap(), -1);
327
328        let unsigned = MysqlValue::new_internal(&[200], MysqlType::UnsignedTiny);
329        assert_eq!(
330            <u8 as FromSql<Unsigned<TinyInt>, DB>>::from_sql(unsigned).unwrap(),
331            200
332        );
333    }
334
335    #[diesel_test_helper::test]
336    fn unsigned_tiny_above_i8_max_through_a_signed_sql_type() {
337        let raw = [200];
338
339        // Used to reinterpret the byte as -56.
340        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedTiny);
341        assert!(<i8 as FromSql<TinyInt, DB>>::from_sql(v).is_err());
342
343        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedTiny);
344        assert_eq!(<i16 as FromSql<SmallInt, DB>>::from_sql(v).unwrap(), 200);
345    }
346
347    // Both used to return those bits reinterpreted under the wrong sign.
348    #[diesel_test_helper::test]
349    fn signed_value_through_an_unsigned_sql_type_is_an_error() {
350        let raw = [0xFF];
351        let v = MysqlValue::new_internal(&raw, MysqlType::Tiny);
352        assert!(<u8 as FromSql<Unsigned<TinyInt>, DB>>::from_sql(v).is_err());
353
354        let raw = (-1i16).to_ne_bytes();
355        let v = MysqlValue::new_internal(&raw, MysqlType::Short);
356        assert!(<u16 as FromSql<Unsigned<SmallInt>, DB>>::from_sql(v).is_err());
357
358        let raw = (-1i32).to_ne_bytes();
359        let v = MysqlValue::new_internal(&raw, MysqlType::Long);
360        assert!(<u32 as FromSql<Unsigned<Integer>, DB>>::from_sql(v).is_err());
361
362        let raw = (-1i64).to_ne_bytes();
363        let v = MysqlValue::new_internal(&raw, MysqlType::LongLong);
364        assert!(<u64 as FromSql<Unsigned<BigInt>, DB>>::from_sql(v).is_err());
365    }
366
367    #[diesel_test_helper::test]
368    fn unsigned_bigint_beyond_i64_through_a_signed_sql_type_is_an_error() {
369        let raw = u64::MAX.to_ne_bytes();
370        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
371        assert!(<i64 as FromSql<BigInt, DB>>::from_sql(v).is_err());
372
373        // The same buffer read as what it actually is still decodes.
374        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
375        assert_eq!(
376            <u64 as FromSql<Unsigned<BigInt>, DB>>::from_sql(v).unwrap(),
377            u64::MAX
378        );
379    }
380
381    #[diesel_test_helper::test]
382    fn unsigned_bigint_at_i64_max_boundary() {
383        // i64::MAX (9223372036854775807) fits in i64 and must succeed.
384        let raw = i64::MAX.to_ne_bytes();
385        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
386        assert_eq!(<i64 as FromSql<BigInt, DB>>::from_sql(v).unwrap(), i64::MAX);
387
388        // i64::MAX + 1 (9223372036854775808) does not fit in i64 and must fail.
389        let raw = (i64::MAX as u64 + 1).to_ne_bytes();
390        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
391        assert!(<i64 as FromSql<BigInt, DB>>::from_sql(v).is_err());
392    }
393
394    #[diesel_test_helper::test]
395    fn unsigned_bigint_beyond_i64_arriving_as_a_decimal() {
396        let v = MysqlValue::new_internal(b"18446744073709551615", MysqlType::Numeric);
397        assert_eq!(
398            <u64 as FromSql<Unsigned<BigInt>, DB>>::from_sql(v).unwrap(),
399            u64::MAX
400        );
401    }
402
403    #[diesel_test_helper::test]
404    fn unsigned_values_reaching_the_float_readers() {
405        let raw = 200u8.to_ne_bytes();
406        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedTiny);
407        assert_eq!(<f32 as FromSql<Float, DB>>::from_sql(v).unwrap(), 200.0);
408
409        let raw = 40000u16.to_ne_bytes();
410        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedShort);
411        assert_eq!(<f64 as FromSql<Double, DB>>::from_sql(v).unwrap(), 40000.0);
412
413        let raw = u32::MAX.to_ne_bytes();
414        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLong);
415        assert_eq!(
416            <f64 as FromSql<Double, DB>>::from_sql(v).unwrap(),
417            4_294_967_295.0
418        );
419        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLong);
420        assert_eq!(
421            <f32 as FromSql<Float, DB>>::from_sql(v).unwrap(),
422            4_294_967_296.0
423        );
424
425        let raw = u64::MAX.to_ne_bytes();
426        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
427        assert_eq!(
428            <f64 as FromSql<Double, DB>>::from_sql(v).unwrap(),
429            18_446_744_073_709_551_616.0
430        );
431        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
432        assert_eq!(
433            <f32 as FromSql<Float, DB>>::from_sql(v).unwrap(),
434            18_446_744_073_709_551_616.0
435        );
436    }
437
438    #[cfg(feature = "numeric")]
439    #[diesel_test_helper::test]
440    fn unsigned_values_reaching_the_decimal_reader() {
441        use bigdecimal::BigDecimal;
442
443        let raw = 200u8.to_ne_bytes();
444        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedTiny);
445        assert_eq!(
446            <BigDecimal as FromSql<Numeric, DB>>::from_sql(v).unwrap(),
447            BigDecimal::from(200u8)
448        );
449
450        let raw = 40000u16.to_ne_bytes();
451        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedShort);
452        assert_eq!(
453            <BigDecimal as FromSql<Numeric, DB>>::from_sql(v).unwrap(),
454            BigDecimal::from(40000u16)
455        );
456
457        let raw = u32::MAX.to_ne_bytes();
458        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLong);
459        assert_eq!(
460            <BigDecimal as FromSql<Numeric, DB>>::from_sql(v).unwrap(),
461            BigDecimal::from(u32::MAX)
462        );
463
464        let raw = u64::MAX.to_ne_bytes();
465        let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
466        assert_eq!(
467            <BigDecimal as FromSql<Numeric, DB>>::from_sql(v).unwrap(),
468            BigDecimal::from(u64::MAX)
469        );
470    }
471}