ayushan003 opened a new issue, #27001: URL: https://github.com/apache/datafusion/issues/27001
### Describe the bug `simplify_expressions` folds `A * 0` to a zero literal typed from the *operands* rather than from the multiplication's *result type*. When those differ, the rewritten plan compares two differently-typed decimals, which fails. On an empty table it fails while planning, with an internal error: ``` Internal error: Assertion failed: lhs_type == rhs_type (left: Decimal128(20, 0), right: Decimal128(38, 0)): Only intervals with the same data type are comparable, lhs:Decimal128(20, 0), rhs:Decimal128(38, 0). ``` With rows it fails at execution instead: ``` Arrow error: Invalid argument error: Invalid comparison operation: Decimal128(20, 0) >= Decimal128(38, 0) ``` `EXPLAIN VERBOSE` shows type coercion doing the right thing and the simplifier then dropping the result type: ``` Filter: t.c * Int64(0) >= Int64(2) after type_coercion: Filter: CAST(t.c AS Decimal128(20, 0)) * CAST(Int64(0) AS Decimal128(20, 0)) >= CAST(Int64(2) AS Decimal128(38, 0)) after simplify_expressions: Filter: Decimal128(0,20,0) >= Decimal128(2,38,0) ``` Coercion is correct: `Decimal128(20, 0) * Decimal128(20, 0)` has result type `Decimal128(38, 0)`, so casting the literal `2` to `Decimal128(38, 0)` is right. The simplifier then replaces the whole multiplication with the zero operand, which is `Decimal128(20, 0)`, and the comparison no longer matches. ### To Reproduce ```sql CREATE TABLE t(c UBIGINT NOT NULL); SELECT c FROM t WHERE (c * 0) >= 2; ``` Every part of that is load-bearing, which I think points at the cause: | variation | result | | --- | --- | | `c UBIGINT NOT NULL` | fails | | `c UBIGINT` (nullable) | plans fine — `A * 0 -> 0` requires non-nullable `A`, so no fold happens | | `c * 1`, `c * 2`, `c * -1`, `c * c` | plan fine — `A * 1` already preserves the result type, via `simplify_right_is_one_case` | | `(c * 0) = 2` | plans fine — `Interval::equal` tolerates differing types, unlike `gt`/`gt_eq` | | `(c * 0) BETWEEN 2 AND 3` | fails (desugars to `>=` and `<=`) | | `USMALLINT`, `UTINYINT` | plan fine — only the 64-bit unsigned width reaches `Decimal128` | ### Expected behavior The query should plan and run, returning no rows: `c * 0` is `0`, and `0 >= 2` is false. ### Additional context Reproduced on `datafusion-cli 55.1.0` built from commit `e8940acd4` (2026-10-28), Linux x86_64. The internal-error form is an instance of the class #22028 describes. That tree already contains #22027 (`631f189f0`, "coerce operand types in Interval mul/div/intersect/union/contains"), which is why the failure surfaces in `Interval::gt_eq` — the comparison path it did not cover. Coercing there too turns the planning-time internal error into the Arrow error above, so the interval assertion is a symptom; the type loss in the simplifier is the cause. Closed #13186 and #17814 report the same assertion text with different types and repros. Found with a metamorphic/differential SQL testing tool I am building for a university software-engineering course. ### Willingness to contribute I have a fix ready and will open a PR referencing this issue: the `A * 0` and `0 * A` arms check `BinaryTypeCoercer::get_result_type()` and cast the zero when it differs, mirroring what `simplify_right_is_one_case` already does for `A * 1`. Two lines changed plus one helper, with a test. -- 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]
