[4.1.x] Fixed #34058 -- Changed sequence types when altering pre-Django 4.1 auto fields on PostgreSQL.

Thanks Anders Kaseorg for the report.

Thanks Florian Apolloner for pair programming.

Regression in 2eea361eff.
Backport of 19e6efa50b from main
This commit is contained in:
Mariusz Felisiak 2022-09-29 13:20:14 +02:00
parent 7607fc8990
commit 97353bc64b
3 changed files with 63 additions and 1 deletions

View File

@ -13,7 +13,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
"UPDATE %(table)s SET %(column)s = %(default)s WHERE %(column)s IS NULL"
"; SET CONSTRAINTS ALL IMMEDIATE"
)
sql_alter_sequence_type = "ALTER SEQUENCE IF EXISTS %(sequence)s AS %(type)s"
sql_delete_sequence = "DROP SEQUENCE IF EXISTS %(sequence)s CASCADE"
sql_create_index = (
@ -183,6 +183,29 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
[],
),
]
elif new_is_auto and old_is_auto and old_internal_type != new_internal_type:
fragment, _ = super()._alter_column_type_sql(
model, old_field, new_field, new_type
)
column = strip_quotes(new_field.column)
sequence_name = f"{table}_{column}_seq"
db_types = {
"AutoField": "integer",
"BigAutoField": "bigint",
"SmallAutoField": "smallint",
}
return fragment, [
# Alter the sequence type if exists (Django 4.1+ identity
# columns don't have it).
(
self.sql_alter_sequence_type
% {
"sequence": self.quote_name(sequence_name),
"type": db_types[new_internal_type],
},
[],
),
]
else:
return super()._alter_column_type_sql(model, old_field, new_field, new_type)

View File

@ -35,3 +35,7 @@ Bugfixes
* Fixed a regression in Django 4.1 where the ``--debug-mode`` argument to
``test`` did not work when running parallel tests with the
``multiprocessing`` start method ``spawn`` (:ticket:`34010`).
* Fixed a regression in Django 4.1 that didn't alter a sequence type when
altering type of pre-Django 4.1 serial columns on PostgreSQL
(:ticket:`34058`).

View File

@ -1785,6 +1785,41 @@ class SchemaTests(TransactionTestCase):
with connection.schema_editor() as editor:
editor.alter_field(SmallIntegerPK, old_field, new_field, strict=True)
@isolate_apps("schema")
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
def test_alter_serial_auto_field_to_bigautofield(self):
class SerialAutoField(Model):
id = SmallAutoField(primary_key=True)
class Meta:
app_label = "schema"
table = SerialAutoField._meta.db_table
column = SerialAutoField._meta.get_field("id").column
with connection.cursor() as cursor:
cursor.execute(
f'CREATE TABLE "{table}" '
f'("{column}" smallserial NOT NULL PRIMARY KEY)'
)
try:
old_field = SerialAutoField._meta.get_field("id")
new_field = BigAutoField(primary_key=True)
new_field.model = SerialAutoField
new_field.set_attributes_from_name("id")
with connection.schema_editor() as editor:
editor.alter_field(SerialAutoField, old_field, new_field, strict=True)
with connection.cursor() as cursor:
cursor.execute(
"SELECT data_type FROM pg_sequences WHERE sequencename = %s",
[f"{table}_{column}_seq"],
)
row = cursor.fetchone()
sequence_data_type = row[0] if row and row[0] else None
self.assertEqual(sequence_data_type, "bigint")
finally:
with connection.cursor() as cursor:
cursor.execute(f'DROP TABLE "{table}"')
def test_alter_int_pk_to_int_unique(self):
"""
Should be able to rename an IntegerField(primary_key=True) to