Skip to content

Commit 8bc889f

Browse files
authored
Fix the null handling for to_char function (#14908)
* fix: handle null inputs in to_char function and add corresponding tests * fix: return null Utf8 result for null date/time inputs in to_char function * add comment fix issue * refactor: remove redundant test for null date input in to_char function
1 parent 58330b6 commit 8bc889f

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

datafusion/functions/src/datetime/to_char.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,14 @@ fn _to_char_scalar(
212212
let is_scalar_expression = matches!(&expression, ColumnarValue::Scalar(_));
213213
let array = expression.into_array(1)?;
214214

215+
// fix https://github.com/apache/datafusion/issues/14884
216+
// If the input date/time is null, return a null Utf8 result.
217+
if array.is_null(0) {
218+
return Ok(match is_scalar_expression {
219+
true => ColumnarValue::Scalar(ScalarValue::Utf8(None)),
220+
false => ColumnarValue::Array(new_null_array(&Utf8, array.len())),
221+
});
222+
}
215223
if format.is_none() {
216224
if is_scalar_expression {
217225
return Ok(ColumnarValue::Scalar(ScalarValue::Utf8(None)));
@@ -252,6 +260,13 @@ fn _to_char_array(args: &[ColumnarValue]) -> Result<ColumnarValue> {
252260
let data_type = arrays[0].data_type();
253261

254262
for idx in 0..arrays[0].len() {
263+
// fix https://github.com/apache/datafusion/issues/14884
264+
// If the date/time value is null, push None.
265+
if arrays[0].is_null(idx) {
266+
results.push(None);
267+
continue;
268+
}
269+
255270
let format = if format_array.is_null(idx) {
256271
None
257272
} else {
@@ -663,4 +678,31 @@ mod tests {
663678
"Execution error: Format for `to_char` must be non-null Utf8, received Timestamp(Nanosecond, None)"
664679
);
665680
}
681+
682+
#[test]
683+
fn test_to_char_input_none_array() {
684+
let date_array = Arc::new(Date32Array::from(vec![Some(18506), None])) as ArrayRef;
685+
let format_array =
686+
StringArray::from(vec!["%Y-%m-%d".to_string(), "%Y-%m-%d".to_string()]);
687+
let args = datafusion_expr::ScalarFunctionArgs {
688+
args: vec![
689+
ColumnarValue::Array(date_array),
690+
ColumnarValue::Array(Arc::new(format_array) as ArrayRef),
691+
],
692+
number_rows: 2,
693+
return_type: &DataType::Utf8,
694+
};
695+
let result = ToCharFunc::new()
696+
.invoke_with_args(args)
697+
.expect("Expected no error");
698+
if let ColumnarValue::Array(result) = result {
699+
let result = result.as_any().downcast_ref::<StringArray>().unwrap();
700+
assert_eq!(result.len(), 2);
701+
// The first element is valid, second is null.
702+
assert!(!result.is_null(0));
703+
assert!(result.is_null(1));
704+
} else {
705+
panic!("Expected an array value");
706+
}
707+
}
666708
}

datafusion/sqllogictest/test_files/timestamps.slt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2845,7 +2845,7 @@ NULL
28452845
query T
28462846
SELECT to_char(null, '%d-%m-%Y');
28472847
----
2848-
(empty)
2848+
NULL
28492849

28502850
query T
28512851
SELECT to_char(column1, column2)

0 commit comments

Comments
 (0)