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

   ### Describe the bug
   
   A Parquet scan with `datafusion.execution.parquet.pushdown_filters = false` 
(the default) can return rows in the wrong order, and `ORDER BY ... LIMIT` can 
return wrong rows.
   
   With `pushdown_filters = false`, `ParquetSource` keeps a pushed-down 
predicate only for row group and page pruning, and it replies `PushedDown::No`, 
so a `FilterExec` stays above the scan. But `FileScanConfig::eq_properties` 
reads the same predicate through `FileSource::filter()` and adds its equalities 
to the scan's equivalence properties. The scan then claims that `a` is constant 
(for `a = 5`) or that `a` and `b` are equal (for `a = b`), while it emits rows 
that violate this.
   
   An operator placed directly on the scan, below the `FilterExec`, trusts the 
false property. An order-preserving `RepartitionExec` takes its merge keys from 
the scan's normalized output ordering. Normalization removes the "constant" 
`a`, so the repartition merges streams that are sorted by `(a, b)` using `b` 
only. The `FilterExec` then removes the `a != 5` rows, and the rows that stay 
are out of order.
   
   ### To Reproduce
   
   ```sql
   COPY (SELECT * FROM (VALUES (3, 9), (5, 1)) v(a, b)) TO 'mre/f1.parquet' 
STORED AS PARQUET;
   COPY (SELECT * FROM (VALUES (5, 2)) v(a, b)) TO 'mre/f2.parquet' STORED AS 
PARQUET;
   CREATE EXTERNAL TABLE t (a INT, b INT) STORED AS PARQUET LOCATION 'mre/' 
WITH ORDER (a ASC, b ASC);
   
   SET datafusion.execution.target_partitions = 4;
   SET datafusion.optimizer.repartition_file_scans = false;
   
   -- Expected (5,1,1), (5,2,1). Actual: (5,2,1), (5,1,1)
   SELECT a, b, count(*) FROM t WHERE a = 5 GROUP BY a, b ORDER BY b;
   
   SET datafusion.optimizer.prefer_existing_sort = true;
   
   -- Expected 1. Actual: 2
   SELECT b FROM t WHERE a = 5 ORDER BY b LIMIT 1;
   ```
   
   The plan of the `LIMIT` query shows the mismatch. The scan declares 
`output_ordering=[a, b]`, but the repartition merges on `b` only:
   
   ```
   SortPreservingMergeExec: [b@0 ASC NULLS LAST], fetch=1
     FilterExec: a@0 = 5, projection=[b@1], fetch=1
       RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2, 
preserve_order=true, sort_exprs=b@1 ASC NULLS LAST
         DataSourceExec: file_groups={2 groups: [...]}, projection=[a, b], 
output_ordering=[a@0 ASC NULLS LAST, b@1 ASC NULLS LAST], file_type=parquet, 
predicate=a@0 = 5, ...
   ```
   
   The equality form fails in the same way. With files sorted by `a`, `WHERE a 
= b ORDER BY a` returns `5, 3` instead of `3, 5`, because the repartition 
merges on `b`.
   
   ### Expected behavior
   
   The results are the same as with `pushdown_filters = true`, which is correct 
in all of these cases. DuckDB gives the same results.
   
   ### Additional context
   
   - Reproduced on `main` at e8e41ae958.
   - With the default configuration, the scan is split into `target_partitions` 
file groups, so no `RoundRobin` repartition is added below the `FilterExec`. 
`repartition_file_scans = false` is sufficient to trigger the bug. Declared 
file partitioning (`preserve_file_partitions`) should also trigger it, but I 
did not test that.
   - The equivalence derivation was added in 
https://github.com/apache/datafusion/pull/16686 (for 
https://github.com/apache/datafusion/issues/16563). It is correct when 
`pushdown_filters = true`, because then the scan applies the filter to every 
row and the `FilterExec` is removed.
   - Operators that filter pushdown moves through (aggregate, sort, projection, 
join, union) are not affected. They commute with the filter, and a property 
that holds on the filtered rows is sufficient for them. The failure needs a 
node that is inserted directly on the scan after pushdown.
   - Dynamic filters (hash join, TopK) are not affected. They are not plain `=` 
expressions, and the equivalences are computed at planning time.
   


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