Skip to content

Aggregate (window) projection keeps the first value for duplicate output names; non-aggregate keeps the last #47

Closed

Description

@ankur-paan

Summary

In an aggregate (window) query, when two SELECT fields have the same output name, the output keeps the first value. In a non-aggregate query, the same SELECT keeps the last value. The two paths give different results for the same projection.

Revision: 0cda7fddf5777b834b534287246ea4c588abca2b (main after #46).

Where

crates/rekuiper-sql/src/eval.rs, eval_aggregate_stateful (line 291). Every non-aggregate branch writes with entry(..).or_insert.., so a later field cannot replace an earlier value of the same name:

Line Branch
319 Expr::Wildcard
333 Expr::WildcardModified
350 Expr::Identifier
365, 375 Expr::FieldAccess with *
387 Expr::FieldAccess
410 general expression (with the comment "Don't overwrite group keys / wildcard copies with same key")

The aggregate-call branch (line 401) uses output.insert(..), and so does the ordinary projection path. So in the aggregate path, the result depends on which branch wrote first.

Reproduction

Rule:

SELECT sum(v) AS x, v AS x, count(*) AS n FROM "order/in" GROUP BY COUNTWINDOW(2)

Input: {"v":1}, then {"v":3}.

  • Expected (same rule as the non-aggregate path: first position, last value): {"x":1,"n":2}
  • Actual (from the code): {"x":4,"n":2}. sum inserts x=4, then the identifier branch does not replace it.

A second case with a wildcard:

SELECT sum(v) AS v, * FROM "order/in" GROUP BY COUNTWINDOW(2)
  • Expected: v stays in the first position and has the first record's raw value, because the later * writes it. Other keys follow in input order.
  • Actual: v keeps the sum.

Proposed fix

In eval_aggregate_stateful, write each field with insert in SELECT order, as the non-aggregate path does. IndexMap::insert keeps the first position of an existing key and replaces its value, so the output order from #46 does not change.

Please add regressions for:

  • duplicate aliases in a window query;
  • an aggregate alias followed by *;
  • * followed by an aggregate alias of the same name;
  • a GROUP BY key that is selected two times.

The comment at line 409 says the or_insert is there on purpose ("Don't overwrite group keys / wildcard copies"). If that behaviour is required, please document it as the rule for both paths. Only the difference between the two paths is the defect.

Impact

A broker that uses this engine gets different output for the same projection with and without a window. It also cannot give one documented rule for duplicate output names. We found this while we wrote order tests against #46.

Activity

  1. self-assigned this
    on Oct 19, 2026
  2. added a commit that references this issue on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions