use vibesql_types::SqlValue;
use crate::errors::ExecutorError;
use crate::evaluator::functions::coercion::coerce_to_number;
pub fn abs(args: &[SqlValue]) -> Result<SqlValue, ExecutorError> {
if args.len() != 1 {
return Err(ExecutorError::UnsupportedFeature(format!(
"ABS requires exactly 1 argument, got {}",
args.len()
)));
}
match &args[0] {
SqlValue::Null => return Ok(SqlValue::Null),
SqlValue::Integer(n) => {
return n.checked_abs().map(SqlValue::Integer).ok_or(ExecutorError::IntegerOverflow);
}
SqlValue::Bigint(n) => {
return n.checked_abs().map(SqlValue::Bigint).ok_or(ExecutorError::IntegerOverflow);
}
SqlValue::Smallint(n) => {
return n.checked_abs().map(SqlValue::Smallint).ok_or(ExecutorError::IntegerOverflow);
}
SqlValue::Float(n) => return Ok(SqlValue::Float(n.abs())),
SqlValue::Double(n) => return Ok(SqlValue::Double(n.abs())),
SqlValue::Real(n) => return Ok(SqlValue::Real(n.abs())),
SqlValue::Numeric(n) => return Ok(SqlValue::Numeric(n.abs())),
SqlValue::Unsigned(n) => return Ok(SqlValue::Unsigned(*n)), _ => {}
}
match coerce_to_number(&args[0]) {
None => Ok(SqlValue::Null),
Some(n) => Ok(SqlValue::Double(n.abs())),
}
}
pub fn sign(args: &[SqlValue]) -> Result<SqlValue, ExecutorError> {
if args.len() != 1 {
return Err(ExecutorError::UnsupportedFeature(format!(
"SIGN requires exactly 1 argument, got {}",
args.len()
)));
}
match &args[0] {
SqlValue::Null => return Ok(SqlValue::Null),
SqlValue::Integer(n) => {
let sign = match n.cmp(&0) {
std::cmp::Ordering::Less => -1,
std::cmp::Ordering::Greater => 1,
std::cmp::Ordering::Equal => 0,
};
return Ok(SqlValue::Integer(sign));
}
SqlValue::Bigint(n) => {
let sign = match n.cmp(&0) {
std::cmp::Ordering::Less => -1,
std::cmp::Ordering::Greater => 1,
std::cmp::Ordering::Equal => 0,
};
return Ok(SqlValue::Bigint(sign));
}
SqlValue::Smallint(n) => {
let sign: i16 = match n.cmp(&0) {
std::cmp::Ordering::Less => -1,
std::cmp::Ordering::Greater => 1,
std::cmp::Ordering::Equal => 0,
};
return Ok(SqlValue::Smallint(sign));
}
SqlValue::Float(n) => {
let sign = if *n < 0.0 {
-1.0
} else if *n > 0.0 {
1.0
} else {
0.0
};
return Ok(SqlValue::Float(sign));
}
SqlValue::Double(n) => {
let sign = if *n < 0.0 {
-1.0
} else if *n > 0.0 {
1.0
} else {
0.0
};
return Ok(SqlValue::Double(sign));
}
SqlValue::Real(n) => {
let sign = if *n < 0.0 {
-1.0
} else if *n > 0.0 {
1.0
} else {
0.0
};
return Ok(SqlValue::Real(sign));
}
SqlValue::Numeric(n) => {
let sign = if *n < 0.0 {
-1.0
} else if *n > 0.0 {
1.0
} else {
0.0
};
return Ok(SqlValue::Numeric(sign));
}
SqlValue::Unsigned(n) => {
let sign: u64 = if *n > 0 { 1 } else { 0 };
return Ok(SqlValue::Unsigned(sign));
}
_ => {}
}
match coerce_to_number(&args[0]) {
None => Ok(SqlValue::Null),
Some(n) => {
let sign = if n < 0.0 {
-1.0
} else if n > 0.0 {
1.0
} else {
0.0
};
Ok(SqlValue::Double(sign))
}
}
}
pub fn mod_fn(args: &[SqlValue]) -> Result<SqlValue, ExecutorError> {
if args.len() != 2 {
return Err(ExecutorError::UnsupportedFeature(format!(
"MOD requires exactly 2 arguments, got {}",
args.len()
)));
}
match (&args[0], &args[1]) {
(SqlValue::Null, _) | (_, SqlValue::Null) => return Ok(SqlValue::Null),
(SqlValue::Integer(x), SqlValue::Integer(y)) => {
if *y == 0 {
return Ok(SqlValue::Null);
}
return Ok(SqlValue::Integer(x % y));
}
(SqlValue::Float(x), SqlValue::Float(y)) => {
if *y == 0.0 {
return Ok(SqlValue::Null);
}
return Ok(SqlValue::Float(x % y));
}
(SqlValue::Real(x), SqlValue::Real(y)) => {
if *y == 0.0 {
return Ok(SqlValue::Null);
}
return Ok(SqlValue::Real(x % y));
}
_ => {}
}
let x = match coerce_to_number(&args[0]) {
Some(n) => n,
None => return Ok(SqlValue::Null),
};
let y = match coerce_to_number(&args[1]) {
Some(n) => n,
None => return Ok(SqlValue::Null),
};
if y == 0.0 {
return Ok(SqlValue::Null);
}
Ok(SqlValue::Double(x % y))
}
pub fn pi(_args: &[SqlValue]) -> Result<SqlValue, ExecutorError> {
Ok(SqlValue::Double(std::f64::consts::PI))
}