Skip to content

fix(parse): end the OUTPUT column list at FROM - #343

Merged
tiagolauer merged 1 commit into
masterfrom
fix/300-tsql-output-from
Aug 2, 2026
Merged

fix(parse): end the OUTPUT column list at FROM#343
tiagolauer merged 1 commit into
masterfrom
fix/300-tsql-output-from

Conversation

@tiagolauer

Copy link
Copy Markdown
Owner

Fixes #300.

The bug

Row<DB, 'update users set name = @p1 output inserted.id from users where id = @p2'>
// { 'from users': number }

Expected { id: number }. The docs describe OUTPUT support without excluding the UPDATE ... FROM form, and this variant is common in real T-SQL.

The fix

OutputClauseColumns<S, 'where'> accumulated entries until it saw where and nothing else, so from did not stop it and inserted.id from users became a single column entry that ParseColumnEntry read as a bare alias.

from now ends the list the same way where does, for both UPDATE and DELETE. IsKeyword compares through Lowercase, which distributes over a union, so the existing stop-keyword parameter takes 'where' | 'from' without any other change.

Verification

tests/tsql-output-from.test-d.ts, seven cases. Four red on master:

tests/tsql-output-from.test-d.ts(17,3): error TS2344: Type 'false' does not satisfy the constraint 'true'.
tests/tsql-output-from.test-d.ts(24,3): ...
tests/tsql-output-from.test-d.ts(31,3): ...
tests/tsql-output-from.test-d.ts(41,3): ...
  • UPDATE ... OUTPUT ... FROM ... WHERE, one column and several, the DELETE form, and the strict-mode variant

The strict case is worth reading: inserted. is stripped before resolution, so an OUTPUT column is looked up against both sources — the test uses inserted.name, which only users has, and qualifies the WHERE. That is existing behaviour, unchanged here.

Controls: OUTPUT without a FROM, OUTPUT as the last clause, and RETURNING are all unchanged.

tsc --noEmit clean, 192 runtime tests pass, budget 192,547 (+61).

    Row<DB, 'update users set name = @p1 output inserted.id from users where id = @p2'>
    // was { 'from users': number }

`UPDATE ... OUTPUT ... FROM` is the common T-SQL shape for writing a row and
returning it while joining against another table, and the docs describe
OUTPUT support without excluding it. OutputClauseColumns accumulated entries
until it saw `where` and nothing else, so the FROM clause was swallowed into
the list and `inserted.id from users` parsed as a single column entry whose
alias was `from users`.

`from` now ends the list the same way `where` does, for both UPDATE and
DELETE. IsKeyword compares through Lowercase, which distributes over a
union, so the stop keyword can be one.

Fixes #300

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tiagolauer
tiagolauer force-pushed the fix/300-tsql-output-from branch from 015379e to 2d443c9 Compare August 2, 2026 13:04
@tiagolauer
tiagolauer merged commit 16bb96f into master Aug 2, 2026
12 checks passed
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.

T-SQL UPDATE ... OUTPUT ... FROM swallows the FROM clause into the column list

1 participant