Commits

shaib committed 2cfc435

Stop leaving defaults in the database (hopefully one last time...)

This commit adds testing to verify that no defaults are left in the
database even through alter-column, and even when the column is not
null, and fixes for all backends to comply (except SQLite and Oracle,
which complied already).

The fix for Firebird is untested. MySQL also untested, but shares the
code path with Postgres, so hopefully ok.

Comments (0)

Files changed (4)

south/db/firebird.py

 
     def _alter_set_defaults(self, field, name, params, sqls):
         "Subcommand of alter_column that sets default values (overrideable)"
-        # Next, set any default
-        if not field.null and field.has_default():
-            default = field.get_default()
-            sqls.append(('ALTER COLUMN %s SET DEFAULT %%s ' % (self.quote_name(name),), [default]))
-        elif self._column_has_default(params):
+        # Historically, we used to set defaults here.
+        # But since South 0.8, we don't ever set defaults on alter-column -- we only
+        # use database-level defaults as scaffolding when adding columns.
+        # However, we still sometimes need to remove defaults in alter-column.
+        if self._column_has_default(params):
             sqls.append(('ALTER COLUMN %s DROP DEFAULT' % (self.quote_name(name),), []))
 
 

south/db/generic.py

 
     def _alter_set_defaults(self, field, name, params, sqls):
         "Subcommand of alter_column that sets default values (overrideable)"
-        # Next, set any default
-        if not field.null and field.has_default():
-            default = field.get_db_prep_save(field.get_default(), connection=self._get_connection())
-            sqls.append(('ALTER COLUMN %s SET DEFAULT %%s ' % (self.quote_name(name),), [default]))
-        else:
-            sqls.append(('ALTER COLUMN %s DROP DEFAULT' % (self.quote_name(name),), []))
+        # Historically, we used to set defaults here.
+        # But since South 0.8, we don't ever set defaults on alter-column -- we only
+        # use database-level defaults as scaffolding when adding columns.
+        # However, we still sometimes need to remove defaults in alter-column.
+        sqls.append(('ALTER COLUMN %s DROP DEFAULT' % (self.quote_name(name),), []))
 
     def _update_nulls_to_default(self, params, field):
         "Subcommand of alter_column that updates nulls to default value (overrideable)"
             sqls.append((self.alter_string_drop_null % params, []))
 
         # Do defaults
-        #self._alter_set_defaults(field, name, params, sqls)
+        self._alter_set_defaults(field, name, params, sqls)
 
         # Actually change the column (step 1 -- Nullity may need to be fixed)
         if self.allows_combined_alters:

south/db/sql_server/pyodbc.py

     
     def _alter_set_defaults(self, field, name, params, sqls): 
         "Subcommand of alter_column that sets default values (overrideable)"
-        # First drop the current default if one exists
+        # Historically, we used to set defaults here.
+        # But since South 0.8, we don't ever set defaults on alter-column -- we only
+        # use database-level defaults as scaffolding when adding columns.
+        # However, we still sometimes need to remove defaults in alter-column.
         table_name = self.quote_name(params['table_name'])
         drop_default = self.drop_column_default_sql(table_name, name)
         if drop_default:
             sqls.append((drop_default, []))
             
-        # Next, set any default
-        
-        if field.has_default():
-            default = field.get_default()
-            literal = self._value_to_unquoted_literal(field, default)
-            sqls.append(('ADD DEFAULT %s for %s' % (self._quote_string(literal), self.quote_name(name),), []))
-
     def _value_to_unquoted_literal(self, field, value):
         # Start with the field's own translation
         conn = self._get_connection()

south/tests/db.py

         null = db.execute("SELECT spam FROM test_altercd")[0][0]
         self.assertFalse(null, "Default for char field was installed into database")
 
+        # Change again to a column with default and not null
+        db.alter_column("test_altercd", "spam", models.CharField(max_length=30, default="loof", null=False))
+        # Assert the default is not in the database
+        if 'oracle' in db.backend_name:
+            # Oracle special treatment -- nulls are always allowed in char columns, so 
+            # inserting doesn't raise an integrity error; so we check again as above
+            db.execute("INSERT INTO test_altercd (eggs) values (12)")
+            null = db.execute("SELECT spam FROM test_altercd")[0][0]
+            self.assertFalse(null, "Default for char field was installed into database")
+        else:
+            # For other backends, insert should now just fail
+            self.assertRaises(IntegrityError,
+                              db.execute, "INSERT INTO test_altercd (eggs) values (12)")
+
     @skipIf('oracle' in db.backend_name, "Oracle does not differentiate empty trings from null")
     def test_default_empty_string(self):
         """