Ticket #697: south-0.7-697.diff

File south-0.7-697.diff, 4.0 KB (added by s_dalton@…, 3 years ago)

Patch to fix the issue

  • south/db/generic.py

    diff -r 69b4986003d6 south/db/generic.py
    a b  
    657657 
    658658    drop_index = alias('delete_index') 
    659659 
     660    def delete_foreign_key_by_keyname(self, table_name, foreign_key_name): 
     661        """ 
     662        Drop a foreign key constraint by name 
     663        """ 
     664        if self.dry_run: 
     665            return # We can't look at the DB to get the constraints 
     666        self.execute(self.delete_foreign_key_sql % { 
     667            "table": self.quote_name(table_name), 
     668            "constraint": self.quote_name(foreign_key_name), 
     669        }) 
    660670 
    661671    def delete_column(self, table_name, name): 
    662672        """ 
  • south/db/mysql.py

    diff -r 69b4986003d6 south/db/mysql.py
    a b  
    6363            rows[0][5] or "", 
    6464        ) 
    6565         
     66        # migrate any foreign keys 
     67        fks_to_reinstate = self._get_all_fks(table_name) 
     68        for constraint in fks_to_reinstate: 
     69            if (fks_to_reinstate[constraint]['column'] == old): 
     70                # delete any applicable foreign keys             
     71                self.delete_foreign_key_by_keyname(table_name, fks_to_reinstate[constraint]['name']) 
     72             
    6673        sql = 'ALTER TABLE %s CHANGE COLUMN %s %s %s %s %s %s %s;' % params 
    6774         
    6875        if rows[0][4]: 
    6976            self.execute(sql, (rows[0][4],)) 
    7077        else: 
    7178            self.execute(sql) 
     79             
     80        # reinstate the foreign keys to the new mapping 
     81        for constraint in fks_to_reinstate: 
     82            if (fks_to_reinstate[constraint]['column'] == old): 
     83                self.foreign_key_sql(fks_to_reinstate[constraint]['src_table'], fks_to_reinstate[constraint]['src_col'], table_name, new) 
    7284     
    7385     
    7486    def delete_column(self, table_name, name): 
     
    107119            # No Operation 
    108120            return 
    109121        params = (self.quote_name(old_table_name), self.quote_name(table_name)) 
    110         self.execute('RENAME TABLE %s TO %s;' % params) 
     122         
     123        # migrate any foreign keys 
     124        fks_to_reinstate = self._get_all_fks(old_table_name) 
     125        for constraint in fks_to_reinstate: 
     126            # delete any foreign keys 
     127            self.delete_foreign_key_by_keyname(old_table_name, fks_to_reinstate[constraint]['name']) 
     128         
     129        self.execute('ALTER TABLE %s RENAME TO %s;' % params) 
     130         
     131        # reinstate foreign keys that had to be removed with the table rename operation 
     132        for constraint in fks_to_reinstate: 
     133            self.foreign_key_sql(fks_to_reinstate[constraint]['src_table'], fks_to_reinstate[constraint]['src_col'], table_name, fks_to_reinstate[constraint]['column']) 
    111134     
     135         
     136    def _get_all_fks(self, table_name): 
     137         
     138        db_name = self._get_setting('NAME') 
     139 
     140        # First, load all constraint->col mappings for this table. 
     141        sql = """ 
     142        SELECT kc.constraint_name, kc.column_name, kc.referenced_table_name, kc.referenced_column_name 
     143            FROM information_schema.key_column_usage AS kc 
     144            JOIN information_schema.table_constraints AS c ON 
     145                kc.table_schema = c.table_schema AND 
     146                kc.table_name = c.table_name AND 
     147                kc.constraint_name = c.constraint_name 
     148            WHERE 
     149                kc.table_schema = '%s' AND 
     150                kc.table_catalog IS NULL AND 
     151                kc.table_name = '%s' AND 
     152                c.constraint_type = 'FOREIGN KEY' 
     153        """     
     154        rows = self.execute(sql % (db_name, table_name)) 
     155         
     156        # Load into a dict 
     157        mapping = {} 
     158        for constraint, column, ref_table, ref_col in rows: 
     159            #mapping.setdefault(constraint, set()) 
     160            mapping[constraint] = {'name': constraint, 'column': column, 'src_table': ref_table, 'src_col': ref_col} 
     161             
     162        return mapping 
    112163     
    113164    def _constraints_affecting_columns(self, table_name, columns, type="UNIQUE"): 
    114165        """