@@ -124,56 +124,62 @@ pub fn build_modify_column_type(
124124 . map ( |c| & c. r#type ) ;
125125
126126 // Check if this is an enum-to-enum migration that needs special handling (PostgreSQL only)
127+ // Covers both: enum value changes (same name) and enum name changes (different name)
127128 let needs_enum_migration = if * backend == DatabaseBackend :: Postgres {
128129 matches ! (
129130 ( old_type, new_type) ,
130131 (
131132 Some ( ColumnType :: Complex ( ComplexColumnType :: Enum { name: old_name, values: old_values } ) ) ,
132133 ColumnType :: Complex ( ComplexColumnType :: Enum { name: new_name, values: new_values } )
133- ) if old_name == new_name && old_values != new_values
134+ ) if old_name != new_name || old_values != new_values
134135 )
135136 } else {
136137 false
137138 } ;
138-
139139 if needs_enum_migration {
140- // Use the safe temp type + USING + RENAME approach for enum value changes
140+ // PostgreSQL enum-to-enum migration with USING clause for safe casting
141141 if let (
142142 Some ( ColumnType :: Complex ( ComplexColumnType :: Enum {
143- name : enum_name, ..
143+ name : old_enum_name,
144+ ..
144145 } ) ) ,
145146 ColumnType :: Complex ( ComplexColumnType :: Enum {
146- values : new_values, ..
147+ name : new_enum_name,
148+ values : new_values,
147149 } ) ,
148150 ) = ( old_type, new_type)
149151 {
150- // Use table-prefixed enum type names
151- let type_name = super :: helpers:: build_enum_type_name ( table, enum_name) ;
152- let temp_type_name = format ! ( "{}_new" , type_name) ;
153-
152+ let old_type_name = super :: helpers:: build_enum_type_name ( table, old_enum_name) ;
153+ let new_type_name = super :: helpers:: build_enum_type_name ( table, new_enum_name) ;
154+ let names_differ = old_enum_name != new_enum_name;
155+
156+ // For same-name changes: create temp type, then rename back
157+ // For different-name changes: create final type directly, no rename needed
158+ let ( target_type_name, needs_rename) = if names_differ {
159+ ( new_type_name, false )
160+ } else {
161+ ( format ! ( "{}_new" , old_type_name) , true )
162+ } ;
154163 // 0. INSERT fill_with UPDATEs before any type changes (rows still have old enum type)
155164 if let Some ( fw) = fill_with {
156165 queries. extend ( build_fill_with_updates ( table, column, fw) ) ;
157166 }
158-
159167 // Check if column has a DEFAULT value that needs to be handled
160168 let column_default = current_schema
161169 . iter ( )
162170 . find ( |t| t. name == table)
163171 . and_then ( |t| t. columns . iter ( ) . find ( |c| c. name == column) )
164172 . and_then ( |c| c. default . clone ( ) ) ;
165-
166- // 1. CREATE TYPE {table}_{enum}_new AS ENUM (new values)
167- let create_temp_values = new_values. to_sql_values ( ) . join ( ", " ) ;
173+ // 1. CREATE TYPE target_type AS ENUM (new values)
174+ let create_values = new_values. to_sql_values ( ) . join ( ", " ) ;
168175 queries. push ( BuiltQuery :: Raw ( super :: types:: RawSql :: per_backend (
169176 format ! (
170177 "CREATE TYPE \" {}\" AS ENUM ({})" ,
171- temp_type_name , create_temp_values
178+ target_type_name , create_values
172179 ) ,
173180 String :: new ( ) ,
174181 String :: new ( ) ,
175182 ) ) ) ;
176-
177183 // 2. DROP DEFAULT if exists (must be done before type change)
178184 if column_default. is_some ( ) {
179185 queries. push ( BuiltQuery :: Raw ( super :: types:: RawSql :: per_backend (
@@ -186,26 +192,34 @@ pub fn build_modify_column_type(
186192 ) ) ) ;
187193 }
188194
189- // 3. ALTER TABLE ... ALTER COLUMN ... TYPE {table}_{enum}_new USING {column}::text::{table}_{enum}_new
190- queries. push ( BuiltQuery :: Raw ( super :: types:: RawSql :: per_backend ( format ! ( "ALTER TABLE \" {}\" ALTER COLUMN \" {}\" TYPE \" {}\" USING \" {}\" ::text::\" {}\" " , table, column, temp_type_name, column, temp_type_name) , String :: new ( ) , String :: new ( ) ) ) ) ;
191-
192- // 4. DROP TYPE {table}_{enum}
195+ // 3. ALTER TABLE ... ALTER COLUMN ... TYPE target_type USING col::text::target_type
193196 queries. push ( BuiltQuery :: Raw ( super :: types:: RawSql :: per_backend (
194- format ! ( "DROP TYPE \" {}\" " , type_name) ,
197+ format ! (
198+ "ALTER TABLE \" {}\" ALTER COLUMN \" {}\" TYPE \" {}\" USING \" {}\" ::text::\" {}\" " ,
199+ table, column, target_type_name, column, target_type_name
200+ ) ,
195201 String :: new ( ) ,
196202 String :: new ( ) ,
197203 ) ) ) ;
198204
199- // 5. ALTER TYPE {table}_{ enum}_new RENAME TO {table}_{enum}
205+ // 4. DROP old enum type
200206 queries. push ( BuiltQuery :: Raw ( super :: types:: RawSql :: per_backend (
201- format ! (
202- "ALTER TYPE \" {}\" RENAME TO \" {}\" " ,
203- temp_type_name, type_name
204- ) ,
207+ format ! ( "DROP TYPE \" {}\" " , old_type_name) ,
205208 String :: new ( ) ,
206209 String :: new ( ) ,
207210 ) ) ) ;
208211
212+ // 5. RENAME temp to final (only for same-name value changes)
213+ if needs_rename {
214+ queries. push ( BuiltQuery :: Raw ( super :: types:: RawSql :: per_backend (
215+ format ! (
216+ "ALTER TYPE \" {}\" RENAME TO \" {}\" " ,
217+ target_type_name, old_type_name
218+ ) ,
219+ String :: new ( ) ,
220+ String :: new ( ) ,
221+ ) ) ) ;
222+ }
209223 // 6. Restore DEFAULT if it existed
210224 if let Some ( default_value) = column_default {
211225 // Use normalize_enum_default to properly quote enum values
0 commit comments