postgres: Drop() also drops custom types - #1426
Open
xhon-pelushi wants to merge 2 commits into
Open
Conversation
Drop() dropped every table in the current schema but left custom types (enums, domains, standalone composite types) behind. A migration that creates one of those types could not be re-run on a database that had just been dropped, since the type it tries to create already exists. Query pg_type for types owned by the current schema, excluding the row type Postgres implicitly creates for every table (relkind != 'c' in the join to pg_class) and the array type Postgres implicitly creates for every type (the typarray back-reference check), then drop what's left the same way tables are dropped: one by one, IF EXISTS, CASCADE. Fixes golang-migrate#626
… Drop()
A second Claude Code session independently verifying this PR found two real
regressions in the type-selection query added in the previous commit:
- Any type an extension installs into the current schema (citext, hstore,
postgis, ...) was selected and DROP TYPE fails on it -- only dropping the
extension can remove it. Drop() would return that error and abort with
the tables already gone.
- A range type's auto-generated multirange type has an internal dependency
on its range type. If the multirange sorts before the range type in the
(unordered) query result, its DROP fails immediately for the same reason,
again aborting with tables already dropped. Reordering wouldn't fully fix
this either -- it would just make the failure order-dependent.
Exclude anything with an extension ('e') or internal ('i') pg_depend entry.
Verified against a real Postgres 16 instance: citext extension + enum +
range type (which also exercises its implicit multirange) + a table, in
combination. Before this commit, Drop() failed outright. After, it succeeds
and drops everything droppable, leaving only the extension-owned type,
which is correct since removing it means dropping the extension.
Adds testDropWithExtensionAndRangeTypes alongside the existing
testDropWithCustomTypes.
Author
|
Pushed a fix for two real regressions caught in independent review: any extension-owned type (citext, postgis, ...) in the current schema made Excluded both via a |
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.
Fixes #626.
Problem
`Drop()` deletes every table in the current schema but leaves custom types (enums, domains, standalone composite types) behind. If a migration creates one of those types, dropping and re-running fails because the type already exists — even though every table is gone.
Root cause
Confirmed empirically against a real local Postgres 16 instance, not just by reading the code:
```
CREATE TYPE mood AS ENUM ('sad','ok','happy');
CREATE TABLE widgets (id serial primary key, m mood);
DROP TABLE widgets CASCADE;
\dT+ -- mood is still there
```
`DROP TABLE ... CASCADE` cascades to things that depend on the table (views, FKs), not to types the table's columns merely reference — the dependency runs the other way. So a type used as a column type always survives a table drop.
Fix
After dropping tables, the same pattern for types: query, then drop one by one, `IF EXISTS ... CASCADE`.
The query mirrors the existing table query's schema-scoping (`current_schema()`) and adds two exclusions, verified against real catalog data:
Tested against enums, domains, and standalone composite types together in the same schema, plus a second schema and a table with columns of all three custom types, to confirm the query returns exactly the 3 real user types and nothing else — not the table's row type, not any array type, not the other schema's type.
Testing
I don't have Docker in this environment, so I could not run the `dktest`-based container suite that `testDropWithCustomTypes` is written for — the direct-driver run above against a real (non-containerized) Postgres 16 is what actually verifies the fix, and the added test is written to match how this repo's CI will run it.