Skip to content

feat(lower): nested SQL query functions via derived tables (#27) - #29

Merged
milindsrivastava1997 merged 1 commit into
mainfrom
feat/sql-nested-query-functions
Jun 21, 2026
Merged

feat(lower): nested SQL query functions via derived tables (#27)#29
milindsrivastava1997 merged 1 commit into
mainfrom
feat/sql-nested-query-functions

Conversation

@zzylol

@zzylol zzylol commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

What & why

Adds nested query function support for SQL — the SQL counterpart of the PromQL nesting in #28 — closing the SQL part of #27.

SQL's lower_plan already recurses through the DataFusion LogicalPlan, so a nested aggregate/filter/projection chain lowered. The gap was derived tables / inline views (FROM (SELECT …) t): the SubqueryAlias arm only accepted a TableScan (or another alias) as input, so an aggregate-over-aggregate had nowhere to go.

SELECT MAX(s) FROM (SELECT service, SUM(bytes) AS s FROM metrics GROUP BY service) t
SELECT AVG(p) FROM (SELECT service, approx_percentile_cont(latency, 0.9) AS p FROM metrics GROUP BY service) t
SELECT t.service, t.s FROM (SELECT service, SUM(bytes) AS s FROM metrics GROUP BY service) t WHERE t.s > 100

How

  • lower_plan's SubqueryAlias arm now lowers an arbitrary inner plan recursively (lower_plan already handles every node a sub-SELECT produces). The alias is dropped; a qualified outer ref (t.col) resolves by bare name against the derived output schema — the same Qualified → bare-name fallback the converter's column resolution already uses for joins. No L3 IR / converter / Binder changes needed.
  • Subquery-valued expressions in a predicate (x > (SELECT …), IN (SELECT …), EXISTS (…)) need a subquery node in the L2 expression IR (+ a correlated/uncorrelated decision), so they're rejected cleanly with an explicit message instead of the generic catch-all.

Tests

  • derived_table_aggregate_over_aggregate_nests — outer Max over inner Sum, schema derivation total across the boundary.
  • derived_table_outer_avg_over_inner_percentile — exact Avg over approximate Quantile (per-node sketch-vs-exact is an L4 decision).
  • filter_over_derived_aggregate_resolves_alias_columnWHERE t.s > 100 resolves the qualified alias column.
  • scalar_subquery_in_predicate_is_rejected — pinned rejection.
  • Full workspace suite green; cargo clippy --all-targets clean.

Scope / follow-ups

Scalar / IN / EXISTS subqueries in predicates (correlated subqueries) remain rejected — tracked in the updated #27. Relates to #28 (PromQL nesting); the two are independent and don't conflict.

Closes the SQL part of #27.

🤖 Generated with Claude Code

The SQL front end already recurses through the DataFusion `LogicalPlan`, so a
nested aggregate/filter/projection chain lowered — but a *derived table* /
inline view (`FROM (SELECT …) t`) was rejected: `lower_plan`'s `SubqueryAlias`
arm only accepted a `TableScan` (or another alias) as its input. That is the
SQL counterpart of the PromQL function nesting added in the sibling change —
an aggregate over an aggregate, a filter over a derived aggregate, etc.

The `SubqueryAlias` arm now lowers an arbitrary inner plan recursively
(`lower_plan` already handles every node a sub-`SELECT` produces). The alias is
dropped; a qualified outer reference (`t.col`) resolves by bare name against
the derived output schema — the same `Qualified → bare-name` fallback the
converter's column resolution already applies for joins.

Subquery-*valued* expressions in a predicate (`x > (SELECT …)`, `IN (SELECT …)`,
`EXISTS (…)`) still need a subquery node in the L2 expression IR, so they are
rejected cleanly with an explicit message rather than the generic catch-all.

Tests: derived-table aggregate-over-aggregate, outer-avg-over-inner-percentile,
filter-over-derived-aggregate (qualified alias resolution), and a pinned
scalar-subquery rejection.

Co-Authored-By: Claude Opus 4.8 (1M context) <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.

2 participants