Skip to content

fix(postgresql): DROP TABLE ... CASCADE drops dependent views (#4416)#4456

Closed
luongs3 wants to merge 1 commit into
sqlc-dev:mainfrom
luongs3:fix/4416-drop-table-cascade-views
Closed

fix(postgresql): DROP TABLE ... CASCADE drops dependent views (#4416)#4456
luongs3 wants to merge 1 commit into
sqlc-dev:mainfrom
luongs3:fix/4416-drop-table-cascade-views

Conversation

@luongs3
Copy link
Copy Markdown

@luongs3 luongs3 commented May 27, 2026

Fixes #4416.

Problem

When a Postgres schema does DROP TABLE foo CASCADE where a view depends on foo, sqlc removes the table from its in-memory catalog but leaves the dependent view behind. A later CREATE VIEW (or CREATE TABLE) reusing that name then fails with a spurious relation "..." already exists, even though the SQL is valid and runs fine on real Postgres (where CASCADE drops the dependent view).

Reproduction

CREATE TABLE reference_rates (id BIGSERIAL PRIMARY KEY, data_ts TIMESTAMPTZ NOT NULL);
CREATE VIEW vw_reference_rates AS SELECT * FROM reference_rates;
CREATE TABLE reference_rates_new (id BIGSERIAL PRIMARY KEY, data_ts TIMESTAMPTZ NOT NULL);
DROP TABLE reference_rates CASCADE;
ALTER TABLE reference_rates_new RENAME TO reference_rates;
CREATE VIEW vw_reference_rates AS SELECT * FROM reference_rates;
  • Before: sqlc generaterelation "vw_reference_rates" already exists (exit 1)
  • After: exit 0

Fix

  • internal/sql/ast: carry the DROP behavior (RESTRICT/CASCADE) into DropTableStmt, and add named DropBehavior constants matching the pg_query enum (UNDEFINED=0, RESTRICT=1, CASCADE=2).
  • internal/engine/postgresql/parse.go: thread n.Behavior into the constructed DropTableStmt.
  • internal/sql/catalog: record each view's referenced tables (DependsOn) at createView time by walking the view query for *ast.RangeVar nodes; on DROP TABLE ... CASCADE, evict dependent views transitively (a view may depend on another view).
  • RESTRICT and unspecified behavior are unchanged — dependent views are kept, preserving today's behavior.

Tests

Added catalog unit tests covering:

  • DROP TABLE ... CASCADE evicts a dependent view, including views-on-views (transitive).
  • DROP TABLE ... RESTRICT and bare DROP TABLE keep the dependent view and preserve its recorded dependency.

go test ./internal/sql/catalog/... ./internal/engine/postgresql/... passes; gofmt/go vet clean.

…ev#4416)

sqlc's in-memory catalog dropped the table but left views that depended
on it, so a later CREATE VIEW reusing the name failed with
'relation "..." already exists' even though the SQL is valid Postgres.

- ast: carry DROP behavior (RESTRICT/CASCADE) into DropTableStmt; add
  named DropBehavior constants matching the pg_query enum.
- postgresql parser: thread n.Behavior into the DropTableStmt.
- catalog: record each view's referenced tables (DependsOn) at create
  time, and on DROP TABLE ... CASCADE evict dependent views transitively.
- RESTRICT / unspecified behavior is unchanged (views are kept).
- tests: catalog unit tests covering cascade eviction (incl. views on
  views) and the restrict/default keep-path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@luongs3
Copy link
Copy Markdown
Author

luongs3 commented May 28, 2026

Apologies — I went looking for an open PR against #4416 before starting this and missed #4419, which has been open since 2026-04-29 and takes essentially the same approach (DropBehavior on DropTableStmt, RangeVar walk in createView, cascade-evict in dropTable).

Closing this in favor of @wucm667's PR. I'll leave a review note over there on one small thing that came up while I was working through it: the pg_query DropBehavior enum (UNDEFINED=0, RESTRICT=1, CASCADE=2) reads as a magic number at the Behavior == 2 check, and named constants in internal/sql/ast/drop_behavior.go make the intent clearer. Happy to send that as a tiny follow-up if maintainers want it after #4419 merges.

Thanks @wucm667 for the original fix.

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.

PostgreSQL schema parser does not drop dependent views for DROP TABLE ... CASCADE

1 participant