Skip to content

Add support for unique=True on BinaryField, TextField, and others #34

@NZSmartie

Description

@NZSmartie

Microsoft SQL server has a set of maximum capacity specifications as documented Maximum capacity specifications for SQL Server

The DatabaseWrapper.data_types dictionary contains a max parameter for some fields in the database that may or may not have a max_length size set in the applications model:

mssql-django/mssql/base.py

Lines 74 to 102 in ff59848

data_types = {
'AutoField': 'int',
'BigAutoField': 'bigint',
'BigIntegerField': 'bigint',
'BinaryField': 'varbinary(max)',
'BooleanField': 'bit',
'CharField': 'nvarchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime2',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'nvarchar(%(max_length)s)',
'FilePathField': 'nvarchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'int',
'IPAddressField': 'nvarchar(15)',
'GenericIPAddressField': 'nvarchar(39)',
'JSONField': 'nvarchar(max)',
'NullBooleanField': 'bit',
'OneToOneField': 'int',
'PositiveIntegerField': 'int',
'PositiveSmallIntegerField': 'smallint',
'SlugField': 'nvarchar(%(max_length)s)',
'SmallAutoField': 'smallint',
'SmallIntegerField': 'smallint',
'TextField': 'nvarchar(max)',
'TimeField': 'time',
'UUIDField': 'char(32)',
}

Specifically, BinaryField, JSONField, TextField have a corresponding max size set instead of respecting the max_length property that can be set in an application's model.

For example:

class ClientDownload(models.Model):
    access_code = models.BinaryField(max_length=15, default=random_access_code, unique=True)
    # ...

A developer should expect the access_code field to be created in the database with the type varbinary(15) (or binary(15), but that may be out of scope of this issue). However, since the field's type will end up with varbinary(max), the unique=True constraint will throw an exception from SQL server as the field is too large to be indexed.

[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'access_code' in table 'mypp_clientupload' is of a type that is invalid for use as a key column in an index. (1919) (SQLExecDirectW); [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Could not create constraint or index. See previous errors. (1750)

This is due to the maximum bytes allowed for an indexable field

SQL Server Database Engine object Maximum sizes/numbers SQL Server (64-bit) Additional Information
Bytes per index key 900 bytes for a clustered index. 1,700 for a nonclustered index. The maximum number of bytes in a clustered index key cannot exceed 900 in SQL Server. For a nonclustered index key, the maximum is 1700 bytes. You can define a key using variable-length columns whose maximum sizes add up to more than the limit. However, the combined sizes of the data in those columns can never exceed the limit. In a nonclustered index, you can include extra non-key columns, and they do not count against the size limit of the key. The non-key columns might help some queries perform better.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions