Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decimal precision is not maintained from postgres to rust_decimal #2247

Closed
jkleinknox opened this issue Dec 20, 2022 · 3 comments
Closed

Decimal precision is not maintained from postgres to rust_decimal #2247

jkleinknox opened this issue Dec 20, 2022 · 3 comments
Labels

Comments

@jkleinknox
Copy link
Contributor

Bug Description

Decimal precision does not match when converting a PgNumeric to a rust_decimal::Decimal. This is corrected by calling .normalize() on rust_decimal::Decimal.

Minimal Reproduction

#[test]
fn precision_match() {
    let m: i128 = 2147483647;
    let s = 2;

    let number = Decimal::new(m as i64, s);
    assert_eq!(m, number.mantissa());
    assert_eq!(s, number.scale());

    let pg_numeric = PgNumeric::try_from(&number).unwrap();
    let new_number : Decimal = pg_numeric.try_into().unwrap();

    assert_eq!(m, new_number.mantissa());
    // ---- postgres::types::decimal::decimal_to_pgnumeric::precision_match stdout ----
    //     thread 'postgres::types::decimal::decimal_to_pgnumeric::precision_match' panicked at 'assertion failed: `(left == right)`
    // left: `2147483647`,
    // right: `214748364700`', sqlx-core/src/postgres/types/decimal.rs:220:9

    assert_eq!(s, new_number.scale());
    // ---- postgres::types::decimal::decimal_to_pgnumeric::precision_match stdout ----
    //     thread 'postgres::types::decimal::decimal_to_pgnumeric::precision_match' panicked at 'assertion failed: `(left == right)`
    // left: `2`,
    // right: `4`', sqlx-core/src/postgres/types/decimal.rs:227:9
}

Info

  • SQLx version: 0.6.2
  • SQLx features enabled: runtime-tokio-rustls,decimal,postgres
  • Database server and version: Postgres 15.1
  • Operating system: Darwin Kernel Version 21.6.0: root:xnu-8020.140.49~2/RELEASE_ARM64_T6000 arm64
  • rustc --version: rustc 1.65.0 (897e37553 2022-11-02)
@jkleinknox jkleinknox added the bug label Dec 20, 2022
@Flowneee
Copy link

Flowneee commented Mar 9, 2023

This is because of https://github.com/launchbadge/sqlx/blob/main/sqlx-postgres/src/types/rust_decimal.rs#L56 (same for bigdecimal). But it seems like this is intended.

We encountered this problem when noticed that passing BigDecimal value from postgres to JSON always producing something like 1234.600, which is technically correct and shouldn't affect anything, but still annoying. I believe rust_decimal and bigdecimal features should call normalize() (normalized() for bigdecimal) at the end of TryFrom. But this will obviously add some overhead.

@Vrajs16
Copy link
Contributor

Vrajs16 commented Aug 30, 2023

Is there a workaround for this? I was thinking that I could use serde's custom deserializer, but that doesn't seem to work (I don't think sqlx deserializes into the struct field.) However I was able to serialize the field which has big decimal to 2.

struct x {
    ...
    #[serde(serialize_with = "size_serializer")]
    pub size: BigDecimal,
    ...
}

fn size_serializer<S>(big_decimal: &BigDecimal, serialize: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    serialize.collect_str(&big_decimal.with_scale(2))
}

If anyone knows of a workaround that would be great.

@jkleinknox
Copy link
Contributor Author

Completed in #2838

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants