Commits

Andrew Godwin committed 8de2e9a

Fix #332: Invalid SQL for primary keys on postgres 8.1 or below.

Comments (0)

Files changed (2)

south/db/generic.py

     drop_index_string = 'DROP INDEX %(index_name)s'
     delete_column_string = 'ALTER TABLE %s DROP COLUMN %s CASCADE;'
     create_primary_key_string = "ALTER TABLE %(table)s ADD CONSTRAINT %(constraint)s PRIMARY KEY (%(columns)s)"
-    drop_primary_key_string = "ALTER TABLE %(table)s DROP CONSTRAINT %(constraint)s"
+    delete_primary_key_sql = "ALTER TABLE %(table)s DROP CONSTRAINT %(constraint)s"
     backend_name = None
 
     def __init__(self, db_alias):
     def _constraints_affecting_columns(self, table_name, columns, type="UNIQUE"):
         """
         Gets the names of the constraints affecting the given columns.
+        If columns is None, returns all constraints of the type on the table.
         """
 
         if self.dry_run:
             raise ValueError("Cannot get constraints for columns during a dry run.")
 
-        columns = set(columns)
+        if columns is not None:
+            columns = set(columns)
 
         if type == "CHECK":
             ifsc_table = "constraint_column_usage"
                 kc.table_name = %%s AND
                 c.constraint_type = %%s
         """ % ifsc_table, ['public', table_name, type])
+        
         # Load into a dict
         mapping = {}
         for constraint, column in rows:
             mapping.setdefault(constraint, set())
             mapping[constraint].add(column)
+        
         # Find ones affecting these columns
         for constraint, itscols in mapping.items():
-            if itscols == columns:
+            # If columns is None we definitely want this field! (see docstring)
+            if itscols == columns or columns is None:
                 yield constraint
 
 
         raise NotImplementedError("rename_column has no generic SQL syntax")
 
 
-    def drop_primary_key(self, table_name):
+    def delete_primary_key(self, table_name):
         """
         Drops the old primary key.
         """
-        self.execute(self.drop_primary_key_string % {
-            "table": self.quote_name(table_name),
-            "constraint": self.quote_name(table_name+"_pkey"),
-        })
-
-    delete_primary_key = alias('drop_primary_key')
+        # Dry runs mean we can't do anything.
+        if self.dry_run:
+            return
+        
+        constraints = list(self._constraints_affecting_columns(table_name, None, type="PRIMARY KEY"))
+        if not constraints:
+            raise ValueError("Cannot find a PRIMARY KEY constraint on table %s" % (table_name,))
+        
+        for constraint in constraints:
+            self.execute(self.delete_primary_key_sql % {
+                "table": self.quote_name(table_name),
+                "constraint": self.quote_name(constraint),
+            })
+    
+    drop_primary_key = alias('delete_primary_key')
 
 
     def create_primary_key(self, table_name, columns):

south/db/mysql.py

     alter_string_set_null = 'MODIFY %(column)s %(type)s NULL;'
     alter_string_drop_null = 'MODIFY %(column)s %(type)s NOT NULL;'
     drop_index_string = 'DROP INDEX %(index_name)s ON %(table_name)s'
-    drop_primary_key_string = "ALTER TABLE %(table)s DROP PRIMARY KEY"
+    delete_primary_key_sql = "ALTER TABLE %(table)s DROP PRIMARY KEY"
     allows_combined_alters = False
     has_ddl_transactions = False
     has_check_constraints = False
     def _constraints_affecting_columns(self, table_name, columns, type="UNIQUE"):
         """
         Gets the names of the constraints affecting the given columns.
+        If columns is None, returns all constraints of the type on the table.
         """
         
         if self.dry_run:
             raise ValueError("Cannot get constraints for columns during a dry run.")
         
-        columns = set(columns)
+        if columns is not None:
+            columns = set(columns)
+        
         db_name = self._get_setting('NAME')
+        
         # First, load all constraint->col mappings for this table.
         rows = self.execute("""
             SELECT kc.constraint_name, kc.column_name
                 kc.table_name = %s AND
                 c.constraint_type = %s
         """, [db_name, table_name, type])
+        
         # Load into a dict
         mapping = {}
         for constraint, column in rows:
             mapping.setdefault(constraint, set())
             mapping[constraint].add(column)
+        
         # Find ones affecting these columns
         for constraint, itscols in mapping.items():
-            if itscols == columns:
+            if itscols == columns or columns is None:
                 yield constraint