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