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

   ### Describe the bug
   
   A filter on a grouping key that contains a volatile function (for example 
`random()`) gives incorrect results. The query returns rows that do not satisfy 
the `WHERE` clause.
   
   The optimizer moves the filter below the aggregate. It then replaces the key 
column with the key expression. Thus DataFusion calculates `random()` two times 
for each row: one time in the filter and one time in the `GROUP BY`. The two 
values are not the same, so the filter and the groups do not agree.
   
   ### To Reproduce
   
   Use `datafusion-cli`:
   
   ```sql
   CREATE TABLE v AS SELECT value AS a FROM generate_series(1, 10000);
   
   SELECT k, c
   FROM (SELECT random() < 0.5 AS k, count(*) AS c FROM v GROUP BY random() < 
0.5)
   WHERE k;
   ```
   
   Actual result (DataFusion 54.0.0 and `main` at 4e907557ad):
   
   ```
   +-------+------+
   | k     | c    |
   +-------+------+
   | false | 2447 |
   | true  | 2474 |
   +-------+------+
   ```
   
   The query returns a row with `k = false`, but the filter is `WHERE k`. Also, 
the total count is approximately 5000, not 10000, because the filter removes 
approximately half of the rows before the aggregate.
   
   The same problem occurs with `GROUP BY k` and with `WHERE k = false`.
   
   `EXPLAIN` shows that the filter is below the aggregate:
   
   ```
   ProjectionExec: c, k
     AggregateExec: mode=FinalPartitioned, group_by=[random() < 0.5]
       RepartitionExec: Hash(...)
         AggregateExec: mode=Partial, group_by=[random() < 0.5]
           FilterExec: random() < 0.5          <-- second calculation of 
random()
             RepartitionExec: RoundRobinBatch
               DataSourceExec
   ```
   
   ### Expected behavior
   
   The query must return only one row, with `k = true`. The count must be 
approximately 5000.
   
   PostgreSQL 17.11 gives the expected result. It keeps the filter above the 
aggregate:
   
   ```sql
   CREATE TABLE v AS SELECT value AS a FROM generate_series(1, 10000) AS value;
   SELECT k, c FROM (SELECT random() < 0.5 AS k, count(*) AS c FROM v GROUP BY 
random() < 0.5) AS s WHERE k;
   ```
   
   ```
    k |  c
   ---+------
    t | 4949
   (1 row)
   ```
   
   ```
    Subquery Scan on s
      Filter: s.k
      ->  HashAggregate
            Group Key: (random() < '0.5'::double precision)
            ->  Seq Scan on v
   ```
   
   Note: DuckDB 1.5.2 has the same bug. It returns both `false` and `true` rows 
for this query, and its plan also has `FILTER (random() < 0.5)` below 
`HASH_GROUP_BY`. Thus DuckDB is not a correct reference for this query.
   
   ### Additional context
   
   The cause is in `PushDownFilter`, in the `LogicalPlan::Aggregate` branch 
([`push_down_filter.rs`](https://github.com/apache/datafusion/blob/4e907557ad7e01d4f4bfaffc7f8df86f205ffed8/datafusion/optimizer/src/push_down_filter.rs#L998-L1030)).
 This branch pushes a predicate below the aggregate when all the columns of the 
predicate are grouping columns. It does not examine whether the grouping 
expression is volatile. The `LogicalPlan::Projection` branch 
(`rewrite_projection`) already keeps predicates on volatile expressions above 
the projection. The `Aggregate` branch must do the same.
   
   Found while investigating https://github.com/apache/datafusion/issues/25329 
and https://github.com/apache/datafusion/pull/25388.
   


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