Skip to content

Commit 5f73359

Browse files
sgrifFiedzia
authored andcommitted
Properly encode BigDecimal values whose first digit is 10k
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.
1 parent e556218 commit 5f73359

File tree

3 files changed

+46
-12
lines changed

3 files changed

+46
-12
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@ All user visible changes to this project will be documented in this file.
44
This project adheres to [Semantic Versioning](http://semver.org/), as described
55
for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md)
66

7+
## Unreleased
8+
79
### Added
810

911
* Added helper types for inner join and left outer join
1012

13+
### Fixed
14+
15+
* `BigDecimal` now properly encodes numbers starting with `10000` on postgres.
16+
See [issue #1044][] for details.
17+
18+
[issue #1044]: https://github.com/diesel-rs/diesel/issues/1044
19+
1120
## [0.15.1] - 2017-07-24
1221

1322
* No changes to public API

diesel/src/pg/types/numeric.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ mod bigdecimal {
2626

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

29-
while ten_k < integer_part {
29+
while ten_k <= integer_part {
3030
weight += 1;
3131
// digit is integer_part REM 10_000
3232
let (div, digit) = integer_part.div_rem(&ten_k);

diesel_tests/tests/types.rs

+36-11
Original file line numberDiff line numberDiff line change
@@ -441,25 +441,50 @@ fn pg_mysql_numeric_bigdecimal_to_sql() {
441441
}
442442

443443
quickcheck(correct_rep as fn(u64, u64) -> bool);
444+
445+
let test_values = vec![
446+
"1.0",
447+
"141.0",
448+
"-1.0",
449+
// Larger than u64
450+
"18446744073709551616",
451+
// Powers of 10k (numeric is represented in base 10k)
452+
"10000",
453+
"100000000",
454+
"1.100001",
455+
"10000.100001",
456+
];
457+
458+
for value in test_values {
459+
let expected = format!("'{}'::numeric", value);
460+
let value = value.parse::<BigDecimal>().unwrap();
461+
query_to_sql_equality::<Numeric, _>(&expected, value);
462+
}
444463
}
445464

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

451-
let query = "1.0::numeric";
452-
let expected_value: BigDecimal = "1.0".parse().expect("Could not parse to a BigDecimal");
453-
assert_eq!(expected_value, query_single_value::<Numeric, BigDecimal>(query));
454-
455-
let query = "141.00::numeric";
456-
let expected_value: BigDecimal = "141.00".parse().expect("Could not parse to a BigDecimal");
457-
assert_eq!(expected_value, query_single_value::<Numeric, BigDecimal>(query));
470+
let values = vec![
471+
"1.0",
472+
"141.0",
473+
"-1.0",
474+
// Larger than u64
475+
"18446744073709551616",
476+
// Powers of 10k (numeric is represented in base 10k)
477+
"10000",
478+
"100000000",
479+
"1.100001",
480+
"10000.100001",
481+
];
458482

459-
// Some non standard values:
460-
let query = "18446744073709551616::numeric"; // 2^64; doesn't fit in u64
461-
let expected_value: BigDecimal = "18446744073709551616.00".parse().expect("Could not parse to a BigDecimal");
462-
assert_eq!(expected_value, query_single_value::<Numeric, BigDecimal>(query));
483+
for value in values {
484+
let query = format!("'{}'::numeric", value);
485+
let expected = value.parse::<BigDecimal>().unwrap();
486+
assert_eq!(expected, query_single_value::<Numeric, BigDecimal>(&query));
487+
}
463488
}
464489

465490
#[test]

0 commit comments

Comments
 (0)