Skip to content

Commit

Permalink
Update CONCAT function behavior - concat with null to return NULL (#899)
Browse files Browse the repository at this point in the history
  • Loading branch information
seonghun-dev authored Oct 22, 2022
1 parent e0d645c commit c674625
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 14 deletions.
31 changes: 23 additions & 8 deletions core/src/executor/evaluate/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use {
data::Value,
result::Result,
},
std::cmp::{max, min},
std::{
cmp::{max, min},
ops::ControlFlow,
},
uuid::Uuid,
};

Expand Down Expand Up @@ -55,13 +58,25 @@ macro_rules! eval_to_float {
// --- text ---

pub fn concat(exprs: Vec<Evaluated<'_>>) -> Result<Value> {
exprs
.into_iter()
.map(|expr| expr.try_into())
.filter(|value| !matches!(value, Ok(Value::Null)))
.try_fold(Value::Str("".to_owned()), |left, right| {
Ok(left.concat(&right?))
})
enum BreakCase {
Null,
Err(crate::result::Error),
}

let control_flow = exprs.into_iter().map(|expr| expr.try_into()).try_fold(
Value::Str(String::new()),
|left, right: Result<Value>| match right {
Ok(value) if value.is_null() => ControlFlow::Break(BreakCase::Null),
Err(err) => ControlFlow::Break(BreakCase::Err(err)),
Ok(value) => ControlFlow::Continue(left.concat(&value)),
},
);

match control_flow {
ControlFlow::Continue(value) => Ok(value),
ControlFlow::Break(BreakCase::Null) => Ok(Value::Null),
ControlFlow::Break(BreakCase::Err(err)) => Err(err),
}
}

pub fn lower(name: String, expr: Evaluated<'_>) -> Result<Value> {
Expand Down
24 changes: 18 additions & 6 deletions test-suite/src/function/concat.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::*,
gluesql_core::{prelude::Value::*, translate::TranslateError},
gluesql_core::{data::ValueError, prelude::Value::*, translate::TranslateError},
};

test_case!(concat, async move {
Expand Down Expand Up @@ -37,12 +37,24 @@ test_case!(concat, async move {

test!(
r#"select concat("ab", "cd", NULL, "ef") as myconcat from Concat;"#,
Ok(select!(
myconcat
Str;
"abcdef".to_owned()
))
Ok(select_with_null!(myconcat; Null))
);

test!(
r#"select concat() as myconcat from Concat;"#,
Err(TranslateError::FunctionArgsLengthNotMatchingMin {
name: "CONCAT".to_owned(),
expected_minimum: 1,
found: 0
}
.into())
);

test!(
r#"select concat(DATE "2020-06-11", DATE "2020-16-3") as myconcat from Concat;"#,
Err(ValueError::FailedToParseDate("2020-16-3".to_owned()).into())
);

// test with non string arguments
test!(
r#"select concat(123, 456, 3.14) as myconcat from Concat;"#,
Expand Down

0 comments on commit c674625

Please sign in to comment.