Skip to content

feat(analysis): analyze UPDATE ... FROM and DELETE ... USING sources - #82

Merged
omer-cengel merged 1 commit into
masterfrom
feature/update-from-and-delete-using
Oct 14, 2026
Merged

omer-cengel merged 1 commit into
masterfrom
feature/update-from-and-delete-using

Conversation

@omer-cengel

Copy link
Copy Markdown
Member

Summary

UPDATE ... FROM and DELETE ... USING now compile. Their added sources are analyzed like a read's sources, so placeholders that compare against those columns are typed and named from them without casts, and RETURNING can return columns of any source. The only full row a joined write returns is the target's, written RETURNING <target>.*, which keeps the target's shared row record.

Changes

  • UPDATE ... FROM accepts one source followed by inner or left joins or by further comma-separated sources. DELETE ... USING accepts a comma-separated list. Each added source is a table, a WITH clause of the write, or an aliased subquery, and subquery and CTE bodies type their own placeholders.
  • The WHERE predicate sees the target and every added source as one level, with the write's WITH clauses in scope for predicate subqueries. Ambiguous unqualified columns and repeated exposed names are rejected.
  • A join condition inside FROM sees only its own comma-separated item, up to its joined source, as PostgreSQL scopes it. Naming the target or an earlier item there is rejected as an unknown source qualifier.
  • In RETURNING, a direct column of any source is typed from its column and is nullable when its source is left-joined.
  • RETURNING <target>.* returns the target's shared <TableName>Row record on any INSERT, UPDATE, or DELETE. Written beside other items, it contributes the target's columns to a query-specific result.
  • The following RETURNING forms are rejected with messages that say what to write instead:
    • a bare RETURNING * on a joined write
    • a wildcard of another source
    • an aliased or modified wildcard
    • an unknown wildcard qualifier
  • UPDATE a, b, UPDATE a JOIN b ... SET, and DELETE a FROM a JOIN b stay rejected. Their messages now point to UPDATE ... FROM and DELETE ... USING.
  • Placeholders bind in textual order across SET, the added sources and their join conditions, and WHERE, and the executable SQL is unchanged.
  • The query documentation describes added sources and the revised RETURNING rules, and the two shapes are removed from the reference service's unsupported-query catalogue.

Scope and non-goals

  • A join inside USING is not supported, because the SQL parser cannot read one there.
  • SET value expressions are not analyzed beyond typing a placeholder from the column it assigns. Other values reach the database as written.
  • Subqueries in written values or in RETURNING keep their existing handling, and the computed-RETURNING diagnostic wording is unchanged.
  • No generator or runtime changes are made.

Added sources (tables, CTEs, and aliased subqueries) join the target in
the WHERE scope, so their columns type and name placeholders, and a join
inside FROM types its condition over its own comma-separated item.
RETURNING may return a column of any source, and RETURNING <target>.*
returns the target's shared row on every write. A bare * on a joined
write and a wildcard of another source are rejected, and the remaining
multi-table UPDATE and joined DELETE forms get messages naming the
supported clause.
@omer-cengel
omer-cengel merged commit dbcb95b into master Oct 14, 2026
7 checks passed
@omer-cengel
omer-cengel deleted the feature/update-from-and-delete-using branch October 14, 2026 18:49
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