Skip to content

Commit

Permalink
Properly encode BigDecimal values whose first digit is 10k
Browse files Browse the repository at this point in the history
When serializing a numeric column, we need to take a decimal value and
convert it to a list of its digits in base 10k. The serialization code
had a bug when the first digit was exactly `10000`, resulting in the
digits being `[10000, ...]` instead of `[1, 0, ...]`. This bug only
affected the integral part, as the decimal portion uses different logic
in order ot strip trailing zeroes.

Fixes diesel-rs#1044.
  • Loading branch information
sgrif authored and Fiedzia committed Jul 31, 2017
1 parent e556218 commit 5f73359
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 12 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ All user visible changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/), as described
for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md)

## Unreleased

### Added

* Added helper types for inner join and left outer join

### Fixed

* `BigDecimal` now properly encodes numbers starting with `10000` on postgres.
See [issue #1044][] for details.

[issue #1044]: https://github.com/diesel-rs/diesel/issues/1044

## [0.15.1] - 2017-07-24

* No changes to public API
Expand Down
2 changes: 1 addition & 1 deletion diesel/src/pg/types/numeric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ mod bigdecimal {

let mut integer_part = absolute.to_bigint().expect("Can always take integer part of BigDecimal");

while ten_k < integer_part {
while ten_k <= integer_part {
weight += 1;
// digit is integer_part REM 10_000
let (div, digit) = integer_part.div_rem(&ten_k);
Expand Down
47 changes: 36 additions & 11 deletions diesel_tests/tests/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,25 +441,50 @@ fn pg_mysql_numeric_bigdecimal_to_sql() {
}

quickcheck(correct_rep as fn(u64, u64) -> bool);

let test_values = vec![
"1.0",
"141.0",
"-1.0",
// Larger than u64
"18446744073709551616",
// Powers of 10k (numeric is represented in base 10k)
"10000",
"100000000",
"1.100001",
"10000.100001",
];

for value in test_values {
let expected = format!("'{}'::numeric", value);
let value = value.parse::<BigDecimal>().unwrap();
query_to_sql_equality::<Numeric, _>(&expected, value);
}
}

#[test]
#[cfg(feature = "postgres")]
fn pg_numeric_bigdecimal_from_sql() {
use self::bigdecimal::BigDecimal;

let query = "1.0::numeric";
let expected_value: BigDecimal = "1.0".parse().expect("Could not parse to a BigDecimal");
assert_eq!(expected_value, query_single_value::<Numeric, BigDecimal>(query));

let query = "141.00::numeric";
let expected_value: BigDecimal = "141.00".parse().expect("Could not parse to a BigDecimal");
assert_eq!(expected_value, query_single_value::<Numeric, BigDecimal>(query));
let values = vec![
"1.0",
"141.0",
"-1.0",
// Larger than u64
"18446744073709551616",
// Powers of 10k (numeric is represented in base 10k)
"10000",
"100000000",
"1.100001",
"10000.100001",
];

// Some non standard values:
let query = "18446744073709551616::numeric"; // 2^64; doesn't fit in u64
let expected_value: BigDecimal = "18446744073709551616.00".parse().expect("Could not parse to a BigDecimal");
assert_eq!(expected_value, query_single_value::<Numeric, BigDecimal>(query));
for value in values {
let query = format!("'{}'::numeric", value);
let expected = value.parse::<BigDecimal>().unwrap();
assert_eq!(expected, query_single_value::<Numeric, BigDecimal>(&query));
}
}

#[test]
Expand Down

0 comments on commit 5f73359

Please sign in to comment.