Skip to content

[Pg-kit]: Drop identity before changing a column's type - #6226

Open
yyuneu wants to merge 2 commits into
drizzle-team:rc5from
yyuneu:fix/pg-drop-identity-before-type-change
Open

[Pg-kit]: Drop identity before changing a column's type#6226
yyuneu wants to merge 2 commits into
drizzle-team:rc5from
yyuneu:fix/pg-drop-identity-before-type-change

Conversation

@yyuneu

@yyuneu yyuneu commented Sep 2, 2026

Copy link
Copy Markdown

Addresses the statement ordering reported in #4178. This PR targets rc5 because the issue reproduces with both 1.0.0-rc.4 and the rc5 branch.

The problem

alterColumnConvertor builds statements for a column alteration in a fixed order:

type change → default → generated → identity → not-null

PostgreSQL imposes two restrictions on identity columns that conflict with this order:

  • Identity columns must use smallint, integer, or bigint. Even when a cast is available, changing to another type while the identity remains fails with identity column type must be smallint, integer, or bigint.
  • Setting a default on an identity column fails with column "id" of relation "users" is an identity column.

When a column drops its identity and changes type in the same alteration, the generated statements run in the wrong order: SET DATA TYPE …, SET DEFAULT …, then DROP IDENTITY.

For a castable target such as text(), PostgreSQL rejects the first statement with the identity error above. For the issue's integer().generatedAlwaysAsIdentity()uuid().defaultRandom() example, PostgreSQL reports cannot cast type integer to uuid first. The same ordering problem is present, but the missing cast is reported before the identity restriction is checked. The cast limitation is discussed separately below.

generate and push share this convertor, so both produce the affected statement order. I reproduced the failures with drizzle-kit@1.0.0-rc.4 against PostgreSQL 17.11. The regression test reproduces the identity error on PGlite.

Scope

Only identity removal moves earlier. Adding an identity (from === null) must remain after the type change because PostgreSQL requires an integer type first. Changes to identity parameters do not depend on this ordering. Both cases remain unchanged.

alter_column is the only statement that emits identity changes. alter_column_change_identity is declared in statements.ts but is never produced.

dialects/cockroach/convertor.ts uses the same ordering. I left it unchanged because I do not have a CockroachDB environment to verify the behavior, but I am happy to include it if you would prefer.

The fix

When diff.identity.to === null, DROP IDENTITY is emitted at the start of alterColumnConvertor, before the type and default blocks.

The previous else if branch is kept, with its body replaced by a comment, so the surrounding if/else chain and its type narrowing remain unchanged.

The production change is limited to one file, with six lines added and one removed, and adds one property check at runtime.


Tests

Added one case to tests/postgres/pg-identity.test.ts, next to the existing drop identity from a column tests:

  • Before: integer('id').generatedByDefaultAsIdentity()
  • After: text('id').default('n/a')

The test asserts the exact statement order for both diff (used by generate) and push. The push path also executes the statements on PGlite, so the test fails before the fix with the PostgreSQL identity error, rather than an assertion mismatch.

generatedAlwaysAsIdentity() follows the same DROP IDENTITY path, so the test exercises the removal logic shared by both variants.

All 18 tests in the file pass with the fix.

Verification

  • Regression test: Fails on unmodified rc5 with identity column type must be smallint, integer, or bigint and passes with the fix.
  • Fork CI: In the [CI run](https://github.com/yyuneu/drizzle-orm/actions/runs/33640885079), kit:postgres, kit:postgres16/17/18, kit:other, kit:cockroach, kit:mssql, prepare (types and lint), and skills-revision-gate pass. The failing shards require Neon, PlanetScale, Turso, or SQLite Cloud credentials.
  • Lint and formatting: oxlint --max-warnings=0 and dprint check pass.

A question for maintainers

The exact integer → uuid change from the issue still fails after this fix at SET DATA TYPE uuid USING "id"::uuid, because PostgreSQL has no integer-to-UUID cast. This PR corrects the statement order; the user still needs to supply an appropriate conversion.

Would a diagnostic for this type change be useful? I am happy to add one separately so that Kit provides a hint instead of exposing only the PostgreSQL error.

I left changelogs/drizzle-kit/ unchanged because the entries appear to be release-scoped. I am happy to add an entry if needed.

Postgres allows identity only on integer types, so SET DATA TYPE issued before DROP IDENTITY failed (drizzle-team#4178).
Covers dropping identity while changing the column type and default in one alter.
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