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

   ### Describe the bug
   
   `SELECT DISTINCT` can return duplicate rows when its input has a functional 
dependency whose determinant columns cover all output columns, but whose 
uniqueness was lost earlier in the plan.
   
   The `ReplaceDistinctWithAggregate` optimizer rule removes `Distinct::All` 
whenever a functional dependence's `source_indices` cover all input fields, 
without checking the dependency `mode`. After a join, 
`FunctionalDependencies::join` downgrades dependencies to `Dependency::Multi` 
because a formerly-unique key (e.g. a primary key) may now occur in many rows. 
The rule ignores this downgrade and removes the `Distinct` anyway, so 
duplicates are returned to the user.
   
   ### To Reproduce
   
   Run the following in `datafusion-cli`:
   
   ```sql
   CREATE TABLE users_with_pk (id INT, name VARCHAR, PRIMARY KEY (id)) AS VALUES
     (1, 'alice'),
     (2, 'bob');
   
   CREATE TABLE user_orders (user_id INT, amount INT) AS VALUES
     (1, 10),
     (1, 20),
     (2, 30);
   
   SELECT DISTINCT u.id
   FROM users_with_pk u
   LEFT JOIN user_orders o ON u.id = o.user_id
   ORDER BY u.id;
   ```
   
   Actual output — `id = 1` is repeated once per matching order:
   
   ```
   +----+
   | id |
   +----+
   | 1  |
   | 1  |
   | 2  |
   +----+
   ```
   
   `EXPLAIN` shows the `DISTINCT` has been dropped entirely — there is no 
`Aggregate` (or any other deduplication) in the plan:
   
   ```
   logical_plan
   01)Projection: u.id
   02)--Left Join: u.id = o.user_id
   03)----SubqueryAlias: u
   04)------TableScan: users_with_pk projection=[id]
   05)----SubqueryAlias: o
   06)------TableScan: user_orders projection=[user_id]
   ```
   
   ### Expected behavior
   
   The query should return each `u.id` once:
   
   ```
   +----+
   | id |
   +----+
   | 1  |
   | 2  |
   +----+
   ```
   
   and the plan should retain an `Aggregate` (or equivalent deduplication) for 
the `DISTINCT`.
   
   ### Additional context
   
   The faulty check is in 
`datafusion/optimizer/src/replace_distinct_aggregate.rs` 
(`ReplaceDistinctWithAggregate::rewrite`): it only verifies that 
`dep.source_indices` covers all fields, but a `Dependency::Multi` dependence 
merely means equal determinant keys imply equal rows — the key may still occur 
in multiple rows, so the input is not necessarily duplicate-free. The removal 
is only sound for `Dependency::Single` dependencies.
   
   Fixed by #23548.
   


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