Skip to content

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

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

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>
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