1pub(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#[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 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#[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 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 #[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 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 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 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}