Skip to content

fix: fix aggregate expression outputs#181

Merged
wackywendell merged 5 commits into
mainfrom
gordon.hamilton/aggregate-expression-outputs
Jul 16, 2026
Merged

fix: fix aggregate expression outputs#181
wackywendell merged 5 commits into
mainfrom
gordon.hamilton/aggregate-expression-outputs

Conversation

@gord02

@gord02 gord02 commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Description

Fix Aggregate output/grouping-expression handling

Aggregate relation output items were mishandled in two ways:

  1. Parser: a function_call output item was always parsed as a new measure, even when it structurally matched an existing grouping expression; should instead map back to that grouping position, not double as a measure.
  2. Textifier: grouping-expression output items were rendered as raw $i field references using the expression's dedup/reference index, instead of resolving through grouping_expressions and printing the actual expression — producing syntactically valid but semantically wrong output whenever the index didn't coincidentally match the field number. Fixed in both the current and deprecated grouping code paths.
  3. non-function-call output expressions (literals, etc.) matching a grouping expression by structural equality are now supported, error messages on unmatched output expressions are asserted in tests.

Type of Change

  • Bug fix

Testing

  • Added tests for new functionality
  • All existing tests pass

Related Issues

Closes #175

@gord02
gord02 requested review from a team and wackywendell as code owners July 13, 2026 17:42
Comment thread src/textify/rels.rs
let mut grouping_set: Vec<Value> = vec![];
for i in &group.expression_references {
grouping_set.push(Value::Reference(*i as i32));
let value = match rel.grouping_expressions.get(*i as usize) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i is an index into rel.grouping_expressions, not a field reference into the input schema which is resolved to the actual expression rather than printing it as $i.

Comment thread src/textify/rels.rs
index // is expression returned by this closure and inserted into map
});
grouping_set.push(Value::Reference(expression_index_map[&key]));
if seen_expressions.insert(exp.encode_to_vec()) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same bug: Value::Reference(index) was replaced with Value::Expression(exp), the index-tracking machinery that value depended on became unused code.

@wackywendell wackywendell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally pretty good! I have one small structural suggestion and a couple comment/docs ones, but pretty good!

Comment thread src/parser/expressions.rs Outdated
}

/// Parses an already-unwrapped inner pair of `Rule::expression`.
pub(crate) fn parse_expression_inner(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple things:

  1. _inner is not a very good name for a function, it looks like its just the 'inside' of another function and doesn't really tell you what its doing.
  2. By exporting an _inner function from one module and importing it in another, the internal complexity of the implementations are being exposed. I think you can just directly use Expression::parse_pair on the outer (you may need to clone the Pair, but a Pair is a lightweight reference so that's fine), which makes it clearer where its called what is happening and preserves the interface boundaries.

Comment thread src/parser/relations.rs Outdated
Comment thread src/parser/relations.rs
Comment thread GRAMMAR.md Outdated
gord02 and others added 3 commits July 14, 2026 13:21
Co-authored-by: Wendell Smith <wackywendell@gmail.com>
….com:DataDog/substrait-explain into gordon.hamilton/aggregate-expression-outputs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes incorrect handling of Aggregate relation outputs across both parsing and textification so that grouping-expression outputs resolve to the correct grouping positions/expressions (rather than being misinterpreted as measures or rendered as raw $i indexes). This aligns the text format more closely with Substrait’s AggregateRel output schema semantics (grouping_expressions + measures) and improves roundtrip correctness.

Changes:

  • Parser: change aggregate_output parsing to accept general expressions, mapping outputs back to grouping-expression positions by structural equality and only treating non-matching function_calls as new measures.
  • Textifier: fix grouping-set rendering to print the actual grouping expressions (resolving expression_references through grouping_expressions), including the deprecated per-Grouping code path.
  • Docs/tests: update grammar documentation and add regression tests for reordered groupings, non-function output expressions, and error messaging.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/textify/rels.rs Fixes grouping-set rendering to print resolved grouping expressions (including deprecated grouping fields) and adds regression tests.
src/parser/relations.rs Reworks aggregate output parsing to map outputs to grouping positions by structural equality and adds tests for correct mapping and errors.
src/parser/expressions.rs Updates aggregate-measure parsing to parse directly from function_call after grammar changes.
src/parser/expression_grammar.pest Broadens aggregate_output grammar from `(reference
GRAMMAR.md Updates user-facing grammar/docs to reflect new aggregate output rules and measure syntax limitations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@wackywendell
wackywendell merged commit dd0bbe2 into main Jul 16, 2026
5 checks passed
@wackywendell
wackywendell deleted the gordon.hamilton/aggregate-expression-outputs branch July 16, 2026 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] All Expression Support in Aggregates

3 participants