datafusion_functions/math/
ceil.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::any::Any;
19use std::sync::Arc;
20
21use arrow::array::{ArrayRef, AsArray};
22use arrow::datatypes::{
23    DataType, Decimal32Type, Decimal64Type, Decimal128Type, Decimal256Type, Float32Type,
24    Float64Type,
25};
26use datafusion_common::{Result, ScalarValue, exec_err};
27use datafusion_expr::interval_arithmetic::Interval;
28use datafusion_expr::sort_properties::{ExprProperties, SortProperties};
29use datafusion_expr::{
30    Coercion, ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
31    TypeSignature, TypeSignatureClass, Volatility,
32};
33use datafusion_macros::user_doc;
34
35use super::decimal::{apply_decimal_op, ceil_decimal_value};
36
37#[user_doc(
38    doc_section(label = "Math Functions"),
39    description = "Returns the nearest integer greater than or equal to a number.",
40    syntax_example = "ceil(numeric_expression)",
41    standard_argument(name = "numeric_expression", prefix = "Numeric"),
42    sql_example = r#"```sql
43> SELECT ceil(3.14);
44+------------+
45| ceil(3.14) |
46+------------+
47| 4.0        |
48+------------+
49```"#
50)]
51#[derive(Debug, PartialEq, Eq, Hash)]
52pub struct CeilFunc {
53    signature: Signature,
54}
55
56impl Default for CeilFunc {
57    fn default() -> Self {
58        Self::new()
59    }
60}
61
62impl CeilFunc {
63    pub fn new() -> Self {
64        let decimal_sig = Coercion::new_exact(TypeSignatureClass::Decimal);
65        Self {
66            signature: Signature::one_of(
67                vec![
68                    TypeSignature::Coercible(vec![decimal_sig]),
69                    TypeSignature::Uniform(1, vec![DataType::Float64, DataType::Float32]),
70                ],
71                Volatility::Immutable,
72            ),
73        }
74    }
75}
76
77impl ScalarUDFImpl for CeilFunc {
78    fn as_any(&self) -> &dyn Any {
79        self
80    }
81
82    fn name(&self) -> &str {
83        "ceil"
84    }
85
86    fn signature(&self) -> &Signature {
87        &self.signature
88    }
89
90    fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
91        match &arg_types[0] {
92            DataType::Null => Ok(DataType::Float64),
93            other => Ok(other.clone()),
94        }
95    }
96
97    fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
98        let args = ColumnarValue::values_to_arrays(&args.args)?;
99        let value = &args[0];
100
101        let result: ArrayRef = match value.data_type() {
102            DataType::Float64 => Arc::new(
103                value
104                    .as_primitive::<Float64Type>()
105                    .unary::<_, Float64Type>(f64::ceil),
106            ),
107            DataType::Float32 => Arc::new(
108                value
109                    .as_primitive::<Float32Type>()
110                    .unary::<_, Float32Type>(f32::ceil),
111            ),
112            DataType::Null => {
113                return Ok(ColumnarValue::Scalar(ScalarValue::Float64(None)));
114            }
115            DataType::Decimal32(precision, scale) => {
116                apply_decimal_op::<Decimal32Type, _>(
117                    value,
118                    *precision,
119                    *scale,
120                    self.name(),
121                    ceil_decimal_value,
122                )?
123            }
124            DataType::Decimal64(precision, scale) => {
125                apply_decimal_op::<Decimal64Type, _>(
126                    value,
127                    *precision,
128                    *scale,
129                    self.name(),
130                    ceil_decimal_value,
131                )?
132            }
133            DataType::Decimal128(precision, scale) => {
134                apply_decimal_op::<Decimal128Type, _>(
135                    value,
136                    *precision,
137                    *scale,
138                    self.name(),
139                    ceil_decimal_value,
140                )?
141            }
142            DataType::Decimal256(precision, scale) => {
143                apply_decimal_op::<Decimal256Type, _>(
144                    value,
145                    *precision,
146                    *scale,
147                    self.name(),
148                    ceil_decimal_value,
149                )?
150            }
151            other => {
152                return exec_err!(
153                    "Unsupported data type {other:?} for function {}",
154                    self.name()
155                );
156            }
157        };
158
159        Ok(ColumnarValue::Array(result))
160    }
161
162    fn output_ordering(&self, input: &[ExprProperties]) -> Result<SortProperties> {
163        Ok(input[0].sort_properties)
164    }
165
166    fn evaluate_bounds(&self, inputs: &[&Interval]) -> Result<Interval> {
167        let data_type = inputs[0].data_type();
168        Interval::make_unbounded(&data_type)
169    }
170
171    fn documentation(&self) -> Option<&Documentation> {
172        self.doc()
173    }
174}