Skip to content

Commit 58e3fee

Browse files
committed
support larger numeric values using i128; add boundary tests for MONEY and SMALLMONEY types
1 parent cc0feec commit 58e3fee

File tree

2 files changed

+46
-7
lines changed

2 files changed

+46
-7
lines changed

sqlx-core/src/mssql/types/decimal.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,19 @@ impl Decode<'_, Mssql> for Decimal {
7373

7474
fn decode_numeric(bytes: &[u8], _precision: u8, scale: u8) -> Result<Decimal, BoxDynError> {
7575
let (sign, numerator) = decode_numeric_bytes(bytes)?;
76-
let small_num: i64 = sign as i64 * i64::try_from(numerator)?;
77-
Ok(Decimal::new(small_num, u32::from(scale)))
76+
77+
// Try to convert to i128 to handle larger values than i64
78+
let signed_numerator = match i128::try_from(numerator) {
79+
Ok(val) => sign as i128 * val,
80+
Err(_) => {
81+
return Err(err_protocol!(
82+
"numeric value {} is too large to be represented as an i128 (max: {}, min: {})",
83+
numerator,
84+
i128::MAX,
85+
i128::MIN
86+
).into());
87+
}
88+
};
89+
90+
Ok(Decimal::from_i128_with_scale(signed_numerator, u32::from(scale)))
7891
}

tests/mssql/types.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,17 +215,43 @@ mod decimal {
215215
== Decimal::from_str_exact("0.01234567890123456789").unwrap(),
216216
"CAST('-12345678901234' AS DECIMAL(28,5))"
217217
== Decimal::from_str_exact("-12345678901234").unwrap(),
218-
"CAST('-1234567890.1234' AS MONEY)" == Decimal::from_str_exact("-1234567890.1234").unwrap(),
219-
"CAST('-123456.1234' AS SMALLMONEY)" == Decimal::from_str_exact("-123456.1234").unwrap(),
218+
));
219+
220+
test_type!(money_boundary_tests<Decimal>(
221+
Mssql,
220222
"CAST('922337203685477.5807' AS MONEY)" == Decimal::from_str_exact("922337203685477.5807").unwrap(),
221223
"CAST('-922337203685477.5808' AS MONEY)" == Decimal::from_str_exact("-922337203685477.5808").unwrap(),
224+
"CAST('922337203685477.5806' AS MONEY)" == Decimal::from_str_exact("922337203685477.5806").unwrap(),
225+
"CAST('-922337203685477.5807' AS MONEY)" == Decimal::from_str_exact("-922337203685477.5807").unwrap(),
226+
"CAST('922337203685477.0000' AS MONEY)" == Decimal::from_str_exact("922337203685477.0000").unwrap(),
227+
"CAST('-922337203685477.0000' AS MONEY)" == Decimal::from_str_exact("-922337203685477.0000").unwrap(),
228+
));
229+
230+
test_type!(smallmoney_boundary_tests<Decimal>(
231+
Mssql,
222232
"CAST('214748.3647' AS SMALLMONEY)" == Decimal::from_str_exact("214748.3647").unwrap(),
223233
"CAST('-214748.3648' AS SMALLMONEY)" == Decimal::from_str_exact("-214748.3648").unwrap(),
234+
"CAST('214748.3646' AS SMALLMONEY)" == Decimal::from_str_exact("214748.3646").unwrap(),
235+
"CAST('-214748.3647' AS SMALLMONEY)" == Decimal::from_str_exact("-214748.3647").unwrap(),
236+
"CAST('214748.0000' AS SMALLMONEY)" == Decimal::from_str_exact("214748.0000").unwrap(),
237+
"CAST('-214748.0000' AS SMALLMONEY)" == Decimal::from_str_exact("-214748.0000").unwrap(),
238+
));
239+
240+
test_type!(money_precision_tests<Decimal>(
241+
Mssql,
242+
"CAST('0.0000' AS MONEY)" == Decimal::from_str_exact("0.0000").unwrap(),
224243
"CAST('0.0001' AS MONEY)" == Decimal::from_str_exact("0.0001").unwrap(),
225244
"CAST('-0.0001' AS MONEY)" == Decimal::from_str_exact("-0.0001").unwrap(),
226-
"CAST('0.0000' AS MONEY)" == Decimal::from_str_exact("0.0000").unwrap(),
227-
"CAST('999999999999999.9999' AS MONEY)" == Decimal::from_str_exact("999999999999999.9999").unwrap(),
228-
"CAST('-999999999999999.9999' AS MONEY)" == Decimal::from_str_exact("-999999999999999.9999").unwrap(),
245+
"CAST('0.9999' AS MONEY)" == Decimal::from_str_exact("0.9999").unwrap(),
246+
"CAST('-0.9999' AS MONEY)" == Decimal::from_str_exact("-0.9999").unwrap(),
247+
"CAST('1.0000' AS MONEY)" == Decimal::from_str_exact("1.0000").unwrap(),
248+
"CAST('-1.0000' AS MONEY)" == Decimal::from_str_exact("-1.0000").unwrap(),
249+
"CAST('2.15' AS MONEY)" == Decimal::from_str_exact("2.15").unwrap(),
250+
"CAST('214748.3647' AS SMALLMONEY)" == Decimal::from_str_exact("214748.3647").unwrap(),
251+
"CAST('922337203685477.5807' AS MONEY)" == Decimal::from_str_exact("922337203685477.5807").unwrap(),
252+
"CAST('-922337203685477.5808' AS MONEY)" == Decimal::from_str_exact("-922337203685477.5808").unwrap(),
253+
"CAST('214748.3647' AS SMALLMONEY)" == Decimal::from_str_exact("214748.3647").unwrap(),
254+
"CAST('-214748.3648' AS SMALLMONEY)" == Decimal::from_str_exact("-214748.3648").unwrap(),
229255
));
230256
}
231257

0 commit comments

Comments
 (0)