diegoQuinas commented on code in PR #21710:
URL: https://github.com/apache/datafusion/pull/21710#discussion_r3293833331


##########
datafusion/spark/src/function/math/ceil.rs:
##########
@@ -121,11 +168,74 @@ fn decimal128_ceil_precision(precision: u8, scale: i8) -> 
u8 {
     ((precision as i64) - (scale as i64) + 1).clamp(1, 38) as u8
 }
 
-fn spark_ceil_scalar(value: &ScalarValue) -> Result<ColumnarValue> {
+/// Compute the ceiling of an integer at the given decimal `scale`.
+///
+/// - `scale >= 0`: integers have no fractional part; returns `value` 
unchanged.
+/// - `scale  < 0`: rounds *up* to the nearest multiple of `10^(-scale)`.
+///   For positive values this rounds away from zero; for negative values it
+///   rounds toward zero (ceiling = toward +∞).
+///
+/// If `10^(-scale)` overflows `i64`, returns `0` (matching Spark / `round`).
+fn ceil_integer(value: i64, scale: i32) -> i64 {
+    if scale >= 0 {
+        return value;
+    }
+    let abs_scale = (-scale) as u32;
+    let Some(factor) = 10_i64.checked_pow(abs_scale) else {
+        return 0;
+    };
+    let remainder = value % factor;
+    if remainder > 0 {
+        // Positive remainder: bump up to the next multiple.
+        value.wrapping_sub(remainder).wrapping_add(factor)
+    } else if remainder < 0 {
+        // Negative remainder (negative value not on boundary): truncating 
toward
+        // zero already gives the ceiling.
+        value.wrapping_sub(remainder)
+    } else {
+        value
+    }
+}
+
+fn spark_ceil_scalar(
+    value: &ScalarValue,
+    scale: i32,
+    has_scale: bool,
+) -> Result<ColumnarValue> {
     let result = match value {
+        // Floats: 2-arg form preserves the input float type for *every* scale,
+        // so the runtime type matches what `return_type` advertised.
+        ScalarValue::Float32(v) if has_scale => {
+            ScalarValue::Float32(v.map(|x| ceil_float(x, scale)))
+        }
+        ScalarValue::Float64(v) if has_scale => {
+            ScalarValue::Float64(v.map(|x| ceil_float(x, scale)))
+        }
+        // 1-arg float: Spark returns Int64.
         ScalarValue::Float32(v) => ScalarValue::Int64(v.map(|x| x.ceil() as 
i64)),
         ScalarValue::Float64(v) => ScalarValue::Int64(v.map(|x| x.ceil() as 
i64)),
+        // Integers: the 1-arg path was a plain `cast_to(Int64)`. The 2-arg 
path
+        // additionally applies a (possibly negative) scale before casting.
+        v if v.data_type().is_integer() && has_scale => {
+            match v.cast_to(&DataType::Int64)? {
+                ScalarValue::Int64(opt) => {
+                    ScalarValue::Int64(opt.map(|x| ceil_integer(x, scale)))
+                }
+                other => {
+                    return exec_err!(
+                        "Internal error: integer cast_to(Int64) yielded {:?}",
+                        other.data_type()
+                    );
+                }
+            }
+        }
         v if v.data_type().is_integer() => v.cast_to(&DataType::Int64)?,
+        // Decimal128 with positive scale (1-arg only).
+        ScalarValue::Decimal128(_, _, _) if has_scale => {
+            return not_impl_err!(
+                "2-argument ceil is not yet supported for decimal inputs"

Review Comment:
   I'm working on this. Maybe this night I add it.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to