Skip to content

Commit 3425709

Browse files
committed
fix the issue #73
1 parent 4ebdd56 commit 3425709

File tree

1 file changed

+87
-64
lines changed

1 file changed

+87
-64
lines changed

sql_server/pyodbc/schema.py

Lines changed: 87 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -131,21 +131,9 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
131131
actions.append(fragment)
132132
post_actions.extend(other_actions)
133133
# Drop unique constraint, SQL Server requires explicit deletion
134-
if old_field.unique and new_field.unique:
135-
constraint_names = self._constraint_names(model, [old_field.column], unique=True)
136-
if strict and len(constraint_names) != 1:
137-
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
138-
len(constraint_names),
139-
model._meta.db_table,
140-
old_field.column,
141-
))
142-
for constraint_name in constraint_names:
143-
self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))
134+
self._delete_unique_constraints(model, old_field, new_field, strict)
144135
# Drop indexes, SQL Server requires explicit deletion
145-
elif old_field.db_index and new_field.db_index:
146-
index_names = self._constraint_names(model, [old_field.column], index=True)
147-
for index_name in index_names:
148-
self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
136+
self._delete_indexes(model, old_field, new_field)
149137
# When changing a column NULL constraint to NOT NULL with a given
150138
# default value, we need to perform 4 steps:
151139
# 1. Add a default for new incoming writes
@@ -205,21 +193,9 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
205193
[],
206194
))
207195
# Drop unique constraint, SQL Server requires explicit deletion
208-
if old_field.unique and new_field.unique:
209-
constraint_names = self._constraint_names(model, [old_field.column], unique=True)
210-
if strict and len(constraint_names) != 1:
211-
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
212-
len(constraint_names),
213-
model._meta.db_table,
214-
old_field.column,
215-
))
216-
for constraint_name in constraint_names:
217-
self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))
196+
self._delete_unique_constraints(model, old_field, new_field, strict)
218197
# Drop indexes, SQL Server requires explicit deletion
219-
elif old_field.db_index and new_field.db_index:
220-
index_names = self._constraint_names(model, [old_field.column], index=True)
221-
for index_name in index_names:
222-
self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
198+
self._delete_indexes(model, old_field, new_field)
223199
# Only if we have a default and there is a change from NULL to NOT NULL
224200
four_way_default_alteration = (
225201
new_field.has_default() and
@@ -276,10 +252,28 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
276252
self.execute(self._create_index_sql(model, [new_field], suffix="_uniq"))
277253
# Restore an index, SQL Server requires explicit restoration
278254
if old_type != new_type or (old_field.null and not new_field.null):
255+
unique_columns = []
279256
if old_field.unique and new_field.unique:
280-
self.execute(self._create_unique_sql(model, [new_field.column]))
281-
elif old_field.db_index and new_field.db_index:
282-
self.execute(self._create_index_sql(model, [new_field]))
257+
unique_columns.append([old_field.column])
258+
else:
259+
for fields in model._meta.unique_together:
260+
columns = [model._meta.get_field(field).column for field in fields]
261+
if old_field.column in columns:
262+
unique_columns.append(columns)
263+
if unique_columns:
264+
for columns in unique_columns:
265+
self.execute(self._create_unique_sql(model, columns))
266+
index_columns = []
267+
if old_field.db_index and new_field.db_index:
268+
index_columns.append([old_field])
269+
else:
270+
for fields in model._meta.index_together:
271+
columns = [model._meta.get_field(field) for field in fields]
272+
if old_field.column in [c.column for c in columns]:
273+
index_columns.append(columns)
274+
if index_columns:
275+
for columns in index_columns:
276+
self.execute(self._create_index_sql(model, columns, suffix='_idx'))
283277
# Type alteration on primary key? Then we need to alter the column
284278
# referring to us.
285279
rels_to_update = []
@@ -369,6 +363,42 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
369363
if self.connection.features.connection_persists_old_columns:
370364
self.connection.close()
371365

366+
def _delete_indexes(self, model, old_field, new_field):
367+
index_columns = []
368+
if old_field.db_index and new_field.db_index:
369+
index_columns.append([old_field.column])
370+
else:
371+
for fields in model._meta.index_together:
372+
columns = [model._meta.get_field(field).column for field in fields]
373+
if old_field.column in columns:
374+
index_columns.append(columns)
375+
if index_columns:
376+
for columns in index_columns:
377+
index_names = self._constraint_names(model, columns, index=True)
378+
for index_name in index_names:
379+
self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
380+
381+
def _delete_unique_constraints(self, model, old_field, new_field, strict=False):
382+
unique_columns = []
383+
if old_field.unique and new_field.unique:
384+
unique_columns.append([old_field.column])
385+
else:
386+
for fields in model._meta.unique_together:
387+
columns = [model._meta.get_field(field).column for field in fields]
388+
if old_field.column in columns:
389+
unique_columns.append(columns)
390+
if unique_columns:
391+
for columns in unique_columns:
392+
constraint_names = self._constraint_names(model, columns, unique=True)
393+
if strict and len(constraint_names) != 1:
394+
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
395+
len(constraint_names),
396+
model._meta.db_table,
397+
old_field.column,
398+
))
399+
for constraint_name in constraint_names:
400+
self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))
401+
372402
def _rename_field_sql(self, table, old_field, new_field, new_type):
373403
new_type = self._set_field_new_type_null_status(old_field, new_type)
374404
return super(DatabaseSchemaEditor, self)._rename_field_sql(table, old_field, new_field, new_type)
@@ -600,47 +630,40 @@ def remove_field(self, model, field):
600630
# It might not actually have a column behind it
601631
if field.db_parameters(connection=self.connection)['type'] is None:
602632
return
603-
# Drop any FK constraints, MySQL requires explicit deletion
604-
if field.remote_field:
605-
fk_names = self._constraint_names(model, [field.column], foreign_key=True)
606-
for fk_name in fk_names:
607-
self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, fk_name))
633+
# Drop any FK constraints, SQL Server requires explicit deletion
634+
with self.connection.cursor() as cursor:
635+
constraints = self.connection.introspection.get_constraints(cursor, model._meta.db_table)
636+
for name, infodict in constraints.items():
637+
if field.column in infodict['columns'] and infodict['foreign_key']:
638+
self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, name))
608639
# Drop any indexes, SQL Server requires explicit deletion
609-
index_names = self._constraint_names(model, [field.column], index=True)
610-
for index_name in index_names:
611-
self.execute(
612-
self.sql_delete_index % {
640+
for name, infodict in constraints.items():
641+
if field.column in infodict['columns'] and infodict['index']:
642+
self.execute(self.sql_delete_index % {
613643
"table": self.quote_name(model._meta.db_table),
614-
"name": self.quote_name(index_name),
615-
}
616-
)
644+
"name": self.quote_name(name),
645+
})
617646
# Drop primary key constraint, SQL Server requires explicit deletion
618-
pk_names = self._constraint_names(model, [field.column], primary_key=True)
619-
for pk_name in pk_names:
620-
self.execute(
621-
self.sql_delete_pk % {
647+
for name, infodict in constraints.items():
648+
if field.column in infodict['columns'] and infodict['primary_key']:
649+
self.execute(self.sql_delete_pk % {
622650
"table": self.quote_name(model._meta.db_table),
623-
"name": self.quote_name(pk_name),
624-
}
625-
)
651+
"name": self.quote_name(name),
652+
})
626653
# Drop check constraints, SQL Server requires explicit deletion
627-
check_names = self._constraint_names(model, [field.column], check=True)
628-
for check_name in check_names:
629-
self.execute(
630-
self.sql_delete_check % {
654+
for name, infodict in constraints.items():
655+
if field.column in infodict['columns'] and infodict['check']:
656+
self.execute(self.sql_delete_check % {
631657
"table": self.quote_name(model._meta.db_table),
632-
"name": self.quote_name(check_name),
633-
}
634-
)
658+
"name": self.quote_name(name),
659+
})
635660
# Drop unique constraints, SQL Server requires explicit deletion
636-
unique_names = self._constraint_names(model, [field.column], unique=True)
637-
for unique_name in unique_names:
638-
self.execute(
639-
self.sql_delete_unique % {
661+
for name, infodict in constraints.items():
662+
if field.column in infodict['columns'] and infodict['unique'] and not infodict['primary_key']:
663+
self.execute(self.sql_delete_unique % {
640664
"table": self.quote_name(model._meta.db_table),
641-
"name": self.quote_name(unique_name),
642-
}
643-
)
665+
"name": self.quote_name(name),
666+
})
644667
# Delete the column
645668
sql = self.sql_delete_column % {
646669
"table": self.quote_name(model._meta.db_table),

0 commit comments

Comments
 (0)