]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- Added a workaround for SQLAlchemy issue #3023 (fixed in 0.9.5) where
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 2 Nov 2014 17:35:47 +0000 (12:35 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 2 Nov 2014 17:35:47 +0000 (12:35 -0500)
a column that's part of an explicit PrimaryKeyConstraint would not
have its "nullable" flag set to False, thus producing a false
autogenerate.  Also added a related correction to MySQL which will
correct for MySQL's implicit server default of '0' when a NULL integer
column is turned into a primary key column. fixes #199

alembic/autogenerate/compare.py
alembic/ddl/mysql.py
docs/build/changelog.rst
tests/test_autogenerate.py

index dbc7b9f3034751d93757fb26c90f36ec80c9ec52..1a87d6673cab3859af62c7280068d07330b5049f 100644 (file)
@@ -167,11 +167,13 @@ def _compare_columns(schema, tname, object_filters, conn_table, metadata_table,
                       metadata_col,
                       col_diff, autogen_context
                       )
-        _compare_nullable(schema, tname, colname,
-                          conn_col,
-                          metadata_col.nullable,
-                          col_diff, autogen_context
-                          )
+        # work around SQLAlchemy issue #3023
+        if not metadata_col.primary_key:
+            _compare_nullable(schema, tname, colname,
+                              conn_col,
+                              metadata_col.nullable,
+                              col_diff, autogen_context
+                              )
         _compare_server_default(schema, tname, colname,
                                 conn_col,
                                 metadata_col,
index 07a32573feb5244291a39de06b755239d34ba4f6..29973fe4c05d1f98a9b8c164a3e5a44fb7c58dd2 100644 (file)
@@ -72,6 +72,22 @@ class MySQLImpl(DefaultImpl):
                 )
             )
 
+    def compare_server_default(self, inspector_column,
+                               metadata_column,
+                               rendered_metadata_default,
+                               rendered_inspector_default):
+        # partially a workaround for SQLAlchemy issue #3023; if the
+        # column were created without "NOT NULL", MySQL may have added
+        # an implicit default of '0' which we need to skip
+        if metadata_column.type._type_affinity is sqltypes.Integer and \
+            inspector_column.primary_key and \
+                not inspector_column.autoincrement and \
+                not rendered_metadata_default and \
+                rendered_inspector_default == "'0'":
+            return False
+        else:
+            return rendered_inspector_default != rendered_metadata_default
+
     def correct_for_autogen_constraints(self, conn_unique_constraints,
                                         conn_indexes,
                                         metadata_unique_constraints,
index e9a95bbd016459e81640da4b2addaa283681dd47..042990b8aa3de0854345e3e91ea012c51c320d20 100644 (file)
@@ -5,6 +5,17 @@ Changelog
 .. changelog::
     :version: 0.7.0
 
+    .. change::
+      :tags: bug, autogenerate
+      :tickets: 199
+
+      Added a workaround for SQLAlchemy issue #3023 (fixed in 0.9.5) where
+      a column that's part of an explicit PrimaryKeyConstraint would not
+      have its "nullable" flag set to False, thus producing a false
+      autogenerate.  Also added a related correction to MySQL which will
+      correct for MySQL's implicit server default of '0' when a NULL integer
+      column is turned into a primary key column.
+
     .. change::
       :tags: bug, autogenerate, mysql
       :tickets: 240
index ce239eddad0eff4f450142a4bf61938e18cc2c81..1f25101da06bd897cd972dfc5d694d08961fdf20 100644 (file)
@@ -3,7 +3,7 @@ import sys
 
 from sqlalchemy import MetaData, Column, Table, Integer, String, Text, \
     Numeric, CHAR, ForeignKey, INTEGER, \
-    TypeDecorator, CheckConstraint, text
+    TypeDecorator, CheckConstraint, text, PrimaryKeyConstraint
 from sqlalchemy.types import NULLTYPE
 from sqlalchemy.engine.reflection import Inspector
 
@@ -38,7 +38,6 @@ def new_table(table, parent):
 
 
 class AutogenTest(object):
-    __only_on__ = 'sqlite'
 
     @classmethod
     def _get_bind(cls):
@@ -370,6 +369,7 @@ class ModelOne(object):
 
 
 class AutogenerateDiffTest(ModelOne, AutogenTest, TestBase):
+    __only_on__ = 'sqlite'
 
     def test_diffs(self):
         """test generation of diff rules"""
@@ -791,6 +791,7 @@ name='extra_uid_fkey'),
 
 
 class AutogenerateCustomCompareTypeTest(AutogenTest, TestBase):
+    __only_on__ = 'sqlite'
 
     @classmethod
     def _get_db_schema(cls):
@@ -857,7 +858,40 @@ class AutogenerateCustomCompareTypeTest(AutogenTest, TestBase):
         eq_(diffs[1][0][0], 'modify_type')
 
 
+class PKConstraintUpgradesIgnoresNullableTest(AutogenTest, TestBase):
+    __backend__ = True
+
+    # test workaround for SQLAlchemy issue #3023, alembic issue #199
+    @classmethod
+    def _get_db_schema(cls):
+        m = MetaData()
+
+        Table(
+            'person_to_role', m,
+            Column('person_id', Integer, autoincrement=False),
+            Column('role_id', Integer, autoincrement=False),
+            PrimaryKeyConstraint('person_id', 'role_id')
+        )
+        return m
+
+    @classmethod
+    def _get_model_schema(cls):
+        return cls._get_db_schema()
+
+    def test_no_change(self):
+        metadata = self.m2
+        connection = self.context.bind
+
+        diffs = []
+
+        autogenerate._produce_net_changes(connection, metadata, diffs,
+                                          self.autogen_context
+                                          )
+        eq_(diffs, [])
+
+
 class AutogenKeyTest(AutogenTest, TestBase):
+    __only_on__ = 'sqlite'
 
     @classmethod
     def _get_db_schema(cls):
@@ -903,6 +937,7 @@ class AutogenKeyTest(AutogenTest, TestBase):
 
 
 class AutogenVersionTableTest(AutogenTest, TestBase):
+    __only_on__ = 'sqlite'
     version_table_name = 'alembic_version'
     version_table_schema = None
 
@@ -957,6 +992,7 @@ class AutogenCustomVersionTableAndSchemaTest(AutogenVersionTableTest):
 
 
 class AutogenerateDiffOrderTest(AutogenTest, TestBase):
+    __only_on__ = 'sqlite'
 
     @classmethod
     def _get_db_schema(cls):
@@ -996,6 +1032,7 @@ class AutogenerateDiffOrderTest(AutogenTest, TestBase):
 
 
 class CompareMetadataTest(ModelOne, AutogenTest, TestBase):
+    __only_on__ = 'sqlite'
 
     def test_compare_metadata(self):
         metadata = self.m2