Commits

and...@69d324d9-c39d-4fdc-8679-7745eae9e2c8  committed 6204b6c

Fix for #54: Actually make null/not null alters work right in MySQL.

  • Participants
  • Parent commits 0a88f9c

Comments (0)

Files changed (2)

File db/generic.py

                 self.alter_column(table_name, name, field)
     
     alter_string_set_type = 'ALTER COLUMN %(column)s TYPE %(type)s'
-    alter_string_set_null = 'ALTER COLUMN %(column)s SET NOT NULL'
-    alter_string_drop_null = 'ALTER COLUMN %(column)s DROP NOT NULL'
+    alter_string_set_null = 'ALTER COLUMN %(column)s DROP NOT NULL'
+    alter_string_drop_null = 'ALTER COLUMN %(column)s SET NOT NULL'
     allows_combined_alters = True
     
     def alter_column(self, table_name, name, field):
             "type": field.db_type(),
         }
         if field.null:
+            sqls.append((self.alter_string_set_null % params, []))
+        else:
             sqls.append((self.alter_string_drop_null % params, []))
-        else:
-            sqls.append((self.alter_string_set_null % params, []))
         
         
         # TODO: Unique

File tests/logic.py

         app = self.create_test_app()
         
         self.assertEqual(
-            ["0001_spam", "0002_eggs"],
+            ["0001_spam", "0002_eggs", "0003_alter_spam"],
             migration.get_migration_names(app),
         )
     
         # Can't use vanilla import, modules beginning with numbers aren't in grammar
         M1 = __import__("fakeapp.migrations.0001_spam", {}, {}, ['Migration']).Migration
         M2 = __import__("fakeapp.migrations.0002_eggs", {}, {}, ['Migration']).Migration
+        M3 = __import__("fakeapp.migrations.0003_alter_spam", {}, {}, ['Migration']).Migration
         
         self.assertEqual(
-            [M1, M2],
+            [M1, M2, M3],
             list(migration.get_migration_classes(app)),
         )
     
             {app: {
                 "0001_spam": migration.get_migration(app, "0001_spam"),
                 "0002_eggs": migration.get_migration(app, "0002_eggs"),
+                "0003_alter_spam": migration.get_migration(app, "0003_alter_spam"),
             }},
             migration.all_migrations(),
         )
             (
                 (u"fakeapp", u"0001_spam"),
                 (u"fakeapp", u"0002_eggs"),
+                (u"fakeapp", u"0003_alter_spam"),
             ),
             migration.MigrationHistory.objects.values_list("app_name", "migration"),
         )
             (
                 (u"fakeapp", u"0001_spam"),
                 (u"fakeapp", u"0002_eggs"),
+                (u"fakeapp", u"0003_alter_spam"),
             ),
             migration.MigrationHistory.objects.values_list("app_name", "migration"),
         )
         
         # Now roll them backwards
+        migration.migrate_app(app, target_name="0002", resolve_mode=None, fake=False, silent=True)
         migration.migrate_app(app, target_name="0001", resolve_mode=None, fake=True, silent=True)
         migration.migrate_app(app, target_name="zero", resolve_mode=None, fake=False, silent=True)
         
         # Finish with none
         self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
+    
+    def test_alter_column_null(self):
+        def null_ok():
+            from django.db import connection, transaction
+            # the DBAPI introspection module fails on postgres NULLs.
+            cursor = connection.cursor()
+            try:
+                cursor.execute("INSERT INTO southtest_spam (id, weight, expires, name) VALUES (100, 10.1, now(), NULL);")
+            except:
+                transaction.rollback()
+                return False
+            else:
+                cursor.execute("DELETE FROM southtest_spam")
+                transaction.commit()
+                return True
+        
+        app = migration.get_app("fakeapp")
+        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
+        
+        # by default name is NOT NULL
+        migration.migrate_app(app, target_name="0002", resolve_mode=None, fake=False, silent=True)
+        self.failIf(null_ok())
+        
+        # after 0003, it should be NULL
+        migration.migrate_app(app, target_name="0003", resolve_mode=None, fake=False, silent=True)
+        self.assert_(null_ok())
+
+        # make sure it is NOT NULL again
+        migration.migrate_app(app, target_name="0002", resolve_mode=None, fake=False, silent=True)
+        self.failIf(null_ok(), 'name not null after migration')
+        
+        # finish with no migrations, otherwise other tests fail...
+        migration.migrate_app(app, target_name="zero", resolve_mode=None, fake=False, silent=True)
+        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])