Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Postgres sql_alter_enum requires missing 'condition' key #5

Open
SpliFF opened this issue Sep 26, 2018 · 4 comments
Open

Postgres sql_alter_enum requires missing 'condition' key #5

SpliFF opened this issue Sep 26, 2018 · 4 comments

Comments

@SpliFF
Copy link

SpliFF commented Sep 26, 2018

When altering an existing enum the SQL format string and dictionary have mismatched signatures, leading to KeyError 'condition' when running ./manage.py migrate. Database is PosgreSQL 10:

django_enum/patches.py line 77:
sql_alter_enum = 'ALTER TYPE %(enum_type)s ADD VALUE %(value)s %(condition)s'

django_enum/operations.py line 319:
sql = schema_editor.sql_alter_enum % { 'enum_type': self.db_type, 'value': '%s'}
Notice that there is no 'condition' key so the operation fails.

https://www.postgresql.org/docs/9.1/static/sql-altertype.html

ALTER TYPE name ADD VALUE new_enum_value [ { BEFORE | AFTER } existing_enum_value ]

So it looks like condition is used to optional set the position of the new enum value but the operation isn't generating or passing the condition.

@SpliFF
Copy link
Author

SpliFF commented Sep 26, 2018

I just realised that ADD VALUE can't work in migrations anyway, not even in RunSQL. The reason is it can't be used inside a transaction and migrations run in a transaction. Per the manual:

Notes
ALTER TYPE ... ADD VALUE (the form that adds a new value to an enum type) cannot be executed inside a transaction block.

So it looks like this needs a more complicated approach. The best hack we could find seems to be coercing the existing enums to text and then dropping and recreating the enum type:

https://blog.yo1.dog/updating-enum-values-in-postgresql-the-safe-and-easy-way/

It's not pretty.

@ashleywaite
Copy link
Owner

Sorry for the delayed response, been a silly year!

The ALTER SQL mismatch on condition seems like a silly oversight, I'll fix that! Thanks

The ALTER TYPE in transaction didn't come up in testing for me but could have been a consequence of me not running it in a situation where transactions were forced, so I'll have another look at that.

If it is a stopper though, it can be done via forcing non-atomic though, so shouldn't be a complicated fix. :)
https://docs.djangoproject.com/en/2.1/howto/writing-migrations/#non-atomic-migrations

@alicederyn
Copy link

Did you make any headway on this @ashleywaite ? We're currently still working around it by coercing to text and back (including dropping and recreating all constraints).

@tlifschitz
Copy link

Please check this workaround:

tlifschitz@0ab5913

This change turns this migration:

class Migration(migrations.Migration):

    dependencies = []

    operations = [
        django_enum.operations.AlterEnum(
            db_type='my_enum_type',
            add_values=['new_value_1', 'new_value_2'],
        ),
    ]

From this invalid SQL transaction

BEGIN;
--
-- Alter enum type my_enum_type, added 2 value(s)
--
ALTER TYPE my_enum_type ADD VALUE 'new_value_1' ;
ALTER TYPE my_enum_type ADD VALUE 'new_value_2' ;
COMMIT;

To this valid SQL transaction

BEGIN;
--
-- Alter enum type my_enum_type, added 2 value(s)
--
CREATE TYPE django_enum_temp AS ENUM ('old_value', 'new_value_1', 'new_value_2');
ALTER TABLE "my_table" ALTER COLUMN "my_enum_type_column" TYPE django_enum_temp USING ("my_enum_type_column"::text::django_enum_temp);
DROP TYPE my_enum_type;
ALTER TYPE django_enum_temp RENAME TO my_enum_type;
COMMIT;

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

No branches or pull requests

4 participants