fix: log(0.0::float8) should error, not return -inf - #24399
Conversation
PostgreSQL treats log(0.0::float8) as a domain error. DataFusion previously returned -inf via IEEE 754. Match the same class of domain error already used for sqrt(negative), power(0, negative), and factorial(negative). Only the logged value is checked. A zero base (log(0, x)) and log(1, 64) are left unchanged so this stays scoped to apache#22261.
|
hi @shinzoxD |
kosiew
left a comment
There was a problem hiding this comment.
Thanks for working on this. The new PostgreSQL-compatible domain error handling and the additional coverage look useful overall.
I found one simplification path that can still bypass the new zero-value invariant, so I think that needs to be addressed before merging. I also left a small testing suggestion for the additional physical types touched by this change.
| Ok(ExprSimplifyResult::Simplified(b)) | ||
| } | ||
| number => { | ||
| if number == base && !base_nullable { |
There was a problem hiding this comment.
I think this simplification can bypass the new invariant. log(a, a) is simplified directly to 1, so the logged value is never evaluated. For example, SELECT log(0.0::float8, 0.0::float8) returns 1.0 on this commit instead of the expected domain error.
The similar log(a, power(a, b)) rewrite around lines 405-412 can also bypass the check when the power result is zero.
Could we guard these rewrites so they only apply when the domain-error preconditions are known to hold? It would also be good to add planner-level regression cases for these zero-valued forms.
|
|
||
| #[test] | ||
| fn test_log_zero_decimal128_errors() { | ||
| let err = invoke_log( |
There was a problem hiding this comment.
Nice to see the new coverage for Float32/64 and Decimal128/256. Since this change also touches the separate Float16, Decimal32, and Decimal64 branches, could we add a small table-driven unit test that exercises every changed physical type?
That should help catch branch-specific regressions in the future.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #24399 +/- ##
========================================
Coverage 81.18% 81.19%
========================================
Files 1110 1110
Lines 388906 389029 +123
Branches 388906 389029 +123
========================================
+ Hits 315733 315854 +121
- Misses 54576 54577 +1
- Partials 18597 18598 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Which issue does this PR close?
log(0.0::float8)should error, not return-inf#22261.Rationale for this change
SELECT log(0.0::float8)currently returns-inf. PostgreSQL raisesERROR: cannot take logarithm of zero.This is the same class of domain error already accepted for
sqrtof a negative number (#22260 / #22308),power(0, negative)(#22272), andfactorialof a negative number (#22270). IEEE 754 would yield-inf; PostgreSQL treats it as undefined.A previous attempt (#22564) grew into a log-function refactor (simplification rewrites,
log(1, 64), etc.) and was closed. This PR stays scoped to the issue: reject a zero value at evaluation time.What changes are included in this PR?
lognow returnscannot take logarithm of zerowhen the number being logged is zero (including-0.0, float32/float64, and decimal zeros).log(0, 64)) andlog(1, 64)are unchanged. Those are separate compatibility cases.logsimplifications (log(a, 1) => 0,log(a, a) => 1,log(a, power(a, b)) => b) are unchanged.log(0)returns-infandsqrt(-1)returnsNaN, both of which are now domain errors.Are these changes tested?
Yes.
datafusion/functions/src/math/log.rscover unary/binary float64, float32,-0.0, array input, decimal128, and decimal256.math.sltadds the issue query plus two-arg, negative-zero, column, and decimal cases, matching the style of thepower(0, -1)tests.scalar.sltupdates the previouslog(0) => -Infinityexpectation to the domain error, and keepslog(1, 64) => Infinity.Ran:
cargo test -p datafusion-functions --lib math::logcargo clippy -p datafusion-functions --lib -- -D warningscargo test -p datafusion-sqllogictest --test sqllogictests -- math.sltcargo test -p datafusion-sqllogictest --test sqllogictests -- scalar.slt(log cases pass; later failures are missingtestingsubmodule testdata foraggregate_test_100, unrelated)Are there any user-facing changes?
Yes.
log(0),log(0.0::float8), and other zero values now fail the query withcannot take logarithm of zeroinstead of returning-inf. Queries that relied on the IEEE result need to filter zeros first.