Skip to content

Fix preagg registration identity#2369

Draft
shangyian wants to merge 7 commits into
DataJunction:mainfrom
shangyian:fix-preagg-registration-identity
Draft

Fix preagg registration identity#2369
shangyian wants to merge 7 commits into
DataJunction:mainfrom
shangyian:fix-preagg-registration-identity

Conversation

@shangyian

Copy link
Copy Markdown
Collaborator

Summary

Test Plan

  • PR has an associated issue: #
  • make check passes
  • make test shows 100% unit test coverage

Deployment Plan

shangyian and others added 6 commits July 26, 2026 03:55
find_matching_preagg matched a metric's measure to a pre-agg measure purely by
compute_expression_hash(component.expression), which hashes only the inner
expression and ignores the Phase-1 aggregation. So SUM(x) and MAX(x) collided on
the same hash: a MAX/MIN metric would bind to a SUM-built pre-agg column and
compute MAX(sum) instead of MAX(row) -- silently wrong (and overstated) results.

Make the measure identity (expression hash, Phase-1 aggregation) on both sides
of the match. PreAggMeasure already stores `aggregation`, so this is a
match-time check only -- no re-registration. A SUM partial can no longer serve a
MAX/MIN metric; such metrics fall back to the base fact (like non-additive
metrics do). Additive SUM/COUNT metrics are unaffected.

Regression test: v3.total_unit_price (SUM(unit_price)) vs v3.max_unit_price
(MAX(unit_price)) sharing the inner expression -- the SUM metric still uses the
agg, the MAX metric falls back to the base fact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The metrics layer applies filters on projected (output) dimensions at the outer
query but deliberately skips "filter-only" dimensions -- ones present in a grain
group but rolled away -- expecting each grain group's CTE to have applied them.
The source-built path does; build_grain_group_from_preagg did not, so a filter on
a dimension that is in the pre-agg grain but not in the requested output was
silently dropped: no WHERE was emitted and the query summed across all values
(e.g. filtering country='US' still returned every country -- an over-count).

Inject those filter-only predicates into the pre-agg scan, mapping each filtered
dimension to its physical (possibly remapped) column and filtering before the
GROUP BY roll-up, mirroring the source path. Filters on projected dimensions are
untouched (the outer query still applies them, no double-apply). A filter on a
column absent from the pre-agg grain already forces a fallback to source.

Regression test: filter on a rolled-up, column-mapped dimension is emitted as
`WHERE <physical_col> = ...` inside the CTE, in both measures and metrics SQL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploy Preview for thriving-cassata-78ae72 canceled.

Name Link
🔨 Latest commit a6f2cfd
🔍 Latest deploy log https://app.netlify.com/projects/thriving-cassata-78ae72/deploys/6a675ceddbb6310008f60daf

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.

1 participant