Skip to content

feat(analysis): analyze CTEs and FROM subqueries as derived sources - #79

Merged
omer-cengel merged 1 commit into
masterfrom
feature/cte-and-subquery-derived-sources
Oct 12, 2026
Merged

omer-cengel merged 1 commit into
masterfrom
feature/cte-and-subquery-derived-sources

Conversation

@omer-cengel

Copy link
Copy Markdown
Member

Summary

Common table expressions and FROM/JOIN subqueries now compile as typed sources. A source that names a WITH clause, or an aliased subquery, exposes the result columns of its own analyzed SELECT, so placeholders inside those bodies are typed and named from columns instead of requiring casts, and every WITH body of every statement is checked against the schema.

Changes

  • A FROM or JOIN source whose unqualified name matches a WITH clause in scope (case-insensitively, innermost first) reads that clause; an aliased subquery source reads its body. Their columns carry the body's names, types, enum, array, and nullability facts, and a left join makes every column nullable.
  • A derived source never returns a shared table-row record, so SELECT * over one returns a query-specific result even when it is named like a table.
  • Each WITH body and subquery source is analyzed like a top-level SELECT: sources, joins, projection rules, and ON/WHERE/LIMIT/OFFSET placeholder typing. A WITH body sees earlier clauses and enclosing ones and reads the schema table it is named like; a subquery source sees no outer source.
  • Every WITH clause of SELECT, INSERT, UPDATE, and DELETE is analyzed in order, read or not, and a returning write may now declare WITH clauses. An indexed cast placeholder in a WITH body is named from its clause, so orders.total = $1::numeric names total.
  • New diagnostics: WITH RECURSIVE is not supported.; A data-modifying statement in WITH is not supported; run it as a query of its own.; A subquery in FROM requires an alias, such as (SELECT ...) AS recent.; A column list on <name> is not supported; alias the columns in its SELECT instead.; and Derived source <name> has more than one column named <column>; give each a distinct alias. A set operation or VALUES body keeps its existing diagnostic.
  • Analyzer, generated-source compilation, and PostgreSQL tests cover the new sources; the reference service's unsupported catalogue drops the two shapes that now compile, and the query documentation describes the behavior.

Scope and non-goals

  • EXISTS, IN (SELECT ...), scalar comparison subqueries, and subqueries in projections, GROUP BY, HAVING, ORDER BY, written values, and RETURNING keep their current handling.
  • Multi-row VALUES, INSERT ... SELECT, UPDATE ... FROM, and DELETE ... USING remain rejected.
  • LATERAL sources and doubly parenthesized sources keep their existing rejections.
  • Generated APIs, the runtime, and executable SQL are unchanged apart from the new accepted shapes and the renamed WITH-body cast parameters.

@omer-cengel
omer-cengel merged commit 292e75a into master Oct 12, 2026
7 checks passed
@omer-cengel
omer-cengel deleted the feature/cte-and-subquery-derived-sources branch October 12, 2026 18:32
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