jayzhan211 commented on code in PR #25781:
URL: https://github.com/apache/datafusion/pull/25781#discussion_r4271517379


##########
datafusion/optimizer/src/decorrelate.rs:
##########
@@ -662,18 +727,37 @@ impl PullUpCorrelatedExpr {
                 .any(|expr| matches!(expr, Expr::Column(c) if c == *col))
         });
         if required_cols.is_empty() {
-            return true;
+            return GroupingSetsPullUp::NoColumnsToAdd;
         }
 
-        grouping_sets.iter().all(|grouping_set| match grouping_set {
-            GroupingSet::Rollup(_) | GroupingSet::Cube(_) => false,
-            GroupingSet::GroupingSets(sets) => sets.iter().all(|set| {
-                required_cols.iter().all(|col| {
-                    set.iter()
-                        .any(|expr| matches!(expr, Expr::Column(c) if c == 
*col))
-                })
-            }),
-        })
+        let already_covered =
+            grouping_sets.iter().all(|grouping_set| match grouping_set {
+                GroupingSet::Rollup(_) | GroupingSet::Cube(_) => false,
+                GroupingSet::GroupingSets(sets) => sets.iter().all(|set| {
+                    required_cols.iter().all(|col| {
+                        set.iter()
+                            .any(|expr| matches!(expr, Expr::Column(c) if c == 
*col))
+                    })
+                }),
+            });
+        if already_covered {
+            return GroupingSetsPullUp::NoColumnsToAdd;
+        }
+
+        let has_empty_set = grouping_sets.iter().any(|grouping_set| match 
grouping_set {
+            GroupingSet::Rollup(_) | GroupingSet::Cube(_) => true,
+            GroupingSet::GroupingSets(sets) => sets.iter().any(|set| 
set.is_empty()),
+        });
+        let reads_grouping_fn = 
aggregate.aggr_expr.iter().any(is_grouping_call);

Review Comment:
   `is_grouping_call` never fires: `ResolveGroupingFunction` already rewrote 
`GROUPING` into `__grouping_id` bit tests in a projection above the 
`Aggregate`, so `aggr_expr` holds no `grouping` call. When `k` is in no set, 
nothing above reads `k`, so this returns `SafeToExtend`. Appending `k` makes 
the group list `[j, k, x]`, and the stale `__grouping_id & 2 >> 1` now reads 
`k`'s bit. Main fails to plan both queries below; this branch returns wrong 
rows.
   
   Repro:
   ```sql
   CREATE TABLE gs_inner3(k INT, j INT, x INT) AS VALUES (1, 10, 100), (NULL, 
20, 200), (5, 30, 300), (2, 40, 400);
   -- expected 1 t, 2 t, 4 f, 5 t, NULL f; returns false for every row
   SELECT gs_outer.k, EXISTS (SELECT 1 FROM gs_inner3 WHERE gs_inner3.k = 
gs_outer.k GROUP BY GROUPING SETS ((gs_inner3.j), (gs_inner3.x)) HAVING 
GROUPING(gs_inner3.j) = 1) FROM gs_outer ORDER BY gs_outer.k;
   -- expected 1, 1, 0, 1, 0; returns 0 for every row
   SELECT gs_outer.k, (SELECT count(*) FROM (SELECT GROUPING(gs_inner3.j) AS g 
FROM gs_inner3 WHERE gs_inner3.k = gs_outer.k GROUP BY GROUPING SETS 
((gs_inner3.j), (gs_inner3.x))) t WHERE t.g = 1) FROM gs_outer ORDER BY 
gs_outer.k;
   ```
   
   Fix (and delete `is_grouping_call`). With this, full slt passes and the 
`((k), (j))` EXISTS case still decorrelates:
   ```diff
   -        let reads_grouping_fn = 
aggregate.aggr_expr.iter().any(is_grouping_call);
   +        // `GROUPING`/`GROUPING_ID` are resolved to bit tests on 
`__grouping_id`
   +        // above the aggregate; adding a column shifts those bits.
   +        let reads_grouping_id = self
   +            .column_refs_above_aggregate
   +            .iter()
   +            .any(|col| col.name == Aggregate::INTERNAL_GROUPING_ID);
            let read_above = required_cols
                .iter()
                .any(|col| self.column_refs_above_aggregate.contains(*col));
   
   -        if has_empty_set || reads_grouping_fn || read_above {
   +        if has_empty_set || reads_grouping_id || read_above {
   ```



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