Skip to content

Commit df14440

Browse files
committed
fix: correct decimal widening check to preserve integer digits
The previous check (tp >= fp && ts >= fs) allowed promotions like decimal(10,2) → decimal(12,8) where the integer part shrinks from 8 to 4 digits, potentially causing overflow. Now checks that both integer digits (precision - scale) and fractional digits don't shrink.
1 parent f1ae269 commit df14440

1 file changed

Lines changed: 9 additions & 3 deletions

File tree

src/types.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,14 @@ fn is_arrow_promotable(from: &DataType, to: &DataType) -> bool {
340340
return true;
341341
}
342342

343-
// Decimal widening: larger precision/scale
343+
// Decimal widening: integer digits don't shrink AND fractional digits don't shrink.
344+
// We check (tp - ts >= fp - fs) to ensure the integer part has enough room,
345+
// in addition to (ts >= fs) for the fractional part.
344346
match (from, to) {
345347
(Decimal128(fp, fs) | Decimal256(fp, fs), Decimal128(tp, ts) | Decimal256(tp, ts)) => {
346-
tp >= fp && ts >= fs
348+
let from_int_digits = *fp as i16 - *fs as i16;
349+
let to_int_digits = *tp as i16 - *ts as i16;
350+
ts >= fs && to_int_digits >= from_int_digits
347351
},
348352
_ => false,
349353
}
@@ -1122,13 +1126,15 @@ mod tests {
11221126
assert!(is_promotable("decimal(10, 2)", "decimal(18, 4)"));
11231127
assert!(is_promotable("decimal(10, 2)", "decimal(10, 2)")); // same
11241128
assert!(is_promotable("decimal(10, 2)", "decimal(20, 2)")); // wider precision
1125-
assert!(is_promotable("decimal(10, 2)", "decimal(10, 4)")); // wider scale
1129+
assert!(is_promotable("decimal(10, 2)", "decimal(12, 4)")); // wider scale with enough integer digits
11261130
}
11271131

11281132
#[test]
11291133
fn test_promotable_decimal_narrowing_rejected() {
11301134
assert!(!is_promotable("decimal(18, 4)", "decimal(10, 2)"));
11311135
assert!(!is_promotable("decimal(20, 2)", "decimal(10, 2)")); // narrower precision
1136+
// Scale widening that shrinks integer digits: 10-2=8 integer digits vs 12-8=4
1137+
assert!(!is_promotable("decimal(10, 2)", "decimal(12, 8)"));
11321138
}
11331139

11341140
#[test]

0 commit comments

Comments
 (0)