fix: bigdecimal decoding ob1 for positive weight multiples of 4

This commit is contained in:
Zachery Gyurkovitz 2020-06-22 14:11:40 -07:00 committed by Austin Bonander
parent f85920acaf
commit 84e8ed0d4c

View File

@ -99,7 +99,8 @@ impl TryFrom<&'_ BigDecimal> for PgNumeric {
let weight: i16 = if weight_10 <= 0 { let weight: i16 = if weight_10 <= 0 {
weight_10 / 4 - 1 weight_10 / 4 - 1
} else { } else {
weight_10 / 4 // the `-1` is a fix for an off by 1 error (4 digits should still be 0 weight)
(weight_10 - 1) / 4
} }
.try_into()?; .try_into()?;
@ -109,11 +110,7 @@ impl TryFrom<&'_ BigDecimal> for PgNumeric {
base_10.len() / 4 base_10.len() / 4
}; };
let offset = if weight_10 < 0 { let offset = weight_10.rem_euclid(4) as usize;
4 - (-weight_10) % 4
} else {
weight_10 % 4
} as usize;
let mut digits = Vec::with_capacity(digits_len); let mut digits = Vec::with_capacity(digits_len);
@ -173,127 +170,238 @@ impl Decode<'_, Postgres> for BigDecimal {
} }
} }
#[test] #[cfg(test)]
fn test_bigdecimal_to_pgnumeric() { mod bigdecimal_to_pgnumeric {
let one: BigDecimal = "1".parse().unwrap(); use super::{BigDecimal, PgNumeric, PgNumericSign};
assert_eq!( use std::convert::TryFrom;
PgNumeric::try_from(&one).unwrap(),
PgNumeric::Number {
sign: PgNumericSign::Positive,
scale: 0,
weight: 0,
digits: vec![1]
}
);
let ten: BigDecimal = "10".parse().unwrap(); #[test]
assert_eq!( fn zero() {
PgNumeric::try_from(&ten).unwrap(), let zero: BigDecimal = "0".parse().unwrap();
PgNumeric::Number {
sign: PgNumericSign::Positive,
scale: 0,
weight: 0,
digits: vec![10]
}
);
let one_hundred: BigDecimal = "100".parse().unwrap(); assert_eq!(
assert_eq!( PgNumeric::try_from(&zero).unwrap(),
PgNumeric::try_from(&one_hundred).unwrap(), PgNumeric::Number {
PgNumeric::Number { sign: PgNumericSign::Positive,
sign: PgNumericSign::Positive, scale: 0,
scale: 0, weight: 0,
weight: 0, digits: vec![]
digits: vec![100] }
} );
); }
// BigDecimal doesn't normalize here #[test]
let ten_thousand: BigDecimal = "10000".parse().unwrap(); fn one() {
assert_eq!( let one: BigDecimal = "1".parse().unwrap();
PgNumeric::try_from(&ten_thousand).unwrap(), assert_eq!(
PgNumeric::Number { PgNumeric::try_from(&one).unwrap(),
sign: PgNumericSign::Positive, PgNumeric::Number {
scale: 0, sign: PgNumericSign::Positive,
weight: 1, scale: 0,
digits: vec![1] weight: 0,
} digits: vec![1]
); }
);
}
let two_digits: BigDecimal = "12345".parse().unwrap(); #[test]
assert_eq!( fn ten() {
PgNumeric::try_from(&two_digits).unwrap(), let ten: BigDecimal = "10".parse().unwrap();
PgNumeric::Number { assert_eq!(
sign: PgNumericSign::Positive, PgNumeric::try_from(&ten).unwrap(),
scale: 0, PgNumeric::Number {
weight: 1, sign: PgNumericSign::Positive,
digits: vec![1, 2345] scale: 0,
} weight: 0,
); digits: vec![10]
}
);
}
let one_tenth: BigDecimal = "0.1".parse().unwrap(); #[test]
assert_eq!( fn one_hundred() {
PgNumeric::try_from(&one_tenth).unwrap(), let one_hundred: BigDecimal = "100".parse().unwrap();
PgNumeric::Number { assert_eq!(
sign: PgNumericSign::Positive, PgNumeric::try_from(&one_hundred).unwrap(),
scale: 1, PgNumeric::Number {
weight: -1, sign: PgNumericSign::Positive,
digits: vec![1000] scale: 0,
} weight: 0,
); digits: vec![100]
}
);
}
let decimal: BigDecimal = "1.2345".parse().unwrap(); #[test]
assert_eq!( fn ten_thousand() {
PgNumeric::try_from(&decimal).unwrap(), // BigDecimal doesn't normalize here
PgNumeric::Number { let ten_thousand: BigDecimal = "10000".parse().unwrap();
sign: PgNumericSign::Positive, assert_eq!(
scale: 4, PgNumeric::try_from(&ten_thousand).unwrap(),
weight: 0, PgNumeric::Number {
digits: vec![1, 2345] sign: PgNumericSign::Positive,
} scale: 0,
); weight: 1,
digits: vec![1]
}
);
}
let decimal: BigDecimal = "0.12345".parse().unwrap(); #[test]
assert_eq!( fn two_digits() {
PgNumeric::try_from(&decimal).unwrap(), let two_digits: BigDecimal = "12345".parse().unwrap();
PgNumeric::Number { assert_eq!(
sign: PgNumericSign::Positive, PgNumeric::try_from(&two_digits).unwrap(),
scale: 5, PgNumeric::Number {
weight: -1, sign: PgNumericSign::Positive,
digits: vec![1234, 5000] scale: 0,
} weight: 1,
); digits: vec![1, 2345]
}
);
}
let decimal: BigDecimal = "0.01234".parse().unwrap(); #[test]
assert_eq!( fn one_tenth() {
PgNumeric::try_from(&decimal).unwrap(), let one_tenth: BigDecimal = "0.1".parse().unwrap();
PgNumeric::Number { assert_eq!(
sign: PgNumericSign::Positive, PgNumeric::try_from(&one_tenth).unwrap(),
scale: 5, PgNumeric::Number {
weight: -1, sign: PgNumericSign::Positive,
digits: vec![0123, 4000] scale: 1,
} weight: -1,
); digits: vec![1000]
}
);
}
let decimal: BigDecimal = "12345.67890".parse().unwrap(); #[test]
assert_eq!( fn decimal_1() {
PgNumeric::try_from(&decimal).unwrap(), let decimal: BigDecimal = "1.2345".parse().unwrap();
PgNumeric::Number { assert_eq!(
sign: PgNumericSign::Positive, PgNumeric::try_from(&decimal).unwrap(),
scale: 5, PgNumeric::Number {
weight: 1, sign: PgNumericSign::Positive,
digits: vec![1, 2345, 6789] scale: 4,
} weight: 0,
); digits: vec![1, 2345]
}
);
}
let one_digit_decimal: BigDecimal = "0.00001234".parse().unwrap(); #[test]
assert_eq!( fn decimal_2() {
PgNumeric::try_from(&one_digit_decimal).unwrap(), let decimal: BigDecimal = "0.12345".parse().unwrap();
PgNumeric::Number { assert_eq!(
sign: PgNumericSign::Positive, PgNumeric::try_from(&decimal).unwrap(),
scale: 8, PgNumeric::Number {
weight: -2, sign: PgNumericSign::Positive,
digits: vec![1234] scale: 5,
} weight: -1,
); digits: vec![1234, 5000]
}
);
}
#[test]
fn decimal_3() {
let decimal: BigDecimal = "0.01234".parse().unwrap();
assert_eq!(
PgNumeric::try_from(&decimal).unwrap(),
PgNumeric::Number {
sign: PgNumericSign::Positive,
scale: 5,
weight: -1,
digits: vec![0123, 4000]
}
);
}
#[test]
fn decimal_4() {
let decimal: BigDecimal = "12345.67890".parse().unwrap();
assert_eq!(
PgNumeric::try_from(&decimal).unwrap(),
PgNumeric::Number {
sign: PgNumericSign::Positive,
scale: 5,
weight: 1,
digits: vec![1, 2345, 6789]
}
);
}
#[test]
fn one_digit_decimal() {
let one_digit_decimal: BigDecimal = "0.00001234".parse().unwrap();
assert_eq!(
PgNumeric::try_from(&one_digit_decimal).unwrap(),
PgNumeric::Number {
sign: PgNumericSign::Positive,
scale: 8,
weight: -2,
digits: vec![1234]
}
);
}
#[test]
fn issue_423_four_digit() {
// This is a regression test for https://github.com/launchbadge/sqlx/issues/423
let four_digit: BigDecimal = "1234".parse().unwrap();
assert_eq!(
PgNumeric::try_from(&four_digit).unwrap(),
PgNumeric::Number {
sign: PgNumericSign::Positive,
scale: 0,
weight: 0,
digits: vec![1234]
}
);
}
#[test]
fn issue_423_negative_four_digit() {
// This is a regression test for https://github.com/launchbadge/sqlx/issues/423
let negative_four_digit: BigDecimal = "-1234".parse().unwrap();
assert_eq!(
PgNumeric::try_from(&negative_four_digit).unwrap(),
PgNumeric::Number {
sign: PgNumericSign::Negative,
scale: 0,
weight: 0,
digits: vec![1234]
}
);
}
#[test]
fn issue_423_eight_digit() {
// This is a regression test for https://github.com/launchbadge/sqlx/issues/423
let eight_digit: BigDecimal = "12345678".parse().unwrap();
assert_eq!(
PgNumeric::try_from(&eight_digit).unwrap(),
PgNumeric::Number {
sign: PgNumericSign::Positive,
scale: 0,
weight: 1,
digits: vec![1234, 5678]
}
);
}
#[test]
fn issue_423_negative_eight_digit() {
// This is a regression test for https://github.com/launchbadge/sqlx/issues/423
let negative_eight_digit: BigDecimal = "-12345678".parse().unwrap();
assert_eq!(
PgNumeric::try_from(&negative_eight_digit).unwrap(),
PgNumeric::Number {
sign: PgNumericSign::Negative,
scale: 0,
weight: 1,
digits: vec![1234, 5678]
}
);
}
} }