You are viewing a plain text version of this content. The canonical link for it is here.
Posted to github@datafusion.apache.org by "adriangb (via GitHub)" <gi...@apache.org> on 2026/10/15 05:58:50 UTC

[PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

adriangb opened a new pull request, #26356:
URL: https://github.com/apache/datafusion/pull/26356

   ## Which issue does this PR close?
   
   No issue filed. The reproduction is below.
   
   ## Rationale for this change
   
   `EliminateGroupByConstant` re-plans the original group expressions over the new `Aggregate` with `LogicalPlanBuilder::project`. Column normalization falls back to the input schema of the aggregate. Thus an unqualified group expression, such as an extracted leaf `__datafusion_extracted_1`, becomes `m.__datafusion_extracted_1` when the input is a `SubqueryAlias: m`. The new aggregate does not output that name, and the rule fails:
   
   ```
   Optimizer rule 'eliminate_group_by_constant' failed
   caused by
   Schema error: No field named m.__datafusion_extracted_1.
   ```
   
   The input plan is valid, and the rule turns it into an invalid one. We reach it when we optimize a plan, bind its parameters with `replace_params_with_values`, and optimize again. The bound value makes a group key redundant only after `ExtractLeafExpressions` has rewritten the plan. In a single `optimize` call, `EliminateGroupByConstant` runs before `ExtractLeafExpressions` in each pass, so I could not reproduce it there. Since #26184, the arguments of filtered aggregates no longer go into a common-expression projection between the aggregate and the alias, so the aggregate can sit directly on the alias and the problem shows.
   
   ```rust
   let ctx = SessionContext::new();
   ctx.sql("CREATE TABLE t AS SELECT * FROM (VALUES (TIMESTAMP '2026-01-01T00:00:00', named_struct('a', 'x'), 1)) AS v(ts, s, x)")
       .await?.collect().await?;
   let scan = ctx.table("t").await?.into_unoptimized_plan();
   let plan = LogicalPlanBuilder::from(scan)
       .alias("m")?
       .aggregate(
           vec![
               date_bin(
                   cast(placeholder("$1"), DataType::Interval(IntervalUnit::MonthDayNano)),
                   col("ts"),
                   lit(ScalarValue::TimestampNanosecond(Some(0), None)),
               ),
               get_field(col("s"), "a").alias("c"),
               col("ts"),
           ],
           vec![
               sum(col("x") + lit(1)).filter(col("x").gt(lit(0))).build()?,
               max(col("x") + lit(1)).filter(col("x").lt(lit(5))).build()?,
           ],
       )?
       .build()?;
   let state = ctx.state();
   let plan = state.optimize(&plan)?;
   let plan = plan.replace_params_with_values(&ParamValues::List(vec![
       ScalarValue::Utf8(Some("1 minute".into())).into(),
   ]))?;
   state.optimize(&plan)?; // fails with the error above
   ```
   
   ## What changes are included in this PR?
   
   - The rule builds the projection with `Projection::try_new` and does not re-plan the group expressions. A kept key or an aggregate becomes a column of the schema of the new aggregate. A redundant key keeps its expression, which reads only bare GROUP BY columns that the new aggregate outputs unchanged. An item gets an alias only when its name differs from the original output field, so existing plans do not change.
   - The rule leaves an aggregate with a `GroupingSet` unchanged, because its output fields do not map one to one to `group_expr`.
   
   ## What is the testing strategy for this PR?
   
   - New unit test `test_eliminate_with_unqualified_reference_to_qualified_input`. It fails without the change, with the same schema error.
   - `cargo test -p datafusion-optimizer` and `cargo test -p datafusion-sqllogictest --test sqllogictests` pass. No existing plan changes.
   
   ## Are there any user-facing changes?
   
   No API changes. A plan that failed in this rule now optimizes.
   


-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #26356:
URL: https://github.com/apache/datafusion/pull/26356#discussion_r4299039619


##########
datafusion/optimizer/src/eliminate_group_by_constant.rs:
##########
@@ -56,33 +57,86 @@ impl OptimizerRule for EliminateGroupByConstant {
                     })
                     .collect();
 
-                let (redundant, required): (Vec<_>, Vec<_>) = aggregate
+                let is_redundant: Vec<bool> = aggregate
                     .group_expr
                     .iter()
-                    .partition(|expr| is_redundant_group_expr(expr, &group_by_columns));
+                    .map(|expr| is_redundant_group_expr(expr, &group_by_columns))
+                    .collect();
+                let redundant_count = is_redundant.iter().filter(|r| **r).count();
                 // Return now if no simplification can be done. We also bail out
                 // if applying the optimization would eliminate all of the
                 // grouping expressions (e.g., GROUP BY on only constant
                 // expressions): this would turn a grouped aggregate into an
                 // ungrouped aggregate, which changes query semantics (grouped
                 // aggregates produce an empty result set on an empty input,
                 // whereas ungrouped aggregates return a single row).
-                if redundant.is_empty() || required.is_empty() {
+                // A grouping set adds output fields that do not map one to one
+                // to `group_expr`, so the rule also leaves it unchanged.
+                if redundant_count == 0
+                    || redundant_count == aggregate.group_expr.len()
+                    || aggregate
+                        .group_expr
+                        .iter()
+                        .any(|expr| matches!(expr, Expr::GroupingSet(_)))
+                {
                     return Ok(Transformed::no(LogicalPlan::Aggregate(aggregate)));
                 }
 
-                let simplified_aggregate = LogicalPlan::Aggregate(Aggregate::try_new(
-                    aggregate.input,
-                    required.into_iter().cloned().collect(),
-                    aggregate.aggr_expr.clone(),
-                )?);
-
-                let projection_expr =
-                    aggregate.group_expr.into_iter().chain(aggregate.aggr_expr);
+                let original_schema = Arc::clone(&aggregate.schema);
+                let required = aggregate
+                    .group_expr
+                    .iter()
+                    .zip(&is_redundant)
+                    .filter(|(_, redundant)| !**redundant)
+                    .map(|(expr, _)| expr.clone())
+                    .collect();
+                let simplified_aggregate =
+                    Aggregate::try_new(aggregate.input, required, aggregate.aggr_expr)?;
+                let simplified_schema = Arc::clone(&simplified_aggregate.schema);
+
+                // Refer to the output columns of the simplified aggregate by
+                // position. Do not re-plan the original group expressions on top
+                // of it: an expression can refer to an input column through a
+                // name that the aggregate output does not carry, so a rebuilt
+                // projection does not always resolve. A redundant expression
+                // refers only to bare GROUP BY columns, which the simplified
+                // aggregate outputs unchanged.
+                let mut projection_expr =
+                    Vec::with_capacity(original_schema.fields().len());
+                let mut next_output = 0;
+                for (i, (expr, redundant)) in aggregate
+                    .group_expr
+                    .into_iter()
+                    .zip(is_redundant)
+                    .enumerate()
+                {
+                    let (qualifier, field) = original_schema.qualified_field(i);
+                    let expr = if redundant {
+                        expr.unalias()

Review Comment:
   `unalias()` discards metadata attached to a redundant group-key alias, and `alias_qualified()` below restores only its name and qualifier. For example, grouping by `col("a")` and `lit(1u32).alias_with_metadata("k", Some(metadata))` now loses `k`'s field metadata in the output schema. Keep the original expression here to preserve the alias and its metadata, and add a regression assertion for the output field metadata.



-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb merged PR #26356:
URL: https://github.com/apache/datafusion/pull/26356


-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on PR #26356:
URL: https://github.com/apache/datafusion/pull/26356#issuecomment-6251954946

   @HairstonE any interest in reviewing this change since you recently fixed this rule in https://github.com/apache/datafusion/pull/22132?


-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on PR #26356:
URL: https://github.com/apache/datafusion/pull/26356#issuecomment-6316390677

   @neilconway could I ask you to review this fix?


-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

Posted by "HairstonE (via GitHub)" <gi...@apache.org>.
HairstonE commented on PR #26356:
URL: https://github.com/apache/datafusion/pull/26356#issuecomment-6279022137

   Hey @adriangb, thanks for pinging me on this. 
   I have one question and I don't think it blocks this from being approved.
   On line 77, `aggregate.group_expr.iter().any(|expr| matches!(expr, Expr::GroupingSet(_)))`
   Here we are checking to see if any of the aggregate group expressions are GroupingSets. Is this redundant with the first condition? I think a grouping set can only ever be the sole group expression, which means the first condition would cause this to bail out here anyways.
   
   I've gone back and forth on this enough that I'm not sure anymore if it's redundant or guarding against a rarer case. Let me know what you think.


-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on PR #26356:
URL: https://github.com/apache/datafusion/pull/26356#issuecomment-6316371385

   Agreed, it looks redundat: `Aggregate::try_new folds` any group list that contains a grouping set into a single `GroupingSet` (via `enumerate_grouping_sets`), so the first two conditions always return first. I removed it in 99902be5a6.


-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

Posted by "codecov-commenter (via GitHub)" <gi...@apache.org>.
codecov-commenter commented on PR #26356:
URL: https://github.com/apache/datafusion/pull/26356#issuecomment-6185913614

   ## [Codecov](https://app.codecov.io/gh/apache/datafusion/pull/26356?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
   :x: Patch coverage is `91.17647%` with `6 lines` in your changes missing coverage. Please review.
   :white_check_mark: Project coverage is 82.83%. Comparing base ([`e732212`](https://app.codecov.io/gh/apache/datafusion/commit/e732212cabd030d500efc35049448b3714017c7b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)) to head ([`f7b82a3`](https://app.codecov.io/gh/apache/datafusion/commit/f7b82a3420ed10582f14e0f7c7cb1e53c966cf40?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
   
   | [Files with missing lines](https://app.codecov.io/gh/apache/datafusion/pull/26356?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Patch % | Lines |
   |---|---|---|
   | [...usion/optimizer/src/eliminate\_group\_by\_constant.rs](https://app.codecov.io/gh/apache/datafusion/pull/26356?src=pr&el=tree&filepath=datafusion%2Foptimizer%2Fsrc%2Feliminate_group_by_constant.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-ZGF0YWZ1c2lvbi9vcHRpbWl6ZXIvc3JjL2VsaW1pbmF0ZV9ncm91cF9ieV9jb25zdGFudC5ycw==) | 91.17% | [2 Missing and 4 partials :warning: ](https://app.codecov.io/gh/apache/datafusion/pull/26356?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   
   <details><summary>Additional details and impacted files</summary>
   
   
   
   ```diff
   @@            Coverage Diff             @@
   ##             main   #26356      +/-   ##
   ==========================================
   - Coverage   82.83%   82.83%   -0.01%     
   ==========================================
     Files        1151     1151              
     Lines      455332   455387      +55     
     Branches   455332   455387      +55     
   ==========================================
   + Hits       377165   377210      +45     
   - Misses      55262    55268       +6     
   - Partials    22905    22909       +4     
   ```
   </details>
   
   [:umbrella: View full report in Codecov by Harness](https://app.codecov.io/gh/apache/datafusion/pull/26356?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).   
   :loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
   <details><summary> :rocket: New features to boost your workflow: </summary>
   
   - :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
   - :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
   </details>


-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org


Re: [PR] fix: keep EliminateGroupByConstant from requalifying group expressions [datafusion]

Posted by "adriangb (via GitHub)" <gi...@apache.org>.
adriangb commented on PR #26356:
URL: https://github.com/apache/datafusion/pull/26356#issuecomment-6327133554

   > What do you think about adopting that as an SLT?
   
   Done!


-- 
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: github-unsubscribe@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org