datafusion_expr/udf.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
18//! [`ScalarUDF`]: Scalar User Defined Functions
19
20use crate::async_udf::AsyncScalarUDF;
21use crate::expr::schema_name_from_exprs_comma_separated_without_space;
22use crate::preimage::PreimageResult;
23use crate::simplify::{ExprSimplifyResult, SimplifyContext};
24use crate::sort_properties::{ExprProperties, SortProperties};
25use crate::udf_eq::UdfEq;
26use crate::{ColumnarValue, Documentation, Expr, Signature};
27use arrow::datatypes::{DataType, Field, FieldRef};
28#[cfg(debug_assertions)]
29use datafusion_common::assert_or_internal_err;
30use datafusion_common::config::ConfigOptions;
31use datafusion_common::{ExprSchema, Result, ScalarValue, not_impl_err};
32use datafusion_expr_common::dyn_eq::{DynEq, DynHash};
33use datafusion_expr_common::interval_arithmetic::Interval;
34use datafusion_expr_common::placement::ExpressionPlacement;
35use std::any::Any;
36use std::cmp::Ordering;
37use std::fmt::Debug;
38use std::hash::{Hash, Hasher};
39use std::sync::Arc;
40
41/// Describes how a struct-producing UDF's output fields correspond to its
42/// input arguments. This enables the optimizer to propagate orderings
43/// through struct projections (e.g., so that sorting by a struct field
44/// can be recognized as equivalent to sorting by the source column).
45///
46/// See [`ScalarUDFImpl::struct_field_mapping`] for details.
47pub struct StructFieldMapping {
48 /// The UDF used to construct field access expressions on the output.
49 /// For example, the `get_field` UDF for accessing struct fields.
50 pub field_accessor: Arc<ScalarUDF>,
51 /// For each output field: the literal arguments to pass to the
52 /// `field_accessor` UDF (after the base expression), and the index
53 /// of the corresponding input argument that produces the field's value.
54 ///
55 /// For `named_struct('a', col1, 'b', col2)`, this would be:
56 /// `[(["a"], 1), (["b"], 3)]` — field `"a"` comes from arg index 1.
57 pub fields: Vec<(Vec<ScalarValue>, usize)>,
58}
59
60/// Logical representation of a Scalar User Defined Function.
61///
62/// A scalar function produces a single row output for each row of input. This
63/// struct contains the information DataFusion needs to plan and invoke
64/// functions you supply such as name, type signature, return type, and actual
65/// implementation.
66///
67/// 1. For simple use cases, use [`create_udf`] (examples in [`simple_udf.rs`]).
68///
69/// 2. For advanced use cases, use [`ScalarUDFImpl`] which provides full API
70/// access (examples in [`advanced_udf.rs`]).
71///
72/// See [`Self::call`] to create an `Expr` which invokes a `ScalarUDF` with arguments.
73///
74/// # API Note
75///
76/// This is a separate struct from [`ScalarUDFImpl`] to maintain backwards
77/// compatibility with the older API.
78///
79/// [`create_udf`]: crate::expr_fn::create_udf
80/// [`simple_udf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/udf/simple_udf.rs
81/// [`advanced_udf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/udf/advanced_udf.rs
82#[derive(Debug, Clone)]
83pub struct ScalarUDF {
84 inner: Arc<dyn ScalarUDFImpl>,
85}
86
87impl PartialEq for ScalarUDF {
88 fn eq(&self, other: &Self) -> bool {
89 self.inner.as_ref().dyn_eq(other.inner.as_ref() as &dyn Any)
90 }
91}
92
93impl PartialOrd for ScalarUDF {
94 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
95 let mut cmp = self.name().cmp(other.name());
96 if cmp == Ordering::Equal {
97 cmp = self.signature().partial_cmp(other.signature())?;
98 }
99 if cmp == Ordering::Equal {
100 cmp = self.aliases().partial_cmp(other.aliases())?;
101 }
102 // Contract for PartialOrd and PartialEq consistency requires that
103 // a == b if and only if partial_cmp(a, b) == Some(Equal).
104 if cmp == Ordering::Equal && self != other {
105 // Functions may have other properties besides name and signature
106 // that differentiate two instances (e.g. type, or arbitrary parameters).
107 // We cannot return Some(Equal) in such case.
108 return None;
109 }
110 debug_assert!(
111 cmp == Ordering::Equal || self != other,
112 "Detected incorrect implementation of PartialEq when comparing functions: '{}' and '{}'. \
113 The functions compare as equal, but they are not equal based on general properties that \
114 the PartialOrd implementation observes,",
115 self.name(),
116 other.name()
117 );
118 Some(cmp)
119 }
120}
121
122impl Eq for ScalarUDF {}
123
124impl Hash for ScalarUDF {
125 fn hash<H: Hasher>(&self, state: &mut H) {
126 self.inner.dyn_hash(state)
127 }
128}
129
130impl ScalarUDF {
131 /// Create a new `ScalarUDF` from a `[ScalarUDFImpl]` trait object
132 ///
133 /// Note this is the same as using the `From` impl (`ScalarUDF::from`)
134 pub fn new_from_impl<F>(fun: F) -> ScalarUDF
135 where
136 F: ScalarUDFImpl + 'static,
137 {
138 Self::new_from_shared_impl(Arc::new(fun))
139 }
140
141 /// Create a new `ScalarUDF` from a `[ScalarUDFImpl]` trait object
142 pub fn new_from_shared_impl(fun: Arc<dyn ScalarUDFImpl>) -> ScalarUDF {
143 Self { inner: fun }
144 }
145
146 /// Return the underlying [`ScalarUDFImpl`] trait object for this function
147 pub fn inner(&self) -> &Arc<dyn ScalarUDFImpl> {
148 &self.inner
149 }
150
151 /// Adds additional names that can be used to invoke this function, in
152 /// addition to `name`
153 ///
154 /// If you implement [`ScalarUDFImpl`] directly you should return aliases directly.
155 pub fn with_aliases(self, aliases: impl IntoIterator<Item = &'static str>) -> Self {
156 Self::new_from_impl(AliasedScalarUDFImpl::new(Arc::clone(&self.inner), aliases))
157 }
158
159 /// Returns a [`Expr`] logical expression to call this UDF with specified
160 /// arguments.
161 ///
162 /// This utility allows easily calling UDFs
163 ///
164 /// # Example
165 /// ```no_run
166 /// use datafusion_expr::{col, lit, ScalarUDF};
167 /// # fn my_udf() -> ScalarUDF { unimplemented!() }
168 /// let my_func: ScalarUDF = my_udf();
169 /// // Create an expr for `my_func(a, 12.3)`
170 /// let expr = my_func.call(vec![col("a"), lit(12.3)]);
171 /// ```
172 pub fn call(&self, args: Vec<Expr>) -> Expr {
173 Expr::ScalarFunction(crate::expr::ScalarFunction::new_udf(
174 Arc::new(self.clone()),
175 args,
176 ))
177 }
178
179 /// Returns this function's name.
180 ///
181 /// See [`ScalarUDFImpl::name`] for more details.
182 pub fn name(&self) -> &str {
183 self.inner.name()
184 }
185
186 /// Returns this function's display_name.
187 ///
188 /// See [`ScalarUDFImpl::display_name`] for more details
189 #[deprecated(
190 since = "50.0.0",
191 note = "This method is unused and will be removed in a future release"
192 )]
193 pub fn display_name(&self, args: &[Expr]) -> Result<String> {
194 #[expect(deprecated)]
195 self.inner.display_name(args)
196 }
197
198 /// Returns this function's schema_name.
199 ///
200 /// See [`ScalarUDFImpl::schema_name`] for more details
201 pub fn schema_name(&self, args: &[Expr]) -> Result<String> {
202 self.inner.schema_name(args)
203 }
204
205 /// Returns the aliases for this function.
206 ///
207 /// See [`ScalarUDF::with_aliases`] for more details
208 pub fn aliases(&self) -> &[String] {
209 self.inner.aliases()
210 }
211
212 /// Returns true if this function always returns NULL when any argument is
213 /// NULL.
214 ///
215 /// See [`ScalarUDFImpl::is_strict`] for more details.
216 pub fn is_strict(&self) -> bool {
217 self.inner.is_strict()
218 }
219
220 /// Returns this function's [`Signature`] (what input types are accepted).
221 ///
222 /// See [`ScalarUDFImpl::signature`] for more details.
223 pub fn signature(&self) -> &Signature {
224 self.inner.signature()
225 }
226
227 /// The datatype this function returns given the input argument types.
228 /// This function is used when the input arguments are [`DataType`]s.
229 ///
230 /// # Notes
231 ///
232 /// If a function implement [`ScalarUDFImpl::return_field_from_args`],
233 /// its [`ScalarUDFImpl::return_type`] should raise an error.
234 ///
235 /// See [`ScalarUDFImpl::return_type`] for more details.
236 pub fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
237 self.inner.return_type(arg_types)
238 }
239
240 /// Return the datatype this function returns given the input argument types.
241 ///
242 /// See [`ScalarUDFImpl::return_field_from_args`] for more details.
243 pub fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
244 self.inner.return_field_from_args(args)
245 }
246
247 /// Returns this scalar function's simplification result.
248 ///
249 /// See [`ScalarUDFImpl::simplify`] for more details.
250 pub fn simplify(
251 &self,
252 args: Vec<Expr>,
253 info: &SimplifyContext,
254 ) -> Result<ExprSimplifyResult> {
255 self.inner.simplify(args, info)
256 }
257
258 #[deprecated(since = "50.0.0", note = "Use `return_field_from_args` instead.")]
259 pub fn is_nullable(&self, args: &[Expr], schema: &dyn ExprSchema) -> bool {
260 #[expect(deprecated)]
261 self.inner.is_nullable(args, schema)
262 }
263
264 /// Return a preimage
265 ///
266 /// See [`ScalarUDFImpl::preimage`] for more details.
267 pub fn preimage(
268 &self,
269 args: &[Expr],
270 lit_expr: &Expr,
271 info: &SimplifyContext,
272 ) -> Result<PreimageResult> {
273 self.inner.preimage(args, lit_expr, info)
274 }
275
276 /// Invoke the function on `args`, returning the appropriate result.
277 ///
278 /// See [`ScalarUDFImpl::invoke_with_args`] for details.
279 pub fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
280 #[cfg(debug_assertions)]
281 let return_field = Arc::clone(&args.return_field);
282 let result = self.inner.invoke_with_args(args)?;
283 // Maybe this could be enabled always?
284 // This doesn't use debug_assert!, but it's meant to run anywhere except on production. It's same in spirit, thus conditioning on debug_assertions.
285 #[cfg(debug_assertions)]
286 {
287 let result_data_type = result.data_type();
288 let expected_type = return_field.data_type();
289 assert_or_internal_err!(
290 result_data_type == *expected_type,
291 "Function '{}' returned value of type '{}' while the following type was promised at planning time and expected: '{}'",
292 self.name(),
293 result_data_type,
294 expected_type
295 );
296 // TODO verify return data is non-null when it was promised to be?
297 }
298 Ok(result)
299 }
300
301 /// Determines which of the arguments passed to this function are evaluated eagerly
302 /// and which may be evaluated lazily.
303 ///
304 /// See [ScalarUDFImpl::conditional_arguments] for more information.
305 pub fn conditional_arguments<'a>(
306 &self,
307 args: &'a [Expr],
308 ) -> Option<(Vec<&'a Expr>, Vec<&'a Expr>)> {
309 self.inner.conditional_arguments(args)
310 }
311
312 /// Returns true if some of this `exprs` subexpressions may not be evaluated
313 /// and thus any side effects (like divide by zero) may not be encountered.
314 ///
315 /// See [ScalarUDFImpl::short_circuits] for more information.
316 pub fn short_circuits(&self) -> bool {
317 self.inner.short_circuits()
318 }
319
320 /// Computes the output interval for a [`ScalarUDF`], given the input
321 /// intervals.
322 ///
323 /// # Parameters
324 ///
325 /// * `inputs` are the intervals for the inputs (children) of this function.
326 ///
327 /// # Example
328 ///
329 /// If the function is `ABS(a)`, and the input interval is `a: [-3, 2]`,
330 /// then the output interval would be `[0, 3]`.
331 pub fn evaluate_bounds(&self, inputs: &[&Interval]) -> Result<Interval> {
332 self.inner.evaluate_bounds(inputs)
333 }
334
335 /// See [`ScalarUDFImpl::struct_field_mapping`] for more details.
336 pub fn struct_field_mapping(
337 &self,
338 literal_args: &[Option<ScalarValue>],
339 ) -> Option<StructFieldMapping> {
340 self.inner.struct_field_mapping(literal_args)
341 }
342
343 /// Updates bounds for child expressions, given a known interval for this
344 /// function. This is used to propagate constraints down through an expression
345 /// tree.
346 ///
347 /// # Parameters
348 ///
349 /// * `interval` is the currently known interval for this function.
350 /// * `inputs` are the current intervals for the inputs (children) of this function.
351 ///
352 /// # Returns
353 ///
354 /// A `Vec` of new intervals for the children, in order.
355 ///
356 /// If constraint propagation reveals an infeasibility for any child, returns
357 /// [`None`]. If none of the children intervals change as a result of
358 /// propagation, may return an empty vector instead of cloning `children`.
359 /// This is the default (and conservative) return value.
360 ///
361 /// # Example
362 ///
363 /// If the function is `ABS(a)`, the current `interval` is `[4, 5]` and the
364 /// input `a` is given as `[-7, 3]`, then propagation would return `[-5, 3]`.
365 pub fn propagate_constraints(
366 &self,
367 interval: &Interval,
368 inputs: &[&Interval],
369 ) -> Result<Option<Vec<Interval>>> {
370 self.inner.propagate_constraints(interval, inputs)
371 }
372
373 /// Calculates the [`SortProperties`] of this function based on its
374 /// children's properties.
375 pub fn output_ordering(&self, inputs: &[ExprProperties]) -> Result<SortProperties> {
376 self.inner.output_ordering(inputs)
377 }
378
379 pub fn preserves_lex_ordering(&self, inputs: &[ExprProperties]) -> Result<bool> {
380 self.inner.preserves_lex_ordering(inputs)
381 }
382
383 /// See [`ScalarUDFImpl::strictly_order_preserving`] for more details.
384 pub fn strictly_order_preserving(&self, inputs: &[ExprProperties]) -> Result<bool> {
385 self.inner.strictly_order_preserving(inputs)
386 }
387
388 /// See [`ScalarUDFImpl::coerce_types`] for more details.
389 pub fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
390 self.inner.coerce_types(arg_types)
391 }
392
393 /// Returns the documentation for this Scalar UDF.
394 ///
395 /// Documentation can be accessed programmatically as well as
396 /// generating publicly facing documentation.
397 pub fn documentation(&self) -> Option<&Documentation> {
398 self.inner.documentation()
399 }
400
401 /// Return true if this function is an async function
402 pub fn as_async(&self) -> Option<&AsyncScalarUDF> {
403 self.inner().downcast_ref::<AsyncScalarUDF>()
404 }
405
406 /// Returns placement information for this function.
407 ///
408 /// See [`ScalarUDFImpl::placement`] for more details.
409 pub fn placement(&self, args: &[ExpressionPlacement]) -> ExpressionPlacement {
410 self.inner.placement(args)
411 }
412}
413
414impl<F> From<F> for ScalarUDF
415where
416 F: ScalarUDFImpl + 'static,
417{
418 fn from(fun: F) -> Self {
419 Self::new_from_impl(fun)
420 }
421}
422
423/// Arguments passed to [`ScalarUDFImpl::invoke_with_args`] when invoking a
424/// scalar function.
425#[derive(Debug, Clone)]
426pub struct ScalarFunctionArgs {
427 /// The evaluated arguments to the function
428 pub args: Vec<ColumnarValue>,
429 /// Field associated with each arg, if it exists
430 pub arg_fields: Vec<FieldRef>,
431 /// The number of rows in record batch being evaluated
432 pub number_rows: usize,
433 /// The return field of the scalar function returned (from `return_type`
434 /// or `return_field_from_args`) when creating the physical expression
435 /// from the logical expression
436 pub return_field: FieldRef,
437 /// The config options at execution time
438 pub config_options: Arc<ConfigOptions>,
439}
440
441impl ScalarFunctionArgs {
442 /// The return type of the function. See [`Self::return_field`] for more
443 /// details.
444 pub fn return_type(&self) -> &DataType {
445 self.return_field.data_type()
446 }
447}
448
449/// Information about arguments passed to the function
450///
451/// This structure contains metadata about how the function was called
452/// such as the type of the arguments, any scalar arguments and if the
453/// arguments can (ever) be null
454///
455/// See [`ScalarUDFImpl::return_field_from_args`] for more information
456#[derive(Debug)]
457pub struct ReturnFieldArgs<'a> {
458 /// The data types of the arguments to the function
459 pub arg_fields: &'a [FieldRef],
460 /// Is argument `i` to the function a scalar (constant)?
461 ///
462 /// If the argument `i` is not a scalar, it will be None
463 ///
464 /// For example, if a function is called like `my_function(column_a, 5)`
465 /// this field will be `[None, Some(ScalarValue::Int32(Some(5)))]`
466 pub scalar_arguments: &'a [Option<&'a ScalarValue>],
467}
468
469/// Trait for implementing user defined scalar functions.
470///
471/// This trait exposes the full API for implementing user defined functions and
472/// can be used to implement any function.
473///
474/// See [`advanced_udf.rs`] for a full example with complete implementation and
475/// [`ScalarUDF`] for other available options.
476///
477/// [`advanced_udf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/udf/advanced_udf.rs
478///
479/// # Basic Example
480/// ```
481/// # use std::any::Any;
482/// # use std::sync::LazyLock;
483/// # use arrow::datatypes::DataType;
484/// # use datafusion_common::{DataFusionError, plan_err, Result};
485/// # use datafusion_expr::{col, ColumnarValue, Documentation, ScalarFunctionArgs, Signature, Volatility};
486/// # use datafusion_expr::{ScalarUDFImpl, ScalarUDF};
487/// # use datafusion_expr::scalar_doc_sections::DOC_SECTION_MATH;
488/// /// This struct for a simple UDF that adds one to an int32
489/// #[derive(Debug, PartialEq, Eq, Hash)]
490/// struct AddOne {
491/// signature: Signature,
492/// }
493///
494/// impl AddOne {
495/// fn new() -> Self {
496/// Self {
497/// signature: Signature::uniform(1, vec![DataType::Int32], Volatility::Immutable),
498/// }
499/// }
500/// }
501///
502/// static DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
503/// Documentation::builder(DOC_SECTION_MATH, "Add one to an int32", "add_one(2)")
504/// .with_argument("arg1", "The int32 number to add one to")
505/// .build()
506/// });
507///
508/// fn get_doc() -> &'static Documentation {
509/// &DOCUMENTATION
510/// }
511///
512/// /// Implement the ScalarUDFImpl trait for AddOne
513/// impl ScalarUDFImpl for AddOne {
514/// fn name(&self) -> &str { "add_one" }
515/// fn signature(&self) -> &Signature { &self.signature }
516/// fn return_type(&self, args: &[DataType]) -> Result<DataType> {
517/// if !matches!(args.get(0), Some(&DataType::Int32)) {
518/// return plan_err!("add_one only accepts Int32 arguments");
519/// }
520/// Ok(DataType::Int32)
521/// }
522/// // The actual implementation would add one to the argument
523/// fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
524/// unimplemented!()
525/// }
526/// fn documentation(&self) -> Option<&Documentation> {
527/// Some(get_doc())
528/// }
529/// }
530///
531/// // Create a new ScalarUDF from the implementation
532/// let add_one = ScalarUDF::from(AddOne::new());
533///
534/// // Call the function `add_one(col)`
535/// let expr = add_one.call(vec![col("a")]);
536/// ```
537pub trait ScalarUDFImpl: Debug + DynEq + DynHash + Send + Sync + Any {
538 /// Returns this function's name
539 fn name(&self) -> &str;
540
541 /// Returns any aliases (alternate names) for this function.
542 ///
543 /// Aliases can be used to invoke the same function using different names.
544 /// For example in some databases `now()` and `current_timestamp()` are
545 /// aliases for the same function. This behavior can be obtained by
546 /// returning `current_timestamp` as an alias for the `now` function.
547 ///
548 /// Note: `aliases` should only include names other than [`Self::name`].
549 /// Defaults to `[]` (no aliases)
550 fn aliases(&self) -> &[String] {
551 &[]
552 }
553
554 /// Returns the user-defined display name of function, given the arguments
555 ///
556 /// This can be used to customize the output column name generated by this
557 /// function.
558 ///
559 /// Defaults to `name(args[0], args[1], ...)`
560 #[deprecated(
561 since = "50.0.0",
562 note = "This method is unused and will be removed in a future release"
563 )]
564 fn display_name(&self, args: &[Expr]) -> Result<String> {
565 let names: Vec<String> = args.iter().map(ToString::to_string).collect();
566 // TODO: join with ", " to standardize the formatting of Vec<Expr>, <https://github.com/apache/datafusion/issues/10364>
567 Ok(format!("{}({})", self.name(), names.join(",")))
568 }
569
570 /// Returns the name of the column this expression would create
571 ///
572 /// See [`Expr::schema_name`] for details
573 fn schema_name(&self, args: &[Expr]) -> Result<String> {
574 Ok(format!(
575 "{}({})",
576 self.name(),
577 schema_name_from_exprs_comma_separated_without_space(args)?
578 ))
579 }
580
581 /// Returns a [`Signature`] describing the argument types for which this
582 /// function has an implementation, and the function's [`Volatility`].
583 ///
584 /// See [`Signature`] for more details on argument type handling
585 /// and [`Self::return_type`] for computing the return type.
586 ///
587 /// [`Volatility`]: datafusion_expr_common::signature::Volatility
588 fn signature(&self) -> &Signature;
589
590 /// [`DataType`] returned by this function, given the types of the
591 /// arguments.
592 ///
593 /// # Arguments
594 ///
595 /// `arg_types` Data types of the arguments. The implementation of
596 /// `return_type` can assume that some other part of the code has coerced
597 /// the actual argument types to match [`Self::signature`].
598 ///
599 /// # Notes
600 ///
601 /// If you provide an implementation for [`Self::return_field_from_args`],
602 /// DataFusion will not call `return_type` (this function). While it is
603 /// valid to put [`unimplemented!()`] or [`unreachable!()`], it is
604 /// recommended to return [`DataFusionError::Internal`] instead, which
605 /// reduces the severity of symptoms if bugs occur (an error rather than a
606 /// panic).
607 ///
608 /// [`DataFusionError::Internal`]: datafusion_common::DataFusionError::Internal
609 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType>;
610
611 /// Create a new instance of this function with updated configuration.
612 ///
613 /// This method is called when configuration options change at runtime
614 /// (e.g., via `SET` statements) to allow functions that depend on
615 /// configuration to update themselves accordingly.
616 ///
617 /// Note the current [`ConfigOptions`] are also passed to [`Self::invoke_with_args`] so
618 /// this API is not needed for functions where the values may
619 /// depend on the current options.
620 ///
621 /// This API is useful for functions where the return
622 /// **type** depends on the configuration options, such as the `now()` function
623 /// which depends on the current timezone.
624 ///
625 /// # Arguments
626 ///
627 /// * `config` - The updated configuration options
628 ///
629 /// # Returns
630 ///
631 /// * `Some(ScalarUDF)` - A new instance of this function configured with the new settings
632 /// * `None` - If this function does not change with new configuration settings (the default)
633 fn with_updated_config(&self, _config: &ConfigOptions) -> Option<ScalarUDF> {
634 None
635 }
636
637 /// What type will be returned by this function, given the arguments?
638 ///
639 /// By default, this function calls [`Self::return_type`] with the
640 /// types of each argument.
641 ///
642 /// # Notes
643 ///
644 /// For the majority of UDFs, implementing [`Self::return_type`] is sufficient,
645 /// as the result type is typically a deterministic function of the input types
646 /// (e.g., `sqrt(f32)` consistently yields `f32`). Implementing this method directly
647 /// is generally unnecessary unless the return type depends on runtime values.
648 ///
649 /// This function can be used for more advanced cases such as:
650 ///
651 /// 1. specifying nullability
652 /// 2. return types based on the **values** of the arguments (rather than
653 /// their **types**.
654 ///
655 /// # Example creating `Field`
656 ///
657 /// Note the name of the [`Field`] is ignored, except for structured types such as
658 /// `DataType::Struct`.
659 ///
660 /// ```rust
661 /// # use std::sync::Arc;
662 /// # use arrow::datatypes::{DataType, Field, FieldRef};
663 /// # use datafusion_common::Result;
664 /// # use datafusion_expr::ReturnFieldArgs;
665 /// # struct Example{}
666 /// # impl Example {
667 /// fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
668 /// // report output is only nullable if any one of the arguments are nullable
669 /// let nullable = args.arg_fields.iter().any(|f| f.is_nullable());
670 /// let field = Arc::new(Field::new("ignored_name", DataType::Int32, nullable));
671 /// Ok(field)
672 /// }
673 /// # }
674 /// ```
675 ///
676 /// # Output Type based on Values
677 ///
678 /// For example, the following two function calls get the same argument
679 /// types (something and a `Utf8` string) but return different types based
680 /// on the value of the second argument:
681 ///
682 /// * `arrow_cast(x, 'Int16')` --> `Int16`
683 /// * `arrow_cast(x, 'Float32')` --> `Float32`
684 ///
685 /// # Requirements
686 ///
687 /// This function **must** consistently return the same type for the same
688 /// logical input even if the input is simplified (e.g. it must return the same
689 /// value for `('foo' | 'bar')` as it does for ('foobar').
690 fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
691 let data_types = args
692 .arg_fields
693 .iter()
694 .map(|f| f.data_type())
695 .cloned()
696 .collect::<Vec<_>>();
697 let return_type = self.return_type(&data_types)?;
698 Ok(Arc::new(Field::new(self.name(), return_type, true)))
699 }
700
701 #[deprecated(
702 since = "45.0.0",
703 note = "Use `return_field_from_args` instead. if you use `is_nullable` that returns non-nullable with `return_type`, you would need to switch to `return_field_from_args`, you might have error"
704 )]
705 fn is_nullable(&self, _args: &[Expr], _schema: &dyn ExprSchema) -> bool {
706 true
707 }
708
709 /// Returns true if this function always returns NULL when any argument is
710 /// NULL.
711 ///
712 /// Strict functions are NULL-propagating: if any argument evaluates to
713 /// NULL, the function result is guaranteed to be NULL. Optimizer rules can
714 /// use this property when reasoning about expression nullability and
715 /// null-rejecting filters.
716 ///
717 /// Defaults to `false` because user-defined functions may choose to accept
718 /// NULL inputs and produce non-NULL results.
719 fn is_strict(&self) -> bool {
720 false
721 }
722
723 /// Invoke the function returning the appropriate result.
724 ///
725 /// # Performance
726 ///
727 /// For the best performance, the implementations should handle the common case
728 /// when one or more of their arguments are constant values (aka
729 /// [`ColumnarValue::Scalar`]).
730 ///
731 /// [`ColumnarValue::values_to_arrays`] can be used to convert the arguments
732 /// to arrays, which will likely be simpler code, but be slower.
733 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue>;
734
735 /// Optionally apply per-UDF simplification / rewrite rules.
736 ///
737 /// This can be used to apply function specific simplification rules during
738 /// optimization (e.g. `arrow_cast` --> `Expr::Cast`). The default
739 /// implementation does nothing.
740 ///
741 /// Note that DataFusion handles simplifying arguments and "constant
742 /// folding" (replacing a function call with constant arguments such as
743 /// `my_add(1,2) --> 3` ). Thus, there is no need to implement such
744 /// optimizations manually for specific UDFs.
745 ///
746 /// # Arguments
747 /// * `args`: The arguments of the function
748 /// * `info`: The necessary information for simplification
749 ///
750 /// # Returns
751 /// [`ExprSimplifyResult`] indicating the result of the simplification NOTE
752 /// if the function cannot be simplified, the arguments *MUST* be returned
753 /// unmodified
754 ///
755 /// # Notes
756 ///
757 /// The returned expression must have the same schema as the original
758 /// expression, including both the data type and nullability. For example,
759 /// if the original expression is nullable, the returned expression must
760 /// also be nullable, otherwise it may lead to schema verification errors
761 /// later in query planning.
762 fn simplify(
763 &self,
764 args: Vec<Expr>,
765 _info: &SimplifyContext,
766 ) -> Result<ExprSimplifyResult> {
767 Ok(ExprSimplifyResult::Original(args))
768 }
769
770 /// Returns a single contiguous preimage for this function and the specified
771 /// scalar expression, if any.
772 ///
773 /// Currently only applies to `=, !=, >, >=, <, <=, is distinct from, is not distinct from` predicates
774 /// # Return Value
775 ///
776 /// Implementations should return a half-open interval: inclusive lower
777 /// bound and exclusive upper bound. This is slightly different from normal
778 /// [`Interval`] semantics where the upper bound is closed (inclusive).
779 /// Typically this means the upper endpoint must be adjusted to the next
780 /// value not included in the preimage. See the Half-Open Intervals section
781 /// below for more details.
782 ///
783 /// # Background
784 ///
785 /// Inspired by the [ClickHouse Paper], a "preimage rewrite" transforms a
786 /// predicate containing a function call into a predicate containing an
787 /// equivalent set of input literal (constant) values. The resulting
788 /// predicate can often be further optimized by other rewrites (see
789 /// Examples).
790 ///
791 /// From the paper:
792 ///
793 /// > some functions can compute the preimage of a given function result.
794 /// > This is used to replace comparisons of constants with function calls
795 /// > on the key columns by comparing the key column value with the preimage.
796 /// > For example, `toYear(k) = 2024` can be replaced by
797 /// > `k >= 2024-01-01 && k < 2025-01-01`
798 ///
799 /// For example, given an expression like
800 /// ```sql
801 /// date_part('YEAR', k) = 2024
802 /// ```
803 ///
804 /// The interval `[2024-01-01, 2025-12-31`]` contains all possible input
805 /// values (preimage values) for which the function `date_part(YEAR, k)`
806 /// produces the output value `2024` (image value). Returning the interval
807 /// (note upper bound adjusted up) `[2024-01-01, 2025-01-01]` the expression
808 /// can be rewritten to
809 ///
810 /// ```sql
811 /// k >= '2024-01-01' AND k < '2025-01-01'
812 /// ```
813 ///
814 /// which is a simpler and a more canonical form, making it easier for other
815 /// optimizer passes to recognize and apply further transformations.
816 ///
817 /// # Examples
818 ///
819 /// Case 1:
820 ///
821 /// Original:
822 /// ```sql
823 /// date_part('YEAR', k) = 2024 AND k >= '2024-06-01'
824 /// ```
825 ///
826 /// After preimage rewrite:
827 /// ```sql
828 /// k >= '2024-01-01' AND k < '2025-01-01' AND k >= '2024-06-01'
829 /// ```
830 ///
831 /// Since this form is much simpler, the optimizer can combine and simplify
832 /// sub-expressions further into:
833 /// ```sql
834 /// k >= '2024-06-01' AND k < '2025-01-01'
835 /// ```
836 ///
837 /// Case 2:
838 ///
839 /// For min/max pruning, simpler predicates such as:
840 /// ```sql
841 /// k >= '2024-01-01' AND k < '2025-01-01'
842 /// ```
843 /// are much easier for the pruner to reason about. See [PruningPredicate]
844 /// for the backgrounds of predicate pruning.
845 ///
846 /// The trade-off with the preimage rewrite is that evaluating the rewritten
847 /// form might be slightly more expensive than evaluating the original
848 /// expression. In practice, this cost is usually outweighed by the more
849 /// aggressive optimization opportunities it enables.
850 ///
851 /// # Half-Open Intervals
852 ///
853 /// The preimage API uses half-open intervals, which makes the rewrite
854 /// easier to implement by avoiding calculations to adjust the upper bound.
855 /// For example, if a function returns its input unchanged and the desired
856 /// output is the single value `5`, a closed interval could be represented
857 /// as `[5, 5]`, but then the rewrite would require adjusting the upper
858 /// bound to `6` to create a proper range predicate. With a half-open
859 /// interval, the same range is represented as `[5, 6)`, which already
860 /// forms a valid predicate.
861 ///
862 /// [PruningPredicate]: https://docs.rs/datafusion/latest/datafusion/physical_optimizer/pruning/struct.PruningPredicate.html
863 /// [ClickHouse Paper]: https://www.vldb.org/pvldb/vol17/p3731-schulze.pdf
864 /// [image]: https://en.wikipedia.org/wiki/Image_(mathematics)#Image_of_an_element
865 /// [preimage]: https://en.wikipedia.org/wiki/Image_(mathematics)#Inverse_image
866 fn preimage(
867 &self,
868 _args: &[Expr],
869 _lit_expr: &Expr,
870 _info: &SimplifyContext,
871 ) -> Result<PreimageResult> {
872 Ok(PreimageResult::None)
873 }
874
875 /// Returns true if some of this `exprs` subexpressions may not be evaluated
876 /// and thus any side effects (like divide by zero) may not be encountered.
877 ///
878 /// Setting this to true prevents certain optimizations such as common
879 /// subexpression elimination
880 ///
881 /// When overriding this function to return `true`, [ScalarUDFImpl::conditional_arguments] can also be
882 /// overridden to report more accurately which arguments are eagerly evaluated and which ones
883 /// lazily.
884 fn short_circuits(&self) -> bool {
885 false
886 }
887
888 /// Determines which of the arguments passed to this function are evaluated eagerly
889 /// and which may be evaluated lazily.
890 ///
891 /// If this function returns `None`, all arguments are eagerly evaluated.
892 /// Returning `None` is a micro optimization that saves a needless `Vec`
893 /// allocation.
894 ///
895 /// If the function returns `Some`, returns (`eager`, `lazy`) where `eager`
896 /// are the arguments that are always evaluated, and `lazy` are the
897 /// arguments that may be evaluated lazily (i.e. may not be evaluated at all
898 /// in some cases).
899 ///
900 /// Implementations must ensure that the two returned `Vec`s are disjunct,
901 /// and that each argument from `args` is present in one the two `Vec`s.
902 ///
903 /// When overriding this function, [ScalarUDFImpl::short_circuits] must
904 /// be overridden to return `true`.
905 fn conditional_arguments<'a>(
906 &self,
907 args: &'a [Expr],
908 ) -> Option<(Vec<&'a Expr>, Vec<&'a Expr>)> {
909 if self.short_circuits() {
910 Some((vec![], args.iter().collect()))
911 } else {
912 None
913 }
914 }
915
916 /// Computes the output [`Interval`] for a [`ScalarUDFImpl`], given the input
917 /// intervals.
918 ///
919 /// # Parameters
920 ///
921 /// * `children` are the intervals for the children (inputs) of this function.
922 ///
923 /// # Example
924 ///
925 /// If the function is `ABS(a)`, and the input interval is `a: [-3, 2]`,
926 /// then the output interval would be `[0, 3]`.
927 fn evaluate_bounds(&self, _input: &[&Interval]) -> Result<Interval> {
928 // We cannot assume the input datatype is the same of output type.
929 Interval::make_unbounded(&DataType::Null)
930 }
931
932 /// Updates bounds for child expressions, given a known [`Interval`]s for this
933 /// function.
934 ///
935 /// This function is used to propagate constraints down through an
936 /// expression tree.
937 ///
938 /// # Parameters
939 ///
940 /// * `interval` is the currently known interval for this function.
941 /// * `inputs` are the current intervals for the inputs (children) of this function.
942 ///
943 /// # Returns
944 ///
945 /// A `Vec` of new intervals for the children, in order.
946 ///
947 /// If constraint propagation reveals an infeasibility for any child, returns
948 /// [`None`]. If none of the children intervals change as a result of
949 /// propagation, may return an empty vector instead of cloning `children`.
950 /// This is the default (and conservative) return value.
951 ///
952 /// # Example
953 ///
954 /// If the function is `ABS(a)`, the current `interval` is `[4, 5]` and the
955 /// input `a` is given as `[-7, 3]`, then propagation would return `[-5, 3]`.
956 fn propagate_constraints(
957 &self,
958 _interval: &Interval,
959 _inputs: &[&Interval],
960 ) -> Result<Option<Vec<Interval>>> {
961 Ok(Some(vec![]))
962 }
963
964 /// Calculates the [`SortProperties`] of this function based on its children's properties.
965 fn output_ordering(&self, inputs: &[ExprProperties]) -> Result<SortProperties> {
966 if !self.preserves_lex_ordering(inputs)? {
967 return Ok(SortProperties::Unordered);
968 }
969
970 let Some(first_order) = inputs.first().map(|p| &p.sort_properties) else {
971 return Ok(SortProperties::Singleton);
972 };
973
974 if inputs
975 .iter()
976 .skip(1)
977 .all(|input| &input.sort_properties == first_order)
978 {
979 Ok(*first_order)
980 } else {
981 Ok(SortProperties::Unordered)
982 }
983 }
984
985 /// Returns true if the function preserves lexicographical ordering based on
986 /// the input ordering.
987 ///
988 /// See [`ExprProperties::preserves_lex_ordering`] for more details
989 fn preserves_lex_ordering(&self, _inputs: &[ExprProperties]) -> Result<bool> {
990 Ok(false)
991 }
992
993 /// Returns true if the function is strictly order-preserving with respect
994 /// to its `Ordered` inputs, i.e. `a.cmp(b) == f(a).cmp(f(b))`.
995 ///
996 /// See [`ExprProperties::strictly_order_preserving`] for more details
997 fn strictly_order_preserving(&self, _inputs: &[ExprProperties]) -> Result<bool> {
998 Ok(false)
999 }
1000
1001 /// Coerce arguments of a function call to types that the function can evaluate.
1002 ///
1003 /// This function is only called if [`ScalarUDFImpl::signature`] returns
1004 /// [`crate::TypeSignature::UserDefined`]. Most UDFs should return one of
1005 /// the other variants of [`TypeSignature`] which handle common cases.
1006 ///
1007 /// See the [type coercion module](crate::type_coercion)
1008 /// documentation for more details on type coercion
1009 ///
1010 /// [`TypeSignature`]: crate::TypeSignature
1011 ///
1012 /// For example, if your function requires a floating point arguments, but the user calls
1013 /// it like `my_func(1::int)` (i.e. with `1` as an integer), coerce_types can return `[DataType::Float64]`
1014 /// to ensure the argument is converted to `1::double`
1015 ///
1016 /// # Parameters
1017 /// * `arg_types`: The argument types of the arguments this function with
1018 ///
1019 /// # Return value
1020 /// A Vec the same length as `arg_types`. DataFusion will `CAST` the function call
1021 /// arguments to these specific types.
1022 fn coerce_types(&self, _arg_types: &[DataType]) -> Result<Vec<DataType>> {
1023 not_impl_err!("Function {} does not implement coerce_types", self.name())
1024 }
1025
1026 /// For struct-producing functions, return how output fields map to input
1027 /// arguments. This enables the optimizer to propagate orderings through
1028 /// struct projections.
1029 ///
1030 /// `literal_args[i]` is `Some(value)` if argument `i` is a known literal,
1031 /// allowing extraction of field names from arguments like
1032 /// `named_struct('field_name', value, ...)`.
1033 ///
1034 /// For example, `named_struct('a', col1, 'b', col2)` would return a
1035 /// mapping indicating that output field `'a'` (accessed via
1036 /// `get_field(output, 'a')`) corresponds to input argument `col1` at
1037 /// index 1, and field `'b'` corresponds to `col2` at index 3.
1038 fn struct_field_mapping(
1039 &self,
1040 _literal_args: &[Option<ScalarValue>],
1041 ) -> Option<StructFieldMapping> {
1042 None
1043 }
1044
1045 /// Returns the documentation for this Scalar UDF.
1046 ///
1047 /// Documentation can be accessed programmatically as well as generating
1048 /// publicly facing documentation.
1049 fn documentation(&self) -> Option<&Documentation> {
1050 None
1051 }
1052
1053 /// Returns placement information for this function.
1054 ///
1055 /// This is used by optimizers to make decisions about expression placement,
1056 /// such as whether to push expressions down through projections.
1057 ///
1058 /// The default implementation returns [`ExpressionPlacement::KeepInPlace`],
1059 /// meaning the expression should be kept where it is in the plan.
1060 ///
1061 /// Override this method to indicate that the function can be pushed down
1062 /// closer to the data source.
1063 fn placement(&self, _args: &[ExpressionPlacement]) -> ExpressionPlacement {
1064 ExpressionPlacement::KeepInPlace
1065 }
1066}
1067
1068impl dyn ScalarUDFImpl {
1069 /// Returns `true` if the implementation is of type `T`.
1070 ///
1071 /// Works correctly when called on `Arc<dyn ScalarUDFImpl>` via auto-deref.
1072 pub fn is<T: ScalarUDFImpl>(&self) -> bool {
1073 (self as &dyn Any).is::<T>()
1074 }
1075
1076 /// Attempts to downcast to a concrete type `T`, returning `None` if the
1077 /// implementation is not of that type.
1078 ///
1079 /// Works correctly when called on `Arc<dyn ScalarUDFImpl>` via auto-deref,
1080 /// unlike `(&arc as &dyn Any).downcast_ref::<T>()` which would attempt to
1081 /// downcast the `Arc` itself.
1082 pub fn downcast_ref<T: ScalarUDFImpl>(&self) -> Option<&T> {
1083 (self as &dyn Any).downcast_ref()
1084 }
1085}
1086
1087/// ScalarUDF that adds an alias to the underlying function. It is better to
1088/// implement [`ScalarUDFImpl`], which supports aliases, directly if possible.
1089#[derive(Debug, PartialEq, Eq, Hash)]
1090struct AliasedScalarUDFImpl {
1091 inner: UdfEq<Arc<dyn ScalarUDFImpl>>,
1092 aliases: Vec<String>,
1093}
1094
1095impl AliasedScalarUDFImpl {
1096 pub fn new(
1097 inner: Arc<dyn ScalarUDFImpl>,
1098 new_aliases: impl IntoIterator<Item = &'static str>,
1099 ) -> Self {
1100 let mut aliases = inner.aliases().to_vec();
1101 aliases.extend(new_aliases.into_iter().map(|s| s.to_string()));
1102 Self {
1103 inner: inner.into(),
1104 aliases,
1105 }
1106 }
1107}
1108
1109#[warn(clippy::missing_trait_methods)] // Delegates, so it should implement every single trait method
1110impl ScalarUDFImpl for AliasedScalarUDFImpl {
1111 fn name(&self) -> &str {
1112 self.inner.name()
1113 }
1114
1115 fn display_name(&self, args: &[Expr]) -> Result<String> {
1116 #[expect(deprecated)]
1117 self.inner.display_name(args)
1118 }
1119
1120 fn schema_name(&self, args: &[Expr]) -> Result<String> {
1121 self.inner.schema_name(args)
1122 }
1123
1124 fn signature(&self) -> &Signature {
1125 self.inner.signature()
1126 }
1127
1128 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
1129 self.inner.return_type(arg_types)
1130 }
1131
1132 fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
1133 self.inner.return_field_from_args(args)
1134 }
1135
1136 fn is_nullable(&self, args: &[Expr], schema: &dyn ExprSchema) -> bool {
1137 #[expect(deprecated)]
1138 self.inner.is_nullable(args, schema)
1139 }
1140
1141 fn is_strict(&self) -> bool {
1142 self.inner.is_strict()
1143 }
1144
1145 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
1146 self.inner.invoke_with_args(args)
1147 }
1148
1149 fn with_updated_config(&self, _config: &ConfigOptions) -> Option<ScalarUDF> {
1150 None
1151 }
1152
1153 fn aliases(&self) -> &[String] {
1154 &self.aliases
1155 }
1156
1157 fn simplify(
1158 &self,
1159 args: Vec<Expr>,
1160 info: &SimplifyContext,
1161 ) -> Result<ExprSimplifyResult> {
1162 self.inner.simplify(args, info)
1163 }
1164
1165 fn preimage(
1166 &self,
1167 args: &[Expr],
1168 lit_expr: &Expr,
1169 info: &SimplifyContext,
1170 ) -> Result<PreimageResult> {
1171 self.inner.preimage(args, lit_expr, info)
1172 }
1173
1174 fn conditional_arguments<'a>(
1175 &self,
1176 args: &'a [Expr],
1177 ) -> Option<(Vec<&'a Expr>, Vec<&'a Expr>)> {
1178 self.inner.conditional_arguments(args)
1179 }
1180
1181 fn short_circuits(&self) -> bool {
1182 self.inner.short_circuits()
1183 }
1184
1185 fn evaluate_bounds(&self, input: &[&Interval]) -> Result<Interval> {
1186 self.inner.evaluate_bounds(input)
1187 }
1188
1189 fn propagate_constraints(
1190 &self,
1191 interval: &Interval,
1192 inputs: &[&Interval],
1193 ) -> Result<Option<Vec<Interval>>> {
1194 self.inner.propagate_constraints(interval, inputs)
1195 }
1196
1197 fn struct_field_mapping(
1198 &self,
1199 literal_args: &[Option<ScalarValue>],
1200 ) -> Option<StructFieldMapping> {
1201 self.inner.struct_field_mapping(literal_args)
1202 }
1203
1204 fn output_ordering(&self, inputs: &[ExprProperties]) -> Result<SortProperties> {
1205 self.inner.output_ordering(inputs)
1206 }
1207
1208 fn preserves_lex_ordering(&self, inputs: &[ExprProperties]) -> Result<bool> {
1209 self.inner.preserves_lex_ordering(inputs)
1210 }
1211
1212 fn strictly_order_preserving(&self, inputs: &[ExprProperties]) -> Result<bool> {
1213 self.inner.strictly_order_preserving(inputs)
1214 }
1215
1216 fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
1217 self.inner.coerce_types(arg_types)
1218 }
1219
1220 fn documentation(&self) -> Option<&Documentation> {
1221 self.inner.documentation()
1222 }
1223
1224 fn placement(&self, args: &[ExpressionPlacement]) -> ExpressionPlacement {
1225 self.inner.placement(args)
1226 }
1227}
1228
1229#[cfg(test)]
1230mod tests {
1231 use super::*;
1232 use datafusion_expr_common::signature::Volatility;
1233 use std::hash::DefaultHasher;
1234
1235 #[derive(Debug, PartialEq, Eq, Hash)]
1236 struct TestScalarUDFImpl {
1237 name: &'static str,
1238 field: &'static str,
1239 signature: Signature,
1240 }
1241 impl ScalarUDFImpl for TestScalarUDFImpl {
1242 fn name(&self) -> &str {
1243 self.name
1244 }
1245
1246 fn signature(&self) -> &Signature {
1247 &self.signature
1248 }
1249
1250 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
1251 unimplemented!()
1252 }
1253
1254 fn invoke_with_args(&self, _args: ScalarFunctionArgs) -> Result<ColumnarValue> {
1255 unimplemented!()
1256 }
1257 }
1258
1259 // PartialEq and Hash must be consistent, and also PartialEq and PartialOrd
1260 // must be consistent, so they are tested together.
1261 #[test]
1262 fn test_partial_eq_hash_and_partial_ord() {
1263 // A parameterized function
1264 let f = test_func("foo", "a");
1265
1266 // Same like `f`, different instance
1267 let f2 = test_func("foo", "a");
1268 assert_eq!(f, f2);
1269 assert_eq!(hash(&f), hash(&f2));
1270 assert_eq!(f.partial_cmp(&f2), Some(Ordering::Equal));
1271
1272 // Different parameter
1273 let b = test_func("foo", "b");
1274 assert_ne!(f, b);
1275 assert_ne!(hash(&f), hash(&b)); // hash can collide for different values but does not collide in this test
1276 assert_eq!(f.partial_cmp(&b), None);
1277
1278 // Different name
1279 let o = test_func("other", "a");
1280 assert_ne!(f, o);
1281 assert_ne!(hash(&f), hash(&o)); // hash can collide for different values but does not collide in this test
1282 assert_eq!(f.partial_cmp(&o), Some(Ordering::Less));
1283
1284 // Different name and parameter
1285 assert_ne!(b, o);
1286 assert_ne!(hash(&b), hash(&o)); // hash can collide for different values but does not collide in this test
1287 assert_eq!(b.partial_cmp(&o), Some(Ordering::Less));
1288 }
1289
1290 fn test_func(name: &'static str, parameter: &'static str) -> ScalarUDF {
1291 ScalarUDF::from(TestScalarUDFImpl {
1292 name,
1293 field: parameter,
1294 signature: Signature::any(1, Volatility::Immutable),
1295 })
1296 }
1297
1298 fn hash<T: Hash>(value: &T) -> u64 {
1299 let hasher = &mut DefaultHasher::new();
1300 value.hash(hasher);
1301 hasher.finish()
1302 }
1303}