Skip to content

Commit

Permalink
Create built-in scalar functions programmatically (#1734)
Browse files Browse the repository at this point in the history
* create build-in scalar functions programatically

Signed-off-by: remzi <[email protected]>

* solve conflict

Signed-off-by: remzi <[email protected]>

* fix spelling mistake

Signed-off-by: remzi <[email protected]>

* rename to call_fn

Signed-off-by: remzi <[email protected]>
  • Loading branch information
HaoYang670 authored Feb 7, 2022
1 parent 31d0adf commit 40c29e5
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 35 deletions.
14 changes: 14 additions & 0 deletions datafusion/src/logical_plan/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2235,6 +2235,20 @@ pub fn exprlist_to_fields<'a>(
expr.into_iter().map(|e| e.to_field(input_schema)).collect()
}

/// Calls a named built in function
/// ```
/// use datafusion::logical_plan::*;
///
/// // create the expression sin(x) < 0.2
/// let expr = call_fn("sin", vec![col("x")]).unwrap().lt(lit(0.2));
/// ```
pub fn call_fn(name: impl AsRef<str>, args: Vec<Expr>) -> Result<Expr> {
match name.as_ref().parse::<functions::BuiltinScalarFunction>() {
Ok(fun) => Ok(Expr::ScalarFunction { fun, args }),
Err(e) => Err(e),
}
}

#[cfg(test)]
mod tests {
use super::super::{col, lit, when};
Expand Down
2 changes: 1 addition & 1 deletion datafusion/src/logical_plan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub use dfschema::{DFField, DFSchema, DFSchemaRef, ToDFSchema};
pub use display::display_schema;
pub use expr::{
abs, acos, and, approx_distinct, approx_percentile_cont, array, ascii, asin, atan,
avg, binary_expr, bit_length, btrim, case, ceil, character_length, chr, col,
avg, binary_expr, bit_length, btrim, call_fn, case, ceil, character_length, chr, col,
columnize_expr, combine_filters, concat, concat_ws, cos, count, count_distinct,
create_udaf, create_udf, date_part, date_trunc, digest, exp, exprlist_to_fields,
floor, in_list, initcap, left, length, lit, lit_timestamp_nano, ln, log10, log2,
Expand Down
45 changes: 11 additions & 34 deletions datafusion/src/optimizer/simplify_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,8 +735,8 @@ mod tests {
use super::*;
use crate::assert_contains;
use crate::logical_plan::{
and, binary_expr, col, create_udf, lit, lit_timestamp_nano, DFField, Expr,
LogicalPlanBuilder,
and, binary_expr, call_fn, col, create_udf, lit, lit_timestamp_nano, DFField,
Expr, LogicalPlanBuilder,
};
use crate::physical_plan::functions::{make_scalar_function, BuiltinScalarFunction};
use crate::physical_plan::udf::ScalarUDF;
Expand Down Expand Up @@ -1010,46 +1010,29 @@ mod tests {
#[test]
fn test_const_evaluator_scalar_functions() {
// concat("foo", "bar") --> "foobar"
let expr = Expr::ScalarFunction {
args: vec![lit("foo"), lit("bar")],
fun: BuiltinScalarFunction::Concat,
};
let expr = call_fn("concat", vec![lit("foo"), lit("bar")]).unwrap();
test_evaluate(expr, lit("foobar"));

// ensure arguments are also constant folded
// concat("foo", concat("bar", "baz")) --> "foobarbaz"
let concat1 = Expr::ScalarFunction {
args: vec![lit("bar"), lit("baz")],
fun: BuiltinScalarFunction::Concat,
};
let expr = Expr::ScalarFunction {
args: vec![lit("foo"), concat1],
fun: BuiltinScalarFunction::Concat,
};
let concat1 = call_fn("concat", vec![lit("bar"), lit("baz")]).unwrap();
let expr = call_fn("concat", vec![lit("foo"), concat1]).unwrap();
test_evaluate(expr, lit("foobarbaz"));

// Check non string arguments
// to_timestamp("2020-09-08T12:00:00+00:00") --> timestamp(1599566400000000000i64)
let expr = Expr::ScalarFunction {
args: vec![lit("2020-09-08T12:00:00+00:00")],
fun: BuiltinScalarFunction::ToTimestamp,
};
let expr =
call_fn("to_timestamp", vec![lit("2020-09-08T12:00:00+00:00")]).unwrap();
test_evaluate(expr, lit_timestamp_nano(1599566400000000000i64));

// check that non foldable arguments are folded
// to_timestamp(a) --> to_timestamp(a) [no rewrite possible]
let expr = Expr::ScalarFunction {
args: vec![col("a")],
fun: BuiltinScalarFunction::ToTimestamp,
};
let expr = call_fn("to_timestamp", vec![col("a")]).unwrap();
test_evaluate(expr.clone(), expr);

// check that non foldable arguments are folded
// to_timestamp(a) --> to_timestamp(a) [no rewrite possible]
let expr = Expr::ScalarFunction {
args: vec![col("a")],
fun: BuiltinScalarFunction::ToTimestamp,
};
let expr = call_fn("to_timestamp", vec![col("a")]).unwrap();
test_evaluate(expr.clone(), expr);

// volatile / stable functions should not be evaluated
Expand Down Expand Up @@ -1090,10 +1073,7 @@ mod tests {
}

fn now_expr() -> Expr {
Expr::ScalarFunction {
args: vec![],
fun: BuiltinScalarFunction::Now,
}
call_fn("now", vec![]).unwrap()
}

fn cast_to_int64_expr(expr: Expr) -> Expr {
Expand All @@ -1104,10 +1084,7 @@ mod tests {
}

fn to_timestamp_expr(arg: impl Into<String>) -> Expr {
Expr::ScalarFunction {
args: vec![lit(arg.into())],
fun: BuiltinScalarFunction::ToTimestamp,
}
call_fn("to_timestamp", vec![lit(arg.into())]).unwrap()
}

#[test]
Expand Down

0 comments on commit 40c29e5

Please sign in to comment.