Skip to content

Commit 13c8b19

Browse files
committed
forward port michiya#184 to azure-2.1
1 parent a902a95 commit 13c8b19

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

sql_server/pyodbc/features.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
1919
requires_literal_defaults = True
2020
requires_sqlparse_for_splitting = False
2121
supports_index_on_text_field = False
22-
supports_nullable_unique_constraints = False
22+
supports_nullable_unique_constraints = True
2323
supports_paramstyle_pyformat = False
2424
supports_partially_nullable_unique_constraints = False
2525
supports_regex_backreferencing = False

sql_server/pyodbc/schema.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
5252
sql_delete_table = "DROP TABLE %(table)s"
5353
sql_rename_column = "EXEC sp_rename '%(table)s.%(old_column)s', %(new_column)s, 'COLUMN'"
5454
sql_rename_table = "EXEC sp_rename %(old_table)s, %(new_table)s"
55+
sql_create_unique_null = "CREATE UNIQUE INDEX %(name)s ON %(table)s(%(columns)s) " \
56+
"WHERE %(columns)s IS NOT NULL"
5557

5658
def _alter_column_default_sql(self, model, old_field, new_field, drop=False):
5759
"""
@@ -320,8 +322,15 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
320322
self._delete_primary_key(model, strict)
321323
# Added a unique?
322324
if self._unique_should_be_added(old_field, new_field):
323-
self.execute(self._create_unique_sql(model, [new_field.column]))
324-
# Added an index?
325+
if not new_field.many_to_many and new_field.null:
326+
self.execute(
327+
self._create_index_sql(
328+
model, [new_field], sql=self.sql_create_unique_null, suffix="_uniq"
329+
)
330+
)
331+
else:
332+
self.execute(self._create_unique_sql(model, [new_field.column]))
333+
# Added an index?
325334
# constraint will no longer be used in lieu of an index. The following
326335
# lines from the truth table show all True cases; the rest are False:
327336
#
@@ -496,6 +505,13 @@ def add_field(self, model, field):
496505
# It might not actually have a column behind it
497506
if definition is None:
498507
return
508+
509+
if not field.many_to_many and field.null and field.unique:
510+
definition = definition.replace(' UNIQUE', '')
511+
self.deferred_sql.append(self._create_index_sql(
512+
model, [field], sql=self.sql_create_unique_null, suffix="_uniq"
513+
))
514+
499515
# Check constraints can go on the column SQL here
500516
db_params = field.db_parameters(connection=self.connection)
501517
if db_params['check']:
@@ -538,6 +554,13 @@ def create_model(self, model):
538554
definition, extra_params = self.column_sql(model, field)
539555
if definition is None:
540556
continue
557+
558+
if not field.many_to_many and field.null and field.unique:
559+
definition = definition.replace(' UNIQUE', '')
560+
self.deferred_sql.append(self._create_index_sql(
561+
model, [field], sql=self.sql_create_unique_null, suffix="_uniq"
562+
))
563+
541564
# Check constraints can go on the column SQL here
542565
db_params = field.db_parameters(connection=self.connection)
543566
if db_params['check']:

0 commit comments

Comments
 (0)