@@ -22,10 +22,11 @@ use arrow::array::{
2222 Int32Array , Int64Array ,
2323} ;
2424use arrow:: compute:: kernels:: arity:: unary;
25- use arrow:: datatypes:: DataType ;
26- use datafusion_common:: { DataFusionError , ScalarValue } ;
25+ use arrow:: datatypes:: { DataType , Field , FieldRef } ;
26+ use datafusion_common:: { DataFusionError , ScalarValue , internal_err } ;
2727use datafusion_expr:: {
28- ColumnarValue , ScalarFunctionArgs , ScalarUDFImpl , Signature , Volatility ,
28+ ColumnarValue , ReturnFieldArgs , ScalarFunctionArgs , ScalarUDFImpl , Signature ,
29+ Volatility ,
2930} ;
3031use std:: any:: Any ;
3132use std:: sync:: Arc ;
@@ -62,17 +63,32 @@ pub fn spark_ceil(args: &[ColumnarValue]) -> Result<ColumnarValue, DataFusionErr
6263 Ok ( ColumnarValue :: Array ( result?) )
6364 }
6465 DataType :: Int8 => {
65- let input = array. as_any ( ) . downcast_ref :: < Int8Array > ( ) . unwrap ( ) ;
66+ let input =
67+ array. as_any ( ) . downcast_ref :: < Int8Array > ( ) . ok_or_else ( || {
68+ DataFusionError :: Internal (
69+ "Failed to downcast to Int8Array" . to_string ( ) ,
70+ )
71+ } ) ?;
6672 let result: Int64Array = unary ( input, |x| x as i64 ) ;
6773 Ok ( ColumnarValue :: Array ( Arc :: new ( result) ) )
6874 }
6975 DataType :: Int16 => {
70- let input = array. as_any ( ) . downcast_ref :: < Int16Array > ( ) . unwrap ( ) ;
76+ let input =
77+ array. as_any ( ) . downcast_ref :: < Int16Array > ( ) . ok_or_else ( || {
78+ DataFusionError :: Internal (
79+ "Failed to downcast to Int16Array" . to_string ( ) ,
80+ )
81+ } ) ?;
7182 let result: Int64Array = unary ( input, |x| x as i64 ) ;
7283 Ok ( ColumnarValue :: Array ( Arc :: new ( result) ) )
7384 }
7485 DataType :: Int32 => {
75- let input = array. as_any ( ) . downcast_ref :: < Int32Array > ( ) . unwrap ( ) ;
86+ let input =
87+ array. as_any ( ) . downcast_ref :: < Int32Array > ( ) . ok_or_else ( || {
88+ DataFusionError :: Internal (
89+ "Failed to downcast to Int32Array" . to_string ( ) ,
90+ )
91+ } ) ?;
7692 let result: Int64Array = unary ( input, |x| x as i64 ) ;
7793 Ok ( ColumnarValue :: Array ( Arc :: new ( result) ) )
7894 }
@@ -147,26 +163,43 @@ fn decimal_ceil_f(scale: i8) -> impl Fn(i128) -> i128 {
147163 }
148164}
149165
166+ /// Spark-compatible `ceil` function.
167+ ///
168+ /// Returns the smallest integer greater than or equal to the input.
169+ /// Unlike standard DataFusion ceil, this returns Int64 for float/integer
170+ /// inputs (matching Spark behavior).
171+ ///
172+ /// # Supported types
173+ /// - Float32, Float64 → Int64
174+ /// - Int8, Int16, Int32, Int64 → Int64
175+ /// - Decimal128(p, s) → Decimal128(p, s) (preserves scale)
176+ ///
177+ /// # Examples
178+ /// ```sql
179+ /// SELECT ceil(1.5); -- Returns 2 (Int64)
180+ /// SELECT ceil(-1.5); -- Returns -1 (Int64)
181+ /// SELECT ceil(5); -- Returns 5 (Int64)
182+ /// ```
150183#[ derive( Debug , PartialEq , Eq , Hash ) ]
151- pub struct SparkCiel {
184+ pub struct SparkCeil {
152185 signature : Signature ,
153186}
154187
155- impl Default for SparkCiel {
188+ impl Default for SparkCeil {
156189 fn default ( ) -> Self {
157190 Self :: new ( )
158191 }
159192}
160193
161- impl SparkCiel {
194+ impl SparkCeil {
162195 pub fn new ( ) -> Self {
163196 Self {
164197 signature : Signature :: numeric ( 1 , Volatility :: Immutable ) ,
165198 }
166199 }
167200}
168201
169- impl ScalarUDFImpl for SparkCiel {
202+ impl ScalarUDFImpl for SparkCeil {
170203 fn as_any ( & self ) -> & dyn Any {
171204 self
172205 }
@@ -183,7 +216,19 @@ impl ScalarUDFImpl for SparkCiel {
183216 & self ,
184217 _arg_types : & [ DataType ] ,
185218 ) -> datafusion_common:: Result < DataType > {
186- Ok ( DataType :: Int64 )
219+ internal_err ! ( "return_field_from_args should be called instead" )
220+ }
221+
222+ fn return_field_from_args (
223+ & self ,
224+ args : ReturnFieldArgs ,
225+ ) -> datafusion_common:: Result < FieldRef > {
226+ let nullable = args. arg_fields . iter ( ) . any ( |f| f. is_nullable ( ) ) ;
227+ let return_type = match args. arg_fields [ 0 ] . data_type ( ) {
228+ DataType :: Decimal128 ( p, s) => DataType :: Decimal128 ( * p, * s) ,
229+ _ => DataType :: Int64 ,
230+ } ;
231+ Ok ( Arc :: new ( Field :: new ( self . name ( ) , return_type, nullable) ) )
187232 }
188233
189234 fn invoke_with_args (
0 commit comments