Skip to content

fix(core): prevent unbindable preaggregation queries, harden preagg tests - #1177

Draft
domoritz wants to merge 6 commits into
mainfrom
sql-fix/preagg
Draft

fix(core): prevent unbindable preaggregation queries, harden preagg tests#1177
domoritz wants to merge 6 commits into
mainfrom
sql-fix/preagg

Conversation

@domoritz

@domoritz domoritz commented Sep 2, 2026

Copy link
Copy Markdown
Member

Fixes #1189, #1187, #1188, #1190. Part of the audit tracked in #1170.

Note: This fix was created by Claude (an agent team ran a binder-error audit of the SQL layer; each fix went through automated implementation, simplification, and adversarial review passes, and the combined branch was re-reviewed for assembly fidelity).

The preaggregator emits an unbindable CREATE TABLE in four different shapes. Since #1090 (and now #1158) the coordinator recovers by falling back to the client's query, so every one of these fails silently as a lost optimization — charts are correct, the speedup just never happens. Relatedly, preaggregator.test.ts mostly asserted !!info, which is also true when the create fails and the fallback answers; that is why none of these were caught. One commit per issue, plus two droppable refactors:

  1. F-PA-03: Preaggregation mean-centering subquery drops the schema of a qualified base table #1189 fix: Qualify preagg mean-centering subquery table refsgetBase keeps the full serialized table path ("s"."data"), restoring the optimization for schema-qualified tables (and fixing cross-schema base-identity comparison as a side effect).
  2. F-PA-01: Preaggregation emits nested aggregates when mean-centering CTE-derived columns #1187 fix: Bail out of preaggregation when mean-centering CTE-derived columns — four explicit guards (divergent bases / aggregate-valued / window-valued / unresolvable-through-subqueries operands) throw into the existing bail channel.
  3. F-PA-02: Preaggregation places window functions without aggregate inputs in GROUP BY #1188 fix: Skip preaggregation for window functions without aggregate inputs — a plain window function among selection outputs skips the optimization instead of landing in GROUP BY (conservative interim relative to Window functions do not work in query with aggregate #259's CTE-hoisting idea).
  4. F-PA-04: Preaggregation does not push verbatim selection fields into CTE client queries #1190 fix: Skip preaggregation when verbatim active columns meet subqueriespreaggregateInfo returns null when verbatim selection fields can't be pushed into client CTEs.
  5. refactor(core): Share one node-presence test across preagg bail-outs — dedupes the walk helpers into containsNode (new preagg/contains-node.ts).
  6. refactor(core): Use a symbol for getBase's divergent-base result — replaces the NaN sentinel; callers read expr === DIVERGENT instead of typeof expr === 'number'.

Commits 5–6 are separately droppable (reviewer-verified they revert cleanly in order) if you'd rather keep this PR fixes-only.

Relationship to #1158

Complementary, verified empirically per fix: #1158 recovers after a failed view create; these guards prevent the invalid CREATE TABLE from being issued at all (cases 2–4), removing the error/log noise the recovery path would absorb. Case 1 is the only one that makes preaggregation work rather than bail.

Test hardening

The schema-qualified test probes the materialized view directly; the bail-out tests assert the non-optimized route plus correct values. Six new tests total (core 72/72); revert checks reproduce exactly the expected per-fix failures.

🤖 Generated with Claude Code

@domoritz
domoritz marked this pull request as ready for review September 3, 2026 02:30
@domoritz
domoritz requested a review from jheer as a code owner September 3, 2026 02:30
domoritz and others added 6 commits September 2, 2026 22:46
Fixes #1189.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes #1187.

Mean-centering builds a scalar subquery over the base table, so an operand
that only exists in an intermediate CTE, or that is aggregate- or
window-valued, cannot be resolved there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes #1188.

A window function with no aggregate inputs was classified as a groupby
dimension, so the preaggregate CREATE TABLE query placed its alias in
GROUP BY and failed to bind (GROUP BY clause cannot contain window
functions). Bail out of the optimization instead; the coordinator then
serves the client through the standard query path. Related to #259,
which covers invalid client queries and a potential CTE-based rewrite;
that broader approach is not attempted here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes #1190.

Column references inside verbatim SQL text (e.g. sql-template selection
fields) can not be identified by collectColumns, so they can not be
pushed down into client query CTEs/subqueries. Bail out of the
preaggregation optimization in that case; the coordinator falls back
to the standard client query.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Part of #1170.

The window and verbatim bail-outs both walk an expression looking for a
single node class, so give them a common `containsNode` helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Part of #1170.

`NaN` forced callers into `typeof` checks that read as type accidents
rather than as a test for base queries that disagree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

F-PA-03: Preaggregation mean-centering subquery drops the schema of a qualified base table

1 participant