@@ -378,6 +378,24 @@ impl ScalarFunctionDefinition {
378378 ScalarFunctionDefinition :: Name ( func_name) => func_name. as_ref ( ) ,
379379 }
380380 }
381+
382+ /// Whether this function is volatile, i.e. whether it can return different results
383+ /// when evaluated multiple times with the same input.
384+ pub fn is_volatile ( & self ) -> Result < bool > {
385+ match self {
386+ ScalarFunctionDefinition :: BuiltIn ( fun) => {
387+ Ok ( fun. volatility ( ) == crate :: Volatility :: Volatile )
388+ }
389+ ScalarFunctionDefinition :: UDF ( udf) => {
390+ Ok ( udf. signature ( ) . volatility == crate :: Volatility :: Volatile )
391+ }
392+ ScalarFunctionDefinition :: Name ( func) => {
393+ internal_err ! (
394+ "Cannot determine volatility of unresolved function: {func}"
395+ )
396+ }
397+ }
398+ }
381399}
382400
383401impl ScalarFunction {
@@ -1678,14 +1696,28 @@ fn create_names(exprs: &[Expr]) -> Result<String> {
16781696 . join ( ", " ) )
16791697}
16801698
1699+ /// Whether the given expression is volatile, i.e. whether it can return different results
1700+ /// when evaluated multiple times with the same input.
1701+ pub fn is_volatile ( expr : & Expr ) -> Result < bool > {
1702+ match expr {
1703+ Expr :: ScalarFunction ( func) => func. func_def . is_volatile ( ) ,
1704+ _ => Ok ( false ) ,
1705+ }
1706+ }
1707+
16811708#[ cfg( test) ]
16821709mod test {
16831710 use crate :: expr:: Cast ;
16841711 use crate :: expr_fn:: col;
1685- use crate :: { case, lit, Expr } ;
1712+ use crate :: {
1713+ case, lit, BuiltinScalarFunction , ColumnarValue , Expr , ReturnTypeFunction ,
1714+ ScalarFunctionDefinition , ScalarFunctionImplementation , ScalarUDF , Signature ,
1715+ Volatility ,
1716+ } ;
16861717 use arrow:: datatypes:: DataType ;
16871718 use datafusion_common:: Column ;
16881719 use datafusion_common:: { Result , ScalarValue } ;
1720+ use std:: sync:: Arc ;
16891721
16901722 #[ test]
16911723 fn format_case_when ( ) -> Result < ( ) > {
@@ -1786,4 +1818,45 @@ mod test {
17861818 "UInt32(1) OR UInt32(2)"
17871819 ) ;
17881820 }
1821+
1822+ #[ test]
1823+ fn test_is_volatile_scalar_func_definition ( ) {
1824+ // BuiltIn
1825+ assert ! (
1826+ ScalarFunctionDefinition :: BuiltIn ( BuiltinScalarFunction :: Random )
1827+ . is_volatile( )
1828+ . unwrap( )
1829+ ) ;
1830+ assert ! (
1831+ !ScalarFunctionDefinition :: BuiltIn ( BuiltinScalarFunction :: Abs )
1832+ . is_volatile( )
1833+ . unwrap( )
1834+ ) ;
1835+
1836+ // UDF
1837+ let return_type: ReturnTypeFunction =
1838+ Arc :: new ( move |_| Ok ( Arc :: new ( DataType :: Utf8 ) ) ) ;
1839+ let fun: ScalarFunctionImplementation =
1840+ Arc :: new ( move |_| Ok ( ColumnarValue :: Scalar ( ScalarValue :: new_utf8 ( "a" ) ) ) ) ;
1841+ let udf = Arc :: new ( ScalarUDF :: new (
1842+ "TestScalarUDF" ,
1843+ & Signature :: uniform ( 1 , vec ! [ DataType :: Float32 ] , Volatility :: Stable ) ,
1844+ & return_type,
1845+ & fun,
1846+ ) ) ;
1847+ assert ! ( !ScalarFunctionDefinition :: UDF ( udf) . is_volatile( ) . unwrap( ) ) ;
1848+
1849+ let udf = Arc :: new ( ScalarUDF :: new (
1850+ "TestScalarUDF" ,
1851+ & Signature :: uniform ( 1 , vec ! [ DataType :: Float32 ] , Volatility :: Volatile ) ,
1852+ & return_type,
1853+ & fun,
1854+ ) ) ;
1855+ assert ! ( ScalarFunctionDefinition :: UDF ( udf) . is_volatile( ) . unwrap( ) ) ;
1856+
1857+ // Unresolved function
1858+ ScalarFunctionDefinition :: Name ( Arc :: from ( "UnresolvedFunc" ) )
1859+ . is_volatile ( )
1860+ . expect_err ( "Shouldn't determine volatility of unresolved function" ) ;
1861+ }
17891862}
0 commit comments