handle int64 overflow by f64

This commit is contained in:
meteorgan 2025-05-08 22:22:55 +08:00
parent ef3f004e30
commit a1f981a973
2 changed files with 15 additions and 25 deletions

View file

@ -888,8 +888,11 @@ pub fn checked_cast_text_to_numeric(text: &str) -> std::result::Result<OwnedValu
e.kind(), e.kind(),
std::num::IntErrorKind::PosOverflow | std::num::IntErrorKind::NegOverflow std::num::IntErrorKind::PosOverflow | std::num::IntErrorKind::NegOverflow
) { ) {
let value = convert_overflow_i64_to_f64(text); // if overflow, we return the representation as a real.
Ok(OwnedValue::Float(value)) // we have to match sqlite exactly here, so we match sqlite3AtoF
let value = text.parse::<f64>().unwrap_or_default();
let factor = 10f64.powi(15 - value.abs().log10().ceil() as i32);
Ok(OwnedValue::Float((value * factor).round() / factor))
} else { } else {
Err(()) Err(())
} }
@ -902,14 +905,6 @@ pub fn checked_cast_text_to_numeric(text: &str) -> std::result::Result<OwnedValu
} }
} }
// if value overflow, we return the representation as a real.
// we have to match sqlite exactly here, so we match sqlite3AtoF
fn convert_overflow_i64_to_f64(value: &str) -> f64 {
let value = value.parse::<f64>().unwrap_or_default();
let factor = 10f64.powi(15 - value.abs().log10().ceil() as i32);
(value * factor).round() / factor
}
fn parse_numeric_str(text: &str) -> Result<(OwnedValueType, &str), ()> { fn parse_numeric_str(text: &str) -> Result<(OwnedValueType, &str), ()> {
let text = text.trim(); let text = text.trim();
let bytes = text.as_bytes(); let bytes = text.as_bytes();
@ -994,20 +989,11 @@ pub fn parse_numeric_literal(text: &str) -> Result<OwnedValue> {
} }
return Ok(OwnedValue::Integer(-value)); return Ok(OwnedValue::Integer(-value));
} }
match text.parse::<i64>() { if let Ok(int_value) = text.parse::<i64>() {
Ok(value) => return Ok(OwnedValue::Integer(value)), return Ok(OwnedValue::Integer(int_value));
Err(e)
if matches!(
e.kind(),
std::num::IntErrorKind::PosOverflow | std::num::IntErrorKind::NegOverflow
) =>
{
let value = convert_overflow_i64_to_f64(&text);
return Ok(OwnedValue::Float(value));
}
_ => {}
} }
let float_value = text.parse::<f64>()?; let float_value = text.parse::<f64>()?;
Ok(OwnedValue::Float(float_value)) Ok(OwnedValue::Float(float_value))
} }
@ -2042,12 +2028,12 @@ pub mod tests {
// > i64::MAX, convert to float // > i64::MAX, convert to float
assert_eq!( assert_eq!(
parse_numeric_literal("9223372036854775808").unwrap(), parse_numeric_literal("9223372036854775808").unwrap(),
OwnedValue::Float(9.22337203685478e+18) OwnedValue::Float(9.223372036854775808e+18)
); );
// < i64::MIN, convert to float // < i64::MIN, convert to float
assert_eq!( assert_eq!(
parse_numeric_literal("-9223372036854775809").unwrap(), parse_numeric_literal("-9223372036854775809").unwrap(),
OwnedValue::Float(-9.22337203685478e+18) OwnedValue::Float(-9.223372036854775809e+18)
); );
} }
} }

View file

@ -63,6 +63,10 @@ do_execsql_test numberic-literal-exceed-max-i64 {
SELECT 9_223_372_036_854_775_808; SELECT 9_223_372_036_854_775_808;
} {9.22337203685478e+18} } {9.22337203685478e+18}
do_execsql_test numberic-literal-exceed-min-i64 {
SELECT -9_223_372_036_854_775_809;
} {-9.22337203685478e+18}
do_execsql_test_any_error invalid-numberic-literal-1 { do_execsql_test_any_error invalid-numberic-literal-1 {
SELECT 0xFF__FF; SELECT 0xFF__FF;
} }