Repository navigation
fix: prevent unsafe integer interval propagation - #25234
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #25234 +/- ##
==========================================
+ Coverage 81.94% 82.29% +0.35%
==========================================
Files 1135 1137 +2
Lines 428166 430429 +2263
Branches 428166 430429 +2263
==========================================
+ Hits 350841 354216 +3375
+ Misses 56378 54789 -1589
- Partials 20947 21424 +477 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Hi @kosiew would you mind reviewing this fix? |
kosiew
left a comment
There was a problem hiding this comment.
@haohuaijin, thanks for working on this. The changes look good to me. I like that this addresses both wrapping integer arithmetic and truncating division while keeping the interval and sort-property inference conservative. The regression coverage around ordering and statistics is also helpful.
I left one non-blocking suggestion for some additional coercion-path coverage.
|
🚀 |
|
Hi @kosiew, I looked into the merge queue failures. The widening change exposed two existing gaps in interval handling: negation doesn’t handle I think we have two options:
I’m perfer 1 to keep this PR focused, then opening a separate issue for the widening optimization. What do you think? I’d like to hear your thoughts before I update the PR. |
|
I agree with option 1. The widening optimization exposes pre-existing interval-bound failures in negation and narrowing casts, and fixing both correctly needs broader boundary coverage than this sort-correctness fix. Please remove the widening change, keep the overflow/division fixes, and update the FIFO and sort expectations. We can track widening separately with targeted tests for those bound transitions. |
kosiew
left a comment
There was a problem hiding this comment.
Thanks for the follow-up. The option 1 changes look good to me.
Removing the widening-integer interval-bound propagation keeps the cast endpoints conservative, and the FIFO fixture and physical-plan SLT expectation have been updated accordingly. The FIFO test now avoids the unrelated integer-bound transition, while widening integer arithmetic correctly retains the required sort.
All of my previous comments have been addressed. The earlier non-blocking suggestion around the coercion path is no longer relevant given the agreed scope reduction.
I don't see any new correctness issues introduced by these follow-up changes. Thanks for working through this!
|
thanks again @kosiew |
## Which issue does this PR close? - close: apache#25232 ## Rationale for this change Arithmetic filters can incorrectly identify a column as constant and eliminate a required `SortExec`, returning rows in the wrong order. Integer multiplication can wrap, and integer division truncates, so their mathematical inverses do not necessarily describe all valid inputs. ```sql CREATE TABLE wrap_test (a INT) AS VALUES (-2147483647), (1); SELECT a FROM wrap_test WHERE a * 2::INT = 2::INT ORDER BY a DESC; -- Expected: 1, -2147483647 -- Actual before this fix: -2147483647, 1 CREATE TABLE division_test (a INT) AS VALUES (2), (3); SELECT a FROM division_test WHERE a / 2::INT = 1::INT ORDER BY a DESC; -- Expected: 3, 2 -- Actual before this fix: 2, 3 ``` Both multiplication inputs evaluate to `2`; both division inputs evaluate to `1`. Nevertheless, interval inference narrows `a` to a singleton and removes the sort. Without the filters, the sorts are retained and these queries return the correct order. With `ORDER BY ... LIMIT`, incorrect sort elimination can also change which rows are returned. ## What changes are included in this PR? - Return unbounded output intervals when unchecked integer addition, subtraction or multiplication may wrap. - Skip inverse propagation for integer division, potentially wrapping arithmetic, and zero products where an operand may be zero. - Retain interval narrowing for supported arithmetic proven safe from these cases. - Correct a Filter statistics test whose previous lower bound excluded a valid wrapping-subtraction input. ## What is the testing strategy for this PR? - SQL regressions in `filter_without_sort_exec.slt` cover both reproductions and sorting a wrapped expression; verified failing before the fix and passing afterward. - Unit tests enumerate selected Int8 domains under checked and wrapping arithmetic, ensuring forward and propagated intervals retain valid runtime values. Additional tests cover unsigned subtraction underflow and safe multiplication narrowing. - Relevant interval, analysis and Filter tests, the complete affected SLT file, Clippy and repository lint checks pass locally. ## Are there any user-facing changes? Affected queries retain necessary sorting. Unsafe interval optimizations are skipped; SQL arithmetic semantics and public APIs are unchanged.
## Which issue does this PR close? Closes apache#25794 ## Rationale for this change Integer multiplication overflow can produce false-empty filter statistics despite returning matching rows. For TINYINT inputs `(0, -3)` and `(20, 7)`, `SELECT a, b, a * b AS x FROM mul_wrap WHERE a * b < -100` has the following behavior: | | Before | After | | --- | --- | --- | | Returned row | `(20, 7, -116)` | `(20, 7, -116)` | | Estimated rows | `Inexact(0)` | `Inexact(2)` | | Column a bounds | `Min=Exact(Int8(NULL)), Max=Exact(Int8(NULL))` | `Min=Inexact(Int8(0)), Max=Inexact(Int8(20))` | | Column b bounds | `Min=Exact(Int8(NULL)), Max=Exact(Int8(NULL))` | `Min=Inexact(Int8(-3)), Max=Inexact(Int8(7))` | | Distinct counts | `Exact(0)` for both columns | Unknown | The estimate of 2 is conservative, not the exact count of the one surviving row. The fix removes the false-empty inference without changing runtime arithmetic or query results in these reproductions. Related: apache#25232 and the merged fix apache#25234. That fix guards wrapping arithmetic when the inferred interval is unbounded. Here, the lower-level multiplication helper discards an overflow-generated unbounded endpoint, preventing that guard from activating. ## What changes are included in this PR? Distinguish lower- and upper-bound comparisons so multiplication preserves overflow-generated unbounded endpoints. Reuse the helpers in intersection and union, preserving their behavior. In the example, interval multiplication now retains `[-60, +infinity]` instead of `[-60, 0]`. The existing wrapping-arithmetic protection then widens the expression range to fully unbounded, allowing the wrapped value `-116`. ## What is the testing strategy for this PR? Add interval overflow cases and a Parquet SQL regression checking results and statistics. Validation on the PR branch: - `cargo test -p datafusion-expr-common --lib interval_arithmetic::tests` — 45 passed. - `cargo test --test sqllogictests -- parquet_statistics` — passed. ## Are there any user-facing changes? Affected filters report conservative statistics instead of false-empty statistics. No public API changes.
Which issue does this PR close?
Rationale for this change
Arithmetic filters can incorrectly identify a column as constant and eliminate a required
SortExec, returning rows in the wrong order. Integer multiplication can wrap, and integer division truncates, so their mathematical inverses do not necessarily describe all valid inputs.Both multiplication inputs evaluate to
2; both division inputs evaluate to1. Nevertheless, interval inference narrowsato a singleton and removes the sort. Without the filters, the sorts are retained and these queries return the correct order. WithORDER BY ... LIMIT, incorrect sort elimination can also change which rows are returned.What changes are included in this PR?
What is the testing strategy for this PR?
filter_without_sort_exec.sltcover both reproductions and sorting a wrapped expression; verified failing before the fix and passing afterward.Are there any user-facing changes?
Affected queries retain necessary sorting. Unsafe interval optimizations are skipped; SQL arithmetic semantics and public APIs are unchanged.