1 use crate::constants::MAX_PRECISION;
2 use crate::{
3     ops::array::{div_by_u32, is_all_zero, mul_by_u32},
4     Decimal,
5 };
6 use core::{convert::TryInto, fmt};
7 use std::error;
8 
9 #[derive(Debug, Clone)]
10 pub struct InvalidDecimal {
11     inner: Option<String>,
12 }
13 
14 impl fmt::Display for InvalidDecimal {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result15     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
16         if let Some(ref msg) = self.inner {
17             fmt.write_fmt(format_args!("Invalid Decimal: {}", msg))
18         } else {
19             fmt.write_str("Invalid Decimal")
20         }
21     }
22 }
23 
24 impl error::Error for InvalidDecimal {}
25 
26 struct PostgresDecimal<D> {
27     neg: bool,
28     weight: i16,
29     scale: u16,
30     digits: D,
31 }
32 
33 impl Decimal {
34     fn from_postgres<D: ExactSizeIterator<Item = u16>>(
35         PostgresDecimal {
36             neg,
37             scale,
38             digits,
39             weight,
40         }: PostgresDecimal<D>,
41     ) -> Self {
42         let mut digits = digits.into_iter().collect::<Vec<_>>();
43 
44         let fractionals_part_count = digits.len() as i32 + (-weight as i32) - 1;
45         let integers_part_count = weight as i32 + 1;
46 
47         let mut result = Decimal::ZERO;
48         // adding integer part
49         if integers_part_count > 0 {
50             let (start_integers, last) = if integers_part_count > digits.len() as i32 {
51                 (integers_part_count - digits.len() as i32, digits.len() as i32)
52             } else {
53                 (0, integers_part_count)
54             };
55             let integers: Vec<_> = digits.drain(..last as usize).collect();
56             for digit in integers {
57                 result *= Decimal::from_i128_with_scale(10i128.pow(4), 0);
58                 result += Decimal::new(digit as i64, 0);
59             }
60             result *= Decimal::from_i128_with_scale(10i128.pow(4 * start_integers as u32), 0);
61         }
62         // adding fractional part
63         if fractionals_part_count > 0 {
64             let start_fractionals = if weight < 0 { (-weight as u32) - 1 } else { 0 };
65             for (i, digit) in digits.into_iter().enumerate() {
66                 let fract_pow = 4 * (i as u32 + 1 + start_fractionals);
67                 if fract_pow <= MAX_PRECISION {
68                     result += Decimal::new(digit as i64, 0) / Decimal::from_i128_with_scale(10i128.pow(fract_pow), 0);
69                 } else if fract_pow == MAX_PRECISION + 4 {
70                     // rounding last digit
71                     if digit >= 5000 {
72                         result += Decimal::new(1_i64, 0) / Decimal::from_i128_with_scale(10i128.pow(MAX_PRECISION), 0);
73                     }
74                 }
75             }
76         }
77 
78         result.set_sign_negative(neg);
79         // Rescale to the postgres value, automatically rounding as needed.
80         result.rescale(scale as u32);
81         result
82     }
83 
to_postgres(self) -> PostgresDecimal<Vec<i16>>84     fn to_postgres(self) -> PostgresDecimal<Vec<i16>> {
85         if self.is_zero() {
86             return PostgresDecimal {
87                 neg: false,
88                 weight: 0,
89                 scale: 0,
90                 digits: vec![0],
91             };
92         }
93         let scale = self.scale() as u16;
94 
95         let groups_diff = scale & 0x3; // groups_diff = scale % 4
96 
97         let mut mantissa = self.mantissa_array4();
98 
99         if groups_diff > 0 {
100             let remainder = 4 - groups_diff;
101             let power = 10u32.pow(u32::from(remainder));
102             mul_by_u32(&mut mantissa, power);
103         }
104 
105         // array to store max mantissa of Decimal in Postgres decimal format
106         const MAX_GROUP_COUNT: usize = 8;
107         let mut digits = Vec::with_capacity(MAX_GROUP_COUNT);
108 
109         while !is_all_zero(&mantissa) {
110             let digit = div_by_u32(&mut mantissa, 10000) as u16;
111             digits.push(digit.try_into().unwrap());
112         }
113         digits.reverse();
114         let digits_after_decimal = (scale + 3) as u16 / 4;
115         let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;
116 
117         let unnecessary_zeroes = if weight >= 0 {
118             let index_of_decimal = (weight + 1) as usize;
119             digits
120                 .get(index_of_decimal..)
121                 .expect("enough digits exist")
122                 .iter()
123                 .rev()
124                 .take_while(|i| **i == 0)
125                 .count()
126         } else {
127             0
128         };
129         let relevant_digits = digits.len() - unnecessary_zeroes;
130         digits.truncate(relevant_digits);
131 
132         PostgresDecimal {
133             neg: self.is_sign_negative(),
134             digits,
135             scale,
136             weight,
137         }
138     }
139 }
140 
141 #[cfg(feature = "diesel")]
142 mod diesel {
143     use super::*;
144     use ::diesel::{
145         deserialize::{self, FromSql},
146         pg::data_types::PgNumeric,
147         pg::Pg,
148         serialize::{self, Output, ToSql},
149         sql_types::Numeric,
150     };
151     use core::convert::{TryFrom, TryInto};
152     use std::io::Write;
153 
154     impl<'a> TryFrom<&'a PgNumeric> for Decimal {
155         type Error = Box<dyn error::Error + Send + Sync>;
156 
try_from(numeric: &'a PgNumeric) -> deserialize::Result<Self>157         fn try_from(numeric: &'a PgNumeric) -> deserialize::Result<Self> {
158             let (neg, weight, scale, digits) = match *numeric {
159                 PgNumeric::Positive {
160                     weight,
161                     scale,
162                     ref digits,
163                 } => (false, weight, scale, digits),
164                 PgNumeric::Negative {
165                     weight,
166                     scale,
167                     ref digits,
168                 } => (true, weight, scale, digits),
169                 PgNumeric::NaN => return Err(Box::from("NaN is not supported in Decimal")),
170             };
171 
172             Ok(Self::from_postgres(PostgresDecimal {
173                 neg,
174                 weight,
175                 scale,
176                 digits: digits.iter().copied().map(|v| v.try_into().unwrap()),
177             }))
178         }
179     }
180 
181     impl TryFrom<PgNumeric> for Decimal {
182         type Error = Box<dyn error::Error + Send + Sync>;
183 
try_from(numeric: PgNumeric) -> deserialize::Result<Self>184         fn try_from(numeric: PgNumeric) -> deserialize::Result<Self> {
185             (&numeric).try_into()
186         }
187     }
188 
189     impl<'a> From<&'a Decimal> for PgNumeric {
from(decimal: &'a Decimal) -> Self190         fn from(decimal: &'a Decimal) -> Self {
191             let PostgresDecimal {
192                 neg,
193                 weight,
194                 scale,
195                 digits,
196             } = decimal.to_postgres();
197 
198             if neg {
199                 PgNumeric::Negative { digits, scale, weight }
200             } else {
201                 PgNumeric::Positive { digits, scale, weight }
202             }
203         }
204     }
205 
206     impl From<Decimal> for PgNumeric {
from(bigdecimal: Decimal) -> Self207         fn from(bigdecimal: Decimal) -> Self {
208             (&bigdecimal).into()
209         }
210     }
211 
212     impl ToSql<Numeric, Pg> for Decimal {
to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result213         fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
214             let numeric = PgNumeric::from(self);
215             ToSql::<Numeric, Pg>::to_sql(&numeric, out)
216         }
217     }
218 
219     impl FromSql<Numeric, Pg> for Decimal {
from_sql(numeric: Option<&[u8]>) -> deserialize::Result<Self>220         fn from_sql(numeric: Option<&[u8]>) -> deserialize::Result<Self> {
221             PgNumeric::from_sql(numeric)?.try_into()
222         }
223     }
224 
225     #[cfg(test)]
226     mod pg_tests {
227         use super::*;
228         use core::str::FromStr;
229 
230         #[test]
test_unnecessary_zeroes()231         fn test_unnecessary_zeroes() {
232             fn extract(value: &str) -> Decimal {
233                 Decimal::from_str(value).unwrap()
234             }
235 
236             let tests = &[
237                 ("0.000001660"),
238                 ("41.120255926293000"),
239                 ("0.5538973300"),
240                 ("08883.55986854293100"),
241                 ("0.0000_0000_0016_6000_00"),
242                 ("0.00000166650000"),
243                 ("1666500000000"),
244                 ("1666500000000.0000054500"),
245                 ("8944.000000000000"),
246             ];
247 
248             for &value in tests {
249                 let value = extract(value);
250                 let pg = PgNumeric::from(value);
251                 let dec = Decimal::try_from(pg).unwrap();
252                 assert_eq!(dec, value);
253             }
254         }
255 
256         #[test]
decimal_to_pgnumeric_converts_digits_to_base_10000()257         fn decimal_to_pgnumeric_converts_digits_to_base_10000() {
258             let decimal = Decimal::from_str("1").unwrap();
259             let expected = PgNumeric::Positive {
260                 weight: 0,
261                 scale: 0,
262                 digits: vec![1],
263             };
264             assert_eq!(expected, decimal.into());
265 
266             let decimal = Decimal::from_str("10").unwrap();
267             let expected = PgNumeric::Positive {
268                 weight: 0,
269                 scale: 0,
270                 digits: vec![10],
271             };
272             assert_eq!(expected, decimal.into());
273 
274             let decimal = Decimal::from_str("10000").unwrap();
275             let expected = PgNumeric::Positive {
276                 weight: 1,
277                 scale: 0,
278                 digits: vec![1, 0],
279             };
280             assert_eq!(expected, decimal.into());
281 
282             let decimal = Decimal::from_str("10001").unwrap();
283             let expected = PgNumeric::Positive {
284                 weight: 1,
285                 scale: 0,
286                 digits: vec![1, 1],
287             };
288             assert_eq!(expected, decimal.into());
289 
290             let decimal = Decimal::from_str("100000000").unwrap();
291             let expected = PgNumeric::Positive {
292                 weight: 2,
293                 scale: 0,
294                 digits: vec![1, 0, 0],
295             };
296             assert_eq!(expected, decimal.into());
297         }
298 
299         #[test]
decimal_to_pg_numeric_properly_adjusts_scale()300         fn decimal_to_pg_numeric_properly_adjusts_scale() {
301             let decimal = Decimal::from_str("1").unwrap();
302             let expected = PgNumeric::Positive {
303                 weight: 0,
304                 scale: 0,
305                 digits: vec![1],
306             };
307             assert_eq!(expected, decimal.into());
308 
309             let decimal = Decimal::from_str("1.0").unwrap();
310             let expected = PgNumeric::Positive {
311                 weight: 0,
312                 scale: 1,
313                 digits: vec![1],
314             };
315             assert_eq!(expected, decimal.into());
316 
317             let decimal = Decimal::from_str("1.1").unwrap();
318             let expected = PgNumeric::Positive {
319                 weight: 0,
320                 scale: 1,
321                 digits: vec![1, 1000],
322             };
323             assert_eq!(expected, decimal.into());
324 
325             let decimal = Decimal::from_str("1.10").unwrap();
326             let expected = PgNumeric::Positive {
327                 weight: 0,
328                 scale: 2,
329                 digits: vec![1, 1000],
330             };
331             assert_eq!(expected, decimal.into());
332 
333             let decimal = Decimal::from_str("100000000.0001").unwrap();
334             let expected = PgNumeric::Positive {
335                 weight: 2,
336                 scale: 4,
337                 digits: vec![1, 0, 0, 1],
338             };
339             assert_eq!(expected, decimal.into());
340 
341             let decimal = Decimal::from_str("0.1").unwrap();
342             let expected = PgNumeric::Positive {
343                 weight: -1,
344                 scale: 1,
345                 digits: vec![1000],
346             };
347             assert_eq!(expected, decimal.into());
348         }
349 
350         #[test]
351         #[cfg(feature = "unstable")]
decimal_to_pg_numeric_retains_sign()352         fn decimal_to_pg_numeric_retains_sign() {
353             let decimal = Decimal::from_str("123.456").unwrap();
354             let expected = PgNumeric::Positive {
355                 weight: 0,
356                 scale: 3,
357                 digits: vec![123, 4560],
358             };
359             assert_eq!(expected, decimal.into());
360 
361             let decimal = Decimal::from_str("-123.456").unwrap();
362             let expected = PgNumeric::Negative {
363                 weight: 0,
364                 scale: 3,
365                 digits: vec![123, 4560],
366             };
367             assert_eq!(expected, decimal.into());
368         }
369 
370         #[test]
pg_numeric_to_decimal_works()371         fn pg_numeric_to_decimal_works() {
372             let expected = Decimal::from_str("50").unwrap();
373             let pg_numeric = PgNumeric::Positive {
374                 weight: 0,
375                 scale: 0,
376                 digits: vec![50],
377             };
378             let res: Decimal = pg_numeric.try_into().unwrap();
379             assert_eq!(res, expected);
380             let expected = Decimal::from_str("123.456").unwrap();
381             let pg_numeric = PgNumeric::Positive {
382                 weight: 0,
383                 scale: 3,
384                 digits: vec![123, 4560],
385             };
386             let res: Decimal = pg_numeric.try_into().unwrap();
387             assert_eq!(res, expected);
388 
389             let expected = Decimal::from_str("-56.78").unwrap();
390             let pg_numeric = PgNumeric::Negative {
391                 weight: 0,
392                 scale: 2,
393                 digits: vec![56, 7800],
394             };
395             let res: Decimal = pg_numeric.try_into().unwrap();
396             assert_eq!(res, expected);
397 
398             // Verify no trailing zeroes are lost.
399 
400             let expected = Decimal::from_str("1.100").unwrap();
401             let pg_numeric = PgNumeric::Positive {
402                 weight: 0,
403                 scale: 3,
404                 digits: vec![1, 1000],
405             };
406             let res: Decimal = pg_numeric.try_into().unwrap();
407             assert_eq!(res.to_string(), expected.to_string());
408 
409             // To represent 5.00, Postgres can return either [5, 0] as the list of digits.
410             let expected = Decimal::from_str("5.00").unwrap();
411             let pg_numeric = PgNumeric::Positive {
412                 weight: 0,
413                 scale: 2,
414 
415                 digits: vec![5, 0],
416             };
417             let res: Decimal = pg_numeric.try_into().unwrap();
418             assert_eq!(res.to_string(), expected.to_string());
419 
420             // To represent 5.00, Postgres can return [5] as the list of digits.
421             let expected = Decimal::from_str("5.00").unwrap();
422             let pg_numeric = PgNumeric::Positive {
423                 weight: 0,
424                 scale: 2,
425                 digits: vec![5],
426             };
427             let res: Decimal = pg_numeric.try_into().unwrap();
428             assert_eq!(res.to_string(), expected.to_string());
429 
430             let expected = Decimal::from_str("3.1415926535897932384626433833").unwrap();
431             let pg_numeric = PgNumeric::Positive {
432                 weight: 0,
433                 scale: 30,
434                 digits: vec![3, 1415, 9265, 3589, 7932, 3846, 2643, 3832, 7950, 2800],
435             };
436             let res: Decimal = pg_numeric.try_into().unwrap();
437             assert_eq!(res.to_string(), expected.to_string());
438 
439             let expected = Decimal::from_str("3.1415926535897932384626433833").unwrap();
440             let pg_numeric = PgNumeric::Positive {
441                 weight: 0,
442                 scale: 34,
443                 digits: vec![3, 1415, 9265, 3589, 7932, 3846, 2643, 3832, 7950, 2800],
444             };
445 
446             let res: Decimal = pg_numeric.try_into().unwrap();
447             assert_eq!(res.to_string(), expected.to_string());
448 
449             let expected = Decimal::from_str("1.2345678901234567890123456790").unwrap();
450             let pg_numeric = PgNumeric::Positive {
451                 weight: 0,
452                 scale: 34,
453                 digits: vec![1, 2345, 6789, 0123, 4567, 8901, 2345, 6789, 5000, 0],
454             };
455 
456             let res: Decimal = pg_numeric.try_into().unwrap();
457             assert_eq!(res.to_string(), expected.to_string());
458         }
459     }
460 }
461 
462 #[cfg(feature = "postgres")]
463 mod postgres {
464     use super::*;
465     use ::postgres::types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
466     use byteorder::{BigEndian, ReadBytesExt};
467     use bytes::{BufMut, BytesMut};
468     use std::io::Cursor;
469 
470     impl<'a> FromSql<'a> for Decimal {
471         // Decimals are represented as follows:
472         // Header:
473         //  u16 numGroups
474         //  i16 weightFirstGroup (10000^weight)
475         //  u16 sign (0x0000 = positive, 0x4000 = negative, 0xC000 = NaN)
476         //  i16 dscale. Number of digits (in base 10) to print after decimal separator
477         //
478         //  Pseudo code :
479         //  const Decimals [
480         //          0.0000000000000000000000000001,
481         //          0.000000000000000000000001,
482         //          0.00000000000000000001,
483         //          0.0000000000000001,
484         //          0.000000000001,
485         //          0.00000001,
486         //          0.0001,
487         //          1,
488         //          10000,
489         //          100000000,
490         //          1000000000000,
491         //          10000000000000000,
492         //          100000000000000000000,
493         //          1000000000000000000000000,
494         //          10000000000000000000000000000
495         //  ]
496         //  overflow = false
497         //  result = 0
498         //  for i = 0, weight = weightFirstGroup + 7; i < numGroups; i++, weight--
499         //    group = read.u16
500         //    if weight < 0 or weight > MaxNum
501         //       overflow = true
502         //    else
503         //       result += Decimals[weight] * group
504         //  sign == 0x4000 ? -result : result
505 
506         // So if we were to take the number: 3950.123456
507         //
508         //  Stored on Disk:
509         //    00 03 00 00 00 00 00 06 0F 6E 04 D2 15 E0
510         //
511         //  Number of groups: 00 03
512         //  Weight of first group: 00 00
513         //  Sign: 00 00
514         //  DScale: 00 06
515         //
516         // 0F 6E = 3950
517         //   result = result + 3950 * 1;
518         // 04 D2 = 1234
519         //   result = result + 1234 * 0.0001;
520         // 15 E0 = 5600
521         //   result = result + 5600 * 0.00000001;
522         //
523 
from_sql(_: &Type, raw: &[u8]) -> Result<Decimal, Box<dyn error::Error + 'static + Sync + Send>>524         fn from_sql(_: &Type, raw: &[u8]) -> Result<Decimal, Box<dyn error::Error + 'static + Sync + Send>> {
525             let mut raw = Cursor::new(raw);
526             let num_groups = raw.read_u16::<BigEndian>()?;
527             let weight = raw.read_i16::<BigEndian>()?; // 10000^weight
528                                                        // Sign: 0x0000 = positive, 0x4000 = negative, 0xC000 = NaN
529             let sign = raw.read_u16::<BigEndian>()?;
530             // Number of digits (in base 10) to print after decimal separator
531             let scale = raw.read_u16::<BigEndian>()?;
532 
533             // Read all of the groups
534             let mut groups = Vec::new();
535             for _ in 0..num_groups as usize {
536                 groups.push(raw.read_u16::<BigEndian>()?);
537             }
538 
539             Ok(Self::from_postgres(PostgresDecimal {
540                 neg: sign == 0x4000,
541                 weight,
542                 scale,
543                 digits: groups.into_iter(),
544             }))
545         }
546 
accepts(ty: &Type) -> bool547         fn accepts(ty: &Type) -> bool {
548             matches!(*ty, Type::NUMERIC)
549         }
550     }
551 
552     impl ToSql for Decimal {
to_sql( &self, _: &Type, out: &mut BytesMut, ) -> Result<IsNull, Box<dyn error::Error + 'static + Sync + Send>>553         fn to_sql(
554             &self,
555             _: &Type,
556             out: &mut BytesMut,
557         ) -> Result<IsNull, Box<dyn error::Error + 'static + Sync + Send>> {
558             let PostgresDecimal {
559                 neg,
560                 weight,
561                 scale,
562                 digits,
563             } = self.to_postgres();
564 
565             let num_digits = digits.len();
566 
567             // Reserve bytes
568             out.reserve(8 + num_digits * 2);
569 
570             // Number of groups
571             out.put_u16(num_digits.try_into().unwrap());
572             // Weight of first group
573             out.put_i16(weight);
574             // Sign
575             out.put_u16(if neg { 0x4000 } else { 0x0000 });
576             // DScale
577             out.put_u16(scale);
578             // Now process the number
579             for digit in digits[0..num_digits].iter() {
580                 out.put_i16(*digit);
581             }
582 
583             Ok(IsNull::No)
584         }
585 
accepts(ty: &Type) -> bool586         fn accepts(ty: &Type) -> bool {
587             matches!(*ty, Type::NUMERIC)
588         }
589 
590         to_sql_checked!();
591     }
592 
593     #[cfg(test)]
594     mod test {
595         use super::*;
596         use ::postgres::{Client, NoTls};
597         use core::str::FromStr;
598 
599         /// Gets the URL for connecting to PostgreSQL for testing. Set the POSTGRES_URL
600         /// environment variable to change from the default of "postgres://postgres@localhost".
get_postgres_url() -> String601         fn get_postgres_url() -> String {
602             if let Ok(url) = std::env::var("POSTGRES_URL") {
603                 return url;
604             }
605             "postgres://postgres@localhost".to_string()
606         }
607 
608         pub static TEST_DECIMALS: &[(u32, u32, &str, &str)] = &[
609             // precision, scale, sent, expected
610             (35, 6, "3950.123456", "3950.123456"),
611             (35, 2, "3950.123456", "3950.12"),
612             (35, 2, "3950.1256", "3950.13"),
613             (10, 2, "3950.123456", "3950.12"),
614             (35, 6, "3950", "3950.000000"),
615             (4, 0, "3950", "3950"),
616             (35, 6, "0.1", "0.100000"),
617             (35, 6, "0.01", "0.010000"),
618             (35, 6, "0.001", "0.001000"),
619             (35, 6, "0.0001", "0.000100"),
620             (35, 6, "0.00001", "0.000010"),
621             (35, 6, "0.000001", "0.000001"),
622             (35, 6, "1", "1.000000"),
623             (35, 6, "-100", "-100.000000"),
624             (35, 6, "-123.456", "-123.456000"),
625             (35, 6, "119996.25", "119996.250000"),
626             (35, 6, "1000000", "1000000.000000"),
627             (35, 6, "9999999.99999", "9999999.999990"),
628             (35, 6, "12340.56789", "12340.567890"),
629             // Scale is only 28 since that is the maximum we can represent.
630             (65, 30, "1.2", "1.2000000000000000000000000000"),
631             // Pi - rounded at scale 28
632             (
633                 65,
634                 30,
635                 "3.141592653589793238462643383279",
636                 "3.1415926535897932384626433833",
637             ),
638             (
639                 65,
640                 34,
641                 "3.1415926535897932384626433832795028",
642                 "3.1415926535897932384626433833",
643             ),
644             // Unrounded number
645             (
646                 65,
647                 34,
648                 "1.234567890123456789012345678950000",
649                 "1.2345678901234567890123456790",
650             ),
651             (
652                 65,
653                 34, // No rounding due to 49999 after significant digits
654                 "1.234567890123456789012345678949999",
655                 "1.2345678901234567890123456789",
656             ),
657             // 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF (96 bit)
658             (35, 0, "79228162514264337593543950335", "79228162514264337593543950335"),
659             // 0x0FFF_FFFF_FFFF_FFFF_FFFF_FFFF (95 bit)
660             (35, 1, "4951760157141521099596496895", "4951760157141521099596496895.0"),
661             // 0x1000_0000_0000_0000_0000_0000
662             (35, 1, "4951760157141521099596496896", "4951760157141521099596496896.0"),
663             (35, 6, "18446744073709551615", "18446744073709551615.000000"),
664             (35, 6, "-18446744073709551615", "-18446744073709551615.000000"),
665             (35, 6, "0.10001", "0.100010"),
666             (35, 6, "0.12345", "0.123450"),
667         ];
668 
669         #[test]
test_null()670         fn test_null() {
671             let mut client = match Client::connect(&get_postgres_url(), NoTls) {
672                 Ok(x) => x,
673                 Err(err) => panic!("{:#?}", err),
674             };
675 
676             // Test NULL
677             let result: Option<Decimal> = match client.query("SELECT NULL::numeric", &[]) {
678                 Ok(x) => x.iter().next().unwrap().get(0),
679                 Err(err) => panic!("{:#?}", err),
680             };
681             assert_eq!(None, result);
682         }
683 
684         #[tokio::test]
685         #[cfg(feature = "tokio-pg")]
async_test_null()686         async fn async_test_null() {
687             use futures::future::FutureExt;
688             use tokio_postgres::connect;
689 
690             let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
691             let connection = connection.map(|e| e.unwrap());
692             tokio::spawn(connection);
693 
694             let statement = client.prepare(&"SELECT NULL::numeric").await.unwrap();
695             let rows = client.query(&statement, &[]).await.unwrap();
696             let result: Option<Decimal> = rows.iter().next().unwrap().get(0);
697 
698             assert_eq!(None, result);
699         }
700 
701         #[test]
read_numeric_type()702         fn read_numeric_type() {
703             let mut client = match Client::connect(&get_postgres_url(), NoTls) {
704                 Ok(x) => x,
705                 Err(err) => panic!("{:#?}", err),
706             };
707             for &(precision, scale, sent, expected) in TEST_DECIMALS.iter() {
708                 let result: Decimal =
709                     match client.query(&*format!("SELECT {}::NUMERIC({}, {})", sent, precision, scale), &[]) {
710                         Ok(x) => x.iter().next().unwrap().get(0),
711                         Err(err) => panic!("SELECT {}::NUMERIC({}, {}), error - {:#?}", sent, precision, scale, err),
712                     };
713                 assert_eq!(
714                     expected,
715                     result.to_string(),
716                     "NUMERIC({}, {}) sent: {}",
717                     precision,
718                     scale,
719                     sent
720                 );
721             }
722         }
723 
724         #[tokio::test]
725         #[cfg(feature = "tokio-pg")]
async_read_numeric_type()726         async fn async_read_numeric_type() {
727             use futures::future::FutureExt;
728             use tokio_postgres::connect;
729 
730             let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
731             let connection = connection.map(|e| e.unwrap());
732             tokio::spawn(connection);
733             for &(precision, scale, sent, expected) in TEST_DECIMALS.iter() {
734                 let statement = client
735                     .prepare(&*format!("SELECT {}::NUMERIC({}, {})", sent, precision, scale))
736                     .await
737                     .unwrap();
738                 let rows = client.query(&statement, &[]).await.unwrap();
739                 let result: Decimal = rows.iter().next().unwrap().get(0);
740 
741                 assert_eq!(expected, result.to_string(), "NUMERIC({}, {})", precision, scale);
742             }
743         }
744 
745         #[test]
write_numeric_type()746         fn write_numeric_type() {
747             let mut client = match Client::connect(&get_postgres_url(), NoTls) {
748                 Ok(x) => x,
749                 Err(err) => panic!("{:#?}", err),
750             };
751             for &(precision, scale, sent, expected) in TEST_DECIMALS.iter() {
752                 let number = Decimal::from_str(sent).unwrap();
753                 let result: Decimal =
754                     match client.query(&*format!("SELECT $1::NUMERIC({}, {})", precision, scale), &[&number]) {
755                         Ok(x) => x.iter().next().unwrap().get(0),
756                         Err(err) => panic!("{:#?}", err),
757                     };
758                 assert_eq!(expected, result.to_string(), "NUMERIC({}, {})", precision, scale);
759             }
760         }
761 
762         #[tokio::test]
763         #[cfg(feature = "tokio-pg")]
async_write_numeric_type()764         async fn async_write_numeric_type() {
765             use futures::future::FutureExt;
766             use tokio_postgres::connect;
767 
768             let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
769             let connection = connection.map(|e| e.unwrap());
770             tokio::spawn(connection);
771 
772             for &(precision, scale, sent, expected) in TEST_DECIMALS.iter() {
773                 let statement = client
774                     .prepare(&*format!("SELECT $1::NUMERIC({}, {})", precision, scale))
775                     .await
776                     .unwrap();
777                 let number = Decimal::from_str(sent).unwrap();
778                 let rows = client.query(&statement, &[&number]).await.unwrap();
779                 let result: Decimal = rows.iter().next().unwrap().get(0);
780 
781                 assert_eq!(expected, result.to_string(), "NUMERIC({}, {})", precision, scale);
782             }
783         }
784 
785         #[test]
numeric_overflow()786         fn numeric_overflow() {
787             let tests = [(4, 4, "3950.1234")];
788             let mut client = match Client::connect(&get_postgres_url(), NoTls) {
789                 Ok(x) => x,
790                 Err(err) => panic!("{:#?}", err),
791             };
792             for &(precision, scale, sent) in tests.iter() {
793                 match client.query(&*format!("SELECT {}::NUMERIC({}, {})", sent, precision, scale), &[]) {
794                     Ok(_) => panic!(
795                         "Expected numeric overflow for {}::NUMERIC({}, {})",
796                         sent, precision, scale
797                     ),
798                     Err(err) => {
799                         assert_eq!("22003", err.code().unwrap().code(), "Unexpected error code");
800                     }
801                 };
802             }
803         }
804 
805         #[tokio::test]
806         #[cfg(feature = "tokio-pg")]
async_numeric_overflow()807         async fn async_numeric_overflow() {
808             use futures::future::FutureExt;
809             use tokio_postgres::connect;
810 
811             let tests = [(4, 4, "3950.1234")];
812             let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
813             let connection = connection.map(|e| e.unwrap());
814             tokio::spawn(connection);
815 
816             for &(precision, scale, sent) in tests.iter() {
817                 let statement = client
818                     .prepare(&*format!("SELECT {}::NUMERIC({}, {})", sent, precision, scale))
819                     .await
820                     .unwrap();
821 
822                 match client.query(&statement, &[]).await {
823                     Ok(_) => panic!(
824                         "Expected numeric overflow for {}::NUMERIC({}, {})",
825                         sent, precision, scale
826                     ),
827                     Err(err) => assert_eq!("22003", err.code().unwrap().code(), "Unexpected error code"),
828                 }
829             }
830         }
831     }
832 }
833