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

   ### Describe the bug
   
   A subquery with `ORDER BY ... LIMIT` over a sorted Parquet file can return 
the wrong rows, with no error and in the default configuration, when an outer 
sort or join reads it. This affects tables with a known sort order 
(`sorting_columns` in the file, which `COPY ... ORDER BY` writes, or `WITH 
ORDER`) whose files have more than one row group.
   
   ### To Reproduce
   
   ```sql
   COPY (SELECT value AS s, value * 10 AS x FROM generate_series(1, 12) ORDER 
BY s)
   TO 'repro/t.parquet' STORED AS PARQUET OPTIONS ('format.max_row_group_size' 
'3');
   COPY (SELECT value AS k FROM generate_series(7, 8))
   TO 'repro/b.parquet' STORED AS PARQUET;
   
   CREATE EXTERNAL TABLE t STORED AS PARQUET LOCATION 'repro/t.parquet';
   CREATE EXTERNAL TABLE b STORED AS PARQUET LOCATION 'repro/b.parquet';
   
   -- Query 1
   SELECT s FROM (SELECT * FROM t ORDER BY s LIMIT 3) ORDER BY s DESC;
   
   -- Query 2
   SELECT s FROM (SELECT * FROM t ORDER BY s LIMIT 3) ORDER BY x DESC LIMIT 1;
   
   -- Query 3
   SELECT i.s FROM b JOIN (SELECT s FROM t ORDER BY s LIMIT 3) i ON b.k = i.s;
   ```
   
   ### Expected behavior
   
   | Query | DataFusion returns | Expected |
   |---|---|---|
   | 1 | 12, 11, 10 | 3, 2, 1 |
   | 2 | 12 | 3 |
   | 3 | 7, 8 | no rows (the subquery holds 1, 2, 3, and `b` holds 7, 8) |
   
   DuckDB returns the expected results on the same files. Tested on main at 
4bf32cb46d.
   
   ### Additional context
   
   The file's sort order lets `EnsureRequirements` remove the subquery's sort, 
and `LimitPushdown` then puts the limit on the scan as `limit=3`. That limit 
keeps the first rows the scan reads, but two later rules change what it reads 
first:
   
   - **Queries 1 and 2:** `PushdownSort` reverses the scan's row groups 
(`pushdown_sort.rs:151`), so the limit keeps the last rows. 
`enable_sort_pushdown = false` avoids this.
   - **Query 3:** the post-optimization `FilterPushdown` pushes the join's 
dynamic filter into the scan (`filter_pushdown.rs:427`), so the limit applies 
after it. `enable_dynamic_filter_pushdown = false` avoids this.
   
   Treating a fetch as a barrier in both rules fixes all three. On main that's 
22 added lines, and all sqllogictests pass unchanged. Two snapshots from #21070 
change, because they merge an outer filter into a filter that has a fetch, 
which changes the rows it keeps.
   
   #23800 and #25065 don't touch these two rules. #27162 is a different bug: 
there the file isn't sorted across its row groups, and here it is.
   
   <details>
   <summary>The scan in each plan, and the two snapshots</summary>
   
   ```text
   Query 1: DataSourceExec: ..., projection=[s], limit=3, ..., 
sort_order_for_reorder=[s@0 DESC], reverse_row_groups=true
   Query 2: DataSourceExec: ..., projection=[s, x], limit=3, ..., 
sort_order_for_reorder=[x@1 DESC], reverse_row_groups=true
   Query 3: DataSourceExec: ..., projection=[s], limit=3, output_ordering=[s@0 
ASC NULLS LAST], ..., predicate=DynamicFilter [ empty ]
   ```
   
   The snapshots are `test_filter_collapse_inner_fetch_preserved` and 
`test_filter_collapse_both_fetch_uses_minimum` in 
`core/tests/physical_optimizer/filter_pushdown.rs`.
   
   </details>
   
   ### Willingness to contribute
   
   I'm not planning to fix this myself, so anyone is welcome to pick it up. 
Feel free to ping me with questions about the cause or when you'd like a review.
   


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