sunchao commented on code in PR #24668:
URL: https://github.com/apache/datafusion/pull/24668#discussion_r3857150340


##########
datafusion/physical-expr/src/expressions/negative.rs:
##########
@@ -128,7 +178,9 @@ impl PhysicalExpr for NegativeExpr {
         interval: &Interval,
         children: &[&Interval],
     ) -> Result<Option<Vec<Interval>>> {
-        let negated_interval = interval.arithmetic_negate()?;
+        let Some(negated_interval) = negate_interval(interval)? else {

Review Comment:
   **[P1] Preserve wrapped minima during inverse constraint propagation**
   
   The new forward-overflow fallback permits an unsafe inverse result here. For 
input statistics `i: [-128, 1]`, the predicate `-i < 0` gives the negation node 
`[NULL, -1]` (unbounded below). Negating those endpoints succeeds as `[1, 
NULL]`, so intersecting with the child incorrectly infers `i = 1`. But array 
negation wraps `-128` back to `-128`, which also satisfies the predicate. 
`FilterExec` then publishes exact singleton statistics and removes the required 
sort.
   
   I reproduced this on a single-partition Int8 Parquet scan containing rows 
`[1, -128]`, with min/max statistics and Parquet pruning/filter pushdown 
disabled:
   
   ```sql
   SELECT i FROM t
   WHERE -i < CAST(0 AS TINYINT)
   ORDER BY i LIMIT 1;
   ```
   
   Head `4e9d57f3` returns `1`, not `-128`. Base `63f5b55f` raised an overflow 
error during forward analysis; the new fallback exposes this silent 
wrong-result path. Could `negate_interval` also fall back for signed intervals 
whose lower endpoint is unbounded, and add a statistics-backed execution 
regression? I verified that this guard restores `SortExec` and the correct 
result in an isolated experiment.



##########
datafusion/physical-expr/src/expressions/negative.rs:
##########
@@ -160,13 +212,31 @@ impl PhysicalExpr for NegativeExpr {
         }
     }
 
-    /// The ordering of a [`NegativeExpr`] is simply the reverse of its child.
+    /// Negation reverses the child ordering unless signed integer values may 
wrap.
     fn get_properties(&self, children: &[ExprProperties]) -> 
Result<ExprProperties> {
+        let (range, overflowed) = match negate_interval(&children[0].range)? {
+            Some(range) => (range, false),
+            None => (
+                Interval::make_unbounded(&children[0].range.data_type())?,
+                true,
+            ),
+        };
+        let may_wrap = children[0].range.data_type().is_signed_integer()
+            && (children[0].range.lower().is_null() || overflowed);

Review Comment:
   **[P2] Retain ordering for safe integer widening on unbounded inputs**
   
   This guard also drops ordering when the signed minimum is provably 
unreachable. For an unbounded CSV source declared with `i INTEGER NOT NULL` and 
`WITH ORDER (i ASC NULLS LAST)`, I tested:
   
   ```sql
   SELECT i FROM neg_order_stream
   ORDER BY -CAST(i AS BIGINT) DESC NULLS LAST;
   ```
   
   Base `63f5b55f` builds a `StreamingTableExec` without a sort. Head 
`4e9d57f3` inserts a global `SortExec` and fails `SanityCheckPlan` with `Cannot 
execute pipeline breaking queries`. `Int32 -> Int64` is an exact widening 
conversion, so its result can never be `Int64::MIN` and negation safely 
reverses the declared ordering. However, `cast_expr_properties` currently 
replaces the source range with unbounded Int64, causing this condition to 
classify it as potentially wrapping.
   
   Could we retain the representable source-domain bounds for strict integer 
widening casts so this guard can preserve safe ordering, with an 
unbounded-source planning regression test? The same new rejection also affects 
`ORDER BY -(-i)`, although wrapping integer-array double negation preserves 
every input value.



-- 
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