adriangb opened a new issue, #25414:
URL: https://github.com/apache/datafusion/issues/25414

   ### Describe the bug
   
   DataFusion returns incorrect values when a query reads a struct field from a 
subquery, and the subquery also computes a column with the same name as a table 
column. The optimizer removes the computation and keeps the original table 
column.
   
   This occurs with the default configuration. It is not a planning error: the 
query completes and shows incorrect data. If the computation changes the data 
type, the query fails with an internal error.
   
   The setting `datafusion.optimizer.enable_leaf_expression_pushdown` controls 
the optimizer rules that cause the problem. When you set it to `false`, the 
results are correct.
   
   ### To Reproduce
   
   Use `datafusion-cli` on `main` (22f9a92178):
   
   ```sql
   create table t(a int, s struct<b varchar>) as values (1, {b: 'x'});
   
   -- 1. Filter in the subquery
   select a, s['b'] from (select -a as a, s from t where a > 0);
   
   -- 2. Limit in the subquery
   select a, s['b'] from (select -a as a, s from t limit 10);
   
   -- 3. Limit in the subquery, and the computation changes the type (Int32 -> 
Int64)
   select a, s['b'] from (select a * 10 as a, s from t limit 10);
   ```
   
   | Query | DataFusion | DuckDB 1.5.2 | PostgreSQL 17.6 |
   |---|---|---|---|
   | 1 | `1, x` | `-1, x` | `-1, x` |
   | 2 | `1, x` | `-1, x` | `-1, x` |
   | 3 | internal error (see below) | `10, x` | `10, x` |
   
   For PostgreSQL, I used a composite type (`create type st1 as (b text)`) and 
`(s).b` in place of `s['b']`. The queries are otherwise the same.
   
   With `set datafusion.optimizer.enable_leaf_expression_pushdown = false;`, 
DataFusion returns `-1, x`, `-1, x` and `10, x`.
   
   The plan of query 1 shows that the negation is not there. The top projection 
reads `t.a` directly:
   
   ```
   Projection: t.a AS a, __datafusion_extracted_1 AS t.s[b]
     Filter: t.a > Int32(0)
       Projection: get_field(t.s, Utf8("b")) AS __datafusion_extracted_1, t.a
         TableScan: t projection=[a, s]
   ```
   
   The plan of query 2 has the same problem:
   
   ```
   Projection: t.a AS a, __datafusion_extracted_1 AS t.s[b]
     Limit: skip=0, fetch=10
       Projection: get_field(t.s, Utf8("b")) AS __datafusion_extracted_1, t.a
         TableScan: t projection=[a, s], fetch=10
   ```
   
   Query 3 fails because the schema check after the rule finds the type change:
   
   ```
   Error: Optimizer rule 'push_down_leaf_projections' failed
   caused by
   Check optimizer-specific invariants after optimizer rule: 
push_down_leaf_projections
   caused by
   Internal error: Assertion failed: compatible: Failed due to a difference in 
schemas: original schema: DFSchema { inner: Schema { fields: [Field { name: 
"a", data_type: Int64, ... }, Field { name: "t.s[b]", data_type: Utf8View, ... 
}] ... }, new schema: DFSchema { inner: Schema { fields: [Field { name: "a", 
data_type: Int32, ... }, Field { name: "t.s[b]", data_type: Utf8View, ... }] 
... }.
   ```
   
   A larger example with CTEs gives the same incorrect result:
   
   ```sql
   create table t1(a int, b int, s struct<a int, b varchar>) as values
     (0, 1, {a: 1, b: 'x'}), (0, 2, {a: 2, b: 'y'}), (0, 3, {a: 3, b: 'z'}),
     (2, 4, {a: 4, b: 'w'}), (2, 5, {a: 5, b: 'v'});
   
   with src as (select a + a as a, b, s from t1),
        l as (select a as b, s from (select * from src limit 100))
   select b, count(s['b']) from l group by b order by b;
   ```
   
   DataFusion returns `(0, 3), (2, 2)`. DuckDB and PostgreSQL return `(0, 3), 
(4, 2)`.
   
   ### Expected behavior
   
   DataFusion returns the same results as when 
`enable_leaf_expression_pushdown` is `false`. The computed column (`-a`, `a * 
10`, `a + a`) stays in the plan above the table column.
   
   ### Additional context
   
   The rules are `ExtractLeafExpressions` and `PushDownLeafProjections` in 
`datafusion/optimizer/src/extract_leaf_expressions.rs`. The problem occurs when 
the extraction projection for `s['b']` moves through a projection that has an 
output column with the same name as one of its input columns (`-t.a AS a`). I 
did not find the root cause. Possibly, the rules resolve columns by name, and 
thus the reference to the computed `a` becomes a reference to the input column 
`t.a`.
   
   Related, but not the same problem:
   - https://github.com/apache/datafusion/pull/25412 fixes a planning error 
("ambiguous" schema) in the same merge function. It does not fix this problem. 
Before that change, some queries of this shape failed with the planning error. 
With that change, they complete and show this problem.
   - https://github.com/apache/datafusion/pull/25388 changes how these rules 
place `BinaryExpr` and similar expressions. Test this problem again after it 
merges.
   - https://github.com/apache/datafusion/issues/24678 was also a wrong-results 
problem in these rules (a volatile expression evaluated two times). It is fixed.
   
   A random test of plans and SQL found this problem.
   


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