Skip to content

Commit

Permalink
Support writing numerics with larger scale than precision
Browse files Browse the repository at this point in the history
  • Loading branch information
aykut-bozkurt committed Jan 24, 2025
1 parent e775b0e commit 852b6af
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 11 deletions.
21 changes: 21 additions & 0 deletions src/pgrx_tests/copy_type_roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,27 @@ mod tests {
test_table.assert_expected_and_result_rows();
}

#[cfg(feature = "pg14")]
#[pg_test]
#[should_panic = "NUMERIC scale 8 must be between 0 and precision 5"]
fn test_numeric_with_larger_scale() {
let test_table = TestTable::<AnyNumeric>::new("numeric(5, 8)".into());
test_table.insert(
"INSERT INTO test_expected (a) VALUES (0.00012345), (0.00012340), (-0.00012345), (-0.00012340), (null), (0);",
);
test_table.assert_expected_and_result_rows();
}

#[cfg(not(feature = "pg14"))]
#[pg_test]
fn test_numeric_with_larger_scale() {
let test_table = TestTable::<AnyNumeric>::new("numeric(5, 8)".into());
test_table.insert(
"INSERT INTO test_expected (a) VALUES (0.00012345), (0.00012340), (-0.00012345), (-0.00012340), (null), (0);",
);
test_table.assert_expected_and_result_rows();
}

#[pg_test]
#[should_panic = "Special numeric values like NaN, Inf, -Inf are not allowed"]
fn test_numeric_nan() {
Expand Down
23 changes: 12 additions & 11 deletions src/type_compat/pg_arrow_type_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,19 @@ pub(crate) fn extract_precision_and_scale_from_numeric_typmod(typmod: i32) -> (u
let mut precision = extract_precision_from_numeric_typmod(typmod);
let mut scale = extract_scale_from_numeric_typmod(typmod);

// Even if PG allows negative scale, arrow does not. We adjust precision by adding scale to it.
// Even if PG allows negative scale, arrow does not.
// We adjust precision by adding scale to it and set scale to 0.
// e.g. "123.34::numeric(3,-2)" becomes "100::numeric(5,0)"
if scale < 0 {
adjust_precision_and_scale_if_negative_scale(&mut precision, &mut scale);
precision += scale.abs();
scale = 0;
}

// Even if PG allows scale to be greater than precision, arrow does not.
// We set precision to the same value as scale.
// e.g. "0.0023::numeric(2,4)" becomes "0.0023::numeric(4,4)"
if scale > precision {
precision = scale;
}

debug_assert!(precision >= 0);
Expand All @@ -345,15 +355,6 @@ fn extract_scale_from_numeric_typmod(typmod: i32) -> i32 {
(((typmod - pg_sys::VARHDRSZ as i32) & 0x7ff) ^ 1024) - 1024
}

// adjust_precision_and_scale_if_negative_scale adjusts precision and scale if scale is negative.
// Even if PG allows negative scale, arrow does not. We adjust precision by adding scale to it.
fn adjust_precision_and_scale_if_negative_scale(precision: &mut i32, scale: &mut i32) {
if *scale < 0 {
*precision += scale.abs();
*scale = 0;
}
}

fn is_unbounded_numeric_typmod(typmod: i32) -> bool {
typmod == -1
}

0 comments on commit 852b6af

Please sign in to comment.