Skip to content

Fix postgres and CockroachDB diff cases that write failing SQL around moves, renames, roles and generated columns - #6511

Open
dankochetov wants to merge 2 commits into
snapshotsfrom
postgres-cockroach-diff-fixes
Open

dankochetov wants to merge 2 commits into
snapshotsfrom
postgres-cockroach-diff-fixes

Conversation

@dankochetov

@dankochetov dankochetov commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

This PR targets the snapshots branch. Its base moves to rc5 after #6503 merges.

What it adds

The tests of #6503 found postgres and CockroachDB diff cases where generate or push writes SQL that fails, loses a change, or never converges. rc5 has the same bugs. This PR fixes them.

Postgres

  • A custom type whose SQL type names an array type, such as customType({ dataType: () => 'text[]' }) without .array(), is an array column. fromDrizzleSchema counts the [] and [n] brackets of the SQL type for dimensions and removes them from type.
  • When a generated column gets a new expression, the diff drops and adds the column again. The foreign keys of the column are now dropped and created again, one time each, also when the action of a key changes. A renamed key is dropped with its old name. An index or a unique constraint of the column gets one create statement, also when two recreated columns use it or when it is new.
  • A view that moves to another schema and gets a new name is renamed in its old schema and then moved. The move uses the old kind of the view, so a view that becomes a materialized view moves with ALTER VIEW.
  • A view with a new definition or a new kind is dropped after its rename or move. Before, the drop used the new name before the rename, and a view that moved and changed its definition stopped generate with Missing view in original ddl.
  • A policy drop, a foreign key drop and the row level security statements of a moved table run after SET SCHEMA, because they name the table in its new schema. Table drops still run before the moves.
  • DROP ROLE runs after the policy statements, because Postgres refuses to drop a role that a policy still names.
  • DROP EXPRESSION runs before the type and default statements of the same column, and a generated column gets no USING clause. Postgres refuses a default and a USING clause for a generated column.
  • The enum recreate finds the columns that a snapshot of format 7 stores with no type schema. It takes the schema from the same column of the schema file when the type name is the same, so a built-in interval column is not taken for a column of an enum named interval.

CockroachDB

  • A view that reads a renamed or moved table is dropped before the table statement and created after it, because CockroachDB refuses to rename or move a table while a view reads it. recreate_view is now a drop_view with cause and a create_view, as in postgres. push asks no data loss question for such a view, and --explain shows it one time.
  • A view or a sequence that moves to another schema and gets a new name gets both statements. A view that moves and changes its definition or kind no longer stops generate with Missing view in original ddl.
  • An index rename and an index drop name the table ("table"@"name") when two tables of the schema hold the index name at that point of the migration.
  • A check rename writes RENAME CONSTRAINT. A check that takes the name of a dropped unique constraint is renamed after the DROP INDEX.
  • The renames of checks, indexes, primary keys, foreign keys and policies change only the row of their own table. Before, a policy rename on one table also renamed a policy with the same name on another table.
  • SET DATA TYPE runs when only the type schema or the array dimensions of a column change, and an enum-to-enum cast across schemas goes through text. A custom type that names an enum equals a column of that enum, and a custom type whose SQL type names an array type is an array column.
  • The table renames and moves run before the row level security statements and before the policy and foreign key drops that name the table.
  • The recreate of a generated column creates its foreign keys again, because CockroachDB drops them together with the column.
  • DROP ROLE runs after the policy statements.

Why it is a separate PR

These are fixes for rc5 bugs. Format 9 and the check of branches in #6503 do not need them. A separate PR keeps the review of #6503 smaller, and each fix here can be reviewed against rc5 behavior.

Tests

Postgres (PGlite):

  • pg-array.test.ts: 'a custom type with the type text $dataType is an array column' (text[] and text[3]).
  • pg-generated.test.ts: thirteen tests named 'a new expression of a generated column ...', 'a new expression of two generated columns ...' and 'a column that becomes generated with a renamed foreign key ...' cover the foreign keys, indexes and unique constraints of a recreated column. '$name gets a type change that runs' covers DROP EXPRESSION and the missing USING.
  • pg-views.test.ts: 'a view that moves to another schema with a new name and a new definition writes SQL that runs', 'a view that moves to another schema and becomes a materialized view writes SQL that runs', 'move view to a new schema and change its definition' and 'rename view and change its definition'.
  • pg-tables.test.ts: 'a table move together with $name writes SQL that runs' (policy drops, the first policy, the RLS flag, a foreign key drop) and 'a table move into a schema where a dropped table holds the name of its primary key writes SQL that runs'.
  • pg-role.test.ts: 'a role drop together with $name writes SQL that runs'. The test 'create and drop role' now expects CREATE ROLE before DROP ROLE.
  • pg-snapshot-v7.test.ts with the fixtures snapshots/schema06.ts and snapshots/schema06new.ts: the three s06 tests for the first diff after the upgrade from format 7.

CockroachDB:

  • views.test.ts: '$name is dropped before the table statement and created after it', 'a view that is created again keeps its place when it does not read the table that moves', the two explain tests, 'push asks for no confirmation when it creates a materialized view with rows again', 'a table rename leaves a view alone that reads a table of a schema with the new table name', and the view move tests with a new name, a new definition or a new kind.
  • indexes.test.ts and constraints.test.ts: index renames that swap a name, an index drop and a rename onto a name that another rename frees, a unique index whose name a new table takes, an index rename next to a primary key with the same name, and the swap tests of foreign keys and primary keys.
  • checks.test.ts: the check rename statement, a swap of check names between two tables, and a rename to the name of a dropped unique constraint.
  • policy.test.ts: 'a policy rename on one table keeps the change of a policy with the same name on another table'.
  • enums.test.ts and array.test.ts: the enum switches across and inside schemas, a custom type that names an enum, scalar and array type changes, and a custom type that names an array type.
  • tables.test.ts: 'a table move together with $name writes SQL that runs', the move with a dropped referenced table, and the rename with the RLS flag.
  • generated.test.ts: 'a new expression of a generated column $name'.
  • role.test.ts: 'a role drop together with $name writes SQL that runs'. 'create and drop role' and 'rename role - recreate' now expect CREATE ROLE before DROP ROLE.
  • sequences.test.ts: 'a sequence that moves to another schema with a new name and new fields writes SQL that runs'.

… moves, renames, roles and generated columns

Postgres:
- Count the brackets of a custom type's SQL type as array dimensions.
- Drop and create the foreign keys of a recreated generated column one
  time each, and create its indexes and unique constraints one time.
- Rename a view in its old schema before it moves, and move it with its
  old kind.
- Drop a recreated view after its rename or move.
- Run the policy drops, foreign key drops and row level security
  statements of a moved table after `SET SCHEMA`.
- Run `DROP ROLE` after the policy statements.
- Run `DROP EXPRESSION` first and write no `USING` clause for a
  generated column.
- Find the enum columns that a format 7 snapshot stores without a type
  schema when the enum is recreated, with the s06 tests and fixtures.

CockroachDB:
- Drop a view that reads a renamed or moved table before the table
  statement and create it after it. Replace `recreate_view` with a
  `drop_view` that has a `cause`, in the diff, in push and in
  `cockroachExplain`.
- Write both statements for a view or a sequence that moves and gets a
  new name, and look up the old view of a moved view that is recreated.
- Name the table in an index rename or drop when two tables hold the
  index name.
- Write `RENAME CONSTRAINT` for a check rename.
- Select the row of the renamed check, index, primary key, foreign key
  or policy by its table.
- Change the column type when only the type schema or the array
  dimensions change, and count the brackets of a custom type's SQL type.
- Run table renames and moves before the statements that name the table
  in its new place.
- Create the foreign keys of a recreated generated column again.
- Run `DROP ROLE` after the policy statements.
@dankochetov
dankochetov force-pushed the postgres-cockroach-diff-fixes branch from b71eb89 to 0d3183f Compare October 15, 2026 14:49
@dankochetov
dankochetov marked this pull request as ready for review October 15, 2026 15:06
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.

1 participant