diff --git a/core/error.rs b/core/error.rs index ca495eb99..64a6e6912 100644 --- a/core/error.rs +++ b/core/error.rs @@ -45,6 +45,8 @@ pub enum LimboError { ExtensionError(String), #[error("Unbound parameter at index {0}")] Unbound(NonZero), + #[error("Runtime error: {0}")] + RuntimeError(String), } #[macro_export] diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index c472da4ec..3b7e4d01a 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -1880,7 +1880,7 @@ impl Program { let reg_value = state.registers[*start_reg].borrow_mut(); let result = match scalar_func { ScalarFunc::Sign => exec_sign(reg_value), - ScalarFunc::Abs => exec_abs(reg_value), + ScalarFunc::Abs => Some(exec_abs(reg_value)?), ScalarFunc::Lower => exec_lower(reg_value), ScalarFunc::Upper => exec_upper(reg_value), ScalarFunc::Length => Some(exec_length(reg_value)), @@ -2705,24 +2705,29 @@ pub fn exec_soundex(reg: &OwnedValue) -> OwnedValue { OwnedValue::build_text(Rc::new(result.to_uppercase())) } -fn exec_abs(reg: &OwnedValue) -> Option { +fn exec_abs(reg: &OwnedValue) -> Result { match reg { OwnedValue::Integer(x) => { + if *x == i64::MIN { + // Special case: if we do the abs of "-9223372036854775808", it causes overflow. + // return RuntimeError + return Err(LimboError::RuntimeError("integer overflow".to_string())); + } if x < &0 { - Some(OwnedValue::Integer(-x)) + Ok(OwnedValue::Integer(-x)) } else { - Some(OwnedValue::Integer(*x)) + Ok(OwnedValue::Integer(*x)) } } OwnedValue::Float(x) => { if x < &0.0 { - Some(OwnedValue::Float(-x)) + Ok(OwnedValue::Float(-x)) } else { - Some(OwnedValue::Float(*x)) + Ok(OwnedValue::Float(*x)) } } - OwnedValue::Null => Some(OwnedValue::Null), - _ => Some(OwnedValue::Float(0.0)), + OwnedValue::Null => Ok(OwnedValue::Null), + _ => Ok(OwnedValue::Float(0.0)), } } @@ -3755,6 +3760,9 @@ mod tests { OwnedValue::Float(0.0) ); assert_eq!(exec_abs(&OwnedValue::Null).unwrap(), OwnedValue::Null); + + // ABS(i64::MIN) should return RuntimeError + assert!(exec_abs(&OwnedValue::Integer(i64::MIN)).is_err()); } #[test]