use vibesql_types::SqlValue;
use super::coerce_numeric_values;
use crate::errors::ExecutorError;
pub struct Modulo;
impl Modulo {
#[inline]
pub fn modulo(left: &SqlValue, right: &SqlValue) -> Result<SqlValue, ExecutorError> {
use SqlValue::*;
if matches!(left, Null) || matches!(right, Null) {
return Ok(Null);
}
if let (Integer(a), Integer(b)) = (left, right) {
if *b == 0 {
return Ok(SqlValue::Null);
}
if *a == i64::MIN && *b == -1 {
return Ok(Integer(0));
}
return Ok(Integer(a % b));
}
let coerced = coerce_numeric_values(left, right, "%")?;
let is_zero = match &coerced {
super::CoercedValues::ExactNumeric(_, right) => *right == 0,
super::CoercedValues::ApproximateNumeric(_, right) => *right == 0.0,
super::CoercedValues::Numeric(_, right) => *right == 0.0,
};
if is_zero {
return Ok(SqlValue::Null);
}
match coerced {
super::CoercedValues::ExactNumeric(a, b) => {
if a == i64::MIN && b == -1 {
Ok(Integer(0))
} else {
Ok(Integer(a % b))
}
}
super::CoercedValues::ApproximateNumeric(a, b) => Ok(Float((a % b) as f32)),
super::CoercedValues::Numeric(a, b) => Ok(Numeric(a % b)),
}
}
}