1use std::{error::Error, fmt};
2
3use cast;
4
5use super::{Decimal, TimeUnit, Value, ValueRef};
6
7#[derive(Debug)]
9#[non_exhaustive]
10pub enum FromSqlError {
11 InvalidType,
14
15 OutOfRange(i128),
18
19 OutOfRangeUnsigned(u128),
23
24 #[cfg(feature = "uuid")]
27 InvalidUuidSize(usize),
28
29 Other(Box<dyn Error + Send + Sync + 'static>),
31}
32
33impl PartialEq for FromSqlError {
34 fn eq(&self, other: &Self) -> bool {
35 match (self, other) {
36 (Self::InvalidType, Self::InvalidType) => true,
37 (Self::OutOfRange(n1), Self::OutOfRange(n2)) => n1 == n2,
38 (Self::OutOfRangeUnsigned(n1), Self::OutOfRangeUnsigned(n2)) => n1 == n2,
39 #[cfg(feature = "uuid")]
40 (Self::InvalidUuidSize(s1), Self::InvalidUuidSize(s2)) => s1 == s2,
41 (..) => false,
42 }
43 }
44}
45
46impl fmt::Display for FromSqlError {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match *self {
49 Self::InvalidType => write!(f, "Invalid type"),
50 Self::OutOfRange(i) => write!(f, "Value {i} out of range"),
51 Self::OutOfRangeUnsigned(i) => write!(f, "Unsigned value {i} out of range"),
52 #[cfg(feature = "uuid")]
53 Self::InvalidUuidSize(s) => {
54 write!(f, "Cannot read UUID value out of {s} byte blob")
55 }
56 Self::Other(ref err) => err.fmt(f),
57 }
58 }
59}
60
61impl Error for FromSqlError {
62 fn source(&self) -> Option<&(dyn Error + 'static)> {
63 if let Self::Other(err) = self {
64 Some(&**err)
65 } else {
66 None
67 }
68 }
69}
70
71pub type FromSqlResult<T> = Result<T, FromSqlError>;
73
74pub trait FromSql: Sized {
76 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
78}
79
80fn rounded_decimal(value: i128, scale: u8) -> Option<i128> {
81 let divisor = 10_i128.checked_pow(u32::from(scale))?;
82 let quotient = value / divisor;
83 let remainder = value % divisor;
84
85 if remainder.unsigned_abs() * 2 < divisor as u128 {
88 return Some(quotient);
89 }
90
91 if value.is_negative() {
92 quotient.checked_sub(1)
93 } else {
94 quotient.checked_add(1)
95 }
96}
97
98fn rounded_decimal_result(value: i128, scale: u8) -> FromSqlResult<i128> {
99 rounded_decimal(value, scale).ok_or(FromSqlError::OutOfRange(value))
100}
101
102fn decimal_to_f32(decimal: Decimal) -> f32 {
103 decimal.value() as f32 / 10_f32.powi(i32::from(decimal.scale()))
105}
106
107fn decimal_to_f64(decimal: Decimal) -> f64 {
108 decimal.value() as f64 / 10_f64.powi(i32::from(decimal.scale()))
110}
111
112macro_rules! from_sql_numeric(
113 ($t:ident, $decimal:expr) => (
114 impl FromSql for $t {
115 #[inline]
116 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
117 match value {
118 ValueRef::TinyInt(i) => <$t as cast::From<i8>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
119 ValueRef::SmallInt(i) => <$t as cast::From<i16>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
120 ValueRef::Int(i) => <$t as cast::From<i32>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
121 ValueRef::BigInt(i) => <$t as cast::From<i64>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
122 ValueRef::HugeInt(i) => <$t as cast::From<i128>>::cast(i).into_result(FromSqlError::OutOfRange(i)),
123 ValueRef::UHugeInt(i) => <$t as cast::From<u128>>::cast(i)
124 .into_result(FromSqlError::OutOfRangeUnsigned(i)),
125
126 ValueRef::UTinyInt(i) => <$t as cast::From<u8>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
127 ValueRef::USmallInt(i) => <$t as cast::From<u16>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
128 ValueRef::UInt(i) => <$t as cast::From<u32>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
129 ValueRef::UBigInt(i) => <$t as cast::From<u64>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
130
131 ValueRef::Float(i) => <$t as cast::From<f32>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
132 ValueRef::Double(i) => <$t as cast::From<f64>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
133
134 ValueRef::Decimal(decimal) => ($decimal)(decimal),
135
136 ValueRef::Timestamp(_, i) => <$t as cast::From<i64>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
137 ValueRef::Date32(i) => <$t as cast::From<i32>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
138 ValueRef::Time64(TimeUnit::Microsecond, i) => <$t as cast::From<i64>>::cast(i).into_result(FromSqlError::OutOfRange(i as i128)),
139 ValueRef::Text(_) => {
140 let s = value.as_str()?;
141 s.parse::<$t>().or_else(|_| {
142 s.parse::<i128>()
143 .map_err(|_| FromSqlError::InvalidType)
144 .and_then(|i| Err(FromSqlError::OutOfRange(i)))
145 })
146 }
147 _ => Err(FromSqlError::InvalidType),
148 }
149 }
150 }
151 )
152);
153
154macro_rules! from_sql_integral(
155 ($t:ident) => (
156 from_sql_numeric!($t, |decimal: Decimal| {
157 let rounded = rounded_decimal_result(decimal.value(), decimal.scale())?;
158 <$t as cast::From<i128>>::cast(rounded)
159 .into_result(FromSqlError::OutOfRange(rounded))
160 });
161 )
162);
163
164macro_rules! from_sql_float(
165 ($t:ident, $decimal_to_float:ident) => (
166 from_sql_numeric!($t, |decimal: Decimal| Ok($decimal_to_float(decimal)));
167 )
168);
169
170trait IntoResult {
173 type Value;
174 fn into_result<E>(self, err: E) -> Result<Self::Value, E>;
175}
176
177macro_rules! into_result_integral(
179 ($type_name:ident) => (
180 impl IntoResult for $type_name {
181 type Value = $type_name;
182
183 #[inline]
184 fn into_result<E>(self, _err: E) -> Result<Self::Value, E> {
185 Ok(self)
186 }
187 }
188 )
189);
190
191into_result_integral!(i8);
192into_result_integral!(i16);
193into_result_integral!(i32);
194into_result_integral!(i64);
195into_result_integral!(i128);
196into_result_integral!(isize);
197into_result_integral!(u8);
198into_result_integral!(u16);
199into_result_integral!(u32);
200into_result_integral!(u64);
201into_result_integral!(u128);
202into_result_integral!(usize);
203into_result_integral!(f32);
204into_result_integral!(f64);
205
206impl<T, E> IntoResult for Result<T, E> {
207 type Value = T;
208
209 #[inline]
210 fn into_result<E2>(self, err: E2) -> Result<Self::Value, E2> {
211 self.map_err(|_| err)
212 }
213}
214
215from_sql_integral!(i8);
216from_sql_integral!(i16);
217from_sql_integral!(i32);
218from_sql_integral!(i64);
219from_sql_integral!(i128);
220from_sql_integral!(isize);
221from_sql_integral!(u8);
222from_sql_integral!(u16);
223from_sql_integral!(u32);
224from_sql_integral!(u64);
225from_sql_integral!(u128);
226from_sql_integral!(usize);
227from_sql_float!(f32, decimal_to_f32);
228from_sql_float!(f64, decimal_to_f64);
229
230impl FromSql for bool {
231 #[inline]
232 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
233 match value {
234 ValueRef::Boolean(b) => Ok(b),
235 _ => i8::column_result(value).map(|i| i != 0),
236 }
237 }
238}
239
240impl FromSql for String {
241 #[inline]
242 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
243 match value {
244 #[cfg(feature = "chrono")]
245 ValueRef::Date32(_) => Ok(chrono::NaiveDate::column_result(value)?.format("%F").to_string()),
246 #[cfg(feature = "chrono")]
247 ValueRef::Time64(..) => Ok(chrono::NaiveTime::column_result(value)?.format("%T%.f").to_string()),
248 #[cfg(feature = "chrono")]
249 ValueRef::Timestamp(..) => Ok(chrono::NaiveDateTime::column_result(value)?
250 .format("%F %T%.f")
251 .to_string()),
252 _ => value.as_str().map(ToString::to_string),
253 }
254 }
255}
256
257impl FromSql for Box<str> {
258 #[inline]
259 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
260 value.as_str().map(Into::into)
261 }
262}
263
264impl FromSql for std::rc::Rc<str> {
265 #[inline]
266 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
267 value.as_str().map(Into::into)
268 }
269}
270
271impl FromSql for std::sync::Arc<str> {
272 #[inline]
273 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
274 value.as_str().map(Into::into)
275 }
276}
277
278impl FromSql for Vec<u8> {
279 #[inline]
280 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
281 value.as_blob().map(|b| b.to_vec())
282 }
283}
284
285#[cfg(feature = "uuid")]
286impl FromSql for uuid::Uuid {
287 #[inline]
288 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
289 match value {
290 ValueRef::Text(..) => value
291 .as_str()
292 .and_then(|s| Self::parse_str(s).map_err(|_| FromSqlError::InvalidUuidSize(s.len()))),
293 ValueRef::Blob(..) => value
294 .as_blob()
295 .and_then(|bytes| {
296 uuid::Builder::from_slice(bytes).map_err(|_| FromSqlError::InvalidUuidSize(bytes.len()))
297 })
298 .map(|builder| builder.into_uuid()),
299 _ => Err(FromSqlError::InvalidType),
300 }
301 }
302}
303
304impl<T: FromSql> FromSql for Option<T> {
305 #[inline]
306 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
307 match value {
308 ValueRef::Null => Ok(None),
309 _ => FromSql::column_result(value).map(Some),
310 }
311 }
312}
313
314impl FromSql for Value {
315 #[inline]
316 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
317 Ok(value.into())
318 }
319}
320
321#[cfg(test)]
322mod test {
323 use super::{FromSql, FromSqlError};
324 use crate::{Connection, Error, Result};
325
326 #[test]
327 fn test_timestamp_raw() -> Result<()> {
328 let db = Connection::open_in_memory()?;
329 let sql = "BEGIN;
330 CREATE TABLE ts (sec TIMESTAMP_S, milli TIMESTAMP_MS, micro TIMESTAMP_US, nano TIMESTAMP_NS );
331 INSERT INTO ts VALUES (NULL,NULL,NULL,NULL );
332 INSERT INTO ts VALUES ('2008-01-01 00:00:01','2008-01-01 00:00:01.594','2008-01-01 00:00:01.88926','2008-01-01 00:00:01.889268000' );
333 -- INSERT INTO ts VALUES (NULL,NULL,NULL,1199145601889268321 );
334 END;";
335 db.execute_batch(sql)?;
336 let v = db.query_row(
337 "SELECT sec, milli, micro, nano FROM ts WHERE sec is not null",
338 [],
339 |row| <(i64, i64, i64, i64)>::try_from(row),
340 )?;
341 assert_eq!(v, (1199145601, 1199145601594, 1199145601889260, 1199145601889268000));
342 Ok(())
343 }
344
345 #[test]
346 fn test_time64_raw() -> Result<()> {
347 let db = Connection::open_in_memory()?;
348 let sql = "BEGIN;
349 CREATE TABLE time64 (t time);
350 INSERT INTO time64 VALUES ('20:08:10.998');
351 END;";
352 db.execute_batch(sql)?;
353 let v = db.query_row("SELECT * FROM time64", [], |row| <(i64,)>::try_from(row))?;
354 assert_eq!(v, (72490998000,));
355 Ok(())
356 }
357
358 #[test]
359 fn test_date32_raw() -> Result<()> {
360 let db = Connection::open_in_memory()?;
361 let sql = "BEGIN;
362 CREATE TABLE date32 (d date);
363 INSERT INTO date32 VALUES ('2008-01-01');
364 END;";
365 db.execute_batch(sql)?;
366 let v = db.query_row("SELECT * FROM date32", [], |row| <(i32,)>::try_from(row))?;
367 assert_eq!(v, (13879,));
368 Ok(())
369 }
370
371 #[test]
372 fn test_unsigned_integer() -> Result<()> {
373 let db = Connection::open_in_memory()?;
374 let sql = "BEGIN;
375 CREATE TABLE unsigned_int (u1 utinyint, u2 usmallint, u4 uinteger, u8 ubigint);
376 INSERT INTO unsigned_int VALUES (255, 65535, 4294967295, 18446744073709551615);
377 END;";
378 db.execute_batch(sql)?;
379 let v = db.query_row("SELECT * FROM unsigned_int", [], |row| {
380 <(u8, u16, u32, u64)>::try_from(row)
381 })?;
382 assert_eq!(v, (255, 65535, 4294967295, 18446744073709551615));
383 Ok(())
384 }
385
386 #[test]
388 fn test_hugeint_max_min() -> Result<()> {
389 let db = Connection::open_in_memory()?;
390 db.execute("CREATE TABLE huge_int (u1 hugeint, u2 hugeint);", [])?;
391 let i128max: i128 = i128::MAX;
393 let i128min: i128 = i128::MIN + 1;
394 db.execute("INSERT INTO huge_int VALUES (?, ?);", [&i128max, &i128min])?;
395 let v = db.query_row("SELECT * FROM huge_int", [], |row| <(i128, i128)>::try_from(row))?;
396 assert_eq!(v, (i128max, i128min));
397 Ok(())
398 }
399
400 #[test]
401 fn test_integral_ranges() -> Result<()> {
402 let db = Connection::open_in_memory()?;
403
404 fn check_ranges<T>(db: &Connection, out_of_range: &[i128], in_range: &[i128])
405 where
406 T: Into<i128> + FromSql + ::std::fmt::Debug,
407 {
408 for n in out_of_range {
409 let err = db.query_row("SELECT ?", [n], |r| r.get::<_, T>(0)).unwrap_err();
410 match err {
411 Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
412 _ => panic!("unexpected error: {err}"),
413 }
414 }
415 for n in in_range {
416 assert_eq!(*n, db.query_row("SELECT ?", [n], |r| r.get::<_, T>(0)).unwrap().into());
417 }
418 }
419
420 check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]);
421 check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]);
422 check_ranges::<i32>(
423 &db,
424 &[-2_147_483_649, 2_147_483_648],
425 &[-2_147_483_648, -1, 0, 1, 2_147_483_647],
426 );
427 check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
428 check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
429 check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
430
431 let err = db
432 .query_row("SELECT (-1)::HUGEINT", [], |r| r.get::<_, u128>(0))
433 .unwrap_err();
434 match err {
435 Error::IntegralValueOutOfRange(_, value) => assert_eq!(value, -1),
436 _ => panic!("unexpected error: {err}"),
437 }
438
439 let ubigint_max = u128::from(u64::MAX);
440 let value = db.query_row("SELECT (18446744073709551615)::UBIGINT", [], |r| r.get::<_, u128>(0))?;
441 assert_eq!(value, ubigint_max);
442
443 let u64_overflow = ubigint_max + 1;
444 let err = db
445 .query_row("SELECT (18446744073709551616)::UHUGEINT", [], |r| r.get::<_, u64>(0))
446 .unwrap_err();
447 match err {
448 Error::UnsignedIntegralValueOutOfRange(_, value) => assert_eq!(value, u64_overflow),
449 _ => panic!("unexpected error: {err}"),
450 }
451
452 assert_eq!(
453 FromSqlError::OutOfRangeUnsigned(u64_overflow).to_string(),
454 "Unsigned value 18446744073709551616 out of range"
455 );
456 Ok(())
457 }
458
459 #[test]
461 fn test_uuid_string() -> Result<()> {
462 let db = Connection::open_in_memory()?;
463 let sql = "BEGIN;
464 CREATE TABLE uuid (u uuid);
465 INSERT INTO uuid VALUES ('10203040-5060-7080-0102-030405060708'),(NULL),('47183823-2574-4bfd-b411-99ed177d3e43');
466 END;";
467 db.execute_batch(sql)?;
468 let v = db.query_row("SELECT u FROM uuid order by u desc nulls last limit 1", [], |row| {
469 <(String,)>::try_from(row)
470 })?;
471 assert_eq!(v, ("47183823-2574-4bfd-b411-99ed177d3e43".to_string(),));
472 let v = db.query_row(
473 "SELECT u FROM uuid where u>?::UUID",
474 ["10203040-5060-7080-0102-030405060708"],
475 |row| <(String,)>::try_from(row),
476 )?;
477 assert_eq!(v, ("47183823-2574-4bfd-b411-99ed177d3e43".to_string(),));
478 Ok(())
479 }
480
481 #[cfg(feature = "uuid")]
482 #[test]
483 fn test_uuid_from_string() -> crate::Result<()> {
484 let db = Connection::open_in_memory()?;
485 let sql = "BEGIN;
486 CREATE TABLE uuid (u uuid);
487 INSERT INTO uuid VALUES ('10203040-5060-7080-0102-030405060708'),(NULL),('47183823-2574-4bfd-b411-99ed177d3e43');
488 END;";
489 db.execute_batch(sql)?;
490 let v = db.query_row("SELECT u FROM uuid order by u desc nulls last limit 1", [], |row| {
491 <(uuid::Uuid,)>::try_from(row)
492 })?;
493 assert_eq!(v.0.to_string(), "47183823-2574-4bfd-b411-99ed177d3e43");
494 Ok(())
495 }
496
497 #[test]
498 fn test_decimal_to_integer() -> Result<()> {
499 let db = Connection::open_in_memory()?;
500
501 assert_eq!(
502 db.query_row("SELECT 0.1::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
503 0
504 );
505 assert_eq!(
506 db.query_row("SELECT 0.4::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
507 0
508 );
509 assert_eq!(
510 db.query_row("SELECT 0.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
511 1
512 );
513 assert_eq!(
514 db.query_row("SELECT 0.6::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
515 1
516 );
517 assert_eq!(
518 db.query_row("SELECT 0.9::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
519 1
520 );
521
522 assert_eq!(
523 db.query_row("SELECT 1.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
524 2
525 );
526 assert_eq!(
527 db.query_row("SELECT 2.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
528 3
529 );
530 assert_eq!(
531 db.query_row("SELECT 3.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
532 4
533 );
534 assert_eq!(
535 db.query_row("SELECT 4.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
536 5
537 );
538 assert_eq!(
539 db.query_row("SELECT 5.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
540 6
541 );
542 assert_eq!(
543 db.query_row("SELECT 10.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
544 11
545 );
546 assert_eq!(
547 db.query_row("SELECT 99.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
548 100
549 );
550
551 assert_eq!(
552 db.query_row("SELECT -0.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
553 -1
554 );
555 assert_eq!(
556 db.query_row("SELECT -1.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
557 -2
558 );
559 assert_eq!(
560 db.query_row("SELECT -2.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
561 -3
562 );
563 assert_eq!(
564 db.query_row("SELECT -3.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
565 -4
566 );
567 assert_eq!(
568 db.query_row("SELECT -4.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
569 -5
570 );
571
572 assert_eq!(
573 db.query_row("SELECT -0.1::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
574 0
575 );
576 assert_eq!(
577 db.query_row("SELECT -0.4::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
578 0
579 );
580 assert_eq!(
581 db.query_row("SELECT -0.6::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
582 -1
583 );
584 assert_eq!(
585 db.query_row("SELECT -0.9::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
586 -1
587 );
588
589 assert_eq!(
590 db.query_row("SELECT 999.4::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
591 999
592 );
593 assert_eq!(
594 db.query_row("SELECT 999.5::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
595 1000
596 );
597 assert_eq!(
598 db.query_row("SELECT 999.6::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
599 1000
600 );
601
602 assert_eq!(
603 db.query_row("SELECT 123456.49::DECIMAL(18,3)", [], |row| row.get::<_, i64>(0))?,
604 123456
605 );
606 assert_eq!(
607 db.query_row("SELECT 123456.50::DECIMAL(18,3)", [], |row| row.get::<_, i64>(0))?,
608 123457
609 );
610 assert_eq!(
611 db.query_row("SELECT 123456.51::DECIMAL(18,3)", [], |row| row.get::<_, i64>(0))?,
612 123457
613 );
614
615 assert_eq!(
616 db.query_row("SELECT 0.49::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
617 0
618 );
619 assert_eq!(
620 db.query_row("SELECT 0.50::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
621 1
622 );
623 assert_eq!(
624 db.query_row("SELECT 0.51::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
625 1
626 );
627 assert_eq!(
628 db.query_row("SELECT -0.49::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
629 0
630 );
631 assert_eq!(
632 db.query_row("SELECT -0.50::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
633 -1
634 );
635 assert_eq!(
636 db.query_row("SELECT -0.51::DECIMAL(10,2)", [], |row| row.get::<_, i32>(0))?,
637 -1
638 );
639
640 assert_eq!(
641 db.query_row("SELECT 0.50::DECIMAL(38,2)", [], |row| row.get::<_, i32>(0))?,
642 1
643 );
644 assert_eq!(
645 db.query_row("SELECT -0.50::DECIMAL(38,2)", [], |row| row.get::<_, i32>(0))?,
646 -1
647 );
648 assert_eq!(
649 db.query_row("SELECT 0.500000000000000000000000000000::DECIMAL(38,30)", [], |row| row
650 .get::<_, i32>(0))?,
651 1
652 );
653 assert_eq!(
654 db.query_row("SELECT -0.500000000000000000000000000000::DECIMAL(38,30)", [], |row| {
655 row.get::<_, i32>(0)
656 })?,
657 -1
658 );
659
660 assert_eq!(
661 db.query_row("SELECT 126.4::DECIMAL(5,1)", [], |row| row.get::<_, i8>(0))?,
662 126
663 );
664 assert_eq!(
665 db.query_row("SELECT 126.6::DECIMAL(5,1)", [], |row| row.get::<_, i8>(0))?,
666 127
667 );
668
669 let err = db
670 .query_row("SELECT 999::DECIMAL(10,0)", [], |row| row.get::<_, i8>(0))
671 .unwrap_err();
672 match err {
673 Error::IntegralValueOutOfRange(_, _) => {} _ => panic!("Expected IntegralValueOutOfRange error, got: {err}"),
675 }
676
677 Ok(())
678 }
679}