Smallfu666 opened a new pull request, #5982:
URL: https://github.com/apache/datafusion-comet/pull/5982

   ## Which issue does this PR close?
   
   Closes #5330.
   
   ## Rationale for this change
   
   `NegativeExpr::get_properties` returned the child's properties with the 
child's own sort order:
   
   ```rust
   let properties = children[0].clone().with_order(children[0].sort_properties);
   Ok(properties)
   ```
   
   So for `-a` it reported the same ordering as `a` rather than the reverse, 
left the range
   unreflected, and inherited `preserves_lex_ordering` as `true` from the child.
   
   That last part is the one with teeth. 
`EquivalenceProperties::discover_new_orderings` gates on
   that flag, so given an ordering of `[c ASC, a ASC]` and `c = -a` it admitted 
a false `[a ASC]`
   into the ordering equivalence class. That is the state `EnforceSorting` 
reads when it decides a
   `SortExec` can be dropped.
   
   ## What changes are included in this PR?
   
   Reverse the ordering, reflect the range about zero, and set 
`preserves_lex_ordering` to false.
   
   The ordering claim and the range claim fail for different reasons, so they 
are decided
   separately:
   
   - Wrapping breaks both. In legacy mode the array path negates an integer 
with two's complement
     wrapping, where the minimum of the type is its own negation, so a range 
reaching that minimum
     gets neither claim. An unbounded range, which is what 
`EquivalenceProperties` hands this hook
     for a column, always reaches it.
   - `NaN` breaks only the ordering. `NaN` is the maximum of the sort order and 
negation leaves it
     `NaN`, so reversing a float ordering would send the maximum to the 
minimum. Negation is exact
     for floats otherwise, so the bounds still reflect soundly.
   
   ANSI mode raises an overflow error where legacy mode wraps, so it keeps the 
ordering claim.
   Unsigned integers are routed to `neg_wrapping` in either mode and get 
neither claim.
   
   Where the reflected bound is not representable, the range widens to 
unbounded rather than
   propagating an error, because `discover_new_orderings` does not absorb one 
and would fail the
   plan instead.
   
   ## How are these changes tested?
   
   14 new unit tests in `negative.rs`, covering both eval modes across signed, 
unsigned, float,
   decimal, duration and interval ranges.
   
   Two of them go through `EquivalenceProperties` rather than calling the hook 
directly. One
   rebuilds the reported scenario: `add_ordering([c ASC, a ASC])`, then
   `add_equal_conditions(c, -a)`, then asserts that `[a ASC]` is not admitted 
into `oeq_class()`.
   It fails on unpatched main.
   
   `cargo test -p datafusion-comet-spark-expr` passes 851 tests.
   `cargo clippy -p datafusion-comet-spark-expr --all-targets -- -D warnings` 
and
   `cargo fmt --all -- --check` are clean.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to