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

enum already exists #1254

Open
chirayushukla28 opened this issue May 29, 2023 · 19 comments
Open

enum already exists #1254

chirayushukla28 opened this issue May 29, 2023 · 19 comments
Labels
autogenerate for enums a long term subject, tagging issues related to this awaiting info waiting for the submitter to give more information expected behavior postgresql

Comments

@chirayushukla28
Copy link

Describe the bug

Whenever I am adding Enum field in a new model it's giving me this error "sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateObject) type "tickettype" already exists" for resolving this I have to delete DB and create a new one.

Optional link from https://docs.sqlalchemy.org which documents the behavior that is expected

https://docs.sqlalchemy.org/en/14/errors.html#error-f405

SQLAlchemy Version in Use

1.4.46

DBAPI (i.e. the database driver)

2.9.5

Database Vendor and Major Version

2.9.5

Python Version

3.8

Operating system

Linux

To Reproduce

alembic revision --autogenerate -m "New Migration"
alemic upgrade head

Error

# Copy the complete stack trace and error message here, including SQL log output if applicable.

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateObject) type "tickettype" already exists

[SQL: CREATE TYPE tickettype AS ENUM ('PAID', 'FREE', 'GROUP', 'DONATION', 'REQUEST', 'GUESTLIST')]

Additional context

No response

@chirayushukla28 chirayushukla28 added the requires triage New issue that requires categorization label May 29, 2023
@CaselIT CaselIT transferred this issue from sqlalchemy/sqlalchemy May 29, 2023
@CaselIT
Copy link
Member

CaselIT commented May 29, 2023

Hi,

Moved to alembic. What version are you using?

@CaselIT CaselIT added postgresql awaiting info waiting for the submitter to give more information and removed requires triage New issue that requires categorization labels May 29, 2023
@CaselIT CaselIT changed the title already exists enum already exists May 29, 2023
@CaselIT CaselIT added the autogenerate for enums a long term subject, tagging issues related to this label May 29, 2023
@zzzeek
Copy link
Member

zzzeek commented May 29, 2023

this isn't a bug as we dont support adding elements to PG enums, you would have to do this manually using op.execute("ALTER ENUM myenum ADD newitem")

@CaselIT
Copy link
Member

CaselIT commented May 29, 2023

I think they are adding a new column of type enum and alembic is generating the migration to add the enum.
IIRC enum have check_exists that defaults to True, so it should not issue the create if it exist. But I may miss-remember

@zzzeek
Copy link
Member

zzzeek commented May 29, 2023

alembic doesnt generate migrations to add enums. The enum gets created only if you run CREATE TABLE via op.create_table(). I dont even see any code that would do this for add_column().

@chirayushukla28
Copy link
Author

Hi,

Moved to alembic. What version are you using?

alembic==1.8.1

@chirayushukla28
Copy link
Author

this isn't a bug as we dont support adding elements to PG enums, you would have to do this manually using op.execute("ALTER ENUM myenum ADD newitem")

Where i have to add this?

@mazen-isstech
Copy link

mazen-isstech commented Oct 24, 2023

this isn't a bug as we dont support adding elements to PG enums, you would have to do this manually using op.execute("ALTER ENUM myenum ADD newitem")

Where i have to add this?

In the revision file that is generated by Alembic, where you have upgrade() and downgrade() defined. You write it inside upgrade(). op should be defined in the file already.

@m-alhajji
Copy link

Here's how you can get around it:
1- Create an enum and two sqlalchemy models.
2- Set a column in both as an enum.
3- Generate alembic migration file for both table.
4- Run alembic upgrade.

OR you can manually change the name the enum.

Here's how to generate this error, replace those steps
3- generate migration for only one table. Then, generate another migration for the other table

@sanchitram1
Copy link

So autogenerate doesn't generate the creation of enum. You manually add it in, here is my example

project_status_enum = sa.Enum(
    "active",
    "deprecated",
    "duplicate",
    "spam",
    "changed_url",
    "no_url",
    name="enum_project_status",
    schema="chai_processed",
)

def upgrade() -> None:
    project_status_enum.create(op.get_bind(), checkfirst=True)

   # other stuff

I kept running into the DuplicateViolation error.

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateObject) type "project_status_enum" already exists

[SQL: CREATE TYPE chai_processed.project_status_enum AS ENUM ('active', 'deprecated', 'duplicate', 'spam', 'changed_url', 'no_url')]
(Background on this error at: https://sqlalche.me/e/20/f405)

I switched the logging level to INFO to see the actual SQLs that alembic was running, and saw it was creating the enum type twice:

INFO  [sqlalchemy.engine.Engine] SELECT pg_catalog.pg_type.typname 
FROM pg_catalog.pg_type JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.oid = pg_catalog.pg_type.typnamespace 
WHERE pg_catalog.pg_type.typname = %(typname_1)s AND pg_catalog.pg_namespace.nspname = %(nspname_1)s
INFO  [sqlalchemy.engine.Engine] [generated in 0.00006s] {'typname_1': 'enum_project_status', 'nspname_1': 'chai_processed'}

INFO  [sqlalchemy.engine.Engine] CREATE TYPE chai_processed.enum_project_status AS ENUM ('active', 'deprecated', 'duplicate', 'spam', 'changed_url', 'no_url')
INFO  [sqlalchemy.engine.Engine] [no key 0.00006s] {}

INFO  [sqlalchemy.engine.Engine] CREATE TYPE chai_processed.enum_project_status AS ENUM ('active', 'deprecated', 'duplicate', 'spam', 'changed_url', 'no_url')
INFO  [sqlalchemy.engine.Engine] [no key 0.00007s] {}
INFO  [sqlalchemy.engine.Engine] ROLLBACK

That first query returned nothing (since no enum existed). The second query created the enum. The third query...why was it doing it again?

My guess is the first project_status_enum.create(op.get_bind(), checkfirst=True) is redundant in the upgrade function, but I wanted to confirm that. My workaround to remove that line did work, and I am not running into the Duplicate Error any more.

So, can anyone confirm that creating the Enum field outside of the actual upgrade step genuinely creates the enum?

@CaselIT
Copy link
Member

CaselIT commented Nov 8, 2023

Other stuff here is important

@sanchitram1
Copy link

    op.create_table(
        "agg_projects_processed",
        sa.Column(
            "tid",
            sa.Integer(),
            sa.Identity(
                always=False,
                start=1,
                increment=1,
                nomaxvalue=True,
                cycle=False,
                minvalue=1,
            ),
            nullable=False,
        ),
        sa.Column("project_name", sa.String(), nullable=False),
        sa.Column(
            "status", project_status_enum, nullable=False, server_default="active"
        ),
        sa.PrimaryKeyConstraint("tid", name=op.f("pk_agg_projects_processed")),
        schema="chai_processed",
    )

creating 4 other tables, none of which use project_status_enum

@sanchitram1
Copy link

sanchitram1 commented Nov 8, 2023

Also @CaselIT, to your earlier point, did you mean checkfirst or check_exists?

@CaselIT
Copy link
Member

CaselIT commented Nov 8, 2023

you are using the enum right here

sa.Column(
            "status", project_status_enum, nullable=False, server_default="active"
        ),

that's why it gets created. please see also #1347 if you want to use create_type and similar PG only options

@VadimKulyba
Copy link

VadimKulyba commented Feb 11, 2024

@CaselIT @zzzeek

I have similar issue

I trying to reuse enum (which created in one of previous migrations), but getting error:

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateObject) type "studyenum" already exists
[SQL: CREATE TYPE studyenum AS ENUM .....

I want to help to fix this issue, it is this same, as described?
Can i help to contiribute?
Can you add some hints where i can start research?

@CaselIT
Copy link
Member

CaselIT commented Feb 11, 2024

Using the postgresql specific type you can indicate in the migration not to create the type:
https://docs.sqlalchemy.org/en/20/dialects/postgresql.html#sqlalchemy.dialects.postgresql.ENUM.params.create_type

@VadimKulyba
Copy link

VadimKulyba commented Feb 11, 2024

@CaselIT @zzzeek

Yes, i already found this solution, but if this issue still open, i think you planning to automate this functionality, right?

@fievelk
Copy link

fievelk commented Mar 5, 2024

I encountered this error after creating a new model with an enum column. I could create and execute the migration (upgrade() operation), but the downgrade() operation didn't seem to remove the enum type automatically. To fix it, I just added the statement manually:

def upgrade():
    op.create_table(
        "my_table",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("source", sa.Enum("SOURCE_ENUM", name="source_enum"), nullable=False),
        sa.PrimaryKeyConstraint("id"),
    )


def downgrade():
    op.drop_table("my_table")
    op.execute("DROP TYPE source_enum")  # <-- This is what I added manually

I'm using SQLAlchemy 1.4.
Hope this can help someone else.

@eddy-di
Copy link

eddy-di commented Mar 31, 2024

I had the same issue for the first migration when the enum is in the table and it is necessary to upgrade.

when I had this code:

sa.Column('role', postgresql.ENUM('USER', 'STAFF', name='role_enum'), nullable=True),

I was getting:

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateObject) type "role_enum" already exists

But I read this explanation:
Screenshot from 2024-03-31 14-18-04

I understood that when creating the table with already available enum it is better to change create_type=False so that it won't double check.
And I was able to overcome it with this addition:

sa.Column('role', postgresql.ENUM('USER', 'STAFF', name='role_enum', create_type=False), nullable=True),

I hope it will be helpful

@chirayushukla28
Copy link
Author

chirayushukla28 commented Mar 31, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autogenerate for enums a long term subject, tagging issues related to this awaiting info waiting for the submitter to give more information expected behavior postgresql
Projects
None yet
Development

No branches or pull requests

9 participants