Describe the bug
Finally being able to upgrade from the latest 1.5.x to 1.7.x, I stumbled on the following problem: when built using SQLAlchemy expressions, check constraints may be duplicated in the DDL statement produced by alembic.
Expected behavior
To Reproduce
Please try to provide a Minimal, Complete, and Verifiable example, with the migration script and/or the SQLAlchemy tables or models involved.
See also Reporting Bugs on the website.
from alembic import op import sqlalchemy as sa from sqlalchemy.dialects.postgresql import UUID # revision identifiers, used by Alembic. revision = 'b126031fd753' down_revision = None branch_labels = None depends_on = None def upgrade(): # Columns forward declarations for those used in constraints column = sa.Column('column', sa.Integer, nullable=True) op.create_table( 't', sa.Column('t_id', UUID, nullable=False), column, sa.PrimaryKeyConstraint('t_id'), sa.CheckConstraint(sa.and_(column > 0, column < 5), name='ck_dim_job_ad_remote_type_range', ), schema='issue', ) def downgrade(): op.drop_table('t', schema='issue')
Will produce the following DLL:
CREATE TABLE issue.t ( t_id UUID NOT NULL, "column" INTEGER, PRIMARY KEY (t_id), CONSTRAINT ck_dim_job_ad_remote_type_range CHECK ("column" > 0 AND "column" < 5), CONSTRAINT ck_dim_job_ad_remote_type_range CHECK ("column" > 0 AND "column" < 5) );
Error
n/a
Versions.
- OS: Ubuntu / Debian
- Python: 3.9.10
- Alembic: >1.6.0 (tested with 1.6.0, 1.6.5, 1.7.5)
- SQLAlchemy: 1.4.31 (also tested with coming 1.4.33)
- Database: postgresql
- DBAPI: psycopg2
Additional context
Rewritting the constraint with a text() expression (e.g. sa.text('"column" > 0 AND "column" < 5') in the above example) works around the issue.
This does not seem to come from SQLAlchemy (or SQLAlchmey somehow works around this). Indeed the following code:
from sqlalchemy.dialects.postgresql import dialect from sqlalchemy.sql.ddl import CreateTable from sqlalchemy import __version__ METADATA = MetaData() T = Table( 't', METADATA, Column('t_id', UUID, nullable=False), # Field to have a constraint applied to Column('column', Integer, nullable=True), PrimaryKeyConstraint('t_id'), comment='Bla bla bla', schema='issue', ) """Dimensions collection table to pull data from datapond (debezium) """ T.append_constraint(CheckConstraint(and_(T.c.column < 5, T.c.column > 0))) print(f'-- SQLAlchemy {__version__}') stmt = CreateTable(T) str(dialect.ddl_compiler(dialect(), stmt))
As well as using the exact same construct as in the migration (column variable, used to build the constraint) yields the expected DDL statement:
-- 1.4.33
CREATE TABLE issue.t (
t_id UUID NOT NULL,
"column" INTEGER,
PRIMARY KEY (t_id),
CHECK ("column" < 5 AND "column" > 0)
)
Have a nice day!
Thanks, have a nice day as well!