use crate::errors::ExecutorError;
pub(in crate::evaluator::functions) fn concat(
args: &[vibesql_types::SqlValue],
sql_mode: &vibesql_types::SqlMode,
) -> Result<vibesql_types::SqlValue, ExecutorError> {
if args.is_empty() {
return Err(ExecutorError::WrongNumberOfArguments { function_name: "concat".to_string() });
}
if matches!(sql_mode, vibesql_types::SqlMode::MySQL { .. }) {
for arg in args {
if matches!(arg, vibesql_types::SqlValue::Null) {
return Ok(vibesql_types::SqlValue::Null);
}
}
}
let mut result = String::new();
for arg in args {
match arg {
vibesql_types::SqlValue::Null => {
continue;
}
vibesql_types::SqlValue::Varchar(s) | vibesql_types::SqlValue::Character(s) => {
result.push_str(s);
}
vibesql_types::SqlValue::Integer(n) => result.push_str(&n.to_string()),
vibesql_types::SqlValue::Bigint(n) => result.push_str(&n.to_string()),
vibesql_types::SqlValue::Smallint(n) => result.push_str(&n.to_string()),
vibesql_types::SqlValue::Numeric(n) => result.push_str(&format_number(*n)),
vibesql_types::SqlValue::Double(n) => result.push_str(&format_number(*n)),
vibesql_types::SqlValue::Real(n) => result.push_str(&format_number(*n)),
vibesql_types::SqlValue::Float(n) => result.push_str(&format_number(*n as f64)),
vibesql_types::SqlValue::Boolean(b) => {
result.push_str(if *b { "1" } else { "0" });
}
vibesql_types::SqlValue::Blob(bytes) => {
result.push_str(&String::from_utf8_lossy(bytes));
}
_ => {
result.push_str(&arg.to_string());
}
}
}
Ok(vibesql_types::SqlValue::Varchar(arcstr::ArcStr::from(result)))
}
fn format_number(n: f64) -> String {
if n.fract() == 0.0 && n.abs() < 1e15 {
format!("{}", n as i64)
} else {
n.to_string()
}
}