1pub(super) mod date_and_time;
4#[cfg(feature = "serde_json")]
5mod json;
6mod numeric;
7mod primitives;
8
9use crate::deserialize::{self, FromSql};
10use crate::mysql::{Mysql, MysqlType, MysqlValue, NumericRepresentation};
11use crate::query_builder::QueryId;
12use crate::serialize::{self, IsNull, Output, ToSql};
13use crate::sql_types::ops::*;
14use crate::sql_types::*;
15use crate::sql_types::{self};
16use byteorder::{NativeEndian, WriteBytesExt};
17use primitives::{decimal_to_integer, f32_to_i64, f64_to_i64, narrow};
18
19#[cfg(feature = "mysql_backend")]
20impl ToSql<TinyInt, Mysql> for i8 {
21 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
22 out.write_i8(*self).map(|_| IsNull::No).map_err(Into::into)
23 }
24}
25
26#[cfg(feature = "mysql_backend")]
27impl FromSql<TinyInt, Mysql> for i8 {
28 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
29 match value.numeric_value()? {
30 NumericRepresentation::Tiny(x) => Ok(x),
31 NumericRepresentation::UnsignedTiny(x) => narrow(x),
32 NumericRepresentation::Small(x) => narrow(x),
33 NumericRepresentation::UnsignedSmall(x) => narrow(x),
34 NumericRepresentation::Medium(x) => narrow(x),
35 NumericRepresentation::UnsignedMedium(x) => narrow(x),
36 NumericRepresentation::Big(x) => narrow(x),
37 NumericRepresentation::UnsignedBig(x) => narrow(x),
38 NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
39 NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
40 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
41 }
42 }
43}
44
45#[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)]
47#[cfg(feature = "mysql_backend")]
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
82#[cfg(feature = "mysql_backend")]
83impl ToSql<Unsigned<TinyInt>, Mysql> for u8 {
84 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
85 out.write_u8(*self)?;
86 Ok(IsNull::No)
87 }
88}
89
90#[cfg(feature = "mysql_backend")]
91impl FromSql<Unsigned<TinyInt>, Mysql> for u8 {
92 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
93 match value.numeric_value()? {
94 NumericRepresentation::Tiny(x) => narrow(x),
95 NumericRepresentation::UnsignedTiny(x) => Ok(x),
96 NumericRepresentation::Small(x) => narrow(x),
97 NumericRepresentation::UnsignedSmall(x) => narrow(x),
98 NumericRepresentation::Medium(x) => narrow(x),
99 NumericRepresentation::UnsignedMedium(x) => narrow(x),
100 NumericRepresentation::Big(x) => narrow(x),
101 NumericRepresentation::UnsignedBig(x) => narrow(x),
102 NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
103 NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
104 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
105 }
106 }
107}
108
109#[cfg(feature = "mysql_backend")]
110impl ToSql<Unsigned<SmallInt>, Mysql> for u16 {
111 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
112 out.write_u16::<NativeEndian>(*self)?;
113 Ok(IsNull::No)
114 }
115}
116
117#[cfg(feature = "mysql_backend")]
118impl FromSql<Unsigned<SmallInt>, Mysql> for u16 {
119 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
120 match value.numeric_value()? {
121 NumericRepresentation::Tiny(x) => narrow(x),
122 NumericRepresentation::UnsignedTiny(x) => Ok(x.into()),
123 NumericRepresentation::Small(x) => narrow(x),
124 NumericRepresentation::UnsignedSmall(x) => Ok(x),
125 NumericRepresentation::Medium(x) => narrow(x),
126 NumericRepresentation::UnsignedMedium(x) => narrow(x),
127 NumericRepresentation::Big(x) => narrow(x),
128 NumericRepresentation::UnsignedBig(x) => narrow(x),
129 NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
130 NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
131 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
132 }
133 }
134}
135
136#[cfg(feature = "mysql_backend")]
137impl ToSql<Unsigned<Integer>, Mysql> for u32 {
138 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
139 out.write_u32::<NativeEndian>(*self)?;
140 Ok(IsNull::No)
141 }
142}
143
144#[cfg(feature = "mysql_backend")]
145impl FromSql<Unsigned<Integer>, Mysql> for u32 {
146 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
147 match value.numeric_value()? {
148 NumericRepresentation::Tiny(x) => narrow(x),
149 NumericRepresentation::UnsignedTiny(x) => Ok(x.into()),
150 NumericRepresentation::Small(x) => narrow(x),
151 NumericRepresentation::UnsignedSmall(x) => Ok(x.into()),
152 NumericRepresentation::Medium(x) => narrow(x),
153 NumericRepresentation::UnsignedMedium(x) => Ok(x),
154 NumericRepresentation::Big(x) => narrow(x),
155 NumericRepresentation::UnsignedBig(x) => narrow(x),
156 NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
157 NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
158 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
159 }
160 }
161}
162
163#[cfg(feature = "mysql_backend")]
164impl ToSql<Unsigned<BigInt>, Mysql> for u64 {
165 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
166 out.write_u64::<NativeEndian>(*self)?;
167 Ok(IsNull::No)
168 }
169}
170
171#[cfg(feature = "mysql_backend")]
172impl FromSql<Unsigned<BigInt>, Mysql> for u64 {
173 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
174 match value.numeric_value()? {
176 NumericRepresentation::Tiny(x) => narrow(x),
177 NumericRepresentation::UnsignedTiny(x) => Ok(x.into()),
178 NumericRepresentation::Small(x) => narrow(x),
179 NumericRepresentation::UnsignedSmall(x) => Ok(x.into()),
180 NumericRepresentation::Medium(x) => narrow(x),
181 NumericRepresentation::UnsignedMedium(x) => Ok(x.into()),
182 NumericRepresentation::Big(x) => narrow(x),
183 NumericRepresentation::UnsignedBig(x) => Ok(x),
184 NumericRepresentation::Float(x) => narrow(f32_to_i64(x)?),
185 NumericRepresentation::Double(x) => narrow(f64_to_i64(x)?),
186 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
187 }
188 }
189}
190
191#[cfg(feature = "mysql_backend")]
192impl ToSql<Bool, Mysql> for bool {
193 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
194 let int_value = i32::from(*self);
195 <i32 as ToSql<Integer, Mysql>>::to_sql(&int_value, &mut out.reborrow())
196 }
197}
198
199#[cfg(feature = "mysql_backend")]
200impl FromSql<Bool, Mysql> for bool {
201 fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
202 Ok(bytes.as_bytes().iter().any(|x| *x != 0))
203 }
204}
205
206#[cfg(feature = "mysql_backend")]
207impl ToSql<sql_types::SmallInt, Mysql> for i16 {
208 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
209 out.write_i16::<NativeEndian>(*self)
210 .map(|_| IsNull::No)
211 .map_err(|e| Box::new(e) as Box<_>)
212 }
213}
214
215#[cfg(feature = "mysql_backend")]
216impl ToSql<sql_types::Integer, Mysql> for i32 {
217 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
218 out.write_i32::<NativeEndian>(*self)
219 .map(|_| IsNull::No)
220 .map_err(|e| Box::new(e) as Box<_>)
221 }
222}
223
224#[cfg(feature = "mysql_backend")]
225impl ToSql<sql_types::BigInt, Mysql> for i64 {
226 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
227 out.write_i64::<NativeEndian>(*self)
228 .map(|_| IsNull::No)
229 .map_err(|e| Box::new(e) as Box<_>)
230 }
231}
232
233#[cfg(feature = "mysql_backend")]
234impl ToSql<sql_types::Double, Mysql> for f64 {
235 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
236 out.write_f64::<NativeEndian>(*self)
237 .map(|_| IsNull::No)
238 .map_err(|e| Box::new(e) as Box<_>)
239 }
240}
241
242#[cfg(feature = "mysql_backend")]
243impl ToSql<sql_types::Float, Mysql> for f32 {
244 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
245 out.write_f32::<NativeEndian>(*self)
246 .map(|_| IsNull::No)
247 .map_err(|e| Box::new(e) as Box<_>)
248 }
249}
250
251#[cfg(feature = "mysql_backend")]
252impl HasSqlType<Unsigned<TinyInt>> for Mysql {
253 fn metadata(_lookup: &mut ()) -> MysqlType {
254 MysqlType::UnsignedTiny
255 }
256}
257
258#[cfg(feature = "mysql_backend")]
259impl HasSqlType<Unsigned<SmallInt>> for Mysql {
260 fn metadata(_lookup: &mut ()) -> MysqlType {
261 MysqlType::UnsignedShort
262 }
263}
264
265#[cfg(feature = "mysql_backend")]
266impl HasSqlType<Unsigned<Integer>> for Mysql {
267 fn metadata(_lookup: &mut ()) -> MysqlType {
268 MysqlType::UnsignedLong
269 }
270}
271
272#[cfg(feature = "mysql_backend")]
273impl HasSqlType<Unsigned<BigInt>> for Mysql {
274 fn metadata(_lookup: &mut ()) -> MysqlType {
275 MysqlType::UnsignedLongLong
276 }
277}
278
279#[cfg_attr(
296 feature = "chrono",
297 doc = " [`chrono::NaiveDateTime`]: chrono::naive::NaiveDateTime"
298)]
299#[cfg_attr(
300 not(feature = "chrono"),
301 doc = " [`chrono::NaiveDateTime`]: https://docs.rs/chrono/0.4.19/chrono/naive/struct.NaiveDateTime.html"
302)]
303#[cfg_attr(
304 feature = "time",
305 doc = " [`time::PrimitiveDateTime`]: time::PrimitiveDateTime"
306)]
307#[cfg_attr(
308 not(feature = "time"),
309 doc = " [`time::PrimitiveDateTime`]: https://docs.rs/time/0.3.9/time/struct.PrimitiveDateTime.html"
310)]
311#[cfg_attr(
312 feature = "time",
313 doc = " [`time::OffsetDateTime`]: time::OffsetDateTime"
314)]
315#[cfg_attr(
316 not(feature = "time"),
317 doc = " [`time::OffsetDateTime`]: https://docs.rs/time/0.3.9/time/struct.OffsetDateTime.html"
318)]
319#[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
}
}
};SqlType)]
320#[diesel(mysql_type(name = "DateTime"))]
321pub struct Datetime;
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326
327 #[cfg(feature = "mysql")]
328 type DB = crate::mysql::Mysql;
329
330 #[diesel_test_helper::test]
331 fn empty_tiny_buffer_is_an_error() {
332 let empty = MysqlValue::new_internal(&[], MysqlType::Tiny);
333 assert!(<i8 as FromSql<TinyInt, DB>>::from_sql(empty).is_err());
334
335 let empty = MysqlValue::new_internal(&[], MysqlType::UnsignedTiny);
336 assert!(<u8 as FromSql<Unsigned<TinyInt>, DB>>::from_sql(empty).is_err());
337 }
338
339 #[diesel_test_helper::test]
340 fn tiny_buffers_keep_their_signedness() {
341 let signed = MysqlValue::new_internal(&[0xFF], MysqlType::Tiny);
342 assert_eq!(<i8 as FromSql<TinyInt, DB>>::from_sql(signed).unwrap(), -1);
343
344 let unsigned = MysqlValue::new_internal(&[200], MysqlType::UnsignedTiny);
345 assert_eq!(
346 <u8 as FromSql<Unsigned<TinyInt>, DB>>::from_sql(unsigned).unwrap(),
347 200
348 );
349 }
350
351 #[diesel_test_helper::test]
352 fn unsigned_tiny_above_i8_max_through_a_signed_sql_type() {
353 let raw = [200];
354
355 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedTiny);
357 assert!(<i8 as FromSql<TinyInt, DB>>::from_sql(v).is_err());
358
359 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedTiny);
360 assert_eq!(<i16 as FromSql<SmallInt, DB>>::from_sql(v).unwrap(), 200);
361 }
362
363 #[diesel_test_helper::test]
365 fn signed_value_through_an_unsigned_sql_type_is_an_error() {
366 let raw = [0xFF];
367 let v = MysqlValue::new_internal(&raw, MysqlType::Tiny);
368 assert!(<u8 as FromSql<Unsigned<TinyInt>, DB>>::from_sql(v).is_err());
369
370 let raw = (-1i16).to_ne_bytes();
371 let v = MysqlValue::new_internal(&raw, MysqlType::Short);
372 assert!(<u16 as FromSql<Unsigned<SmallInt>, DB>>::from_sql(v).is_err());
373
374 let raw = (-1i32).to_ne_bytes();
375 let v = MysqlValue::new_internal(&raw, MysqlType::Long);
376 assert!(<u32 as FromSql<Unsigned<Integer>, DB>>::from_sql(v).is_err());
377
378 let raw = (-1i64).to_ne_bytes();
379 let v = MysqlValue::new_internal(&raw, MysqlType::LongLong);
380 assert!(<u64 as FromSql<Unsigned<BigInt>, DB>>::from_sql(v).is_err());
381 }
382
383 #[diesel_test_helper::test]
384 fn unsigned_bigint_beyond_i64_through_a_signed_sql_type_is_an_error() {
385 let raw = u64::MAX.to_ne_bytes();
386 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
387 assert!(<i64 as FromSql<BigInt, DB>>::from_sql(v).is_err());
388
389 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
391 assert_eq!(
392 <u64 as FromSql<Unsigned<BigInt>, DB>>::from_sql(v).unwrap(),
393 u64::MAX
394 );
395 }
396
397 #[diesel_test_helper::test]
398 fn unsigned_bigint_at_i64_max_boundary() {
399 let raw = i64::MAX.to_ne_bytes();
401 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
402 assert_eq!(<i64 as FromSql<BigInt, DB>>::from_sql(v).unwrap(), i64::MAX);
403
404 let raw = (i64::MAX as u64 + 1).to_ne_bytes();
406 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
407 assert!(<i64 as FromSql<BigInt, DB>>::from_sql(v).is_err());
408 }
409
410 #[diesel_test_helper::test]
411 fn unsigned_bigint_beyond_i64_arriving_as_a_decimal() {
412 let v = MysqlValue::new_internal(b"18446744073709551615", MysqlType::Numeric);
413 assert_eq!(
414 <u64 as FromSql<Unsigned<BigInt>, DB>>::from_sql(v).unwrap(),
415 u64::MAX
416 );
417 }
418
419 #[diesel_test_helper::test]
420 fn unsigned_values_reaching_the_float_readers() {
421 let raw = 200u8.to_ne_bytes();
422 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedTiny);
423 assert_eq!(<f32 as FromSql<Float, DB>>::from_sql(v).unwrap(), 200.0);
424
425 let raw = 40000u16.to_ne_bytes();
426 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedShort);
427 assert_eq!(<f64 as FromSql<Double, DB>>::from_sql(v).unwrap(), 40000.0);
428
429 let raw = u32::MAX.to_ne_bytes();
430 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLong);
431 assert_eq!(
432 <f64 as FromSql<Double, DB>>::from_sql(v).unwrap(),
433 4_294_967_295.0
434 );
435 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLong);
436 assert_eq!(
437 <f32 as FromSql<Float, DB>>::from_sql(v).unwrap(),
438 4_294_967_296.0
439 );
440
441 let raw = u64::MAX.to_ne_bytes();
442 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
443 assert_eq!(
444 <f64 as FromSql<Double, DB>>::from_sql(v).unwrap(),
445 18_446_744_073_709_551_616.0
446 );
447 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
448 assert_eq!(
449 <f32 as FromSql<Float, DB>>::from_sql(v).unwrap(),
450 18_446_744_073_709_551_616.0
451 );
452 }
453
454 #[cfg(feature = "numeric")]
455 #[diesel_test_helper::test]
456 fn unsigned_values_reaching_the_decimal_reader() {
457 use bigdecimal::BigDecimal;
458
459 let raw = 200u8.to_ne_bytes();
460 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedTiny);
461 assert_eq!(
462 <BigDecimal as FromSql<Numeric, DB>>::from_sql(v).unwrap(),
463 BigDecimal::from(200u8)
464 );
465
466 let raw = 40000u16.to_ne_bytes();
467 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedShort);
468 assert_eq!(
469 <BigDecimal as FromSql<Numeric, DB>>::from_sql(v).unwrap(),
470 BigDecimal::from(40000u16)
471 );
472
473 let raw = u32::MAX.to_ne_bytes();
474 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLong);
475 assert_eq!(
476 <BigDecimal as FromSql<Numeric, DB>>::from_sql(v).unwrap(),
477 BigDecimal::from(u32::MAX)
478 );
479
480 let raw = u64::MAX.to_ne_bytes();
481 let v = MysqlValue::new_internal(&raw, MysqlType::UnsignedLongLong);
482 assert_eq!(
483 <BigDecimal as FromSql<Numeric, DB>>::from_sql(v).unwrap(),
484 BigDecimal::from(u64::MAX)
485 );
486 }
487}