datafusion_spark/function/datetime/
date_add.rs1use std::any::Any;
19use std::sync::Arc;
20
21use arrow::array::ArrayRef;
22use arrow::compute;
23use arrow::datatypes::{DataType, Date32Type};
24use datafusion_common::cast::{
25 as_date32_array, as_int16_array, as_int32_array, as_int8_array,
26};
27use datafusion_common::{internal_err, Result};
28use datafusion_expr::{
29 ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature, TypeSignature,
30 Volatility,
31};
32use datafusion_functions::utils::make_scalar_function;
33
34#[derive(Debug, PartialEq, Eq, Hash)]
35pub struct SparkDateAdd {
36 signature: Signature,
37 aliases: Vec<String>,
38}
39
40impl Default for SparkDateAdd {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl SparkDateAdd {
47 pub fn new() -> Self {
48 Self {
49 signature: Signature::one_of(
50 vec![
51 TypeSignature::Exact(vec![DataType::Date32, DataType::Int8]),
52 TypeSignature::Exact(vec![DataType::Date32, DataType::Int16]),
53 TypeSignature::Exact(vec![DataType::Date32, DataType::Int32]),
54 ],
55 Volatility::Immutable,
56 ),
57 aliases: vec!["dateadd".to_string()],
58 }
59 }
60}
61
62impl ScalarUDFImpl for SparkDateAdd {
63 fn as_any(&self) -> &dyn Any {
64 self
65 }
66
67 fn name(&self) -> &str {
68 "date_add"
69 }
70
71 fn aliases(&self) -> &[String] {
72 &self.aliases
73 }
74
75 fn signature(&self) -> &Signature {
76 &self.signature
77 }
78
79 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
80 Ok(DataType::Date32)
81 }
82
83 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
84 make_scalar_function(spark_date_add, vec![])(&args.args)
85 }
86}
87
88fn spark_date_add(args: &[ArrayRef]) -> Result<ArrayRef> {
89 let [date_arg, days_arg] = args else {
90 return internal_err!(
91 "Spark `date_add` function requires 2 arguments, got {}",
92 args.len()
93 );
94 };
95 let date_array = as_date32_array(date_arg)?;
96 let result = match days_arg.data_type() {
97 DataType::Int8 => {
98 let days_array = as_int8_array(days_arg)?;
99 compute::binary::<_, _, _, Date32Type>(
100 date_array,
101 days_array,
102 |date, days| date + days as i32,
103 )?
104 }
105 DataType::Int16 => {
106 let days_array = as_int16_array(days_arg)?;
107 compute::binary::<_, _, _, Date32Type>(
108 date_array,
109 days_array,
110 |date, days| date + days as i32,
111 )?
112 }
113 DataType::Int32 => {
114 let days_array = as_int32_array(days_arg)?;
115 compute::binary::<_, _, _, Date32Type>(
116 date_array,
117 days_array,
118 |date, days| date + days,
119 )?
120 }
121 _ => {
122 return internal_err!(
123 "Spark `date_add` function: argument must be int8, int16, int32, got {:?}",
124 days_arg.data_type()
125 );
126 }
127 };
128 Ok(Arc::new(result))
129}