postgresql: support OLD and NEW in RETURNING clauses - #4562
Merged
Conversation
PostgreSQL 18 allows the RETURNING clause of INSERT, UPDATE and DELETE statements to reference the row before and after modification through the OLD and NEW aliases, optionally renamed with RETURNING WITH (OLD AS ..., NEW AS ...). sqlc rejected such queries with 'column does not exist' because neither alias resolved to a table. Resolve both aliases to virtual copies of the statement's target table when computing output columns and expanding star references. Columns reached through OLD in an INSERT and through NEW in a DELETE become nullable, since no old or new row exists for those statements. A source table already known under the alias name shadows the virtual table, matching PostgreSQL. The WITH (...) option list is carried through the AST so renamed aliases resolve and format correctly. Fixes #4556 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4yURXfrJTANespBca2wDE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PostgreSQL 18 allows the RETURNING clause of INSERT, UPDATE and DELETE statements to reference the row before and after modification through the OLD and NEW aliases, optionally renamed with
RETURNING WITH (OLD AS ..., NEW AS ...). sqlc rejected such queries withcolumn "..." does not existbecause neither alias resolved to a table.Fixes #4556
Changes
internal/compiler/returning.go): builds virtual tables for the OLD and NEW aliases from the statement's target table, consulted when computing output columns and expanding star references (RETURNING old.*). The virtual tables are only used for references qualified with an alias name, so unqualified columns cannot become ambiguous and bareRETURNING *still expands once. A source table already known under the alias name shadows the virtual table, matching PostgreSQL.ON CONFLICT DO UPDATE) and no new row exists after delete. UPDATE keeps catalog nullability for both aliases.InsertStmt,UpdateStmtandDeleteStmtgainedReturningOldAlias/ReturningNewAliasfields, populated from the parser'sReturningClauseoptions and emitted by the SQL formatter, so renamed aliases likeRETURNING WITH (OLD AS o, NEW AS n) o.name, n.nameresolve and round-trip through formatting.Testing
New end-to-end case
internal/endtoend/testdata/returning_old_new(pgx/v5 and stdlib) covering OLD/NEW on all three statement types,old.*expansion, and renamed aliases. The case is restricted to thebasecontext because the live test databases run PostgreSQL 16, which lacks this syntax. FullTestReplay/base,TestFormat, unit tests andgo vetpass.The experimental core analyzer path (
SQLCEXPERIMENT=coreanalyzer) does not gain this support yet; the test case excludes the opt-incorecontext accordingly.🤖 Generated with Claude Code
https://claude.ai/code/session_01Q4yURXfrJTANespBca2wDE
Generated by Claude Code