Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions datafusion/core/tests/sqllogictests/test_files/scalar.slt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

#############
## Scalar Function Tests
#############

statement ok
CREATE TABLE t1(
a INT,
b INT
) as VALUES
(1, 100),
(2, 1000),
(3, 10000)
;

# log scalar function
query IT rowsort
select log(2, 64) a, log(100) b union all select log(2, 8), log(10);
----
3 1
6 2

# log scalar function
query IT rowsort
select log(a, 64) a, log(b), log(10, b) from t1;
----
3.7855785 4 4
6 3 3
Infinity 2 2

# log scalar nulls
query IT rowsort
select log(null, 64) a, log(null) b
----
NULL NULL

# log scalar nulls 1
query IT rowsort
select log(2, null) a, log(null) b
----
NULL NULL

# log scalar nulls 2
query IT rowsort
select log(null, null) a, log(null) b
----

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add the test cases you identified in the PR here (log(0), log(1, 64)) as well to document the behavior and also file a ticket to document the discrepancy?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, filed #5259

NULL NULL

# log scalar ops with zero edgecases
# please see https://github.com/apache/arrow-datafusion/pull/5245#issuecomment-1426828382
query IT rowsort
select log(0) a, log(1, 64) b
----
-Infinity Infinity
1 change: 1 addition & 0 deletions datafusion/expr/src/expr_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ scalar_expr!(
"returns the hexdecimal representation of an integer"
);
scalar_expr!(Uuid, uuid, , "Returns uuid v4 as a string value");
scalar_expr!(Log, log, base x, "logarithm of a `x` for a particular `base`");

// string functions
scalar_expr!(Ascii, ascii, chr, "ASCII code value of the character");
Expand Down
15 changes: 14 additions & 1 deletion datafusion/expr/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ pub fn return_type(
_ => Ok(DataType::Float64),
},

BuiltinScalarFunction::Log => match &input_expr_types[0] {
DataType::Float32 => Ok(DataType::Float32),
_ => Ok(DataType::Float64),
},

BuiltinScalarFunction::ArrowTypeof => Ok(DataType::Utf8),

BuiltinScalarFunction::Abs
Expand All @@ -265,7 +270,6 @@ pub fn return_type(
| BuiltinScalarFunction::Cos
| BuiltinScalarFunction::Exp
| BuiltinScalarFunction::Floor
| BuiltinScalarFunction::Log
| BuiltinScalarFunction::Ln
| BuiltinScalarFunction::Log10
| BuiltinScalarFunction::Log2
Expand Down Expand Up @@ -607,6 +611,15 @@ pub fn signature(fun: &BuiltinScalarFunction) -> Signature {
],
fun.volatility(),
),
BuiltinScalarFunction::Log => Signature::one_of(
vec![
TypeSignature::Exact(vec![DataType::Float32]),
TypeSignature::Exact(vec![DataType::Float64]),
TypeSignature::Exact(vec![DataType::Float32, DataType::Float32]),
TypeSignature::Exact(vec![DataType::Float64, DataType::Float64]),
],
fun.volatility(),
),
BuiltinScalarFunction::ArrowTypeof => Signature::any(1, fun.volatility()),
// math expressions expect 1 argument of type f64 or f32
// priority is given to f64 because e.g. `sqrt(1i32)` is in IR (real numbers) and thus we
Expand Down
4 changes: 3 additions & 1 deletion datafusion/physical-expr/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,6 @@ pub fn create_physical_fun(
BuiltinScalarFunction::Cos => Arc::new(math_expressions::cos),
BuiltinScalarFunction::Exp => Arc::new(math_expressions::exp),
BuiltinScalarFunction::Floor => Arc::new(math_expressions::floor),
BuiltinScalarFunction::Log => Arc::new(math_expressions::log10),
BuiltinScalarFunction::Ln => Arc::new(math_expressions::ln),
BuiltinScalarFunction::Log10 => Arc::new(math_expressions::log10),
BuiltinScalarFunction::Log2 => Arc::new(math_expressions::log2),
Expand All @@ -340,6 +339,9 @@ pub fn create_physical_fun(
BuiltinScalarFunction::Atan2 => {
Arc::new(|args| make_scalar_function(math_expressions::atan2)(args))
}
BuiltinScalarFunction::Log => {
Arc::new(|args| make_scalar_function(math_expressions::log)(args))
}

// string functions
BuiltinScalarFunction::MakeArray => Arc::new(array_expressions::array),
Expand Down
34 changes: 34 additions & 0 deletions datafusion/physical-expr/src/math_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,40 @@ pub fn atan2(args: &[ArrayRef]) -> Result<ArrayRef> {
}
}

pub fn log(args: &[ArrayRef]) -> Result<ArrayRef> {
// Support overloaded log(base, x) and log(x) which defaults to log(10, x)
// note in f64::log params order is different than in sql. e.g in sql log(base, x) == f64::log(x, base)
let mut base = &(Arc::new(Float32Array::from_value(10.0, args[0].len())) as ArrayRef);
let mut x = &args[0];
if args.len() == 2 {
x = &args[1];
base = &args[0];
}
match args[0].data_type() {
DataType::Float64 => Ok(Arc::new(make_function_inputs2!(
x,
base,
"x",
"base",
Float64Array,
{ f64::log }
)) as ArrayRef),

DataType::Float32 => Ok(Arc::new(make_function_inputs2!(
x,
base,
"x",
"base",
Float32Array,
{ f32::log }
)) as ArrayRef),

other => Err(DataFusionError::Internal(format!(
"Unsupported data type {other:?} for function log"
))),
}
}

#[cfg(test)]
mod tests {

Expand Down
6 changes: 5 additions & 1 deletion datafusion/proto/src/logical_plan/from_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use datafusion_expr::{
character_length, chr, coalesce, concat_expr, concat_ws_expr, cos, date_bin,
date_part, date_trunc, digest, exp,
expr::{self, Sort, WindowFunction},
floor, from_unixtime, left, ln, log10, log2,
floor, from_unixtime, left, ln, log, log10, log2,
logical_plan::{PlanType, StringifiedPlan},
lower, lpad, ltrim, md5, now, nullif, octet_length, power, random, regexp_match,
regexp_replace, repeat, replace, reverse, right, round, rpad, rtrim, sha224, sha256,
Expand Down Expand Up @@ -1303,6 +1303,10 @@ pub fn parse_expr(
parse_expr(&args[0], registry)?,
parse_expr(&args[1], registry)?,
)),
ScalarFunction::Log => Ok(log(
parse_expr(&args[0], registry)?,
parse_expr(&args[1], registry)?,
)),
ScalarFunction::FromUnixtime => {
Ok(from_unixtime(parse_expr(&args[0], registry)?))
}
Expand Down