common_function/scalars/timestamp/
greatest.rs1use std::fmt::{self};
16
17use common_query::error::{
18 self, ArrowComputeSnafu, InvalidFuncArgsSnafu, Result, UnsupportedInputDataTypeSnafu,
19};
20use common_query::prelude::{Signature, Volatility};
21use datafusion::arrow::compute::kernels::cmp::gt;
22use datatypes::arrow::array::AsArray;
23use datatypes::arrow::compute::cast;
24use datatypes::arrow::compute::kernels::zip;
25use datatypes::arrow::datatypes::{
26 DataType as ArrowDataType, Date32Type, TimeUnit, TimestampMicrosecondType,
27 TimestampMillisecondType, TimestampNanosecondType, TimestampSecondType,
28};
29use datatypes::prelude::ConcreteDataType;
30use datatypes::types::TimestampType;
31use datatypes::vectors::{Helper, VectorRef};
32use snafu::{ensure, ResultExt};
33
34use crate::function::{Function, FunctionContext};
35
36#[derive(Clone, Debug, Default)]
37pub struct GreatestFunction;
38
39const NAME: &str = "greatest";
40
41macro_rules! gt_time_types {
42 ($ty: ident, $columns:expr) => {{
43 let column1 = $columns[0].to_arrow_array();
44 let column2 = $columns[1].to_arrow_array();
45
46 let column1 = column1.as_primitive::<$ty>();
47 let column2 = column2.as_primitive::<$ty>();
48 let boolean_array = gt(&column1, &column2).context(ArrowComputeSnafu)?;
49
50 let result = zip::zip(&boolean_array, &column1, &column2).context(ArrowComputeSnafu)?;
51 Helper::try_into_vector(&result).context(error::FromArrowArraySnafu)
52 }};
53}
54
55impl Function for GreatestFunction {
56 fn name(&self) -> &str {
57 NAME
58 }
59
60 fn return_type(&self, input_types: &[ConcreteDataType]) -> Result<ConcreteDataType> {
61 ensure!(
62 input_types.len() == 2,
63 InvalidFuncArgsSnafu {
64 err_msg: format!(
65 "The length of the args is not correct, expect exactly two, have: {}",
66 input_types.len()
67 )
68 }
69 );
70
71 match &input_types[0] {
72 ConcreteDataType::String(_) => Ok(ConcreteDataType::timestamp_millisecond_datatype()),
73 ConcreteDataType::Date(_) => Ok(ConcreteDataType::date_datatype()),
74 ConcreteDataType::Timestamp(ts_type) => Ok(ConcreteDataType::Timestamp(*ts_type)),
75 _ => UnsupportedInputDataTypeSnafu {
76 function: NAME,
77 datatypes: input_types,
78 }
79 .fail(),
80 }
81 }
82
83 fn signature(&self) -> Signature {
84 Signature::uniform(
85 2,
86 vec![
87 ConcreteDataType::string_datatype(),
88 ConcreteDataType::date_datatype(),
89 ConcreteDataType::timestamp_nanosecond_datatype(),
90 ConcreteDataType::timestamp_microsecond_datatype(),
91 ConcreteDataType::timestamp_millisecond_datatype(),
92 ConcreteDataType::timestamp_second_datatype(),
93 ],
94 Volatility::Immutable,
95 )
96 }
97
98 fn eval(&self, _func_ctx: &FunctionContext, columns: &[VectorRef]) -> Result<VectorRef> {
99 ensure!(
100 columns.len() == 2,
101 InvalidFuncArgsSnafu {
102 err_msg: format!(
103 "The length of the args is not correct, expect exactly two, have: {}",
104 columns.len()
105 ),
106 }
107 );
108 match columns[0].data_type() {
109 ConcreteDataType::String(_) => {
110 let column1 = cast(
111 &columns[0].to_arrow_array(),
112 &ArrowDataType::Timestamp(TimeUnit::Millisecond, None),
113 )
114 .context(ArrowComputeSnafu)?;
115 let column1 = column1.as_primitive::<TimestampMillisecondType>();
116 let column2 = cast(
117 &columns[1].to_arrow_array(),
118 &ArrowDataType::Timestamp(TimeUnit::Millisecond, None),
119 )
120 .context(ArrowComputeSnafu)?;
121 let column2 = column2.as_primitive::<TimestampMillisecondType>();
122 let boolean_array = gt(&column1, &column2).context(ArrowComputeSnafu)?;
123 let result =
124 zip::zip(&boolean_array, &column1, &column2).context(ArrowComputeSnafu)?;
125 Ok(Helper::try_into_vector(&result).context(error::FromArrowArraySnafu)?)
126 }
127 ConcreteDataType::Date(_) => gt_time_types!(Date32Type, columns),
128 ConcreteDataType::Timestamp(ts_type) => match ts_type {
129 TimestampType::Second(_) => gt_time_types!(TimestampSecondType, columns),
130 TimestampType::Millisecond(_) => {
131 gt_time_types!(TimestampMillisecondType, columns)
132 }
133 TimestampType::Microsecond(_) => {
134 gt_time_types!(TimestampMicrosecondType, columns)
135 }
136 TimestampType::Nanosecond(_) => {
137 gt_time_types!(TimestampNanosecondType, columns)
138 }
139 },
140 _ => UnsupportedInputDataTypeSnafu {
141 function: NAME,
142 datatypes: columns.iter().map(|c| c.data_type()).collect::<Vec<_>>(),
143 }
144 .fail(),
145 }
146 }
147}
148
149impl fmt::Display for GreatestFunction {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 write!(f, "GREATEST")
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use std::sync::Arc;
158
159 use common_time::timestamp::TimeUnit;
160 use common_time::{Date, Timestamp};
161 use datatypes::types::{
162 DateType, TimestampMicrosecondType, TimestampMillisecondType, TimestampNanosecondType,
163 TimestampSecondType,
164 };
165 use datatypes::value::Value;
166 use datatypes::vectors::{
167 DateVector, StringVector, TimestampMicrosecondVector, TimestampMillisecondVector,
168 TimestampNanosecondVector, TimestampSecondVector, Vector,
169 };
170 use paste::paste;
171
172 use super::*;
173 #[test]
174 fn test_greatest_takes_string_vector() {
175 let function = GreatestFunction;
176 assert_eq!(
177 function
178 .return_type(&[
179 ConcreteDataType::string_datatype(),
180 ConcreteDataType::string_datatype()
181 ])
182 .unwrap(),
183 ConcreteDataType::timestamp_millisecond_datatype()
184 );
185 let columns = vec![
186 Arc::new(StringVector::from(vec![
187 "1970-01-01".to_string(),
188 "2012-12-23".to_string(),
189 ])) as _,
190 Arc::new(StringVector::from(vec![
191 "2001-02-01".to_string(),
192 "1999-01-01".to_string(),
193 ])) as _,
194 ];
195
196 let result = function
197 .eval(&FunctionContext::default(), &columns)
198 .unwrap();
199 let result = result
200 .as_any()
201 .downcast_ref::<TimestampMillisecondVector>()
202 .unwrap();
203 assert_eq!(result.len(), 2);
204 assert_eq!(
205 result.get(0),
206 Value::Timestamp(Timestamp::from_str("2001-02-01 00:00:00", None).unwrap())
207 );
208 assert_eq!(
209 result.get(1),
210 Value::Timestamp(Timestamp::from_str("2012-12-23 00:00:00", None).unwrap())
211 );
212 }
213
214 #[test]
215 fn test_greatest_takes_date_vector() {
216 let function = GreatestFunction;
217 assert_eq!(
218 function
219 .return_type(&[
220 ConcreteDataType::date_datatype(),
221 ConcreteDataType::date_datatype()
222 ])
223 .unwrap(),
224 ConcreteDataType::Date(DateType)
225 );
226
227 let columns = vec![
228 Arc::new(DateVector::from_slice(vec![-1, 2])) as _,
229 Arc::new(DateVector::from_slice(vec![0, 1])) as _,
230 ];
231
232 let result = function
233 .eval(&FunctionContext::default(), &columns)
234 .unwrap();
235 let result = result.as_any().downcast_ref::<DateVector>().unwrap();
236 assert_eq!(result.len(), 2);
237 assert_eq!(
238 result.get(0),
239 Value::Date(Date::from_str_utc("1970-01-01").unwrap())
240 );
241 assert_eq!(
242 result.get(1),
243 Value::Date(Date::from_str_utc("1970-01-03").unwrap())
244 );
245 }
246
247 #[test]
248 fn test_greatest_takes_datetime_vector() {
249 let function = GreatestFunction;
250 assert_eq!(
251 function
252 .return_type(&[
253 ConcreteDataType::timestamp_millisecond_datatype(),
254 ConcreteDataType::timestamp_millisecond_datatype()
255 ])
256 .unwrap(),
257 ConcreteDataType::timestamp_millisecond_datatype()
258 );
259
260 let columns = vec![
261 Arc::new(TimestampMillisecondVector::from_slice(vec![-1, 2])) as _,
262 Arc::new(TimestampMillisecondVector::from_slice(vec![0, 1])) as _,
263 ];
264
265 let result = function
266 .eval(&FunctionContext::default(), &columns)
267 .unwrap();
268 let result = result
269 .as_any()
270 .downcast_ref::<TimestampMillisecondVector>()
271 .unwrap();
272 assert_eq!(result.len(), 2);
273 assert_eq!(
274 result.get(0),
275 Value::Timestamp(Timestamp::from_str("1970-01-01 00:00:00", None).unwrap())
276 );
277 assert_eq!(
278 result.get(1),
279 Value::Timestamp(Timestamp::from_str("1970-01-01 00:00:00.002", None).unwrap())
280 );
281 }
282
283 macro_rules! test_timestamp {
284 ($type: expr,$unit: ident) => {
285 paste! {
286 #[test]
287 fn [<test_greatest_takes_ $unit:lower _vector>]() {
288 let function = GreatestFunction;
289 assert_eq!(
290 function.return_type(&[$type, $type]).unwrap(),
291 ConcreteDataType::Timestamp(TimestampType::$unit([<Timestamp $unit Type>]))
292 );
293
294 let columns = vec![
295 Arc::new([<Timestamp $unit Vector>]::from_slice(vec![-1, 2])) as _,
296 Arc::new([<Timestamp $unit Vector>]::from_slice(vec![0, 1])) as _,
297 ];
298
299 let result = function.eval(&FunctionContext::default(), &columns).unwrap();
300 let result = result.as_any().downcast_ref::<[<Timestamp $unit Vector>]>().unwrap();
301 assert_eq!(result.len(), 2);
302 assert_eq!(
303 result.get(0),
304 Value::Timestamp(Timestamp::new(0, TimeUnit::$unit))
305 );
306 assert_eq!(
307 result.get(1),
308 Value::Timestamp(Timestamp::new(2, TimeUnit::$unit))
309 );
310 }
311 }
312 }
313 }
314
315 test_timestamp!(
316 ConcreteDataType::timestamp_nanosecond_datatype(),
317 Nanosecond
318 );
319 test_timestamp!(
320 ConcreteDataType::timestamp_microsecond_datatype(),
321 Microsecond
322 );
323 test_timestamp!(
324 ConcreteDataType::timestamp_millisecond_datatype(),
325 Millisecond
326 );
327 test_timestamp!(ConcreteDataType::timestamp_second_datatype(), Second);
328}