common_function/scalars/timestamp/
greatest.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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}