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