Skip to content

fix(drop): drop a PostgreSQL enum type only when no column uses it - #1632

Merged
dimitri-yatsenko merged 1 commit into
masterfrom
fix/postgres-shared-enum-drop
Oct 21, 2026
Merged

dimitri-yatsenko merged 1 commit into
masterfrom
fix/postgres-shared-enum-drop

Conversation

@dimitri-yatsenko

Copy link
Copy Markdown
Member

On PostgreSQL, dropping a table could drop columns of other tables, with their data. An enum attribute is declared with an enum type named by its values, so every column in the schema with the same values shares one type. drop_quick() dropped the table's enum types afterwards with DROP TYPE ... CASCADE, and CASCADE also dropped every other column of that type. Two tables that both declare species : enum('mouse', 'rat') share a type, and dropping one took the other's species column. Every jobs table has the same status enum, so dropping one jobs table removed status from all the others in the schema. MySQL has no enum types and was not affected.

An enum type is now dropped only when no column uses it any more, and the statement no longer cascades, so a type still in use is never dropped with its columns.

The new tests, on both backends, drop one of two tables that share an enum and check that the other keeps its column and values, that the type is removed once neither table remains, and that dropping one jobs table leaves another's status column and jobs in place. Both fail on PostgreSQL before this change.

The drafts #1615 and #1616 (drop() removes the jobs table, for #1601) go back to review after this merges: they drop a jobs table on every drop() of an auto-populated table, which made this loss much more likely.

Closes #1630.

On PostgreSQL, dropping a table could drop columns of other tables, with their data. An enum attribute is declared with an enum type named by its values, so every column in the schema with the same values shares one type. `drop_quick()` dropped the table's enum types afterwards with `DROP TYPE ... CASCADE`, and CASCADE also dropped every other column of that type. Two tables that both declare `species : enum('mouse', 'rat')` share a type, and dropping one took the other's `species` column. Every jobs table has the same `status` enum, so dropping one jobs table removed `status` from all the others in the schema. MySQL has no enum types and was not affected.

An enum type is now dropped only when no column uses it any more, and the statement no longer cascades, so a type still in use is never dropped with its columns.

The new tests, on both backends, drop one of two tables that share an enum and check that the other keeps its column and values, that the type is removed once neither table remains, and that dropping one jobs table leaves another's status column and jobs in place. Both fail on PostgreSQL before this change.
@dimitri-yatsenko

Copy link
Copy Markdown
Member Author

@MilagrosMarin @lum-agilyti: this, with its backport (#1633), is the last fix holding the v2.3.5 tag. It fixes data loss in 2.3.4, and everything else in v2.3.5 is merged. Could one of you review it? The backport is the same commit.

@MilagrosMarin MilagrosMarin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Without CASCADE, an enum type still in use can't take other tables' columns with it, and checking pg_attribute first avoids sending a DROP TYPE that would fail. The integration tests cover both cases from #1630, the shared species enum and the jobs tables' status column, on both backends.

Minor, not blocking: '…'::regtype raises when the type no longer exists. The except catches that, but inside a transaction it would abort it the same way a failed DROP TYPE would. That only matters if enum_types_to_drop can list a type twice or one that is already gone; to_regtype(…) would return NULL instead.

@dimitri-yatsenko

Copy link
Copy Markdown
Member Author

Thanks, @MilagrosMarin. Merging, then #1633. On '…'::regtype: enum_types_to_drop is read with SELECT DISTINCT just before the table is dropped, so it can list a type neither twice nor after it's gone, unless another session drops the type in between. to_regtype(…) is still the more robust form, so I'll switch to it in 2.4.

@dimitri-yatsenko
dimitri-yatsenko merged commit 69d63bf into master Oct 21, 2026
9 checks passed
@dimitri-yatsenko
dimitri-yatsenko deleted the fix/postgres-shared-enum-drop branch October 21, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Indicates an unexpected problem or unintended behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostgreSQL: dropping a table drops other tables' columns that share an enum type

2 participants