Skip to content

Commit

Permalink
fix the issue #73
Browse files Browse the repository at this point in the history
  • Loading branch information
michiya committed Aug 13, 2016
1 parent b6e7d51 commit 5c8cb03
Showing 1 changed file with 87 additions and 64 deletions.
151 changes: 87 additions & 64 deletions sql_server/pyodbc/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,21 +134,9 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
actions.append(fragment)
post_actions.extend(other_actions)
# Drop unique constraint, SQL Server requires explicit deletion
if old_field.unique and new_field.unique:
constraint_names = self._constraint_names(model, [old_field.column], unique=True)
if strict and len(constraint_names) != 1:
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
len(constraint_names),
model._meta.db_table,
old_field.column,
))
for constraint_name in constraint_names:
self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))
self._delete_unique_constraints(model, old_field, new_field, strict)
# Drop indexes, SQL Server requires explicit deletion
elif old_field.db_index and new_field.db_index:
index_names = self._constraint_names(model, [old_field.column], index=True)
for index_name in index_names:
self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
self._delete_indexes(model, old_field, new_field)
# When changing a column NULL constraint to NOT NULL with a given
# default value, we need to perform 4 steps:
# 1. Add a default for new incoming writes
Expand Down Expand Up @@ -206,21 +194,9 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
[],
))
# Drop unique constraint, SQL Server requires explicit deletion
if old_field.unique and new_field.unique:
constraint_names = self._constraint_names(model, [old_field.column], unique=True)
if strict and len(constraint_names) != 1:
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
len(constraint_names),
model._meta.db_table,
old_field.column,
))
for constraint_name in constraint_names:
self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))
self._delete_unique_constraints(model, old_field, new_field, strict)
# Drop indexes, SQL Server requires explicit deletion
elif old_field.db_index and new_field.db_index:
index_names = self._constraint_names(model, [old_field.column], index=True)
for index_name in index_names:
self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
self._delete_indexes(model, old_field, new_field)
# Only if we have a default and there is a change from NULL to NOT NULL
four_way_default_alteration = (
new_field.has_default() and
Expand Down Expand Up @@ -277,10 +253,28 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
self.execute(self._create_index_sql(model, [new_field], suffix="_uniq"))
# Restore an index, SQL Server requires explicit restoration
if old_type != new_type or (old_field.null and not new_field.null):
unique_columns = []
if old_field.unique and new_field.unique:
self.execute(self._create_unique_sql(model, [new_field.column]))
elif old_field.db_index and new_field.db_index:
self.execute(self._create_index_sql(model, [new_field]))
unique_columns.append([old_field.column])
else:
for fields in model._meta.unique_together:
columns = [model._meta.get_field(field).column for field in fields]
if old_field.column in columns:
unique_columns.append(columns)
if unique_columns:
for columns in unique_columns:
self.execute(self._create_unique_sql(model, columns))
index_columns = []
if old_field.db_index and new_field.db_index:
index_columns.append([old_field])
else:
for fields in model._meta.index_together:
columns = [model._meta.get_field(field) for field in fields]
if old_field.column in [c.column for c in columns]:
index_columns.append(columns)
if index_columns:
for columns in index_columns:
self.execute(self._create_index_sql(model, columns, suffix='_idx'))
# Type alteration on primary key? Then we need to alter the column
# referring to us.
rels_to_update = []
Expand Down Expand Up @@ -369,6 +363,42 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
if self.connection.features.connection_persists_old_columns:
self.connection.close()

def _delete_indexes(self, model, old_field, new_field):
index_columns = []
if old_field.db_index and new_field.db_index:
index_columns.append([old_field.column])
else:
for fields in model._meta.index_together:
columns = [model._meta.get_field(field).column for field in fields]
if old_field.column in columns:
index_columns.append(columns)
if index_columns:
for columns in index_columns:
index_names = self._constraint_names(model, columns, index=True)
for index_name in index_names:
self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))

def _delete_unique_constraints(self, model, old_field, new_field, strict=False):
unique_columns = []
if old_field.unique and new_field.unique:
unique_columns.append([old_field.column])
else:
for fields in model._meta.unique_together:
columns = [model._meta.get_field(field).column for field in fields]
if old_field.column in columns:
unique_columns.append(columns)
if unique_columns:
for columns in unique_columns:
constraint_names = self._constraint_names(model, columns, unique=True)
if strict and len(constraint_names) != 1:
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
len(constraint_names),
model._meta.db_table,
old_field.column,
))
for constraint_name in constraint_names:
self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))

def _rename_field_sql(self, table, old_field, new_field, new_type):
new_type = self._set_field_new_type_null_status(old_field, new_type)
return super(DatabaseSchemaEditor, self)._rename_field_sql(table, old_field, new_field, new_type)
Expand Down Expand Up @@ -601,47 +631,40 @@ def remove_field(self, model, field):
# It might not actually have a column behind it
if field.db_parameters(connection=self.connection)['type'] is None:
return
# Drop any FK constraints, MySQL requires explicit deletion
if field.rel:
fk_names = self._constraint_names(model, [field.column], foreign_key=True)
for fk_name in fk_names:
self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, fk_name))
# Drop any FK constraints, SQL Server requires explicit deletion
with self.connection.cursor() as cursor:
constraints = self.connection.introspection.get_constraints(cursor, model._meta.db_table)
for name, infodict in constraints.items():
if field.column in infodict['columns'] and infodict['foreign_key']:
self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, name))
# Drop any indexes, SQL Server requires explicit deletion
index_names = self._constraint_names(model, [field.column], index=True)
for index_name in index_names:
self.execute(
self.sql_delete_index % {
for name, infodict in constraints.items():
if field.column in infodict['columns'] and infodict['index']:
self.execute(self.sql_delete_index % {
"table": self.quote_name(model._meta.db_table),
"name": self.quote_name(index_name),
}
)
"name": self.quote_name(name),
})
# Drop primary key constraint, SQL Server requires explicit deletion
pk_names = self._constraint_names(model, [field.column], primary_key=True)
for pk_name in pk_names:
self.execute(
self.sql_delete_pk % {
for name, infodict in constraints.items():
if field.column in infodict['columns'] and infodict['primary_key']:
self.execute(self.sql_delete_pk % {
"table": self.quote_name(model._meta.db_table),
"name": self.quote_name(pk_name),
}
)
"name": self.quote_name(name),
})
# Drop check constraints, SQL Server requires explicit deletion
check_names = self._constraint_names(model, [field.column], check=True)
for check_name in check_names:
self.execute(
self.sql_delete_check % {
for name, infodict in constraints.items():
if field.column in infodict['columns'] and infodict['check']:
self.execute(self.sql_delete_check % {
"table": self.quote_name(model._meta.db_table),
"name": self.quote_name(check_name),
}
)
"name": self.quote_name(name),
})
# Drop unique constraints, SQL Server requires explicit deletion
unique_names = self._constraint_names(model, [field.column], unique=True)
for unique_name in unique_names:
self.execute(
self.sql_delete_unique % {
for name, infodict in constraints.items():
if field.column in infodict['columns'] and infodict['unique'] and not infodict['primary_key']:
self.execute(self.sql_delete_unique % {
"table": self.quote_name(model._meta.db_table),
"name": self.quote_name(unique_name),
}
)
"name": self.quote_name(name),
})
# Delete the column
sql = self.sql_delete_column % {
"table": self.quote_name(model._meta.db_table),
Expand Down

0 comments on commit 5c8cb03

Please sign in to comment.