diff --git a/datafusion/functions-nested/src/make_array.rs b/datafusion/functions-nested/src/make_array.rs index 6f083ab70007b..f1928be8765ae 100644 --- a/datafusion/functions-nested/src/make_array.rs +++ b/datafusion/functions-nested/src/make_array.rs @@ -37,6 +37,7 @@ use datafusion_expr::{ ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature, Volatility, }; +use datafusion_expr_common::sort_properties::ExprProperties; use datafusion_macros::user_doc; use itertools::Itertools as _; @@ -113,6 +114,11 @@ impl ScalarUDFImpl for MakeArray { &self.aliases } + fn strictly_order_preserving(&self, _inputs: &[ExprProperties]) -> Result { + // Not strictly order preserving since null input does not correspond to null output + Ok(false) + } + fn coerce_types(&self, arg_types: &[DataType]) -> Result> { if arg_types.is_empty() { Ok(vec![]) diff --git a/datafusion/functions-nested/src/repeat.rs b/datafusion/functions-nested/src/repeat.rs index d7dff21141429..a8e094f65a2d4 100644 --- a/datafusion/functions-nested/src/repeat.rs +++ b/datafusion/functions-nested/src/repeat.rs @@ -37,6 +37,7 @@ use datafusion_expr::{ Volatility, }; use datafusion_expr_common::signature::{Coercion, TypeSignatureClass}; +use datafusion_expr_common::sort_properties::ExprProperties; use datafusion_macros::user_doc; use std::mem::size_of; use std::sync::Arc; @@ -137,6 +138,12 @@ impl ScalarUDFImpl for ArrayRepeat { make_scalar_function(array_repeat_inner)(&args.args) } + fn strictly_order_preserving(&self, _inputs: &[ExprProperties]) -> Result { + // this is not strictly order preserving + // since array_repeat(NULL, 2) = [NULL, NULL] and not NULL + Ok(false) + } + fn aliases(&self) -> &[String] { &self.aliases } diff --git a/datafusion/functions/src/math/factorial.rs b/datafusion/functions/src/math/factorial.rs index f4e9b60dd3799..0d01406d351e0 100644 --- a/datafusion/functions/src/math/factorial.rs +++ b/datafusion/functions/src/math/factorial.rs @@ -28,6 +28,7 @@ use datafusion_expr::{ ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature, Volatility, }; +use datafusion_expr_common::sort_properties::{ExprProperties, SortProperties}; use datafusion_macros::user_doc; #[user_doc( @@ -116,6 +117,17 @@ impl ScalarUDFImpl for FactorialFunc { } } + fn output_ordering(&self, inputs: &[ExprProperties]) -> Result { + // Keep the same ordering as the input + Ok(inputs[0].sort_properties) + } + + fn strictly_order_preserving(&self, _inputs: &[ExprProperties]) -> Result { + // There is one-to-one mapping between input and output and nulls maps to nulls + // and because overflow will be resulted in an error and not wrapping or saturating we are ok + Ok(true) + } + fn documentation(&self) -> Option<&Documentation> { self.doc() } diff --git a/datafusion/functions/src/math/floor.rs b/datafusion/functions/src/math/floor.rs index 4ab6e0eb5effd..dfca5577132ef 100644 --- a/datafusion/functions/src/math/floor.rs +++ b/datafusion/functions/src/math/floor.rs @@ -234,6 +234,11 @@ impl ScalarUDFImpl for FloorFunc { Ok(input[0].sort_properties) } + fn strictly_order_preserving(&self, _inputs: &[ExprProperties]) -> Result { + // floor allow distinct inputs to collapse into equal outputs + Ok(false) + } + fn evaluate_bounds(&self, inputs: &[&Interval]) -> Result { let data_type = inputs[0].data_type(); Interval::make_unbounded(&data_type) diff --git a/datafusion/functions/src/string/repeat.rs b/datafusion/functions/src/string/repeat.rs index a53f1e2e4fc42..edd5e56be11f3 100644 --- a/datafusion/functions/src/string/repeat.rs +++ b/datafusion/functions/src/string/repeat.rs @@ -32,6 +32,7 @@ use datafusion_common::{ use datafusion_expr::{ColumnarValue, Documentation, Volatility}; use datafusion_expr::{ScalarFunctionArgs, ScalarUDFImpl, Signature}; use datafusion_expr_common::signature::{Coercion, TypeSignatureClass}; +use datafusion_expr_common::sort_properties::ExprProperties; use datafusion_macros::user_doc; #[user_doc( @@ -160,6 +161,12 @@ impl ScalarUDFImpl for RepeatFunc { fn documentation(&self) -> Option<&Documentation> { self.doc() } + + fn strictly_order_preserving(&self, _inputs: &[ExprProperties]) -> Result { + // repeat does not strictly preserve ordering since for the following 2 rows: + // "bc" and "bca" and repeat(2) the result will be "bcbc" and "bcabca" which now the order is different + Ok(false) + } } /// Computes repeat for a single string value with max size check