master 79e421ad3772 cached
44 files
184.3 KB
42.3k tokens
216 symbols
1 requests
Download .txt
Repository: ESSolutions/django-mssql-backend
Branch: master
Commit: 79e421ad3772
Files: 44
Total size: 184.3 KB

Directory structure:
gitextract_g2cq4foq/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── MANIFEST.in
├── README.rst
├── docker/
│   ├── Dockerfile
│   └── docker-compose.yml
├── manage.py
├── setup.cfg
├── setup.py
├── sql_server/
│   ├── __init__.py
│   └── pyodbc/
│       ├── __init__.py
│       ├── base.py
│       ├── client.py
│       ├── compiler.py
│       ├── creation.py
│       ├── features.py
│       ├── functions.py
│       ├── introspection.py
│       ├── management/
│       │   ├── __init__.py
│       │   └── commands/
│       │       ├── __init__.py
│       │       └── install_regex_clr.py
│       ├── operations.py
│       └── schema.py
├── test.sh
├── testapp/
│   ├── __init__.py
│   ├── migrations/
│   │   ├── 0001_initial.py
│   │   ├── 0002_test_unique_nullable_part1.py
│   │   ├── 0003_test_unique_nullable_part2.py
│   │   ├── 0004_test_issue45_unique_type_change_part1.py
│   │   ├── 0005_test_issue45_unique_type_change_part2.py
│   │   ├── 0006_test_remove_onetoone_field_part1.py
│   │   ├── 0007_test_remove_onetoone_field_part2.py
│   │   └── __init__.py
│   ├── models.py
│   ├── runner.py
│   ├── settings.py
│   └── tests/
│       ├── __init__.py
│       ├── test_constraints.py
│       ├── test_expressions.py
│       └── test_fields.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# https://editorconfig.org/

root = true

[*]
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8
max_line_length = 119

[*.{yml,yaml}]
indent_size = 2


================================================
FILE: .github/workflows/main.yml
================================================
name: Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

env:
  DATABASE_URL: "mssql://SA:MyPassword42@localhost:1433/default?isolation_level=read committed&driver=ODBC Driver 17 for SQL Server"
  DATABASE_URL_OTHER: "mssql://SA:MyPassword42@localhost:1433/other?isolation_level=read committed&driver=ODBC Driver 17 for SQL Server"

jobs:
  linting:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1

      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: "3.8"

      - name: Install
        run: |
          python -m pip install --upgrade pip
          pip install flake8
      - name: Linting
        run: |
          flake8 --exclude testapp

  build:
    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest]
        tox_env:
          - "py36-django22"
          - "py36-django30"
          - "py36-django31"

          - "py37-django22"
          - "py37-django30"
          - "py37-django31"

          - "py38-django30"
          - "py38-django31"

        include:
          - python: "3.6"
            tox_env: "py36-django22"

          - python: "3.6"
            tox_env: "py36-django30"

          - python: "3.6"
            tox_env: "py36-django31"

          - python: "3.7"
            tox_env: "py37-django22"

          - python: "3.7"
            tox_env: "py37-django30"

          - python: "3.7"
            tox_env: "py37-django31"

          - python: "3.8"
            tox_env: "py38-django30"

          - python: "3.8"
            tox_env: "py38-django31"


    steps:
      - uses: actions/checkout@v2
      - uses: actions/checkout@v2
        with:
          repository: django/django
          path: django
      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: ${{ matrix.python }}

      - name: Install Linux deps
        if: matrix.os == 'ubuntu-latest'
        run: |
          curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
          curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list
          sudo apt-get update
          sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17 g++ unixodbc-dev libmemcached-dev

      - name: Install Windows deps
        if: matrix.os == 'windows-latest'
        run: |
            powershell wget https://download.microsoft.com/download/E/6/B/E6BFDC7A-5BCD-4C51-9912-635646DA801E/en-US/msodbcsql_17.3.1.1_x64.msi -OutFile msodbcsql_17.3.1.1_x64.msi
            powershell "Start-Process msiexec.exe -Wait -ArgumentList '/I msodbcsql_17.3.1.1_x64.msi /qn /norestart IACCEPTMSODBCSQLLICENSETERMS=YES'"

      - name: Install
        run: |
          python -m pip install --upgrade pip wheel setuptools
          pip install tox tox-venv

      - name: Test Linux
        if: matrix.os == 'ubuntu-latest'
        run: |
          docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=MyPassword42' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest-ubuntu
          tox -e ${{ matrix.tox_env }}

      - name: Test Windows
        if: matrix.os == 'windows-latest'
        run: |
          docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=MyPassword42' -p 1433:1433 -d christianacca/mssql-server-windows-express:1809
          tox -e ${{ matrix.tox_env }}


================================================
FILE: .gitignore
================================================
*.py[co]
*.sw[a-z]
*.orig
*~
.DS_Store
Thumbs.db

*.egg-info

tests/local_settings.py

# Virtual Env
/venv/
.idea/


================================================
FILE: .travis.yml
================================================
sudo: required
language: python
dist: xenial
cache: pip

branches:
  only:
    - master

env:
  global:
    - PYTHONPATH=$PYTHONPATH:$TRAVIS_BUILD_DIR/django
    - DATABASE_URL="mssql://SA:MyPassword42@localhost:1433/default?isolation_level=read committed&driver=ODBC Driver 17 for SQL Server"
    - DATABASE_URL_OTHER="mssql://SA:MyPassword42@localhost:1433/other?isolation_level=read committed&driver=ODBC Driver 17 for SQL Server"

services: docker

templates:
  linux_before_install: &linux_before_install
    - docker pull mcr.microsoft.com/mssql/server:2017-latest-ubuntu
    - docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=MyPassword42' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest-ubuntu
    - curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
    - curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list
    - sudo apt-get update
    - sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17 g++ unixodbc-dev

  win_before_install: &win_before_install
    - docker pull christianacca/mssql-server-windows-express:1803
    - docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=MyPassword42' -p 1433:1433 -d christianacca/mssql-server-windows-express:1803
    - wget https://download.microsoft.com/download/E/6/B/E6BFDC7A-5BCD-4C51-9912-635646DA801E/en-US/msodbcsql_17.3.1.1_x64.msi
    - powershell "Start-Process msiexec.exe -Wait -ArgumentList '/I msodbcsql_17.3.1.1_x64.msi /qn /norestart IACCEPTMSODBCSQLLICENSETERMS=YES'"
    - choco install python3 --version 3.7.2
    - export PATH="/c/Python37:/c/Python37/Scripts:$PATH"

matrix:
  include:
    - env: FLAKE8
      python: "3.7"
      install: pip install flake8==3.7.1
      script: flake8

    - { before_install: *linux_before_install, python: "3.6", os: linux, env: TOX_ENV=py36-django22 }
    - { before_install: *linux_before_install, python: "3.6", os: linux, env: TOX_ENV=py36-django30 }
    - { before_install: *linux_before_install, python: "3.6", os: linux, env: TOX_ENV=py36-django31 }

    - { before_install: *linux_before_install, python: "3.7", os: linux, env: TOX_ENV=py37-django22 }
    - { before_install: *linux_before_install, python: "3.7", os: linux, env: TOX_ENV=py37-django30 }
    - { before_install: *linux_before_install, python: "3.7", os: linux, env: TOX_ENV=py37-django31 }

    - { before_install: *linux_before_install, python: "3.8", os: linux, env: TOX_ENV=py38-django30 }
    - { before_install: *linux_before_install, python: "3.8", os: linux, env: TOX_ENV=py38-django31 }

    - { before_install: *win_before_install, language: sh, python: "3.6", os: windows, env: TOX_ENV=py36-django22 }
    - { before_install: *win_before_install, language: sh, python: "3.6", os: windows, env: TOX_ENV=py36-django30 }
    - { before_install: *win_before_install, language: sh, python: "3.6", os: windows, env: TOX_ENV=py36-django31 }

    - { before_install: *win_before_install, language: sh, python: "3.7", os: windows, env: TOX_ENV=py37-django22 }
    - { before_install: *win_before_install, language: sh, python: "3.7", os: windows, env: TOX_ENV=py37-django30 }
    - { before_install: *win_before_install, language: sh, python: "3.7", os: windows, env: TOX_ENV=py37-django31 }

    - { before_install: *win_before_install, language: sh, python: "3.8", os: windows, env: TOX_ENV=py38-django30 }
    - { before_install: *win_before_install, language: sh, python: "3.8", os: windows, env: TOX_ENV=py38-django31 }



install:
  - python -m pip install --upgrade pip wheel setuptools
  - pip install tox tox-travis tox-venv
  - git clone https://github.com/django/django.git

script:
  - tox -e $TOX_ENV


================================================
FILE: LICENSE
================================================
BSD 3-Clause License

Copyright (c) 2019, ES Solutions AB
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: MANIFEST.in
================================================
include LICENSE
include MANIFEST.in
include README.rst
recursive-include sql_server *.py
recursive-exclude docker *


================================================
FILE: README.rst
================================================
django-mssql-backend
====================

.. image:: https://img.shields.io/pypi/v/django-mssql-backend.svg
   :target: https://pypi.python.org/pypi/django-mssql-backend

*django-mssql-backend* is a fork of
`django-pyodbc-azure <https://pypi.org/project/django-pyodbc-azure/>`__

Features
--------

-  Supports Django 2.2, 3.0
-  Supports Microsoft SQL Server 2008/2008R2, 2012, 2014, 2016, 2017, 2019
-  Passes most of the tests of the Django test suite
-  Compatible with
   `Micosoft ODBC Driver for SQL Server <https://docs.microsoft.com/en-us/sql/connect/odbc/microsoft-odbc-driver-for-sql-server>`__,
   `SQL Server Native Client <https://msdn.microsoft.com/en-us/library/ms131321(v=sql.120).aspx>`__,
   and `FreeTDS <http://www.freetds.org/>`__ ODBC drivers

Dependencies
------------

-  Django 2.2 or newer
-  pyodbc 3.0 or newer

Installation
------------

1. Install pyodbc and Django

2. Install django-mssql-backend ::

    pip install django-mssql-backend

3. Now you can point the ``ENGINE`` setting in the settings file used by
   your Django application or project to the ``'sql_server.pyodbc'``
   module path ::

    'ENGINE': 'sql_server.pyodbc'

Regex Support
-------------

django-mssql-backend supports regex using a CLR .dll file. To install it, run ::

    python manage.py install_regex_clr {database_name}

Configuration
-------------

Standard Django settings
~~~~~~~~~~~~~~~~~~~~~~~~

The following entries in a database-level settings dictionary
in DATABASES control the behavior of the backend:

-  ENGINE

   String. It must be ``"sql_server.pyodbc"``.

-  NAME

   String. Database name. Required.

-  HOST

   String. SQL Server instance in ``"server\instance"`` format.

-  PORT

   String. Server instance port.
   An empty string means the default port.

-  USER

   String. Database user name in ``"user"`` format.
   If not given then MS Integrated Security will be used.

-  PASSWORD

   String. Database user password.

-  AUTOCOMMIT

   Boolean. Set this to False if you want to disable
   Django's transaction management and implement your own.

and the following entries are also available in the TEST dictionary
for any given database-level settings dictionary:

-  NAME

   String. The name of database to use when running the test suite.
   If the default value (``None``) is used, the test database will use
   the name "test\_" + ``NAME``.

-  COLLATION

   String. The collation order to use when creating the test database.
   If the default value (``None``) is used, the test database is assigned
   the default collation of the instance of SQL Server.

-  DEPENDENCIES

   String. The creation-order dependencies of the database.
   See the official Django documentation for more details.

-  MIRROR

   String. The alias of the database that this database should
   mirror during testing. Default value is ``None``.
   See the official Django documentation for more details.

OPTIONS
~~~~~~~

Dictionary. Current available keys are:

-  driver

   String. ODBC Driver to use (``"ODBC Driver 13 for SQL Server"``,
   ``"SQL Server Native Client 11.0"``, ``"FreeTDS"`` etc).
   Default is ``"ODBC Driver 13 for SQL Server"``.

-  isolation_level

   String. Sets `transaction isolation level
   <https://docs.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql>`__
   for each database session. Valid values for this entry are
   ``READ UNCOMMITTED``, ``READ COMMITTED``, ``REPEATABLE READ``,
   ``SNAPSHOT``, and ``SERIALIZABLE``. Default is ``None`` which means
   no isolation levei is set to a database session and SQL Server default
   will be used.

-  dsn

   String. A named DSN can be used instead of ``HOST``.

-  host_is_server

   Boolean. Only relevant if using the FreeTDS ODBC driver under
   Unix/Linux.

   By default, when using the FreeTDS ODBC driver the value specified in
   the ``HOST`` setting is used in a ``SERVERNAME`` ODBC connection
   string component instead of being used in a ``SERVER`` component;
   this means that this value should be the name of a *dataserver*
   definition present in the ``freetds.conf`` FreeTDS configuration file
   instead of a hostname or an IP address.

   But if this option is present and its value is ``True``, this
   special behavior is turned off. Instead, connections to the database
   server will be established using ``HOST`` and ``PORT`` options, without
   requiring ``freetds.conf`` to be configured.

   See https://www.freetds.org/userguide/dsnless.html for more information.

-  unicode_results

   Boolean. If it is set to ``True``, pyodbc's *unicode_results* feature
   is activated and strings returned from pyodbc are always Unicode.
   Default value is ``False``.

-  extra_params

   String. Additional parameters for the ODBC connection. The format is
   ``"param=value;param=value"``.

-  collation

   String. Name of the collation to use when performing text field
   lookups against the database. Default is ``None``; this means no
   collation specifier is added to your lookup SQL (the default
   collation of your database will be used). For Chinese language you
   can set it to ``"Chinese_PRC_CI_AS"``.

-  connection_timeout

   Integer. Sets the timeout in seconds for the database connection process.
   Default value is ``0`` which disables the timeout.

-  connection_retries

   Integer. Sets the times to retry the database connection process.
   Default value is ``5``.

-  connection_retry_backoff_time

   Integer. Sets the back off time in seconds for reries of
   the database connection process. Default value is ``5``.

-  query_timeout

   Integer. Sets the timeout in seconds for the database query.
   Default value is ``0`` which disables the timeout.

backend-specific settings
~~~~~~~~~~~~~~~~~~~~~~~~~

The following project-level settings also control the behavior of the backend:

-  DATABASE_CONNECTION_POOLING

   Boolean. If it is set to ``False``, pyodbc's connection pooling feature
   won't be activated.

Example
~~~~~~~

Here is an example of the database settings:

::

    DATABASES = {
        'default': {
            'ENGINE': 'sql_server.pyodbc',
            'NAME': 'mydb',
            'USER': 'user@myserver',
            'PASSWORD': 'password',
            'HOST': 'myserver.database.windows.net',
            'PORT': '',

            'OPTIONS': {
                'driver': 'ODBC Driver 13 for SQL Server',
            },
        },
    }

    # set this to False if you want to turn off pyodbc's connection pooling
    DATABASE_CONNECTION_POOLING = False

Limitations
-----------

The following features are currently not supported:

- Altering a model field from or to AutoField at migration


================================================
FILE: docker/Dockerfile
================================================
FROM python:3.7

ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn

RUN apt-get update && apt-get install -y apt-transport-https git

RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/debian/9/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update
RUN ACCEPT_EULA=Y apt-get install -y msodbcsql17 g++ unixodbc-dev

ADD . /code
WORKDIR /code
RUN pip install -e .["tests"]

ENV PYTHONPATH=$PYTHONPATH:/code

RUN git clone --branch=stable/2.2.x https://github.com/django/django.git "/code/django" --depth=1

RUN pip install -r /code/django/tests/requirements/py3.txt


================================================
FILE: docker/docker-compose.yml
================================================
version: "3.3"

services:
  app:
    build:
      context: ..
      dockerfile: docker/Dockerfile
    volumes:
      - ..:/code
    environment:
      DATABASE_URL: "mssql://SA:MyPassword42@db:1433/default?isolation_level=read committed&driver=ODBC Driver 17 for SQL Server"
      DATABASE_URL_OTHER: "mssql://SA:MyPassword42@db:1433/other?isolation_level=read committed&driver=ODBC Driver 17 for SQL Server"
    depends_on:
      - db

  db:
    image: "mcr.microsoft.com/mssql/server:2017-latest-ubuntu"
    environment:
      ACCEPT_EULA: Y
      SA_PASSWORD: MyPassword42
    ports:
      - 1433:1433


================================================
FILE: manage.py
================================================
#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testapp.settings")

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)


================================================
FILE: setup.cfg
================================================
[flake8]
exclude = .git,__pycache__,migrations
# W504 is mutually exclusive with W503
ignore = W504
max-line-length = 119


================================================
FILE: setup.py
================================================
from setuptools import find_packages, setup

CLASSIFIERS = [
    'License :: OSI Approved :: BSD License',
    'Framework :: Django',
    "Operating System :: POSIX :: Linux",
    "Operating System :: Microsoft :: Windows",
    'Programming Language :: Python',
    'Programming Language :: Python :: 3',
    'Programming Language :: Python :: 3.5',
    'Programming Language :: Python :: 3.6',
    'Programming Language :: Python :: 3.7',
    'Framework :: Django :: 2.2',
    'Framework :: Django :: 3.0',
]

setup(
    name='django-mssql-backend',
    version='2.8.1',
    description='Django backend for Microsoft SQL Server',
    long_description=open('README.rst').read(),
    author='ES Solutions AB',
    author_email='info@essolutions.se',
    url='https://github.com/ESSolutions/django-mssql-backend',
    license='BSD',
    packages=find_packages(),
    install_requires=[
        'pyodbc>=3.0',
    ],
    package_data={'sql_server.pyodbc': ['regex_clr.dll']},
    classifiers=CLASSIFIERS,
    keywords='django',
)


================================================
FILE: sql_server/__init__.py
================================================


================================================
FILE: sql_server/pyodbc/__init__.py
================================================
import sql_server.pyodbc.functions  # noqa


================================================
FILE: sql_server/pyodbc/base.py
================================================
"""
MS SQL Server database backend for Django.
"""
import os
import re
import time

from django.core.exceptions import ImproperlyConfigured

try:
    import pyodbc as Database
except ImportError as e:
    raise ImproperlyConfigured("Error loading pyodbc module: %s" % e)

from django.utils.version import get_version_tuple  # noqa

pyodbc_ver = get_version_tuple(Database.version)
if pyodbc_ver < (3, 0):
    raise ImproperlyConfigured("pyodbc 3.0 or newer is required; you have %s" % Database.version)

from django.conf import settings  # noqa
from django.db import NotSupportedError  # noqa
from django.db.backends.base.base import BaseDatabaseWrapper  # noqa
from django.utils.encoding import smart_str  # noqa
from django.utils.functional import cached_property  # noqa

if hasattr(settings, 'DATABASE_CONNECTION_POOLING'):
    if not settings.DATABASE_CONNECTION_POOLING:
        Database.pooling = False

from .client import DatabaseClient  # noqa
from .creation import DatabaseCreation  # noqa
from .features import DatabaseFeatures  # noqa
from .introspection import DatabaseIntrospection  # noqa
from .operations import DatabaseOperations  # noqa
from .schema import DatabaseSchemaEditor  # noqa

EDITION_AZURE_SQL_DB = 5


def encode_connection_string(fields):
    """Encode dictionary of keys and values as an ODBC connection String.

    See [MS-ODBCSTR] document:
    https://msdn.microsoft.com/en-us/library/ee208909%28v=sql.105%29.aspx
    """
    # As the keys are all provided by us, don't need to encode them as we know
    # they are ok.
    return ';'.join(
        '%s=%s' % (k, encode_value(v))
        for k, v in fields.items()
    )


def encode_value(v):
    """If the value contains a semicolon, or starts with a left curly brace,
    then enclose it in curly braces and escape all right curly braces.
    """
    if ';' in v or v.strip(' ').startswith('{'):
        return '{%s}' % (v.replace('}', '}}'),)
    return v


class DatabaseWrapper(BaseDatabaseWrapper):
    vendor = 'microsoft'
    display_name = 'SQL Server'
    # This dictionary maps Field objects to their associated MS SQL column
    # types, as strings. Column-type strings can contain format strings; they'll
    # be interpolated against the values of Field.__dict__ before being output.
    # If a column type is set to None, it won't be included in the output.
    data_types = {
        'AutoField': 'int IDENTITY (1, 1)',
        'BigAutoField': 'bigint IDENTITY (1, 1)',
        '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)',
        'NullBooleanField': 'bit',
        'OneToOneField': 'int',
        'PositiveIntegerField': 'int',
        'PositiveSmallIntegerField': 'smallint',
        'PositiveBigIntegerField': 'bigint',
        'SlugField': 'nvarchar(%(max_length)s)',
        'SmallAutoField': 'smallint IDENTITY (1, 1)',
        'SmallIntegerField': 'smallint',
        'TextField': 'nvarchar(max)',
        'TimeField': 'time',
        'UUIDField': 'char(32)',
        'JSONField': 'nvarchar(max)',
    }
    data_type_check_constraints = {
        'PositiveIntegerField': '[%(column)s] >= 0',
        'PositiveSmallIntegerField': '[%(column)s] >= 0',
    }
    operators = {
        # Since '=' is used not only for string comparision there is no way
        # to make it case (in)sensitive.
        'exact': '= %s',
        'iexact': "= UPPER(%s)",
        'contains': "LIKE %s ESCAPE '\\'",
        'icontains': "LIKE UPPER(%s) ESCAPE '\\'",
        'gt': '> %s',
        'gte': '>= %s',
        'lt': '< %s',
        'lte': '<= %s',
        'startswith': "LIKE %s ESCAPE '\\'",
        'endswith': "LIKE %s ESCAPE '\\'",
        'istartswith': "LIKE UPPER(%s) ESCAPE '\\'",
        'iendswith': "LIKE UPPER(%s) ESCAPE '\\'",
    }

    # The patterns below are used to generate SQL pattern lookup clauses when
    # the right-hand side of the lookup isn't a raw string (it might be an expression
    # or the result of a bilateral transformation).
    # In those cases, special characters for LIKE operators (e.g. \, *, _) should be
    # escaped on database side.
    #
    # Note: we use str.format() here for readability as '%' is used as a wildcard for
    # the LIKE operator.
    pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '[\]'), '%%', '[%%]'), '_', '[_]')"
    pattern_ops = {
        'contains': "LIKE '%%' + {} + '%%'",
        'icontains': "LIKE '%%' + UPPER({}) + '%%'",
        'startswith': "LIKE {} + '%%'",
        'istartswith': "LIKE UPPER({}) + '%%'",
        'endswith': "LIKE '%%' + {}",
        'iendswith': "LIKE '%%' + UPPER({})",
    }

    Database = Database
    SchemaEditorClass = DatabaseSchemaEditor
    # Classes instantiated in __init__().
    client_class = DatabaseClient
    creation_class = DatabaseCreation
    features_class = DatabaseFeatures
    introspection_class = DatabaseIntrospection
    ops_class = DatabaseOperations

    _codes_for_networkerror = (
        '08S01',
        '08S02',
    )
    _sql_server_versions = {
        9: 2005,
        10: 2008,
        11: 2012,
        12: 2014,
        13: 2016,
        14: 2017,
        15: 2019,
    }

    # https://azure.microsoft.com/en-us/documentation/articles/sql-database-develop-csharp-retry-windows/
    _transient_error_numbers = (
        '4060',
        '10928',
        '10929',
        '40197',
        '40501',
        '40613',
        '49918',
        '49919',
        '49920',
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        opts = self.settings_dict["OPTIONS"]

        # capability for multiple result sets or cursors
        self.supports_mars = False

        # Some drivers need unicode encoded as UTF8. If this is left as
        # None, it will be determined based on the driver, namely it'll be
        # False if the driver is a windows driver and True otherwise.
        #
        # However, recent versions of FreeTDS and pyodbc (0.91 and 3.0.6 as
        # of writing) are perfectly okay being fed unicode, which is why
        # this option is configurable.
        if 'driver_needs_utf8' in opts:
            self.driver_charset = 'utf-8'
        else:
            self.driver_charset = opts.get('driver_charset', None)

        # interval to wait for recovery from network error
        interval = opts.get('connection_recovery_interval_msec', 0.0)
        self.connection_recovery_interval_msec = float(interval) / 1000

        # make lookup operators to be collation-sensitive if needed
        collation = opts.get('collation', None)
        if collation:
            self.operators = dict(self.__class__.operators)
            ops = {}
            for op in self.operators:
                sql = self.operators[op]
                if sql.startswith('LIKE '):
                    ops[op] = '%s COLLATE %s' % (sql, collation)
            self.operators.update(ops)

    def create_cursor(self, name=None):
        return CursorWrapper(self.connection.cursor(), self)

    def _cursor(self):
        new_conn = False

        if self.connection is None:
            new_conn = True

        conn = super()._cursor()
        if new_conn:
            if self.sql_server_version <= 2005:
                self.data_types['DateField'] = 'datetime'
                self.data_types['DateTimeField'] = 'datetime'
                self.data_types['TimeField'] = 'datetime'

        return conn

    def get_connection_params(self):
        settings_dict = self.settings_dict
        if settings_dict['NAME'] == '':
            raise ImproperlyConfigured(
                "settings.DATABASES is improperly configured. "
                "Please supply the NAME value.")
        conn_params = settings_dict.copy()
        if conn_params['NAME'] is None:
            conn_params['NAME'] = 'master'
        return conn_params

    def get_new_connection(self, conn_params):
        database = conn_params['NAME']
        host = conn_params.get('HOST', 'localhost')
        user = conn_params.get('USER', None)
        password = conn_params.get('PASSWORD', None)
        port = conn_params.get('PORT', None)

        options = conn_params.get('OPTIONS', {})
        driver = options.get('driver', 'ODBC Driver 13 for SQL Server')
        dsn = options.get('dsn', None)

        # Microsoft driver names assumed here are:
        # * SQL Server Native Client 10.0/11.0
        # * ODBC Driver 11/13 for SQL Server
        ms_drivers = re.compile('^ODBC Driver .* for SQL Server$|^SQL Server Native Client')

        # available ODBC connection string keywords:
        # (Microsoft drivers for Windows)
        # https://docs.microsoft.com/en-us/sql/relational-databases/native-client/applications/using-connection-string-keywords-with-sql-server-native-client
        # (Microsoft drivers for Linux/Mac)
        # https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/connection-string-keywords-and-data-source-names-dsns
        # (FreeTDS)
        # http://www.freetds.org/userguide/odbcconnattr.htm
        cstr_parts = {}
        if dsn:
            cstr_parts['DSN'] = dsn
        else:
            # Only append DRIVER if DATABASE_ODBC_DSN hasn't been set
            cstr_parts['DRIVER'] = driver

            if ms_drivers.match(driver):
                if port:
                    host = ','.join((host, str(port)))
                cstr_parts['SERVER'] = host
            elif options.get('host_is_server', False):
                if port:
                    cstr_parts['PORT'] = str(port)
                cstr_parts['SERVER'] = host
            else:
                cstr_parts['SERVERNAME'] = host

        if user:
            cstr_parts['UID'] = user
            cstr_parts['PWD'] = password
        else:
            if ms_drivers.match(driver):
                cstr_parts['Trusted_Connection'] = 'yes'
            else:
                cstr_parts['Integrated Security'] = 'SSPI'

        cstr_parts['DATABASE'] = database

        if ms_drivers.match(driver) and os.name == 'nt':
            cstr_parts['MARS_Connection'] = 'yes'

        connstr = encode_connection_string(cstr_parts)

        # extra_params are glued on the end of the string without encoding,
        # so it's up to the settings writer to make sure they're appropriate -
        # use encode_connection_string if constructing from external input.
        if options.get('extra_params', None):
            connstr += ';' + options['extra_params']

        unicode_results = options.get('unicode_results', False)
        timeout = options.get('connection_timeout', 0)
        retries = options.get('connection_retries', 5)
        backoff_time = options.get('connection_retry_backoff_time', 5)
        query_timeout = options.get('query_timeout', 0)

        conn = None
        retry_count = 0
        need_to_retry = False
        while conn is None:
            try:
                conn = Database.connect(connstr,
                                        unicode_results=unicode_results,
                                        timeout=timeout)
            except Exception as e:
                for error_number in self._transient_error_numbers:
                    if error_number in e.args[1]:
                        if error_number in e.args[1] and retry_count < retries:
                            time.sleep(backoff_time)
                            need_to_retry = True
                            retry_count = retry_count + 1
                        else:
                            need_to_retry = False
                        break
                if not need_to_retry:
                    raise

        conn.timeout = query_timeout
        return conn

    def init_connection_state(self):
        drv_name = self.connection.getinfo(Database.SQL_DRIVER_NAME).upper()

        if drv_name.startswith('LIBTDSODBC'):
            try:
                drv_ver = self.connection.getinfo(Database.SQL_DRIVER_VER)
                ver = get_version_tuple(drv_ver)[:2]
                if ver < (0, 95):
                    raise ImproperlyConfigured(
                        "FreeTDS 0.95 or newer is required.")
            except Exception:
                # unknown driver version
                pass

        ms_drv_names = re.compile('^(LIB)?(SQLNCLI|MSODBCSQL)')

        if ms_drv_names.match(drv_name):
            self.driver_charset = None
            # http://msdn.microsoft.com/en-us/library/ms131686.aspx
            self.supports_mars = True
            self.features.can_use_chunked_reads = True

        settings_dict = self.settings_dict
        cursor = self.create_cursor()

        options = settings_dict.get('OPTIONS', {})
        isolation_level = options.get('isolation_level', None)
        if isolation_level:
            cursor.execute('SET TRANSACTION ISOLATION LEVEL %s' % isolation_level)

        # Set date format for the connection. Also, make sure Sunday is
        # considered the first day of the week (to be consistent with the
        # Django convention for the 'week_day' Django lookup) if the user
        # hasn't told us otherwise
        datefirst = options.get('datefirst', 7)
        cursor.execute('SET DATEFORMAT ymd; SET DATEFIRST %s' % datefirst)

        val = self.get_system_datetime()
        if isinstance(val, str):
            raise ImproperlyConfigured(
                "The database driver doesn't support modern datatime types.")

    def is_usable(self):
        try:
            self.create_cursor().execute("SELECT 1")
        except Database.Error:
            return False
        else:
            return True

    def get_system_datetime(self):
        # http://blogs.msdn.com/b/sqlnativeclient/archive/2008/02/27/microsoft-sql-server-native-client-and-microsoft-sql-server-2008-native-client.aspx
        with self.temporary_connection() as cursor:
            if self.sql_server_version <= 2005:
                return cursor.execute('SELECT GETDATE()').fetchone()[0]
            else:
                return cursor.execute('SELECT SYSDATETIME()').fetchone()[0]

    @cached_property
    def sql_server_version(self, _known_versions={}):
        """
        Get the SQL server version

        The _known_versions default dictionary is created on the class. This is
        intentional - it allows us to cache this property's value across instances.
        Therefore, when Django creates a new database connection using the same
        alias, we won't need query the server again.
        """
        if self.alias not in _known_versions:
            with self.temporary_connection() as cursor:
                cursor.execute("SELECT CAST(SERVERPROPERTY('ProductVersion') AS varchar)")
                ver = cursor.fetchone()[0]
                ver = int(ver.split('.')[0])
                if ver not in self._sql_server_versions:
                    raise NotSupportedError('SQL Server v%d is not supported.' % ver)
                _known_versions[self.alias] = self._sql_server_versions[ver]
        return _known_versions[self.alias]

    @cached_property
    def to_azure_sql_db(self, _known_azures={}):
        """
        Whether this connection is to a Microsoft Azure database server

        The _known_azures default dictionary is created on the class. This is
        intentional - it allows us to cache this property's value across instances.
        Therefore, when Django creates a new database connection using the same
        alias, we won't need query the server again.
        """
        if self.alias not in _known_azures:
            with self.temporary_connection() as cursor:
                cursor.execute("SELECT CAST(SERVERPROPERTY('EngineEdition') AS integer)")
                _known_azures[self.alias] = cursor.fetchone()[0] == EDITION_AZURE_SQL_DB
        return _known_azures[self.alias]

    def _execute_foreach(self, sql, table_names=None):
        cursor = self.cursor()
        if table_names is None:
            table_names = self.introspection.table_names(cursor)
        for table_name in table_names:
            cursor.execute(sql % self.ops.quote_name(table_name))

    def _get_trancount(self):
        with self.connection.cursor() as cursor:
            return cursor.execute('SELECT @@TRANCOUNT').fetchone()[0]

    def _on_error(self, e):
        if e.args[0] in self._codes_for_networkerror:
            try:
                # close the stale connection
                self.close()
                # wait a moment for recovery from network error
                time.sleep(self.connection_recovery_interval_msec)
            except Exception:
                pass
            self.connection = None

    def _savepoint(self, sid):
        with self.cursor() as cursor:
            cursor.execute('SELECT @@TRANCOUNT')
            trancount = cursor.fetchone()[0]
            if trancount == 0:
                cursor.execute(self.ops.start_transaction_sql())
            cursor.execute(self.ops.savepoint_create_sql(sid))

    def _savepoint_commit(self, sid):
        # SQL Server has no support for partial commit in a transaction
        pass

    def _savepoint_rollback(self, sid):
        with self.cursor() as cursor:
            # FreeTDS requires TRANCOUNT that is greater than 0
            cursor.execute('SELECT @@TRANCOUNT')
            trancount = cursor.fetchone()[0]
            if trancount > 0:
                cursor.execute(self.ops.savepoint_rollback_sql(sid))

    def _set_autocommit(self, autocommit):
        with self.wrap_database_errors:
            allowed = not autocommit
            if not allowed:
                # FreeTDS requires TRANCOUNT that is greater than 0
                allowed = self._get_trancount() > 0
            if allowed:
                self.connection.autocommit = autocommit

    def check_constraints(self, table_names=None):
        self._execute_foreach('ALTER TABLE %s WITH CHECK CHECK CONSTRAINT ALL',
                              table_names)

    def disable_constraint_checking(self):
        if not self.needs_rollback:
            self.cursor().execute('EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL"')
        return not self.needs_rollback

    def enable_constraint_checking(self):
        if not self.needs_rollback:
            self.cursor().execute('EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL"')


class CursorWrapper(object):
    """
    A wrapper around the pyodbc's cursor that takes in account a) some pyodbc
    DB-API 2.0 implementation and b) some common ODBC driver particularities.
    """

    def __init__(self, cursor, connection):
        self.active = True
        self.cursor = cursor
        self.connection = connection
        self.driver_charset = connection.driver_charset
        self.last_sql = ''
        self.last_params = ()

    def close(self):
        if self.active:
            self.active = False
            self.cursor.close()

    def format_sql(self, sql, params):
        if self.driver_charset and isinstance(sql, str):
            # FreeTDS (and other ODBC drivers?) doesn't support Unicode
            # yet, so we need to encode the SQL clause itself in utf-8
            sql = smart_str(sql, self.driver_charset)

        # pyodbc uses '?' instead of '%s' as parameter placeholder.
        if params is not None:
            sql = sql % tuple('?' * len(params))

        return sql

    def format_params(self, params):
        fp = []
        if params is not None:
            for p in params:
                if isinstance(p, str):
                    if self.driver_charset:
                        # FreeTDS (and other ODBC drivers?) doesn't support Unicode
                        # yet, so we need to encode parameters in utf-8
                        fp.append(smart_str(p, self.driver_charset))
                    else:
                        fp.append(p)

                elif isinstance(p, bytes):
                    fp.append(p)

                elif isinstance(p, type(True)):
                    if p:
                        fp.append(1)
                    else:
                        fp.append(0)

                else:
                    fp.append(p)

        return tuple(fp)

    def execute(self, sql, params=None):
        self.last_sql = sql
        sql = self.format_sql(sql, params)
        params = self.format_params(params)
        self.last_params = params
        try:
            return self.cursor.execute(sql, params)
        except Database.Error as e:
            self.connection._on_error(e)
            raise

    def executemany(self, sql, params_list=()):
        if not params_list:
            return None
        raw_pll = [p for p in params_list]
        sql = self.format_sql(sql, raw_pll[0])
        params_list = [self.format_params(p) for p in raw_pll]
        try:
            return self.cursor.executemany(sql, params_list)
        except Database.Error as e:
            self.connection._on_error(e)
            raise

    def format_rows(self, rows):
        return list(map(self.format_row, rows))

    def format_row(self, row):
        """
        Decode data coming from the database if needed and convert rows to tuples
        (pyodbc Rows are not hashable).
        """
        if self.driver_charset:
            for i in range(len(row)):
                f = row[i]
                # FreeTDS (and other ODBC drivers?) doesn't support Unicode
                # yet, so we need to decode utf-8 data coming from the DB
                if isinstance(f, bytes):
                    row[i] = f.decode(self.driver_charset)
        return tuple(row)

    def fetchone(self):
        row = self.cursor.fetchone()
        if row is not None:
            row = self.format_row(row)
        # Any remaining rows in the current set must be discarded
        # before changing autocommit mode when you use FreeTDS
        if not self.connection.supports_mars:
            self.cursor.nextset()
        return row

    def fetchmany(self, chunk):
        return self.format_rows(self.cursor.fetchmany(chunk))

    def fetchall(self):
        return self.format_rows(self.cursor.fetchall())

    def __getattr__(self, attr):
        if attr in self.__dict__:
            return self.__dict__[attr]
        return getattr(self.cursor, attr)

    def __iter__(self):
        return iter(self.cursor)


================================================
FILE: sql_server/pyodbc/client.py
================================================
import re
import subprocess

from django.db.backends.base.client import BaseDatabaseClient


class DatabaseClient(BaseDatabaseClient):
    executable_name = 'sqlcmd'

    def runshell(self):
        settings_dict = self.connection.settings_dict
        options = settings_dict['OPTIONS']
        user = options.get('user', settings_dict['USER'])
        password = options.get('passwd', settings_dict['PASSWORD'])

        driver = options.get('driver', 'ODBC Driver 13 for SQL Server')
        ms_drivers = re.compile('^ODBC Driver .* for SQL Server$|^SQL Server Native Client')
        if not ms_drivers.match(driver):
            self.executable_name = 'isql'

        if self.executable_name == 'sqlcmd':
            db = options.get('db', settings_dict['NAME'])
            server = options.get('host', settings_dict['HOST'])
            port = options.get('port', settings_dict['PORT'])
            defaults_file = options.get('read_default_file')

            args = [self.executable_name]
            if server:
                if port:
                    server = ','.join((server, str(port)))
                args += ["-S", server]
            if user:
                args += ["-U", user]
                if password:
                    args += ["-P", password]
            else:
                args += ["-E"]  # Try trusted connection instead
            if db:
                args += ["-d", db]
            if defaults_file:
                args += ["-i", defaults_file]
        else:
            dsn = options.get('dsn', '')
            args = ['%s -v %s %s %s' % (self.executable_name, dsn, user, password)]

        try:
            subprocess.check_call(args)
        except KeyboardInterrupt:
            pass


================================================
FILE: sql_server/pyodbc/compiler.py
================================================
import types
from itertools import chain

import django
from django.db.models.aggregates import Avg, Count, StdDev, Variance
from django.db.models.expressions import Ref, Subquery, Value
from django.db.models.functions import (
    Chr, ConcatPair, Greatest, Least, Length, LPad, Repeat, RPad, StrIndex, Substr, Trim
)
from django.db.models.sql import compiler
from django.db.transaction import TransactionManagementError
from django.db.utils import NotSupportedError


def _as_sql_agv(self, compiler, connection):
    return self.as_sql(compiler, connection, template='%(function)s(CONVERT(float, %(field)s))')


def _as_sql_chr(self, compiler, connection):
    return self.as_sql(compiler, connection, function='NCHAR')


def _as_sql_concatpair(self, compiler, connection):
    if connection.sql_server_version < 2012:
        node = self.coalesce()
        return node.as_sql(compiler, connection, arg_joiner=' + ', template='%(expressions)s')
    else:
        return self.as_sql(compiler, connection)


def _as_sql_count(self, compiler, connection):
    return self.as_sql(compiler, connection, function='COUNT_BIG')


def _as_sql_greatest(self, compiler, connection):
    # SQL Server does not provide GREATEST function,
    # so we emulate it with a table value constructor
    # https://msdn.microsoft.com/en-us/library/dd776382.aspx
    template = '(SELECT MAX(value) FROM (VALUES (%(expressions)s)) AS _%(function)s(value))'
    return self.as_sql(compiler, connection, arg_joiner='), (', template=template)


def _as_sql_least(self, compiler, connection):
    # SQL Server does not provide LEAST function,
    # so we emulate it with a table value constructor
    # https://msdn.microsoft.com/en-us/library/dd776382.aspx
    template = '(SELECT MIN(value) FROM (VALUES (%(expressions)s)) AS _%(function)s(value))'
    return self.as_sql(compiler, connection, arg_joiner='), (', template=template)


def _as_sql_length(self, compiler, connection):
    return self.as_sql(compiler, connection, function='LEN')


def _as_sql_lpad(self, compiler, connection):
    i = iter(self.get_source_expressions())
    expression, expression_arg = compiler.compile(next(i))
    length, length_arg = compiler.compile(next(i))
    fill_text, fill_text_arg = compiler.compile(next(i))
    params = []
    params.extend(fill_text_arg)
    params.extend(length_arg)
    params.extend(length_arg)
    params.extend(expression_arg)
    params.extend(length_arg)
    params.extend(expression_arg)
    params.extend(expression_arg)
    template = ('LEFT(REPLICATE(%(fill_text)s, %(length)s), CASE WHEN %(length)s > LEN(%(expression)s) '
                'THEN %(length)s - LEN(%(expression)s) ELSE 0 END) + %(expression)s')
    return template % {'expression': expression, 'length': length, 'fill_text': fill_text}, params


def _as_sql_repeat(self, compiler, connection):
    return self.as_sql(compiler, connection, function='REPLICATE')


def _as_sql_rpad(self, compiler, connection):
    i = iter(self.get_source_expressions())
    expression, expression_arg = compiler.compile(next(i))
    length, length_arg = compiler.compile(next(i))
    fill_text, fill_text_arg = compiler.compile(next(i))
    params = []
    params.extend(expression_arg)
    params.extend(fill_text_arg)
    params.extend(length_arg)
    params.extend(length_arg)
    template = 'LEFT(%(expression)s + REPLICATE(%(fill_text)s, %(length)s), %(length)s)'
    return template % {'expression': expression, 'length': length, 'fill_text': fill_text}, params


def _as_sql_stddev(self, compiler, connection):
    function = 'STDEV'
    if self.function == 'STDDEV_POP':
        function = '%sP' % function
    return self.as_sql(compiler, connection, function=function)


def _as_sql_strindex(self, compiler, connection):
    self.source_expressions.reverse()
    sql = self.as_sql(compiler, connection, function='CHARINDEX')
    self.source_expressions.reverse()
    return sql


def _as_sql_substr(self, compiler, connection):
    if len(self.get_source_expressions()) < 3:
        self.get_source_expressions().append(Value(2**31 - 1))
    return self.as_sql(compiler, connection)


def _as_sql_trim(self, compiler, connection):
    return self.as_sql(compiler, connection, template='LTRIM(RTRIM(%(expressions)s))')


def _as_sql_variance(self, compiler, connection):
    function = 'VAR'
    if self.function == 'VAR_POP':
        function = '%sP' % function
    return self.as_sql(compiler, connection, function=function)


def _cursor_iter(cursor, sentinel, col_count, itersize):
    """
    Yields blocks of rows from a cursor and ensures the cursor is closed when
    done.
    """
    if not hasattr(cursor.db, 'supports_mars') or cursor.db.supports_mars:
        # same as the original Django implementation
        try:
            for rows in iter((lambda: cursor.fetchmany(itersize)), sentinel):
                yield rows if col_count is None else [r[:col_count] for r in rows]
        finally:
            cursor.close()
    else:
        # retrieve all chunks from the cursor and close it before yielding
        # so that we can open an another cursor over an iteration
        # (for drivers such as FreeTDS)
        chunks = []
        try:
            for rows in iter((lambda: cursor.fetchmany(itersize)), sentinel):
                chunks.append(rows if col_count is None else [r[:col_count] for r in rows])
        finally:
            cursor.close()
        for rows in chunks:
            yield rows


compiler.cursor_iter = _cursor_iter


class SQLCompiler(compiler.SQLCompiler):

    def as_sql(self, with_limits=True, with_col_aliases=False):
        """
        Create the SQL for this query. Return the SQL string and list of
        parameters.

        If 'with_limits' is False, any limit/offset information is not included
        in the query.
        """
        refcounts_before = self.query.alias_refcount.copy()
        try:
            extra_select, order_by, group_by = self.pre_sql_setup()
            for_update_part = None
            # Is a LIMIT/OFFSET clause needed?
            with_limit_offset = with_limits and (self.query.high_mark is not None or self.query.low_mark)
            combinator = self.query.combinator
            features = self.connection.features

            # The do_offset flag indicates whether we need to construct
            # the SQL needed to use limit/offset w/SQL Server.
            high_mark = self.query.high_mark
            low_mark = self.query.low_mark
            do_limit = with_limits and high_mark is not None
            do_offset = with_limits and low_mark != 0
            # SQL Server 2012 or newer supports OFFSET/FETCH clause
            supports_offset_clause = self.connection.sql_server_version >= 2012
            do_offset_emulation = do_offset and not supports_offset_clause

            if combinator:
                if not getattr(features, 'supports_select_{}'.format(combinator)):
                    raise NotSupportedError('{} is not supported on this database backend.'.format(combinator))
                result, params = self.get_combinator_sql(combinator, self.query.combinator_all)
            else:
                distinct_fields, distinct_params = self.get_distinct()
                # This must come after 'select', 'ordering', and 'distinct' -- see
                # docstring of get_from_clause() for details.
                from_, f_params = self.get_from_clause()
                where, w_params = self.compile(self.where) if self.where is not None else ("", [])
                having, h_params = self.compile(self.having) if self.having is not None else ("", [])
                params = []
                result = ['SELECT']

                if self.query.distinct:
                    distinct_result, distinct_params = self.connection.ops.distinct_sql(
                        distinct_fields,
                        distinct_params,
                    )
                    result += distinct_result
                    params += distinct_params

                # SQL Server requires the keword for limitting at the begenning
                if do_limit and not do_offset:
                    result.append('TOP %d' % high_mark)

                out_cols = []
                col_idx = 1
                for _, (s_sql, s_params), alias in self.select + extra_select:
                    if alias:
                        s_sql = '%s AS %s' % (s_sql, self.connection.ops.quote_name(alias))
                    elif with_col_aliases or do_offset_emulation:
                        s_sql = '%s AS %s' % (s_sql, 'Col%d' % col_idx)
                        col_idx += 1
                    params.extend(s_params)
                    out_cols.append(s_sql)

                # SQL Server requires an order-by clause for offsetting
                if do_offset:
                    meta = self.query.get_meta()
                    qn = self.quote_name_unless_alias
                    offsetting_order_by = '%s.%s' % (qn(meta.db_table), qn(meta.pk.db_column or meta.pk.column))
                    if do_offset_emulation:
                        if order_by:
                            ordering = []
                            for expr, (o_sql, o_params, _) in order_by:
                                # value_expression in OVER clause cannot refer to
                                # expressions or aliases in the select list. See:
                                # http://msdn.microsoft.com/en-us/library/ms189461.aspx
                                src = next(iter(expr.get_source_expressions()))
                                if isinstance(src, Ref):
                                    src = next(iter(src.get_source_expressions()))
                                    o_sql, _ = src.as_sql(self, self.connection)
                                    odir = 'DESC' if expr.descending else 'ASC'
                                    o_sql = '%s %s' % (o_sql, odir)
                                ordering.append(o_sql)
                                params.extend(o_params)
                            offsetting_order_by = ', '.join(ordering)
                            order_by = []
                        out_cols.append('ROW_NUMBER() OVER (ORDER BY %s) AS [rn]' % offsetting_order_by)
                    elif not order_by:
                        order_by.append(((None, ('%s ASC' % offsetting_order_by, [], None))))

                if self.query.select_for_update and self.connection.features.has_select_for_update:
                    if self.connection.get_autocommit():
                        raise TransactionManagementError('select_for_update cannot be used outside of a transaction.')

                    if with_limit_offset and not self.connection.features.supports_select_for_update_with_limit:
                        raise NotSupportedError(
                            'LIMIT/OFFSET is not supported with '
                            'select_for_update on this database backend.'
                        )
                    nowait = self.query.select_for_update_nowait
                    skip_locked = self.query.select_for_update_skip_locked
                    of = self.query.select_for_update_of
                    # If it's a NOWAIT/SKIP LOCKED/OF query but the backend
                    # doesn't support it, raise NotSupportedError to prevent a
                    # possible deadlock.
                    if nowait and not self.connection.features.has_select_for_update_nowait:
                        raise NotSupportedError('NOWAIT is not supported on this database backend.')
                    elif skip_locked and not self.connection.features.has_select_for_update_skip_locked:
                        raise NotSupportedError('SKIP LOCKED is not supported on this database backend.')
                    elif of and not self.connection.features.has_select_for_update_of:
                        raise NotSupportedError('FOR UPDATE OF is not supported on this database backend.')
                    for_update_part = self.connection.ops.for_update_sql(
                        nowait=nowait,
                        skip_locked=skip_locked,
                        of=self.get_select_for_update_of_arguments(),
                    )

                if for_update_part and self.connection.features.for_update_after_from:
                    from_.insert(1, for_update_part)

                result += [', '.join(out_cols), 'FROM', *from_]
                params.extend(f_params)

                if where:
                    result.append('WHERE %s' % where)
                    params.extend(w_params)

                grouping = []
                for g_sql, g_params in group_by:
                    grouping.append(g_sql)
                    params.extend(g_params)
                if grouping:
                    if distinct_fields:
                        raise NotImplementedError('annotate() + distinct(fields) is not implemented.')
                    order_by = order_by or self.connection.ops.force_no_ordering()
                    result.append('GROUP BY %s' % ', '.join(grouping))

                if having:
                    result.append('HAVING %s' % having)
                    params.extend(h_params)

            if self.query.explain_query:
                result.insert(0, self.connection.ops.explain_query_prefix(
                    self.query.explain_format,
                    **self.query.explain_options
                ))

            if order_by:
                ordering = []
                for _, (o_sql, o_params, _) in order_by:
                    ordering.append(o_sql)
                    params.extend(o_params)
                result.append('ORDER BY %s' % ', '.join(ordering))

            # SQL Server requires the backend-specific emulation (2008 or earlier)
            # or an offset clause (2012 or newer) for offsetting
            if do_offset:
                if do_offset_emulation:
                    # Construct the final SQL clause, using the initial select SQL
                    # obtained above.
                    result = ['SELECT * FROM (%s) AS X WHERE X.rn' % ' '.join(result)]
                    # Place WHERE condition on `rn` for the desired range.
                    if do_limit:
                        result.append('BETWEEN %d AND %d' % (low_mark + 1, high_mark))
                    else:
                        result.append('>= %d' % (low_mark + 1))
                    if not self.query.subquery:
                        result.append('ORDER BY X.rn')
                else:
                    result.append(self.connection.ops.limit_offset_sql(self.query.low_mark, self.query.high_mark))

            if self.query.subquery and extra_select:
                # If the query is used as a subquery, the extra selects would
                # result in more columns than the left-hand side expression is
                # expecting. This can happen when a subquery uses a combination
                # of order_by() and distinct(), forcing the ordering expressions
                # to be selected as well. Wrap the query in another subquery
                # to exclude extraneous selects.
                sub_selects = []
                sub_params = []
                for index, (select, _, alias) in enumerate(self.select, start=1):
                    if not alias and with_col_aliases:
                        alias = 'col%d' % index
                    if alias:
                        sub_selects.append("%s.%s" % (
                            self.connection.ops.quote_name('subquery'),
                            self.connection.ops.quote_name(alias),
                        ))
                    else:
                        select_clone = select.relabeled_clone({select.alias: 'subquery'})
                        subselect, subparams = select_clone.as_sql(self, self.connection)
                        sub_selects.append(subselect)
                        sub_params.extend(subparams)
                return 'SELECT %s FROM (%s) subquery' % (
                    ', '.join(sub_selects),
                    ' '.join(result),
                ), tuple(sub_params + params)

            return ' '.join(result), tuple(params)
        finally:
            # Finally do cleanup - get rid of the joins we created above.
            self.query.reset_refcounts(refcounts_before)

    def compile(self, node, *args, **kwargs):
        node = self._as_microsoft(node)
        return super().compile(node, *args, **kwargs)

    def collapse_group_by(self, expressions, having):
        expressions = super().collapse_group_by(expressions, having)
        return [e for e in expressions if not isinstance(e, Subquery)]

    def _as_microsoft(self, node):
        as_microsoft = None
        if isinstance(node, Avg):
            as_microsoft = _as_sql_agv
        elif isinstance(node, Chr):
            as_microsoft = _as_sql_chr
        elif isinstance(node, ConcatPair):
            as_microsoft = _as_sql_concatpair
        elif isinstance(node, Count):
            as_microsoft = _as_sql_count
        elif isinstance(node, Greatest):
            as_microsoft = _as_sql_greatest
        elif isinstance(node, Least):
            as_microsoft = _as_sql_least
        elif isinstance(node, Length):
            as_microsoft = _as_sql_length
        elif isinstance(node, RPad):
            as_microsoft = _as_sql_rpad
        elif isinstance(node, LPad):
            as_microsoft = _as_sql_lpad
        elif isinstance(node, Repeat):
            as_microsoft = _as_sql_repeat
        elif isinstance(node, StdDev):
            as_microsoft = _as_sql_stddev
        elif isinstance(node, StrIndex):
            as_microsoft = _as_sql_strindex
        elif isinstance(node, Substr):
            as_microsoft = _as_sql_substr
        elif isinstance(node, Trim):
            as_microsoft = _as_sql_trim
        elif isinstance(node, Variance):
            as_microsoft = _as_sql_variance
        if as_microsoft:
            node = node.copy()
            node.as_microsoft = types.MethodType(as_microsoft, node)
        return node


class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler):
    def get_returned_fields(self):
        if django.VERSION >= (3, 0, 0):
            return self.returning_fields
        return self.return_id

    def fix_auto(self, sql, opts, fields, qn):
        if opts.auto_field is not None:
            # db_column is None if not explicitly specified by model field
            auto_field_column = opts.auto_field.db_column or opts.auto_field.column
            columns = [f.column for f in fields]
            if auto_field_column in columns:
                id_insert_sql = []
                table = qn(opts.db_table)
                sql_format = 'SET IDENTITY_INSERT %s ON; %s; SET IDENTITY_INSERT %s OFF'
                for q, p in sql:
                    id_insert_sql.append((sql_format % (table, q, table), p))
                sql = id_insert_sql

        return sql

    def as_sql(self):
        # We don't need quote_name_unless_alias() here, since these are all
        # going to be column names (so we can avoid the extra overhead).
        qn = self.connection.ops.quote_name
        opts = self.query.get_meta()
        result = ['INSERT INTO %s' % qn(opts.db_table)]
        fields = self.query.fields or [opts.pk]

        if self.query.fields:
            result.append('(%s)' % ', '.join(qn(f.column) for f in fields))
            values_format = 'VALUES (%s)'
            value_rows = [
                [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
                for obj in self.query.objs
            ]
        else:
            values_format = '%s VALUES'
            # An empty object.
            value_rows = [[self.connection.ops.pk_default_value()] for _ in self.query.objs]
            fields = [None]

        # Currently the backends just accept values when generating bulk
        # queries and generate their own placeholders. Doing that isn't
        # necessary and it should be possible to use placeholders and
        # expressions in bulk inserts too.
        can_bulk = (not self.get_returned_fields() and self.connection.features.has_bulk_insert) and self.query.fields

        placeholder_rows, param_rows = self.assemble_as_sql(fields, value_rows)

        if self.get_returned_fields() and self.connection.features.can_return_id_from_insert:
            result.insert(0, 'SET NOCOUNT ON')
            result.append((values_format + ';') % ', '.join(placeholder_rows[0]))
            params = [param_rows[0]]
            result.append('SELECT CAST(SCOPE_IDENTITY() AS bigint)')
            sql = [(" ".join(result), tuple(chain.from_iterable(params)))]
        else:
            if can_bulk:
                result.append(self.connection.ops.bulk_insert_sql(fields, placeholder_rows))
                sql = [(" ".join(result), tuple(p for ps in param_rows for p in ps))]
            else:
                sql = [
                    (" ".join(result + [values_format % ", ".join(p)]), vals)
                    for p, vals in zip(placeholder_rows, param_rows)
                ]

        if self.query.fields:
            sql = self.fix_auto(sql, opts, fields, qn)

        return sql


class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler):
    def as_sql(self):
        sql, params = super().as_sql()
        if sql:
            sql = '; '.join(['SET NOCOUNT OFF', sql])
        return sql, params


class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler):
    def as_sql(self):
        sql, params = super().as_sql()
        if sql:
            sql = '; '.join(['SET NOCOUNT OFF', sql])
        return sql, params


class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler):
    pass


================================================
FILE: sql_server/pyodbc/creation.py
================================================
import binascii
import os

import django
from django.db.backends.base.creation import BaseDatabaseCreation


class DatabaseCreation(BaseDatabaseCreation):
    @property
    def cursor(self):
        if django.VERSION >= (3, 1):
            return self.connection._nodb_cursor

        return self.connection._nodb_connection.cursor

    def _destroy_test_db(self, test_database_name, verbosity):
        """
        Internal implementation - remove the test db tables.
        """
        # Remove the test database to clean up after
        # ourselves. Connect to the previous database (not the test database)
        # to do so, because it's not allowed to delete a database while being
        # connected to it.
        with self.cursor() as cursor:
            to_azure_sql_db = self.connection.to_azure_sql_db
            if not to_azure_sql_db:
                cursor.execute("ALTER DATABASE %s SET SINGLE_USER WITH ROLLBACK IMMEDIATE"
                               % self.connection.ops.quote_name(test_database_name))
            cursor.execute("DROP DATABASE %s"
                           % self.connection.ops.quote_name(test_database_name))

    def sql_table_creation_suffix(self):
        suffix = []
        collation = self.connection.settings_dict['TEST'].get('COLLATION', None)
        if collation:
            suffix.append('COLLATE %s' % collation)
        return ' '.join(suffix)

    # The following code to add regex support in SQLServer is taken from django-mssql
    # see https://bitbucket.org/Manfre/django-mssql
    def enable_clr(self):
        """ Enables clr for server if not already enabled
        This function will not fail if current user doesn't have
        permissions to enable clr, and clr is already enabled
        """
        with self.cursor() as cursor:
            # check whether clr is enabled
            cursor.execute('''
            SELECT value FROM sys.configurations
            WHERE name = 'clr enabled'
            ''')
            res = None
            try:
                res = cursor.fetchone()
            except Exception:
                pass

            if not res or not res[0]:
                # if not enabled enable clr
                cursor.execute("sp_configure 'clr enabled', 1")
                cursor.execute("RECONFIGURE")

                cursor.execute("sp_configure 'show advanced options', 1")
                cursor.execute("RECONFIGURE")

                cursor.execute("sp_configure 'clr strict security', 0")
                cursor.execute("RECONFIGURE")

    def install_regex_clr(self, database_name):
        sql = '''
USE {database_name};
-- Drop and recreate the function if it already exists
IF OBJECT_ID('REGEXP_LIKE') IS NOT NULL
DROP FUNCTION [dbo].[REGEXP_LIKE]
IF EXISTS(select * from sys.assemblies where name like 'regex_clr')
DROP ASSEMBLY regex_clr
;
CREATE ASSEMBLY regex_clr
FROM 0x{assembly_hex}
WITH PERMISSION_SET = SAFE;
create function [dbo].[REGEXP_LIKE]
(
@input nvarchar(max),
@pattern nvarchar(max),
@caseSensitive int
)
RETURNS INT  AS
EXTERNAL NAME regex_clr.UserDefinedFunctions.REGEXP_LIKE
        '''.format(
            database_name=self.connection.ops.quote_name(database_name),
            assembly_hex=self.get_regex_clr_assembly_hex(),
        ).split(';')

        self.enable_clr()

        with self.cursor() as cursor:
            for s in sql:
                cursor.execute(s)

    def get_regex_clr_assembly_hex(self):
        with open(os.path.join(os.path.dirname(__file__), 'regex_clr.dll'), 'rb') as f:
            return binascii.hexlify(f.read()).decode('ascii')


================================================
FILE: sql_server/pyodbc/features.py
================================================
from django.db.backends.base.features import BaseDatabaseFeatures
from django.utils.functional import cached_property


class DatabaseFeatures(BaseDatabaseFeatures):
    can_introspect_json_field = False
    has_native_json_field = False
    has_native_uuid_field = False
    allow_sliced_subqueries_with_in = False
    can_introspect_autofield = True
    can_introspect_small_integer_field = True
    can_return_columns_from_insert = True
    can_return_id_from_insert = True
    can_use_chunked_reads = False
    for_update_after_from = True
    greatest_least_ignores_nulls = True
    has_real_datatype = True
    has_select_for_update = True
    has_select_for_update_nowait = True
    has_select_for_update_skip_locked = True
    has_zoneinfo_database = False
    ignores_table_name_case = True
    ignores_quoted_identifier_case = True
    requires_literal_defaults = True
    requires_sqlparse_for_splitting = False
    supports_boolean_expr_in_select_clause = False
    supports_deferrable_unique_constraints = False
    supports_ignore_conflicts = False
    supports_index_on_text_field = False
    supports_paramstyle_pyformat = False
    supports_regex_backreferencing = True
    supports_sequence_reset = False
    supports_subqueries_in_group_by = False
    supports_tablespaces = True
    supports_temporal_subtraction = True
    supports_timezones = False
    supports_transactions = True
    uses_savepoints = True
    supports_order_by_nulls_modifier = False
    supports_order_by_is_nulls = False
    order_by_nulls_first = True

    @cached_property
    def has_bulk_insert(self):
        return self.connection.sql_server_version > 2005

    @cached_property
    def supports_nullable_unique_constraints(self):
        return self.connection.sql_server_version > 2005

    @cached_property
    def supports_partially_nullable_unique_constraints(self):
        return self.connection.sql_server_version > 2005

    @cached_property
    def supports_partial_indexes(self):
        return self.connection.sql_server_version > 2005

    @cached_property
    def supports_functions_in_partial_indexes(self):
        return self.connection.sql_server_version > 2005

    @cached_property
    def introspected_field_types(self):
        return {
            **super().introspected_field_types,
            'GenericIPAddressField': 'CharField',
            'PositiveBigIntegerField': 'BigIntegerField'
        }


================================================
FILE: sql_server/pyodbc/functions.py
================================================
from django import VERSION
from django.db.models import BooleanField
from django.db.models.functions import Cast
from django.db.models.functions.math import ATan2, Log, Ln, Mod, Round
from django.db.models.expressions import Case, Exists, OrderBy, When
from django.db.models.lookups import Lookup

DJANGO3 = VERSION[0] >= 3


class TryCast(Cast):
    function = 'TRY_CAST'


def sqlserver_as_sql(self, compiler, connection, template=None, **extra_context):
    template = template or self.template
    if connection.features.supports_order_by_nulls_modifier:
        if self.nulls_last:
            template = '%s NULLS LAST' % template
        elif self.nulls_first:
            template = '%s NULLS FIRST' % template
    else:
        if self.nulls_last and not (
            self.descending and connection.features.order_by_nulls_first
        ) and connection.features.supports_order_by_is_nulls:
            template = '%%(expression)s IS NULL, %s' % template
        elif self.nulls_first and not (
            not self.descending and connection.features.order_by_nulls_first
        ) and connection.features.supports_order_by_is_nulls:
            template = '%%(expression)s IS NOT NULL, %s' % template
    connection.ops.check_expression_support(self)
    expression_sql, params = compiler.compile(self.expression)
    placeholders = {
        'expression': expression_sql,
        'ordering': 'DESC' if self.descending else 'ASC',
        **extra_context,
    }
    template = template or self.template
    params *= template.count('%(expression)s')
    return (template % placeholders).rstrip(), params


def sqlserver_atan2(self, compiler, connection, **extra_context):
    return self.as_sql(compiler, connection, function='ATN2', **extra_context)


def sqlserver_log(self, compiler, connection, **extra_context):
    clone = self.copy()
    clone.set_source_expressions(self.get_source_expressions()[::-1])
    return clone.as_sql(compiler, connection, **extra_context)


def sqlserver_ln(self, compiler, connection, **extra_context):
    return self.as_sql(compiler, connection, function='LOG', **extra_context)


def sqlserver_mod(self, compiler, connection, **extra_context):
    return self.as_sql(compiler, connection, template='%(expressions)s', arg_joiner='%%', **extra_context)


def sqlserver_round(self, compiler, connection, **extra_context):
    return self.as_sql(compiler, connection, template='%(function)s(%(expressions)s, 0)', **extra_context)


def sqlserver_exists(self, compiler, connection, template=None, **extra_context):
    # MS SQL doesn't allow EXISTS() in the SELECT list, so wrap it with a
    # CASE WHEN expression. Change the template since the When expression
    # requires a left hand side (column) to compare against.
    sql, params = self.as_sql(compiler, connection, template, **extra_context)
    sql = 'CASE WHEN {} THEN 1 ELSE 0 END'.format(sql)
    return sql, params


def sqlserver_lookup(self, compiler, connection):
    # MSSQL doesn't allow EXISTS() to be compared to another expression
    # unless it's wrapped in a CASE WHEN.
    wrapped = False
    exprs = []
    for expr in (self.lhs, self.rhs):
        if isinstance(expr, Exists):
            expr = Case(When(expr, then=True), default=False, output_field=BooleanField())
            wrapped = True
        exprs.append(expr)
    lookup = type(self)(*exprs) if wrapped else self
    return lookup.as_sql(compiler, connection)


def sqlserver_orderby(self, compiler, connection):
    # MSSQL doesn't allow ORDER BY EXISTS() unless it's wrapped in
    # a CASE WHEN.

    template = None
    if self.nulls_last:
        template = 'CASE WHEN %(expression)s IS NULL THEN 1 ELSE 0 END, %(expression)s %(ordering)s'
    if self.nulls_first:
        template = 'CASE WHEN %(expression)s IS NULL THEN 0 ELSE 1 END, %(expression)s %(ordering)s'

    if isinstance(self.expression, Exists):
        copy = self.copy()
        copy.expression = Case(
            When(self.expression, then=True),
            default=False,
            output_field=BooleanField(),
        )
        return copy.as_sql(compiler, connection, template=template)
    return self.as_sql(compiler, connection, template=template)


ATan2.as_microsoft = sqlserver_atan2
Log.as_microsoft = sqlserver_log
Ln.as_microsoft = sqlserver_ln
Mod.as_microsoft = sqlserver_mod
Round.as_microsoft = sqlserver_round

if DJANGO3:
    Lookup.as_microsoft = sqlserver_lookup
else:
    Exists.as_microsoft = sqlserver_exists

OrderBy.as_microsoft = sqlserver_orderby
OrderBy.as_sql = sqlserver_as_sql


================================================
FILE: sql_server/pyodbc/introspection.py
================================================
import pyodbc as Database
from collections import namedtuple

from django.db.backends.base.introspection import (
    BaseDatabaseIntrospection, TableInfo,
)
from django.db.models.indexes import Index

SQL_AUTOFIELD = -777555
SQL_BIGAUTOFIELD = -777444

FieldInfo = namedtuple('FieldInfo', 'name type_code display_size internal_size precision scale null_ok default')


class DatabaseIntrospection(BaseDatabaseIntrospection):
    # Map type codes to Django Field types.
    data_types_reverse = {
        SQL_AUTOFIELD: 'AutoField',
        SQL_BIGAUTOFIELD: 'BigAutoField',
        Database.SQL_BIGINT: 'BigIntegerField',
        # Database.SQL_BINARY:            ,
        Database.SQL_BIT: 'BooleanField',
        Database.SQL_CHAR: 'CharField',
        Database.SQL_DECIMAL: 'DecimalField',
        Database.SQL_DOUBLE: 'FloatField',
        Database.SQL_FLOAT: 'FloatField',
        Database.SQL_GUID: 'TextField',
        Database.SQL_INTEGER: 'IntegerField',
        Database.SQL_LONGVARBINARY: 'BinaryField',
        # Database.SQL_LONGVARCHAR:       ,
        Database.SQL_NUMERIC: 'DecimalField',
        Database.SQL_REAL: 'FloatField',
        Database.SQL_SMALLINT: 'SmallIntegerField',
        Database.SQL_SS_TIME2: 'TimeField',
        Database.SQL_TINYINT: 'SmallIntegerField',
        Database.SQL_TYPE_DATE: 'DateField',
        Database.SQL_TYPE_TIME: 'TimeField',
        Database.SQL_TYPE_TIMESTAMP: 'DateTimeField',
        Database.SQL_VARBINARY: 'BinaryField',
        Database.SQL_VARCHAR: 'TextField',
        Database.SQL_WCHAR: 'CharField',
        Database.SQL_WLONGVARCHAR: 'TextField',
        Database.SQL_WVARCHAR: 'TextField',
    }

    ignored_tables = []

    def get_field_type(self, data_type, description):
        field_type = super().get_field_type(data_type, description)
        # the max nvarchar length is described as 0 or 2**30-1
        # (it depends on the driver)
        size = description.internal_size
        if field_type == 'CharField':
            if size == 0 or size >= 2**30 - 1:
                field_type = "TextField"
        elif field_type == 'TextField':
            if size > 0 and size < 2**30 - 1:
                field_type = 'CharField'
        return field_type

    def get_table_list(self, cursor):
        """
        Returns a list of table and view names in the current database.
        """
        sql = 'SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = SCHEMA_NAME()'
        cursor.execute(sql)
        types = {'BASE TABLE': 't', 'VIEW': 'v'}
        return [TableInfo(row[0], types.get(row[1]))
                for row in cursor.fetchall()
                if row[0] not in self.ignored_tables]

    def _is_auto_field(self, cursor, table_name, column_name):
        """
        Checks whether column is Identity
        """
        # COLUMNPROPERTY: http://msdn2.microsoft.com/en-us/library/ms174968.aspx

        # from django.db import connection
        # cursor.execute("SELECT COLUMNPROPERTY(OBJECT_ID(%s), %s, 'IsIdentity')",
        #                 (connection.ops.quote_name(table_name), column_name))
        cursor.execute("SELECT COLUMNPROPERTY(OBJECT_ID(%s), %s, 'IsIdentity')",
                       (self.connection.ops.quote_name(table_name), column_name))
        return cursor.fetchall()[0][0]

    def get_table_description(self, cursor, table_name, identity_check=True):
        """Returns a description of the table, with DB-API cursor.description interface.

        The 'auto_check' parameter has been added to the function argspec.
        If set to True, the function will check each of the table's fields for the
        IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField).

        When an integer field is found with an IDENTITY property, it is given a custom field number
        of SQL_AUTOFIELD, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict.

        When a bigint field is found with an IDENTITY property, it is given a custom field number
        of SQL_BIGAUTOFIELD, which maps to the 'BigAutoField' value in the DATA_TYPES_REVERSE dict.
        """

        # map pyodbc's cursor.columns to db-api cursor description
        columns = [[c[3], c[4], None, c[6], c[6], c[8], c[10], c[12]] for c in cursor.columns(table=table_name)]
        items = []
        for column in columns:
            if identity_check and self._is_auto_field(cursor, table_name, column[0]):
                if column[1] == Database.SQL_BIGINT:
                    column[1] = SQL_BIGAUTOFIELD
                else:
                    column[1] = SQL_AUTOFIELD
            if column[1] == Database.SQL_WVARCHAR and column[3] < 4000:
                column[1] = Database.SQL_WCHAR
            items.append(FieldInfo(*column))
        return items

    def get_sequences(self, cursor, table_name, table_fields=()):
        cursor.execute("""
            SELECT c.name FROM sys.columns c
            INNER JOIN sys.tables t ON c.object_id = t.object_id
            WHERE t.schema_id = SCHEMA_ID() AND t.name = %s AND c.is_identity = 1""",
                       [table_name])
        # SQL Server allows only one identity column per table
        # https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
        row = cursor.fetchone()
        return [{'table': table_name, 'column': row[0]}] if row else []

    def get_relations(self, cursor, table_name):
        """
        Returns a dictionary of {field_name: (field_name_other_table, other_table)}
        representing all relationships to the given table.
        """
        # CONSTRAINT_COLUMN_USAGE: http://msdn2.microsoft.com/en-us/library/ms174431.aspx
        # CONSTRAINT_TABLE_USAGE:  http://msdn2.microsoft.com/en-us/library/ms179883.aspx
        # REFERENTIAL_CONSTRAINTS: http://msdn2.microsoft.com/en-us/library/ms179987.aspx
        # TABLE_CONSTRAINTS:       http://msdn2.microsoft.com/en-us/library/ms181757.aspx

        sql = """
SELECT e.COLUMN_NAME AS column_name,
  c.TABLE_NAME AS referenced_table_name,
  d.COLUMN_NAME AS referenced_column_name
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a
INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS b
  ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME AND a.TABLE_SCHEMA = b.CONSTRAINT_SCHEMA
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE AS c
  ON b.UNIQUE_CONSTRAINT_NAME = c.CONSTRAINT_NAME AND b.CONSTRAINT_SCHEMA = c.CONSTRAINT_SCHEMA
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS d
  ON c.CONSTRAINT_NAME = d.CONSTRAINT_NAME AND c.CONSTRAINT_SCHEMA = d.CONSTRAINT_SCHEMA
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS e
  ON a.CONSTRAINT_NAME = e.CONSTRAINT_NAME AND a.TABLE_SCHEMA = e.TABLE_SCHEMA
WHERE a.TABLE_SCHEMA = SCHEMA_NAME() AND a.TABLE_NAME = %s AND a.CONSTRAINT_TYPE = 'FOREIGN KEY'"""
        cursor.execute(sql, (table_name,))
        return dict([[item[0], (item[2], item[1])] for item in cursor.fetchall()])

    def get_key_columns(self, cursor, table_name):
        """
        Returns a list of (column_name, referenced_table_name, referenced_column_name) for all
        key columns in given table.
        """
        key_columns = []
        cursor.execute("""
            SELECT c.name AS column_name, rt.name AS referenced_table_name, rc.name AS referenced_column_name
            FROM sys.foreign_key_columns fk
            INNER JOIN sys.tables t ON t.object_id = fk.parent_object_id
            INNER JOIN sys.columns c ON c.object_id = t.object_id AND c.column_id = fk.parent_column_id
            INNER JOIN sys.tables rt ON rt.object_id = fk.referenced_object_id
            INNER JOIN sys.columns rc ON rc.object_id = rt.object_id AND rc.column_id = fk.referenced_column_id
            WHERE t.schema_id = SCHEMA_ID() AND t.name = %s""", [table_name])
        key_columns.extend([tuple(row) for row in cursor.fetchall()])
        return key_columns

    def get_constraints(self, cursor, table_name):
        """
        Retrieves any constraints or keys (unique, pk, fk, check, index)
        across one or more columns.

        Returns a dict mapping constraint names to their attributes,
        where attributes is a dict with keys:
         * columns: List of columns this covers
         * primary_key: True if primary key, False otherwise
         * unique: True if this is a unique constraint, False otherwise
         * foreign_key: (table, column) of target, or None
         * check: True if check constraint, False otherwise
         * index: True if index, False otherwise.
         * orders: The order (ASC/DESC) defined for the columns of indexes
         * type: The type of the index (btree, hash, etc.)
        """
        constraints = {}
        # Loop over the key table, collecting things as constraints
        # This will get PKs, FKs, and uniques, but not CHECK
        cursor.execute("""
            SELECT
                kc.constraint_name,
                kc.column_name,
                tc.constraint_type,
                fk.referenced_table_name,
                fk.referenced_column_name
            FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kc
            INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc ON
                kc.table_schema = tc.table_schema AND
                kc.table_name = tc.table_name AND
                kc.constraint_name = tc.constraint_name
            LEFT OUTER JOIN (
                SELECT
                    ps.name AS table_schema,
                    pt.name AS table_name,
                    pc.name AS column_name,
                    rt.name AS referenced_table_name,
                    rc.name AS referenced_column_name
                FROM
                    sys.foreign_key_columns fkc
                INNER JOIN sys.tables pt ON
                    fkc.parent_object_id = pt.object_id
                INNER JOIN sys.schemas ps ON
                    pt.schema_id = ps.schema_id
                INNER JOIN sys.columns pc ON
                    fkc.parent_object_id = pc.object_id AND
                    fkc.parent_column_id = pc.column_id
                INNER JOIN sys.tables rt ON
                    fkc.referenced_object_id = rt.object_id
                INNER JOIN sys.schemas rs ON
                    rt.schema_id = rs.schema_id
                INNER JOIN sys.columns rc ON
                    fkc.referenced_object_id = rc.object_id AND
                    fkc.referenced_column_id = rc.column_id
            ) fk ON
                kc.table_schema = fk.table_schema AND
                kc.table_name = fk.table_name AND
                kc.column_name = fk.column_name
            WHERE
                kc.table_schema = SCHEMA_NAME() AND
                kc.table_name = %s
            ORDER BY
                kc.constraint_name ASC,
                kc.ordinal_position ASC
        """, [table_name])
        for constraint, column, kind, ref_table, ref_column in cursor.fetchall():
            # If we're the first column, make the record
            if constraint not in constraints:
                constraints[constraint] = {
                    "columns": [],
                    "primary_key": kind.lower() == "primary key",
                    "unique": kind.lower() in ["primary key", "unique"],
                    "foreign_key": (ref_table, ref_column) if kind.lower() == "foreign key" else None,
                    "check": False,
                    "index": False,
                }
            # Record the details
            constraints[constraint]['columns'].append(column)
        # Now get CHECK constraint columns
        cursor.execute("""
            SELECT kc.constraint_name, kc.column_name
            FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS kc
            JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS c ON
                kc.table_schema = c.table_schema AND
                kc.table_name = c.table_name AND
                kc.constraint_name = c.constraint_name
            WHERE
                c.constraint_type = 'CHECK' AND
                kc.table_schema = SCHEMA_NAME() AND
                kc.table_name = %s
        """, [table_name])
        for constraint, column in cursor.fetchall():
            # If we're the first column, make the record
            if constraint not in constraints:
                constraints[constraint] = {
                    "columns": [],
                    "primary_key": False,
                    "unique": False,
                    "foreign_key": None,
                    "check": True,
                    "index": False,
                }
            # Record the details
            constraints[constraint]['columns'].append(column)
        # Now get indexes
        cursor.execute("""
            SELECT
                i.name AS index_name,
                i.is_unique,
                i.is_primary_key,
                i.type,
                i.type_desc,
                ic.is_descending_key,
                c.name AS column_name
            FROM
                sys.tables AS t
            INNER JOIN sys.schemas AS s ON
                t.schema_id = s.schema_id
            INNER JOIN sys.indexes AS i ON
                t.object_id = i.object_id
            INNER JOIN sys.index_columns AS ic ON
                i.object_id = ic.object_id AND
                i.index_id = ic.index_id
            INNER JOIN sys.columns AS c ON
                ic.object_id = c.object_id AND
                ic.column_id = c.column_id
            WHERE
                t.schema_id = SCHEMA_ID() AND
                t.name = %s
            ORDER BY
                i.index_id ASC,
                ic.index_column_id ASC
        """, [table_name])
        indexes = {}
        for index, unique, primary, type_, desc, order, column in cursor.fetchall():
            if index not in indexes:
                indexes[index] = {
                    "columns": [],
                    "primary_key": primary,
                    "unique": unique,
                    "foreign_key": None,
                    "check": False,
                    "index": True,
                    "orders": [],
                    "type": Index.suffix if type_ in (1, 2) else desc.lower(),
                }
            indexes[index]["columns"].append(column)
            indexes[index]["orders"].append("DESC" if order == 1 else "ASC")
        for index, constraint in indexes.items():
            if index not in constraints:
                constraints[index] = constraint
        return constraints


================================================
FILE: sql_server/pyodbc/management/__init__.py
================================================


================================================
FILE: sql_server/pyodbc/management/commands/__init__.py
================================================


================================================
FILE: sql_server/pyodbc/management/commands/install_regex_clr.py
================================================
# Add regex support in SQLServer
# Code taken from django-mssql (see https://bitbucket.org/Manfre/django-mssql)

from django.core.management.base import BaseCommand
from django.db import connection


class Command(BaseCommand):
    help = "Installs the regex_clr.dll assembly with the database"

    requires_model_validation = False

    args = 'database_name'

    def add_arguments(self, parser):
        parser.add_argument('database_name')

    def handle(self, *args, **options):
        database_name = options['database_name']
        if not database_name:
            self.print_help('manage.py', 'install_regex_clr')
            return

        connection.creation.install_regex_clr(database_name)
        print('Installed regex_clr to database %s' % database_name)


================================================
FILE: sql_server/pyodbc/operations.py
================================================
import datetime
import uuid
import warnings
import django

from django.conf import settings
from django.db.backends.base.operations import BaseDatabaseOperations
from django.db.models import Exists, ExpressionWrapper
from django.db.models.expressions import RawSQL
from django.db.models.sql.where import WhereNode
from django.utils import timezone
from django.utils.encoding import force_str

import pytz


class DatabaseOperations(BaseDatabaseOperations):
    compiler_module = 'sql_server.pyodbc.compiler'

    cast_char_field_without_max_length = 'nvarchar(max)'

    def _convert_field_to_tz(self, field_name, tzname):
        if settings.USE_TZ and not tzname == 'UTC':
            offset = self._get_utcoffset(tzname)
            field_name = 'DATEADD(second, %d, %s)' % (offset, field_name)
        return field_name

    def _get_utcoffset(self, tzname):
        """
        Returns UTC offset for given time zone in seconds
        """
        # SQL Server has no built-in support for tz database, see:
        # http://blogs.msdn.com/b/sqlprogrammability/archive/2008/03/18/using-time-zone-data-in-sql-server-2008.aspx
        zone = pytz.timezone(tzname)
        # no way to take DST into account at this point
        now = datetime.datetime.now()
        delta = zone.localize(now, is_dst=False).utcoffset()
        return delta.days * 86400 + delta.seconds

    def bulk_batch_size(self, fields, objs):
        """
        Returns the maximum allowed batch size for the backend. The fields
        are the fields going to be inserted in the batch, the objs contains
        all the objects to be inserted.
        """
        objs_len, fields_len, max_row_values = len(objs), len(fields), 1000
        if (objs_len * fields_len) <= max_row_values:
            size = objs_len
        else:
            size = max_row_values // fields_len
        return size

    def bulk_insert_sql(self, fields, placeholder_rows):
        placeholder_rows_sql = (", ".join(row) for row in placeholder_rows)
        values_sql = ", ".join("(%s)" % sql for sql in placeholder_rows_sql)
        return "VALUES " + values_sql

    def cache_key_culling_sql(self):
        """
        Returns a SQL query that retrieves the first cache key greater than the
        smallest.

        This is used by the 'db' cache backend to determine where to start
        culling.
        """
        return "SELECT cache_key FROM (SELECT cache_key, " \
               "ROW_NUMBER() OVER (ORDER BY cache_key) AS rn FROM %s" \
               ") cache WHERE rn = %%s + 1"

    def combine_duration_expression(self, connector, sub_expressions):
        lhs, rhs = sub_expressions
        sign = ' * -1' if connector == '-' else ''
        if lhs.startswith('DATEADD'):
            col, sql = rhs, lhs
        else:
            col, sql = lhs, rhs
        params = [sign for _ in range(sql.count('DATEADD'))]
        params.append(col)
        return sql % tuple(params)

    def combine_expression(self, connector, sub_expressions):
        """
        SQL Server requires special cases for some operators in query expressions
        """
        if connector == '^':
            return 'POWER(%s)' % ','.join(sub_expressions)
        elif connector == '<<':
            return '%s * (2 * %s)' % tuple(sub_expressions)
        elif connector == '>>':
            return '%s / (2 * %s)' % tuple(sub_expressions)
        return super().combine_expression(connector, sub_expressions)

    def convert_datetimefield_value(self, value, expression, connection):
        if value is not None:
            if settings.USE_TZ:
                value = timezone.make_aware(value, self.connection.timezone)
        return value

    def convert_floatfield_value(self, value, expression, connection):
        if value is not None:
            value = float(value)
        return value

    def convert_uuidfield_value(self, value, expression, connection):
        if value is not None:
            value = uuid.UUID(value)
        return value

    def convert_booleanfield_value(self, value, expression, connection):
        return bool(value) if value in (0, 1) else value

    def date_extract_sql(self, lookup_type, field_name):
        if lookup_type == 'week_day':
            return "DATEPART(weekday, %s)" % field_name
        elif lookup_type == 'week':
            return "DATEPART(iso_week, %s)" % field_name
        elif lookup_type == 'iso_year':
            return "YEAR(DATEADD(day, 26 - DATEPART(isoww, %s), %s))" % (field_name, field_name)
        else:
            return "DATEPART(%s, %s)" % (lookup_type, field_name)

    def date_interval_sql(self, timedelta):
        """
        implements the interval functionality for expressions
        """
        sec = timedelta.seconds + timedelta.days * 86400
        sql = 'DATEADD(second, %d%%s, CAST(%%s AS datetime2))' % sec
        if timedelta.microseconds:
            sql = 'DATEADD(microsecond, %d%%s, CAST(%s AS datetime2))' % (timedelta.microseconds, sql)
        return sql

    def date_trunc_sql(self, lookup_type, field_name):
        CONVERT_YEAR = 'CONVERT(varchar, DATEPART(year, %s))' % field_name
        CONVERT_QUARTER = 'CONVERT(varchar, 1+((DATEPART(quarter, %s)-1)*3))' % field_name
        CONVERT_MONTH = 'CONVERT(varchar, DATEPART(month, %s))' % field_name

        if lookup_type == 'year':
            return "CONVERT(datetime2, %s + '/01/01')" % CONVERT_YEAR
        if lookup_type == 'quarter':
            return "CONVERT(datetime2, %s + '/' + %s + '/01')" % (CONVERT_YEAR, CONVERT_QUARTER)
        if lookup_type == 'month':
            return "CONVERT(datetime2, %s + '/' + %s + '/01')" % (CONVERT_YEAR, CONVERT_MONTH)
        if lookup_type == 'week':
            CONVERT = "CONVERT(datetime2, CONVERT(varchar(12), %s, 112))" % field_name
            return "DATEADD(DAY, (DATEPART(weekday, %s) + 5) %%%% 7 * -1, %s)" % (CONVERT, field_name)
        if lookup_type == 'day':
            return "CONVERT(datetime2, CONVERT(varchar(12), %s, 112))" % field_name

    def datetime_cast_date_sql(self, field_name, tzname):
        field_name = self._convert_field_to_tz(field_name, tzname)
        sql = 'CAST(%s AS date)' % field_name
        return sql

    def datetime_cast_time_sql(self, field_name, tzname):
        field_name = self._convert_field_to_tz(field_name, tzname)
        sql = 'CAST(%s AS time)' % field_name
        return sql

    def datetime_extract_sql(self, lookup_type, field_name, tzname):
        field_name = self._convert_field_to_tz(field_name, tzname)
        return self.date_extract_sql(lookup_type, field_name)

    def datetime_trunc_sql(self, lookup_type, field_name, tzname):
        field_name = self._convert_field_to_tz(field_name, tzname)
        sql = ''
        if lookup_type in ('year', 'quarter', 'month', 'week', 'day'):
            sql = self.date_trunc_sql(lookup_type, field_name)
        elif lookup_type == 'hour':
            sql = "CONVERT(datetime2, SUBSTRING(CONVERT(varchar, %s, 20), 0, 14) + ':00:00')" % field_name
        elif lookup_type == 'minute':
            sql = "CONVERT(datetime2, SUBSTRING(CONVERT(varchar, %s, 20), 0, 17) + ':00')" % field_name
        elif lookup_type == 'second':
            sql = "CONVERT(datetime2, CONVERT(varchar, %s, 20))" % field_name
        return sql

    def for_update_sql(self, nowait=False, skip_locked=False, of=()):
        if skip_locked:
            return 'WITH (ROWLOCK, UPDLOCK, READPAST)'
        elif nowait:
            return 'WITH (NOWAIT, ROWLOCK, UPDLOCK)'
        else:
            return 'WITH (ROWLOCK, UPDLOCK)'

    def format_for_duration_arithmetic(self, sql):
        if sql == '%s':
            # use DATEADD only once because Django prepares only one parameter for this
            fmt = 'DATEADD(second, %s / 1000000%%s, CAST(%%s AS datetime2))'
            sql = '%%s'
        else:
            # use DATEADD twice to avoid arithmetic overflow for number part
            MICROSECOND = "DATEADD(microsecond, %s %%%%%%%% 1000000%%s, CAST(%%s AS datetime2))"
            fmt = 'DATEADD(second, %s / 1000000%%s, {})'.format(MICROSECOND)
            sql = (sql, sql)
        return fmt % sql

    def fulltext_search_sql(self, field_name):
        """
        Returns the SQL WHERE clause to use in order to perform a full-text
        search of the given field_name. Note that the resulting string should
        contain a '%s' placeholder for the value being searched against.
        """
        return 'CONTAINS(%s, %%s)' % field_name

    def get_db_converters(self, expression):
        converters = super().get_db_converters(expression)
        internal_type = expression.output_field.get_internal_type()
        if internal_type == 'DateTimeField':
            converters.append(self.convert_datetimefield_value)
        elif internal_type == 'FloatField':
            converters.append(self.convert_floatfield_value)
        elif internal_type == 'UUIDField':
            converters.append(self.convert_uuidfield_value)
        elif internal_type in ('BooleanField', 'NullBooleanField'):
            converters.append(self.convert_booleanfield_value)
        return converters

    def last_insert_id(self, cursor, table_name, pk_name):
        """
        Given a cursor object that has just performed an INSERT statement into
        a table that has an auto-incrementing ID, returns the newly created ID.

        This method also receives the table name and the name of the primary-key
        column.
        """
        # TODO: Check how the `last_insert_id` is being used in the upper layers
        #       in context of multithreaded access, compare with other backends

        # IDENT_CURRENT:  http://msdn2.microsoft.com/en-us/library/ms175098.aspx
        # SCOPE_IDENTITY: http://msdn2.microsoft.com/en-us/library/ms190315.aspx
        # @@IDENTITY:     http://msdn2.microsoft.com/en-us/library/ms187342.aspx

        # IDENT_CURRENT is not limited by scope and session; it is limited to
        # a specified table. IDENT_CURRENT returns the value generated for
        # a specific table in any session and any scope.
        # SCOPE_IDENTITY and @@IDENTITY return the last identity values that
        # are generated in any table in the current session. However,
        # SCOPE_IDENTITY returns values inserted only within the current scope;
        # @@IDENTITY is not limited to a specific scope.

        table_name = self.quote_name(table_name)
        cursor.execute("SELECT CAST(IDENT_CURRENT(%s) AS int)", [table_name])
        return cursor.fetchone()[0]

    def lookup_cast(self, lookup_type, internal_type=None):
        if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
            return "UPPER(%s)"
        return "%s"

    def max_name_length(self):
        return 128

    def no_limit_value(self):
        return None

    def prepare_sql_script(self, sql, _allow_fallback=False):
        return [sql]

    def quote_name(self, name):
        """
        Returns a quoted version of the given table, index or column name. Does
        not quote the given name if it's already been quoted.
        """
        if name.startswith('[') and name.endswith(']'):
            return name  # Quoting once is enough.
        return '[%s]' % name

    def random_function_sql(self):
        """
        Returns a SQL expression that returns a random value.
        """
        return "RAND()"

    def regex_lookup(self, lookup_type):
        """
        Returns the string to use in a query when performing regular expression
        lookups (using "regex" or "iregex"). The resulting string should
        contain a '%s' placeholder for the column being searched against.

        If the feature is not supported (or part of it is not supported), a
        NotImplementedError exception can be raised.
        """
        match_option = {'iregex': 0, 'regex': 1}[lookup_type]
        return "dbo.REGEXP_LIKE(%%s, %%s, %s)=1" % (match_option,)

    def limit_offset_sql(self, low_mark, high_mark):
        """Return LIMIT/OFFSET SQL clause."""
        limit, offset = self._get_limit_offset_params(low_mark, high_mark)
        return '%s%s' % (
            (' OFFSET %d ROWS' % offset) if offset else '',
            (' FETCH FIRST %d ROWS ONLY' % limit) if limit else '',
        )

    def last_executed_query(self, cursor, sql, params):
        """
        Returns a string of the query last executed by the given cursor, with
        placeholders replaced with actual values.

        `sql` is the raw query containing placeholders, and `params` is the
        sequence of parameters. These are used by default, but this method
        exists for database backends to provide a better implementation
        according to their own quoting schemes.
        """
        return super().last_executed_query(cursor, cursor.last_sql, cursor.last_params)

    def savepoint_create_sql(self, sid):
        """
        Returns the SQL for starting a new savepoint. Only required if the
        "uses_savepoints" feature is True. The "sid" parameter is a string
        for the savepoint id.
        """
        return "SAVE TRANSACTION %s" % sid

    def savepoint_rollback_sql(self, sid):
        """
        Returns the SQL for rolling back the given savepoint.
        """
        return "ROLLBACK TRANSACTION %s" % sid

    def _build_sequences(self, sequences, cursor):
        seqs = []
        for seq in sequences:
            cursor.execute("SELECT COUNT(*) FROM %s" % self.quote_name(seq["table"]))
            rowcnt = cursor.fetchone()[0]
            elem = {}
            if rowcnt:
                elem['start_id'] = 0
            else:
                elem['start_id'] = 1
            elem.update(seq)
            seqs.append(elem)
        return seqs

    def _sql_flush_new(self, style, tables, *, reset_sequences=False, allow_cascade=False):
        if reset_sequences:
            return [
                sequence
                for sequence in self.connection.introspection.sequence_list()
            ]

        return []

    def _sql_flush_old(self, style, tables, sequences, allow_cascade=False):
        return sequences

    def sql_flush(self, style, tables, *args, **kwargs):
        """
        Returns a list of SQL statements required to remove all data from
        the given database tables (without actually removing the tables
        themselves).

        The returned value also includes SQL statements required to reset DB
        sequences passed in :param sequences:.

        The `style` argument is a Style object as returned by either
        color_style() or no_style() in django.core.management.color.

        The `allow_cascade` argument determines whether truncation may cascade
        to tables with foreign keys pointing the tables being truncated.
        """

        if not tables:
            return []

        if django.VERSION >= (3, 1):
            sequences = self._sql_flush_new(style, tables, *args, **kwargs)
        else:
            sequences = self._sql_flush_old(style, tables, *args, **kwargs)

        from django.db import connections
        cursor = connections[self.connection.alias].cursor()

        seqs = self._build_sequences(sequences, cursor)

        COLUMNS = "TABLE_NAME, CONSTRAINT_NAME"
        WHERE = "CONSTRAINT_TYPE not in ('PRIMARY KEY','UNIQUE')"
        cursor.execute(
            "SELECT {} FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE {}".format(COLUMNS, WHERE))
        fks = cursor.fetchall()
        sql_list = ['ALTER TABLE %s NOCHECK CONSTRAINT %s;' %
                    (self.quote_name(fk[0]), self.quote_name(fk[1])) for fk in fks]
        sql_list.extend(['%s %s %s;' % (style.SQL_KEYWORD('DELETE'), style.SQL_KEYWORD('FROM'),
                                        style.SQL_FIELD(self.quote_name(table))) for table in tables])

        if self.connection.to_azure_sql_db and self.connection.sql_server_version < 2014:
            warnings.warn("Resetting identity columns is not supported "
                          "on this versios of Azure SQL Database.",
                          RuntimeWarning)
        else:
            # Then reset the counters on each table.
            sql_list.extend(['%s %s (%s, %s, %s) %s %s;' % (
                style.SQL_KEYWORD('DBCC'),
                style.SQL_KEYWORD('CHECKIDENT'),
                style.SQL_FIELD(self.quote_name(seq["table"])),
                style.SQL_KEYWORD('RESEED'),
                style.SQL_FIELD('%d' % seq['start_id']),
                style.SQL_KEYWORD('WITH'),
                style.SQL_KEYWORD('NO_INFOMSGS'),
            ) for seq in seqs])

        sql_list.extend(['ALTER TABLE %s CHECK CONSTRAINT %s;' %
                         (self.quote_name(fk[0]), self.quote_name(fk[1])) for fk in fks])
        return sql_list

    def start_transaction_sql(self):
        """
        Returns the SQL statement required to start a transaction.
        """
        return "BEGIN TRANSACTION"

    def subtract_temporals(self, internal_type, lhs, rhs):
        lhs_sql, lhs_params = lhs
        rhs_sql, rhs_params = rhs
        if internal_type == 'DateField':
            sql = "CAST(DATEDIFF(day, %(rhs)s, %(lhs)s) AS bigint) * 86400 * 1000000"
            params = rhs_params + lhs_params
        else:
            SECOND = "DATEDIFF(second, %(rhs)s, %(lhs)s)"
            MICROSECOND = "DATEPART(microsecond, %(lhs)s) - DATEPART(microsecond, %(rhs)s)"
            sql = "CAST({} AS bigint) * 1000000 + {}".format(SECOND, MICROSECOND)
            params = rhs_params + lhs_params * 2 + rhs_params
        return sql % {'lhs': lhs_sql, 'rhs': rhs_sql}, params

    def tablespace_sql(self, tablespace, inline=False):
        """
        Returns the SQL that will be appended to tables or rows to define
        a tablespace. Returns '' if the backend doesn't use tablespaces.
        """
        return "ON %s" % self.quote_name(tablespace)

    def prep_for_like_query(self, x):
        """Prepares a value for use in a LIKE query."""
        # http://msdn2.microsoft.com/en-us/library/ms179859.aspx
        return force_str(x).replace('\\', '\\\\').replace('[', '[[]').replace('%', '[%]').replace('_', '[_]')

    def prep_for_iexact_query(self, x):
        """
        Same as prep_for_like_query(), but called for "iexact" matches, which
        need not necessarily be implemented using "LIKE" in the backend.
        """
        return x

    def adapt_datetimefield_value(self, value):
        """
        Transforms a datetime value to an object compatible with what is expected
        by the backend driver for datetime columns.
        """
        if value is None:
            return None
        if settings.USE_TZ and timezone.is_aware(value):
            # pyodbc donesn't support datetimeoffset
            value = value.astimezone(self.connection.timezone).replace(tzinfo=None)
        return value

    def time_trunc_sql(self, lookup_type, field_name):
        # if self.connection.sql_server_version >= 2012:
        #    fields = {
        #        'hour': 'DATEPART(hour, %s)' % field_name,
        #        'minute': 'DATEPART(minute, %s)' % field_name if lookup_type != 'hour' else '0',
        #        'second': 'DATEPART(second, %s)' % field_name if lookup_type == 'second' else '0',
        #    }
        #    sql = 'TIMEFROMPARTS(%(hour)s, %(minute)s, %(second)s, 0, 0)' % fields
        if lookup_type == 'hour':
            sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 3) + ':00:00')" % field_name
        elif lookup_type == 'minute':
            sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 6) + ':00')" % field_name
        elif lookup_type == 'second':
            sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 9))" % field_name
        return sql

    def conditional_expression_supported_in_where_clause(self, expression):
        """
        Following "Moved conditional expression wrapping to the Exact lookup" in django 3.1
        https://github.com/django/django/commit/37e6c5b79bd0529a3c85b8c478e4002fd33a2a1d
        """
        if django.VERSION >= (3, 1):
            if isinstance(expression, (Exists, WhereNode)):
                return True
            if isinstance(expression, ExpressionWrapper) and expression.conditional:
                return self.conditional_expression_supported_in_where_clause(expression.expression)
            if isinstance(expression, RawSQL) and expression.conditional:
                return True
            return False
        return True


================================================
FILE: sql_server/pyodbc/schema.py
================================================
import binascii
import datetime
import django

from django.db.backends.base.schema import (
    BaseDatabaseSchemaEditor,
    _is_relevant_relation,
    _related_non_m2m_objects,
    logger,
)
from django.db.backends.ddl_references import (
    Columns,
    IndexName,
    Statement as DjStatement,
    Table,
)
from django.db.models import Index
from django.db.models.fields import AutoField, BigAutoField
from django.db.transaction import TransactionManagementError
from django.utils.encoding import force_str


class Statement(DjStatement):
    def __hash__(self):
        return hash((self.template, str(self.parts['name'])))

    def __eq__(self, other):
        return self.template == other.template and str(self.parts['name']) == str(other.parts['name'])


class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):

    _sql_check_constraint = " CONSTRAINT %(name)s CHECK (%(check)s)"
    _sql_select_default_constraint_name = "SELECT" \
                                          " d.name " \
                                          "FROM sys.default_constraints d " \
                                          "INNER JOIN sys.tables t ON" \
                                          " d.parent_object_id = t.object_id " \
                                          "INNER JOIN sys.columns c ON" \
                                          " d.parent_object_id = c.object_id AND" \
                                          " d.parent_column_id = c.column_id " \
                                          "INNER JOIN sys.schemas s ON" \
                                          " t.schema_id = s.schema_id " \
                                          "WHERE" \
                                          " t.name = %(table)s AND" \
                                          " c.name = %(column)s"
    _sql_select_foreign_key_constraints = "SELECT" \
                                          " po.name AS table_name," \
                                          " co.name AS constraint_name " \
                                          "FROM sys.foreign_key_columns fkc " \
                                          "INNER JOIN sys.objects co ON" \
                                          " fkc.constraint_object_id = co.object_id " \
                                          "INNER JOIN sys.tables po ON" \
                                          " fkc.parent_object_id = po.object_id " \
                                          "INNER JOIN sys.tables ro ON" \
                                          " fkc.referenced_object_id = ro.object_id " \
                                          "WHERE ro.name = %(table)s"
    sql_alter_column_default = "ADD DEFAULT %(default)s FOR %(column)s"
    sql_alter_column_no_default = "DROP CONSTRAINT %(column)s"
    sql_alter_column_not_null = "ALTER COLUMN %(column)s %(type)s NOT NULL"
    sql_alter_column_null = "ALTER COLUMN %(column)s %(type)s NULL"
    sql_alter_column_type = "ALTER COLUMN %(column)s %(type)s"
    sql_create_column = "ALTER TABLE %(table)s ADD %(column)s %(definition)s"
    sql_delete_column = "ALTER TABLE %(table)s DROP COLUMN %(column)s"
    sql_delete_index = "DROP INDEX %(name)s ON %(table)s"
    sql_delete_table = "DROP TABLE %(table)s"
    sql_rename_column = "EXEC sp_rename '%(table)s.%(old_column)s', %(new_column)s, 'COLUMN'"
    sql_rename_table = "EXEC sp_rename %(old_table)s, %(new_table)s"
    sql_create_unique_null = "CREATE UNIQUE INDEX %(name)s ON %(table)s(%(columns)s) " \
                             "WHERE %(columns)s IS NOT NULL"

    def _alter_column_default_sql(self, model, old_field, new_field, drop=False):
        """
        Hook to specialize column default alteration.

        Return a (sql, params) fragment to add or drop (depending on the drop
        argument) a default to new_field's column.
        """
        new_default = self.effective_default(new_field)
        default = '%s'
        params = [new_default]
        column = self.quote_name(new_field.column)

        if drop:
            params = []
            # SQL Server requires the name of the default constraint
            result = self.execute(
                self._sql_select_default_constraint_name % {
                    "table": self.quote_value(model._meta.db_table),
                    "column": self.quote_value(new_field.column),
                },
                has_result=True
            )
            if result:
                for row in result:
                    column = self.quote_name(next(iter(row)))
        elif self.connection.features.requires_literal_defaults:
            # Some databases (Oracle) can't take defaults as a parameter
            # If this is the case, the SchemaEditor for that database should
            # implement prepare_default().
            default = self.prepare_default(new_default)
            params = []

        new_db_params = new_field.db_parameters(connection=self.connection)
        sql = self.sql_alter_column_no_default if drop else self.sql_alter_column_default
        return (
            sql % {
                'column': column,
                'type': new_db_params['type'],
                'default': default,
            },
            params,
        )

    def _alter_column_null_sql(self, model, old_field, new_field):
        """
        Hook to specialize column null alteration.

        Return a (sql, params) fragment to set a column to null or non-null
        as required by new_field, or None if no changes are required.
        """
        if (self.connection.features.interprets_empty_strings_as_nulls and
                new_field.get_internal_type() in ("CharField", "TextField")):
            # The field is nullable in the database anyway, leave it alone.
            return
        else:
            new_db_params = new_field.db_parameters(connection=self.connection)
            sql = self.sql_alter_column_null if new_field.null else self.sql_alter_column_not_null
            return (
                sql % {
                    'column': self.quote_name(new_field.column),
                    'type': new_db_params['type'],
                },
                [],
            )

    def _alter_column_type_sql(self, model, old_field, new_field, new_type):
        new_type = self._set_field_new_type_null_status(old_field, new_type)
        return super()._alter_column_type_sql(model, old_field, new_field, new_type)

    def alter_unique_together(self, model, old_unique_together, new_unique_together):
        """
        Deal with a model changing its unique_together. The input
        unique_togethers must be doubly-nested, not the single-nested
        ["foo", "bar"] format.
        """
        olds = {tuple(fields) for fields in old_unique_together}
        news = {tuple(fields) for fields in new_unique_together}
        # Deleted uniques
        for fields in olds.difference(news):
            self._delete_composed_index(model, fields, {'unique': True}, self.sql_delete_index)
        # Created uniques
        for fields in news.difference(olds):
            columns = [model._meta.get_field(field).column for field in fields]
            condition = ' AND '.join(["[%s] IS NOT NULL" % col for col in columns])
            sql = self._create_unique_sql(model, columns, condition=condition)
            self.execute(sql)

    def _model_indexes_sql(self, model):
        """
        Return a list of all index SQL statements (field indexes,
        index_together, Meta.indexes) for the specified model.
        """
        if not model._meta.managed or model._meta.proxy or model._meta.swapped:
            return []
        output = []
        for field in model._meta.local_fields:
            output.extend(self._field_indexes_sql(model, field))

        for field_names in model._meta.index_together:
            fields = [model._meta.get_field(field) for field in field_names]
            output.append(self._create_index_sql(model, fields, suffix="_idx"))

        for field_names in model._meta.unique_together:
            columns = [model._meta.get_field(field).column for field in field_names]
            condition = ' AND '.join(["[%s] IS NOT NULL" % col for col in columns])
            sql = self._create_unique_sql(model, columns, condition=condition)
            output.append(sql)

        for index in model._meta.indexes:
            output.append(index.create_sql(model, self))
        return output

    def _alter_many_to_many(self, model, old_field, new_field, strict):
        """Alter M2Ms to repoint their to= endpoints."""

        for idx in self._constraint_names(old_field.remote_field.through, index=True, unique=True):
            self.execute(self.sql_delete_index % {'name': idx, 'table': old_field.remote_field.through._meta.db_table})

        return super()._alter_many_to_many(model, old_field, new_field, strict)

    def _db_table_constraint_names(self, db_table, column_names=None, unique=None,
                                   primary_key=None, index=None, foreign_key=None,
                                   check=None, type_=None, exclude=None):
        """Return all constraint names matching the columns and conditions."""
        if column_names is not None:
            column_names = [
                self.connection.introspection.identifier_converter(name)
                for name in column_names
            ]
        with self.connection.cursor() as cursor:
            constraints = self.connection.introspection.get_constraints(cursor, db_table)
        result = []
        for name, infodict in constraints.items():
            if column_names is None or column_names == infodict['columns']:
                if unique is not None and infodict['unique'] != unique:
                    continue
                if primary_key is not None and infodict['primary_key'] != primary_key:
                    continue
                if index is not None and infodict['index'] != index:
                    continue
                if check is not None and infodict['check'] != check:
                    continue
                if foreign_key is not None and not infodict['foreign_key']:
                    continue
                if type_ is not None and infodict['type'] != type_:
                    continue
                if not exclude or name not in exclude:
                    result.append(name)
        return result

    def _db_table_delete_constraint_sql(self, template, db_table, name):
        return Statement(
            template,
            table=Table(db_table, self.quote_name),
            name=self.quote_name(name),
        )

    def alter_db_table(self, model, old_db_table, new_db_table):
        index_names = self._db_table_constraint_names(old_db_table, index=True)
        for index_name in index_names:
            self.execute(self._db_table_delete_constraint_sql(self.sql_delete_index, old_db_table, index_name))

        index_names = self._db_table_constraint_names(new_db_table, index=True)
        for index_name in index_names:
            self.execute(self._db_table_delete_constraint_sql(self.sql_delete_index, new_db_table, index_name))

        return super().alter_db_table(model, old_db_table, new_db_table)

    def _alter_field(self, model, old_field, new_field, old_type, new_type,
                     old_db_params, new_db_params, strict=False):
        """Actually perform a "physical" (non-ManyToMany) field update."""

        # the backend doesn't support altering from/to (Big)AutoField
        # because of the limited capability of SQL Server to edit IDENTITY property
        for t in (AutoField, BigAutoField):
            if isinstance(old_field, t) or isinstance(new_field, t):
                raise NotImplementedError("the backend doesn't support altering from/to %s." % t.__name__)
        # Drop any FK constraints, we'll remake them later
        fks_dropped = set()
        if old_field.remote_field and old_field.db_constraint:
            # Drop index, SQL Server requires explicit deletion
            if not hasattr(new_field, 'db_constraint') or not new_field.db_constraint:
                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))

            fk_names = self._constraint_names(model, [old_field.column], foreign_key=True)
            if strict and len(fk_names) != 1:
                raise ValueError("Found wrong number (%s) of foreign key constraints for %s.%s" % (
                    len(fk_names),
                    model._meta.db_table,
                    old_field.column,
                ))
            for fk_name in fk_names:
                fks_dropped.add((old_field.column,))
                self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, fk_name))
        # Has unique been removed?
        if old_field.unique and (not new_field.unique or self._field_became_primary_key(old_field, new_field)):
            # Find the unique constraint for this field
            constraint_names = self._constraint_names(model, [old_field.column], unique=True, primary_key=False)
            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))
        # Drop incoming FK constraints if the field is a primary key or unique,
        # which might be a to_field target, and things are going to change.
        drop_foreign_keys = (
            (
                (old_field.primary_key and new_field.primary_key) or
                (old_field.unique and new_field.unique)
            ) and old_type != new_type
        )
        if drop_foreign_keys:
            # '_meta.related_field' also contains M2M reverse fields, these
            # will be filtered out
            for _old_rel, new_rel in _related_non_m2m_objects(old_field, new_field):
                rel_fk_names = self._constraint_names(
                    new_rel.related_model, [new_rel.field.column], foreign_key=True
                )
                for fk_name in rel_fk_names:
                    self.execute(self._delete_constraint_sql(self.sql_delete_fk, new_rel.related_model, fk_name))
        # Removed an index? (no strict check, as multiple indexes are possible)
        # Remove indexes if db_index switched to False or a unique constraint
        # will now be used in lieu of an index. The following lines from the
        # truth table show all True cases; the rest are False:
        #
        # old_field.db_index | old_field.unique | new_field.db_index | new_field.unique
        # ------------------------------------------------------------------------------
        # True               | False            | False              | False
        # True               | False            | False              | True
        # True               | False            | True               | True
        if (old_field.db_index and not old_field.unique and (not new_field.db_index or new_field.unique)) or (
                # Drop indexes on nvarchar columns that are changing to a different type
                # SQL Server requires explicit deletion
                (old_field.db_index or old_field.unique) and (
                    (old_type.startswith('nvarchar') and not new_type.startswith('nvarchar'))
                )):
            # Find the index for this field
            meta_index_names = {index.name for index in model._meta.indexes}
            # Retrieve only BTREE indexes since this is what's created with
            # db_index=True.
            index_names = self._constraint_names(model, [old_field.column], index=True, type_=Index.suffix)
            for index_name in index_names:
                if index_name not in meta_index_names:
                    # The only way to check if an index was created with
                    # db_index=True or with Index(['field'], name='foo')
                    # is to look at its name (refs #28053).
                    self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
        # Change check constraints?
        if (old_db_params['check'] != new_db_params['check'] and old_db_params['check']) or (
            # SQL Server requires explicit deletion befor altering column type with the same constraint
            old_db_params['check'] == new_db_params['check'] and old_db_params['check'] and
            old_db_params['type'] != new_db_params['type']
        ):
            constraint_names = self._constraint_names(model, [old_field.column], check=True)
            if strict and len(constraint_names) != 1:
                raise ValueError("Found wrong number (%s) of check 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_check, model, constraint_name))
        # Have they renamed the column?
        if old_field.column != new_field.column:
            # remove old indices
            self._delete_indexes(model, old_field, new_field)

            self.execute(self._rename_field_sql(model._meta.db_table, old_field, new_field, new_type))
            # Rename all references to the renamed column.
            for sql in self.deferred_sql:
                if isinstance(sql, DjStatement):
                    sql.rename_column_references(model._meta.db_table, old_field.column, new_field.column)

        # Next, start accumulating actions to do
        actions = []
        null_actions = []
        post_actions = []
        # Type change?
        if old_type != new_type:
            fragment, other_actions = self._alter_column_type_sql(model, old_field, new_field, new_type)
            actions.append(fragment)
            post_actions.extend(other_actions)
            # Drop unique constraint, SQL Server requires explicit deletion
            self._delete_unique_constraints(model, old_field, new_field, strict)
            # Drop indexes, SQL Server requires explicit deletion
            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
        #  2. Update existing NULL rows with new default
        #  3. Replace NULL constraint with NOT NULL
        #  4. Drop the default again.
        # Default change?
        old_default = self.effective_default(old_field)
        new_default = self.effective_default(new_field)
        needs_database_default = (
            old_field.null and
            not new_field.null and
            old_default != new_default and
            new_default is not None and
            not self.skip_default(new_field)
        )
        if needs_database_default:
            actions.append(self._alter_column_default_sql(model, old_field, new_field))
        # Nullability change?
        if old_field.null != new_field.null:
            fragment = self._alter_column_null_sql(model, old_field, new_field)
            if fragment:
                null_actions.append(fragment)
                if not new_field.null:
                    # Drop unique constraint, SQL Server requires explicit deletion
                    self._delete_unique_constraints(model, old_field, new_field, strict)
                    # Drop indexes, SQL Server requires explicit deletion
                    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
            (old_field.null and not new_field.null)
        )
        if actions or null_actions:
            if not four_way_default_alteration:
                # If we don't have to do a 4-way default alteration we can
                # directly run a (NOT) NULL alteration
                actions = actions + null_actions
            # Combine actions together if we can (e.g. postgres)
            if self.connection.features.supports_combined_alters and actions:
                sql, params = tuple(zip(*actions))
                actions = [(", ".join(sql), sum(params, []))]
            # Apply those actions
            for sql, params in actions:
                self._delete_indexes(model, old_field, new_field)
                self.execute(
                    self.sql_alter_column % {
                        "table": self.quote_name(model._meta.db_table),
                        "changes": sql,
                    },
                    params,
                )
            if four_way_default_alteration:
                # Update existing rows with default value
                self.execute(
                    self.sql_update_with_default % {
                        "table": self.quote_name(model._meta.db_table),
                        "column": self.quote_name(new_field.column),
                        "default": "%s",
                    },
                    [new_default],
                )
                # Since we didn't run a NOT NULL change before we need to do it
                # now
                for sql, params in null_actions:
                    self.execute(
                        self.sql_alter_column % {
                            "table": self.quote_name(model._meta.db_table),
                            "changes": sql,
                        },
                        params,
                    )
        if post_actions:
            for sql, params in post_actions:
                self.execute(sql, params)
        # If primary_key changed to False, delete the primary key constraint.
        if old_field.primary_key and not new_field.primary_key:
            self._delete_primary_key(model, strict)
        # Added a unique?
        if self._unique_should_be_added(old_field, new_field):
            if (self.connection.features.supports_nullable_unique_constraints and
                    not new_field.many_to_many and new_field.null):

                self.execute(
                    self._create_index_sql(
                        model, [new_field], sql=self.sql_create_unique_null, suffix="_uniq"
                    )
                )
            else:
                self.execute(self._create_unique_sql(model, [new_field.column]))
        # Added an index?
        # constraint will no longer be used in lieu of an index. The following
        # lines from the truth table show all True cases; the rest are False:
        #
        # old_field.db_index | old_field.unique | new_field.db_index | new_field.unique
        # ------------------------------------------------------------------------------
        # False              | False            | True               | False
        # False              | True             | True               | False
        # True               | True             | True               | False
        if (not old_field.db_index or old_field.unique) and new_field.db_index and not new_field.unique:
            self.execute(self._create_index_sql(model, [new_field]))

        # Restore indexes & unique constraints deleted above, SQL Server requires explicit restoration
        if (old_type != new_type or (old_field.null and not new_field.null)) and (
            old_field.column == new_field.column
        ):
            # Restore unique constraints
            # Note: if nullable they are implemented via an explicit filtered UNIQUE INDEX (not CONSTRAINT)
            # in order to get ANSI-compliant NULL behaviour (i.e. NULL != NULL, multiple are allowed)
            if old_field.unique and new_field.unique:
                if new_field.null:
                    self.execute(
                        self._create_index_sql(
                            model, [old_field], sql=self.sql_create_unique_null, suffix="_uniq"
                        )
                    )
                else:
                    self.execute(self._create_unique_sql(model, columns=[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:
                        condition = ' AND '.join(["[%s] IS NOT NULL" % col for col in columns])
                        self.execute(self._create_unique_sql(model, columns, condition=condition))
            # Restore indexes
            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 = []
        if old_field.primary_key and new_field.primary_key and old_type != new_type:
            rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
        # Changed to become primary key?
        if self._field_became_primary_key(old_field, new_field):
            # Make the new one
            self.execute(
                self.sql_create_pk % {
                    "table": self.quote_name(model._meta.db_table),
                    "name": self.quote_name(
                        self._create_index_name(model._meta.db_table, [new_field.column], suffix="_pk")
                    ),
                    "columns": self.quote_name(new_field.column),
                }
            )
            # Update all referencing columns
            rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
        # Handle our type alters on the other end of rels from the PK stuff above
        for old_rel, new_rel in rels_to_update:
            rel_db_params = new_rel.field.db_parameters(connection=self.connection)
            rel_type = rel_db_params['type']
            fragment, other_actions = self._alter_column_type_sql(
                new_rel.related_model, old_rel.field, new_rel.field, rel_type
            )
            self.execute(
                self.sql_alter_column % {
                    "table": self.quote_name(new_rel.related_model._meta.db_table),
                    "changes": fragment[0],
                },
                fragment[1],
            )
            for sql, params in other_actions:
                self.execute(sql, params)
        # Does it have a foreign key?
        if (new_field.remote_field and
                (fks_dropped or not old_field.remote_field or not old_field.db_constraint) and
                new_field.db_constraint):
            self.execute(self._create_fk_sql(model, new_field, "_fk_%(to_table)s_%(to_column)s"))
        # Rebuild FKs that pointed to us if we previously had to drop them
        if drop_foreign_keys:
            for rel in new_field.model._meta.related_objects:
                if _is_relevant_relation(rel, new_field) and rel.field.db_constraint:
                    self.execute(self._create_fk_sql(rel.related_model, rel.field, "_fk"))
        # Does it have check constraints we need to add?
        if (old_db_params['check'] != new_db_params['check'] and new_db_params['check']) or (
            # SQL Server requires explicit creation after altering column type with the same constraint
            old_db_params['check'] == new_db_params['check'] and new_db_params['check'] and
            old_db_params['type'] != new_db_params['type']
        ):
            self.execute(
                self.sql_create_check % {
                    "table": self.quote_name(model._meta.db_table),
                    "name": self.quote_name(
                        self._create_index_name(model._meta.db_table, [new_field.column], suffix="_check")
                    ),
                    "column": self.quote_name(new_field.column),
                    "check": new_db_params['check'],
                }
            )
        # Drop the default if we need to
        # (Django usually does not use in-database defaults)
        if needs_database_default:
            changes_sql, params = self._alter_column_default_sql(model, old_field, new_field, drop=True)
            sql = self.sql_alter_column % {
                "table": self.quote_name(model._meta.db_table),
                "changes": changes_sql,
            }
            self.execute(sql, params)

        # Reset connection if required
        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])
        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)

        for fields in model._meta.unique_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])
        if unique_columns:
            for columns in unique_columns:
                constraint_names_normal = self._constraint_names(model, columns, unique=True, index=False)
                constraint_names_index = self._constraint_names(model, columns, unique=True, index=True)
                constraint_names = constraint_names_normal + constraint_names_index
                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_normal:
                    self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))
                # Unique indexes which are not table constraints must be deleted using the appropriate SQL.
                # These may exist for example to enforce ANSI-compliant unique constraints on nullable columns.
                for index_name in constraint_names_index:
                    self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_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()._rename_field_sql(table, old_field, new_field, new_type)

    def _set_field_new_type_null_status(self, field, new_type):
        """
        Keep the null property of the old field. If it has changed, it will be
        handled separately.
        """
        if field.null:
            new_type += " NULL"
        else:
            new_type += " NOT NULL"
        return new_type

    def add_field(self, model, field):
        """
        Create a field on a model. Usually involves adding a column, but may
        involve adding a table instead (for M2M fields).
        """
        # Special-case implicit M2M tables
        if field.many_to_many and field.remote_field.through._meta.auto_created:
            return self.create_model(field.remote_field.through)
        # Get the column's definition
        definition, params = self.column_sql(model, field, include_default=True)
        # It might not actually have a column behind it
        if definition is None:
            return

        if (self.connection.features.supports_nullable_unique_constraints and
                not field.many_to_many and field.null and field.unique):

            definition = definition.replace(' UNIQUE', '')
            self.deferred_sql.append(self._create_index_sql(
                model, [field], sql=self.sql_create_unique_null, suffix="_uniq"
            ))

        # Check constraints can go on the column SQL here
        db_params = field.db_parameters(connection=self.connection)
        if db_params['check']:
            definition += " CHECK (%s)" % db_params['check']
        # Build the SQL and run it
        sql = self.sql_create_column % {
            "table": self.quote_name(model._meta.db_table),
            "column": self.quote_name(field.column),
            "definition": definition,
        }
        self.execute(sql, params)
        # Drop the default if we need to
        # (Django usually does not use in-database defaults)
        if not self.skip_default(field) and self.effective_default(field) is not None:
            changes_sql, params = self._alter_column_default_sql(model, None, field, drop=True)
            sql = self.sql_alter_column % {
                "table": self.quote_name(model._meta.db_table),
                "changes": changes_sql,
            }
            self.execute(sql, params)
        # Add an index, if required
        self.deferred_sql.extend(self._field_indexes_sql(model, field))
        # Add any FK constraints later
        if field.remote_field and self.connection.features.supports_foreign_keys and field.db_constraint:
            self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
        # Reset connection if required
        if self.connection.features.connection_persists_old_columns:
            self.connection.close()

    def _create_unique_sql(self, model, columns, name=None, condition=None, deferrable=None):
        if (deferrable and not getattr(self.connection.features, 'supports_deferrable_unique_constraints', False)):
            return None

        def create_unique_name(*args, **kwargs):
            return self.quote_name(self._create_index_name(*args, **kwargs))

        table = Table(model._meta.db_table, self.quote_name)
        if name is None:
            name = IndexName(model._meta.db_table, columns, '_uniq', create_unique_name)
        else:
            name = self.quote_name(name)
        columns = Columns(table, columns, self.quote_name)
        statement_args = {
            "deferrable": self._deferrable_constraint_sql(deferrable)
        } if django.VERSION >= (3, 1) else {}

        if condition:
            return Statement(
                self.sql_create_unique_index,
                table=table,
                name=name,
                columns=columns,
                condition=' WHERE ' + condition,
                **statement_args
            ) if self.connection.features.supports_partial_indexes else None
        else:
            return Statement(
                self.sql_create_unique,
                table=table,
                name=name,
                columns=columns,
                **statement_args
            )

    def _create_index_sql(self, model, fields, *, name=None, suffix='', using='',
                          db_tablespace=None, col_suffixes=(), sql=None, opclasses=(),
                          condition=None):
        """
        Return the SQL statement to create the index for one or several fields.
        `sql` can be specified if the syntax differs from the standard (GIS
        indexes, ...).
        """
        tablespace_sql = self._get_index_tablespace_sql(model, fields, db_tablespace=db_tablespace)
        columns = [field.column for field in fields]
        sql_create_index = sql or self.sql_create_index
        table = model._meta.db_table

        def create_index_name(*args, **kwargs):
            nonlocal name
            if name is None:
                name = self._create_index_name(*args, **kwargs)
            return self.quote_name(name)

        return Statement(
            sql_create_index,
            table=Table(table, self.quote_name),
            name=IndexName(table, columns, suffix, create_index_name),
            using=using,
            columns=self._index_columns(table, columns, col_suffixes, opclasses),
            extra=tablespace_sql,
            condition=(' WHERE ' + condition) if condition else '',
        )

    def create_model(self, model):
        """
        Takes a model and creates a table for it in the database.
        Will also create any accompanying indexes or unique constraints.
        """
        # Create column SQL, add FK deferreds if needed
        column_sqls = []
        params = []
        for field in model._meta.local_fields:
            # SQL
            definition, extra_params = self.column_sql(model, field)
            if definition is None:
                continue

            if (self.connection.features.supports_nullable_unique_constraints and
                    not field.many_to_many and field.null and field.unique):

                definition = definition.replace(' UNIQUE', '')
                self.deferred_sql.append(self._create_index_sql(
                    model, [field], sql=self.sql_create_unique_null, suffix="_uniq"
                ))

            # Check constraints can go on the column SQL here
            db_params = field.db_parameters(connection=self.connection)
            if db_params['check']:
                # SQL Server requires a name for the check constraint
                definition += self._sql_check_constraint % {
                    "name": self._create_index_name(model._meta.db_table, [field.column], suffix="_check"),
                    "check": db_params['check']
                }
            # Autoincrement SQL (for backends with inline variant)
            col_type_suffix = field.db_type_suffix(connection=self.connection)
            if col_type_suffix:
                definition += " %s" % col_type_suffix
            params.extend(extra_params)
            # FK
            if field.remote_field and field.db_constraint:
                to_table = field.remote_field.model._meta.db_table
                to_column = field.remote_field.model._meta.get_field(field.remote_field.field_name).column
                if self.sql_create_inline_fk:
                    definition += " " + self.sql_create_inline_fk % {
                        "to_table": self.quote_name(to_table),
                        "to_column": self.quote_name(to_column),
                    }
                elif self.connection.features.supports_foreign_keys:
                    self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
            # Add the SQL to our big list
            column_sqls.append("%s %s" % (
                self.quote_name(field.column),
                definition,
            ))
            # Autoincrement SQL (for backends with post table definition variant)
            if field.get_internal_type() in ("AutoField", "BigAutoField"):
                autoinc_sql = self.connection.ops.autoinc_sql(model._meta.db_table, field.column)
                if autoinc_sql:
                    self.deferred_sql.extend(autoinc_sql)

        # Add any unique_togethers (always deferred, as some fields might be
        # created afterwards, like geometry fields with some backends)
        for fields in model._meta.unique_together:
            columns = [model._meta.get_field(field).column for field in fields]
            condition = ' AND '.join(["[%s] IS NOT NULL" % col for col in columns])
            self.deferred_sql.append(self._create_unique_sql(model, columns, condition=condition))

        # Make the table
        sql = self.sql_create_table % {
            "table": self.quote_name(model._meta.db_table),
            "definition": ", ".join(column_sqls)
        }
        if model._meta.db_tablespace:
            tablespace_sql = self.connection.ops.tablespace_sql(model._meta.db_tablespace)
            if tablespace_sql:
                sql += ' ' + tablespace_sql
        # Prevent using [] as params, in the case a literal '%' is used in the definition
        self.execute(sql, params or None)

        # Add any field index and index_together's (deferred as SQLite3 _remake_table needs it)
        self.deferred_sql.extend(self._model_indexes_sql(model))
        self.deferred_sql = list(set(self.deferred_sql))

        # Make M2M tables
        for field in model._meta.local_many_to_many:
            if field.remote_field.through._meta.auto_created:
                self.create_model(field.remote_field.through)

    def delete_model(self, model):
        """
        Deletes a model from the database.
        """
        # Delete the foreign key constraints
        result = self.execute(
            self._sql_select_foreign_key_constraints % {
                "table": self.quote_value(model._meta.db_table),
            },
            has_result=True
        )
        if result:
            for table, constraint in result:
                sql = self.sql_alter_column % {
                    "table": self.quote_name(table),
                    "changes": self.sql_alter_column_no_default % {
                        "column": self.quote_name(constraint),
                    }
                }
                self.execute(sql)

        # Delete the table
        super().delete_model(model)
        # Remove all deferred statements referencing the deleted table.
        for sql in list(self.deferred_sql):
            if isinstance(sql, Statement) and sql.references_table(model._meta.db_table):
                self.deferred_sql.remove(sql)

    def execute(self, sql, params=(), has_result=False):
        """
        Executes the given SQL statement, with optional parameters.
        """
        result = None
        # Don't perform the transactional DDL check if SQL is being collected
        # as it's not going to be executed anyway.
        if not self.collect_sql and self.connection.in_atomic_block and not self.connection.features.can_rollback_ddl:
            raise TransactionManagementError(
                "Executing DDL statements while in a transaction on databases "
                "that can't perform a rollback is prohibited."
            )
        # Account for non-string statement objects.
        sql = str(sql)
        # Log the command we're running, then run it
        logger.debug("%s; (params %r)", sql, params, extra={'params': params, 'sql': sql})
        if self.collect_sql:
            ending = "" if sql.endswith(";") else ";"
            if params is not None:
                self.collected_sql.append((sql % tuple(map(self.quote_value, params))) + ending)
            else:
                self.collected_sql.append(sql + ending)
        else:
            cursor = self.connection.cursor()
            cursor.execute(sql, params)
            if has_result:
                result = cursor.fetchall()
            # the cursor can be closed only when the driver supports opening
            # multiple cursors on a connection because the migration command
            # has already opened a cursor outside this method
            if self.connection.supports_mars:
                cursor.close()
        return result

    def prepare_default(self, value):
        return self.quote_value(value)

    def quote_value(self, value):
        """
        Returns a quoted version of the value so it's safe to use in an SQL
        string. This is not safe against injection from user code; it is
        intended only for use in making SQL scripts or preparing default values
        for particularly tricky backends (defaults are not user-defined, though,
        so this is safe).
        """
        if isinstance(value, (datetime.datetime, datetime.date, datetime.time)):
            return "'%s'" % value
        elif isinstance(value, str):
            return "'%s'" % value.replace("'", "''")
        elif isinstance(value, (bytes, bytearray, memoryview)):
            return "0x%s" % force_str(binascii.hexlify(value))
        elif isinstance(value, bool):
            return "1" if value else "0"
        else:
            return str(value)

    def remove_field(self, model, field):
        """
        Removes a field from a model. Usually involves deleting a column,
        but for M2Ms may involve deleting a table.
        """
        # Special-case implicit M2M tables
        if field.many_to_many and field.remote_field.through._meta.auto_created:
            return self.delete_model(field.remote_field.through)
        # It might not actually have a column behind it
        if field.db_parameters(connection=self.connection)['type'] is None:
            return
        # 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
        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(name),
                })
        # Drop primary key constraint, SQL Server requires explicit deletion
        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(name),
                })
        # Drop check constraints, SQL Server requires explicit deletion
        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(name),
                })
        # Drop unique constraints, SQL Server requires explicit deletion
        for name, infodict in constraints.items():
            if (field.column in infodict['columns'] and infodict['unique'] and
                    not infodict['primary_key'] and not infodict['index']):
                self.execute(self.sql_delete_unique % {
                    "table": self.quote_name(model._meta.db_table),
                    "name": self.quote_name(name),
                })
        # Delete the column
        sql = self.sql_delete_column % {
            "table": self.quote_name(model._meta.db_table),
            "column": self.quote_name(field.column),
        }
        self.execute(sql)
        # Reset connection if required
        if self.connection.features.connection_persists_old_columns:
            self.connection.close()
        # Remove all deferred statements referencing the deleted column.
        for sql in list(self.deferred_sql):
            if isinstance(sql, Statement) and sql.references_column(model._meta.db_table, field.column):
                self.deferred_sql.remove(sql)


================================================
FILE: test.sh
================================================
# TODO:
#
# * m2m_through_regress
# * many_to_one_null

set -e

DJANGO_VERSION="$(python -m django --version)"

cd django
git fetch -q --depth=1 origin +refs/tags/*:refs/tags/*
git checkout -q $DJANGO_VERSION
pip install -q -r tests/requirements/py3.txt

python tests/runtests.py --settings=testapp.settings --noinput --keepdb \
    aggregation \
    aggregation_regress \
    annotations \
    backends \
    basic \
    bulk_create \
    constraints \
    custom_columns \
    custom_lookups \
    custom_managers \
    custom_methods \
    custom_migration_operations \
    custom_pk \
    datatypes \
    dates \
    datetimes \
    db_functions \
    db_typecasts \
    db_utils \
    dbshell \
    defer \
    defer_regress \
    delete \
    delete_regress \
    distinct_on_fields \
    empty \
    expressions \
    expressions_case \
    expressions_window \
    extra_regress \
    field_deconstruction \
    field_defaults \
    field_subclassing \
    filtered_relation \
    fixtures \
    fixtures_model_package \
    fixtures_regress \
    force_insert_update \
    foreign_object \
    from_db_value \
    generic_relations \
    generic_relations_regress \
    get_earliest_or_latest \
    get_object_or_404 \
    get_or_create \
    indexes \
    inspectdb \
    introspection \
    invalid_models_tests \
    known_related_objects \
    lookup \
    m2m_and_m2o \
    m2m_intermediary \
    m2m_multiple \
    m2m_recursive \
    m2m_regress \
    m2m_signals \
    m2m_through \
    m2o_recursive \
    managers_regress \
    many_to_many \
    many_to_one \
    max_lengths \
    migrate_signals \
    model_fields \
    model_indexes \
    model_options \
    mutually_referential \
    nested_foreign_keys \
    null_fk \
    null_fk_ordering \
    null_queries \
    one_to_one \
    or_lookups \
    order_with_respect_to \
    ordering \
    pagination \
    prefetch_related \
    queries \
    queryset_pickle \
    raw_query \
    reverse_lookup \
    save_delete_hooks \
    schema \
    select_for_update \
    select_related \
    select_related_onetoone \
    select_related_regress \
    transaction_hooks \
    transactions \
    update \
    update_only_fields


================================================
FILE: testapp/__init__.py
================================================


================================================
FILE: testapp/migrations/0001_initial.py
================================================
# Generated by Django 2.2.8.dev20191112211527 on 2019-11-15 01:38

import uuid

from django.db import migrations, models
import django


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Author',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=100)),
            ],
        ),
        migrations.CreateModel(
            name='Editor',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=100)),
            ],
        ),
        migrations.CreateModel(
            name='Post',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('title', models.CharField(max_length=255, verbose_name='title')),
            ],
        ),
        migrations.AddField(
            model_name='post',
            name='alt_editor',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='testapp.Editor'),
        ),
        migrations.AddField(
            model_name='post',
            name='author',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='testapp.Author'),
        ),
        migrations.AlterUniqueTogether(
            name='post',
            unique_together={('author', 'title', 'alt_editor')},
        ),
        migrations.CreateModel(
            name='Comment',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='testapp.Post')),
                ('text', models.TextField(verbose_name='text')),
                ('created_at', models.DateTimeField(default=django.utils.timezone.now)),
            ],
        ),
        migrations.CreateModel(
            name='UUIDModel',
            fields=[
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
            ],
        ),
    ]


================================================
FILE: testapp/migrations/0002_test_unique_nullable_part1.py
================================================
from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('testapp', '0001_initial'),
    ]

    operations = [
        # Issue #38 test prep
        # Create with a field that is unique *and* nullable so it is implemented with a filtered unique index.
        migrations.CreateModel(
            name='TestUniqueNullableModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('test_field', models.CharField(max_length=100, null=True, unique=True)),
            ],
        ),
    ]


================================================
FILE: testapp/migrations/0003_test_unique_nullable_part2.py
================================================
from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('testapp', '0002_test_unique_nullable_part1'),
    ]

    operations = [
        # Issue #38 test
        # Now remove the null=True to check this transition is correctly handled.
        migrations.AlterField(
            model_name='testuniquenullablemodel',
            name='test_field',
            field=models.CharField(default='', max_length=100, unique=True),
            preserve_default=False,
        ),
    ]


================================================
FILE: testapp/migrations/0004_test_issue45_unique_type_change_part1.py
================================================
from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('testapp', '0003_test_unique_nullable_part2'),
    ]

    # Issue #45 test prep
    operations = [
        # for case 1:
        migrations.AddField(
            model_name='testuniquenullablemodel',
            name='x',
            field=models.CharField(max_length=10, null=True, unique=True),
        ),

        # for case 2:
        migrations.CreateModel(
            name='TestNullableUniqueTogetherModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('a', models.CharField(max_length=50, null=True)),
                ('b', models.CharField(max_length=50)),
                ('c', models.CharField(max_length=50)),
            ],
            options={
                'unique_together': {('a', 'b')},
            },
        ),
    ]


================================================
FILE: testapp/migrations/0005_test_issue45_unique_type_change_part2.py
================================================
from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('testapp', '0004_test_issue45_unique_type_change_part1'),
    ]

    # Issue #45 test
    operations = [
        # Case 1: changing max_length changes the column type - the filtered UNIQUE INDEX which implements
        # the nullable unique constraint, should be correctly reinstated after this change of column type
        # (see also the specific unit test which checks that multiple rows with NULL are allowed)
        migrations.AlterField(
            model_name='testuniquenullablemodel',
            name='x',
            field=models.CharField(max_length=11, null=True, unique=True),
        ),

        # Case 2: the filtered UNIQUE INDEX implementing the partially nullable `unique_together` constraint
        # should be correctly reinstated after this column type change
        migrations.AlterField(
            model_name='testnullableuniquetogethermodel',
            name='a',
            field=models.CharField(max_length=51, null=True),
        ),
        # ...similarly adding another field to the `unique_together` should preserve the constraint correctly
        migrations.AlterUniqueTogether(
            name='testnullableuniquetogethermodel',
            unique_together={('a', 'b', 'c')},
        ),
    ]


================================================
FILE: testapp/migrations/0006_test_remove_onetoone_field_part1.py
================================================
# Generated by Django 3.0.4 on 2020-04-20 14:59

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('testapp', '0005_test_issue45_unique_type_change_part2'),
    ]

    operations = [
        migrations.CreateModel(
            name='TestRemoveOneToOneFieldModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('a', models.CharField(max_length=50)),
                ('b', models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, to='testapp.TestRemoveOneToOneFieldModel')),
            ],
        ),
    ]


================================================
FILE: testapp/migrations/0007_test_remove_onetoone_field_part2.py
================================================
# Generated by Django 3.0.4 on 2020-04-20 14:59

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('testapp', '0006_test_remove_onetoone_field_part1'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='testremoveonetoonefieldmodel',
            name='b',
        ),
    ]


================================================
FILE: testapp/migrations/__init__.py
================================================


================================================
FILE: testapp/models.py
================================================
import uuid

from django.db import models
from django.utils import timezone


class Author(models.Model):
    name = models.CharField(max_length=100)


class Editor(models.Model):
    name = models.CharField(max_length=100)


class Post(models.Model):
    title = models.CharField('title', max_length=255)
    author = models.ForeignKey(Author, models.CASCADE)
    # Optional secondary author
    alt_editor = models.ForeignKey(Editor, models.SET_NULL, blank=True, null=True)

    class Meta:
        unique_together = (
            ('author', 'title', 'alt_editor'),
        )

    def __str__(self):
        return self.title


class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    text = models.TextField('text')
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.text


class UUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    def __str__(self):
        return self.pk


class TestUniqueNullableModel(models.Model):
    # Issue #38:
    # This field started off as unique=True *and* null=True so it is implemented with a filtered unique index
    # Then it is made non-nullable by a subsequent migration, to check this is correctly handled (the index
    # should be dropped, then a normal unique constraint should be added, now that the column is not nullable)
    test_field = models.CharField(max_length=100, unique=True)

    # Issue #45 (case 1)
    # Field used for testing changing the 'type' of a field that's both unique & nullable
    x = models.CharField(max_length=11, null=True, unique=True)


class TestNullableUniqueTogetherModel(models.Model):
    class Meta:
        unique_together = (('a', 'b', 'c'),)

    # Issue #45 (case 2)
    # Fields used for testing changing the 'type of a field that is in a `unique_together`
    a = models.CharField(max_length=51, null=True)
    b = models.CharField(max_length=50)
    c = models.CharField(max_length=50)


class TestRemoveOneToOneFieldModel(models.Model):
    # Fields used for testing removing OneToOne field. Verifies that delete_unique do not try to remove indexes
    # thats already is removed.
    # b = models.OneToOneField('self', on_delete=models.SET_NULL, null=True)
    a = models.CharField(max_length=50)


================================================
FILE: testapp/runner.py
================================================
from unittest import skip
from django.test.runner import DiscoverRunner
from django.conf import settings


EXCLUDED_TESTS = getattr(settings, 'EXCLUDED_TESTS', [])


class ExcludeTestSuiteRunner(DiscoverRunner):
    def build_suite(self, *args, **kwargs):
        suite = super().build_suite(*args, **kwargs)
        for case in suite:
            cls = case.__class__
            for attr in dir(cls):
                if not attr.startswith('test_'):
                    continue
                fullname = f'{cls.__module__}.{cls.__name__}.{attr}'
                if len(list(filter(fullname.startswith, EXCLUDED_TESTS))):
                    setattr(cls, attr, skip('Does not work on MSSQL')(getattr(cls, attr)))

        return suite


================================================
FILE: testapp/settings.py
================================================
import dj_database_url

DATABASES = {
    'default': dj_database_url.config(default='sqlite:///db.sqlite'),
    'other': dj_database_url.config(env='DATABASE_URL_OTHER', default='sqlite:///db.sqlite'),
}

INSTALLED_APPS = (
    'django.contrib.contenttypes',
    'django.contrib.staticfiles',
    'django.contrib.auth',
    'sql_server.pyodbc',
    'testapp',
)


TEST_RUNNER = 'testapp.runner.ExcludeTestSuiteRunner'
EXCLUDED_TESTS = (
    'aggregation.tests.AggregateTestCase.test_aggregation_subquery_annotation_exists',
    'aggregation.tests.AggregateTestCase.test_aggregation_subquery_annotation_values_collision',
    'aggregation.tests.AggregateTestCase.test_count_star',
    'aggregation.tests.AggregateTestCase.test_distinct_on_aggregate',
    'aggregation.tests.AggregateTestCase.test_expression_on_aggregation',
    'aggregation_regress.tests.AggregationTests.test_annotated_conditional_aggregate',
    'aggregation_regress.tests.AggregationTests.test_annotation_with_value',
    'aggregation_regress.tests.AggregationTests.test_more_more',
    'aggregation_regress.tests.AggregationTests.test_more_more_more',
    'aggregation_regress.tests.AggregationTests.test_ticket_11293',
    'aggregation_regress.tests.AggregationTests.test_values_list_annotation_args_ordering',
    'annotations.tests.NonAggregateAnnotationTestCase.test_annotate_exists',
    'annotations.tests.NonAggregateAnnotationTestCase.test_combined_expression_annotation_with_aggregation',
    'backends.tests.BackendTestCase.test_queries',
    'backends.tests.BackendTestCase.test_unicode_password',
    'backends.tests.FkConstraintsTests.test_disable_constraint_checks_context_manager',
    'backends.tests.FkConstraintsTests.test_disable_constraint_checks_manually',
    'backends.tests.LastExecutedQueryTest.test_last_executed_query',
    'bulk_create.tests.BulkCreateTests.test_bulk_insert_nullable_fields',
    'constraints.tests.CheckConstraintTests.test_abstract_name',
    'constraints.tests.CheckConstraintTests.test_database_constraint',
    'constraints.tests.CheckConstraintTests.test_database_constraint_expression',
    'constraints.tests.CheckConstraintTests.test_database_constraint_expressionwrapper',
    'constraints.tests.CheckConstraintTests.test_name',
    'constraints.tests.UniqueConstraintTests.test_database_constraint',
    'constraints.tests.UniqueConstraintTests.test_database_constraint_with_condition',
    'constraints.tests.UniqueConstraintTests.test_name',
    'custom_lookups.tests.BilateralTransformTests.test_transform_order_by',
    'datatypes.tests.DataTypesTestCase.test_error_on_timezone',
    'datetimes.tests.DateTimesTests.test_datetimes_ambiguous_and_invalid_times',
    'datetimes.tests.DateTimesTests.test_datetimes_returns_available_dates_for_given_scope_and_given_field',
    'datetimes.tests.DateTimesTests.test_related_model_traverse',
    'db_functions.comparison.test_cast.CastTests.test_cast_to_integer',
    'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_func',
    'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_iso_weekday_func',
    'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_year_exact_lookup',
    'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_year_greaterthan_lookup',
    'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_year_lessthan_lookup',
    'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_func',
    'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_week_func',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_extract_func',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_extract_func_with_timezone',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_extract_iso_weekday_func',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_extract_year_exact_lookup',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_extract_year_greaterthan_lookup',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_extract_year_lessthan_lookup',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_ambiguous_and_invalid_times',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_func_with_timezone',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_none',
    'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_week_func',
    'db_functions.math.test_degrees.DegreesTests.test_integer',
    'db_functions.math.test_mod.ModTests.test_float',
    'db_functions.math.test_power.PowerTests.test_integer',
    'db_functions.math.test_radians.RadiansTests.test_integer',
    'db_functions.text.test_md5',
    'db_functions.text.test_pad.PadTests.test_pad',
    'db_functions.text.test_replace.ReplaceTests.test_case_sensitive',
    'db_functions.text.test_sha1',
    'db_functions.text.test_sha224',
    'db_functions.text.test_sha256',
    'db_functions.text.test_sha384',
    'db_functions.text.test_sha512',
    'dbshell.tests.DbshellCommandTestCase.test_command_missing',
    'defer_regress.tests.DeferRegressionTest.test_ticket_23270',
    'delete.tests.DeletionTests.test_only_referenced_fields_selected',
    'expressions.tests.BasicExpressionsTests.test_case_in_filter_if_boolean_output_field',
    'expressions.tests.BasicExpressionsTests.test_filtering_on_annotate_that_uses_q',
    'expressions.tests.BasicExpressionsTests.test_order_by_exists',
    'expressions.tests.BasicExpressionsTests.test_subquery_in_filter',
    'expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_right_shift_operator',
    'expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor',
    'expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_null',
    'expressions.tests.ExpressionOperatorTests.test_righthand_power',
    'expressions.tests.FTimeDeltaTests.test_date_subquery_subtraction',
    'expressions.tests.FTimeDeltaTests.test_datetime_subquery_subtraction',
    'expressions.tests.FTimeDeltaTests.test_datetime_subtraction_microseconds',
    'expressions.tests.FTimeDeltaTests.test_duration_with_datetime_microseconds',
    'expressions.tests.FTimeDeltaTests.test_invalid_operator',
    'expressions.tests.FTimeDeltaTests.test_time_subquery_subtraction',
    'expressions.tests.IterableLookupInnerExpressionsTests.test_expressions_in_lookups_join_choice',
    'expressions_case.tests.CaseExpressionTests.test_annotate_with_in_clause',
    'fixtures_regress.tests.TestFixtures.test_loaddata_raises_error_when_fixture_has_invalid_foreign_key',
    'fixtures_regress.tests.TestFixtures.test_loaddata_with_m2m_to_self',
    'fixtures_regress.tests.TestFixtures.test_loaddata_with_valid_fixture_dirs',
    'fixtures_regress.tests.TestFixtures.test_loaddata_works_when_fixture_has_forward_refs',
    'fixtures_regress.tests.TestFixtures.test_path_containing_dots',
    'fixtures_regress.tests.TestFixtures.test_pg_sequence_resetting_checks',
    'fixtures_regress.tests.TestFixtures.test_pretty_print_xml',
    'fixtures_regress.tests.TestFixtures.test_proxy_model_included',
    'fixtures_regress.tests.TestFixtures.test_relative_path',
    'fixtures_regress.tests.TestFixtures.test_relative_path_in_fixture_dirs',
    'fixtures_regress.tests.TestFixtures.test_ticket_20820',
    'fixtures_regress.tests.TestFixtures.test_ticket_22421',
    'get_or_create.tests.UpdateOrCreateTransactionTests.test_creation_in_transaction',
    'indexes.tests.PartialIndexTests.test_multiple_conditions',
    'indexes.tests.SchemaIndexesNotPostgreSQLTests.test_create_index_ignores_opclasses',
    'inspectdb.tests.InspectDBTestCase.test_introspection_errors',
    'introspection.tests.IntrospectionTests.test_get_constraints',
    'introspection.tests.IntrospectionTests.test_get_table_description_types',
    'introspection.tests.IntrospectionTests.test_smallautofield',
    'invalid_models_tests.test_ordinary_fields.TextFieldTests.test_max_length_warning',
    'migrate_signals.tests.MigrateSignalTests.test_migrations_only',
    'model_fields.test_integerfield.PositiveBigIntegerFieldTests',
    'model_fields.test_jsonfield',
    'model_indexes.tests.IndexesTests.test_db_tablespace',
    'ordering.tests.OrderingTests.test_deprecated_values_annotate',
    'ordering.tests.OrderingTests.test_order_by_fk_attname',
    'ordering.tests.OrderingTests.test_order_by_pk',
    'ordering.tests.OrderingTests.test_orders_nulls_first_on_filtered_subquery',
    'prefetch_related.tests.GenericRelationTests.test_prefetch_GFK_nonint_pk',
    'queries.test_bulk_update.BulkUpdateNoteTests.test_set_field_to_null',
    'queries.test_bulk_update.BulkUpdateTests.test_json_field',
    'queries.test_db_returning',
    'queries.test_qs_combinators.QuerySetSetOperationTests.test_limits',
    'queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_by_f_expression_and_alias',
    'schema.tests.SchemaTests.test_add_foreign_key_quoted_db_table',
    'schema.tests.SchemaTests.test_alter_auto_field_quoted_db_column',
    'schema.tests.SchemaTests.test_alter_auto_field_to_char_field',
    'schema.tests.SchemaTests.test_alter_auto_field_to_integer_field',
    'schema.tests.SchemaTests.test_alter_autofield_pk_to_bigautofield_pk_sequence_owner',
    'schema.tests.SchemaTests.test_alter_autofield_pk_to_smallautofield_pk_sequence_owner',
    'schema.tests.SchemaTests.test_alter_implicit_id_to_explicit',
    'schema.tests.SchemaTests.test_alter_int_pk_to_autofield_pk',
    'schema.tests.SchemaTests.test_alter_int_pk_to_bigautofield_pk',
    'schema.tests.SchemaTests.test_alter_pk_with_self_referential_field',
    'schema.tests.SchemaTests.test_alter_primary_key_quoted_db_table',
    'schema.tests.SchemaTests.test_alter_smallint_pk_to_smallautofield_pk',
    'schema.tests.SchemaTests.test_char_field_pk_to_auto_field',
    'schema.tests.SchemaTests.test_inline_fk',
    'schema.tests.SchemaTests.test_no_db_constraint_added_during_primary_key_change',
    'schema.tests.SchemaTests.test_remove_field_check_does_not_remove_meta_constraints',
    'schema.tests.SchemaTests.test_remove_field_unique_does_not_remove_meta_constraints',
    'schema.tests.SchemaTests.test_remove_unique_together_does_not_remove_meta_constraints',
    'schema.tests.SchemaTests.test_text_field_with_db_index',
    'schema.tests.SchemaTests.test_unique_and_reverse_m2m',
    'schema.tests.SchemaTests.test_unique_no_unnecessary_fk_drops',
    'schema.tests.SchemaTests.test_unique_together_with_fk',
    'schema.tests.SchemaTests.test_unique_together_with_fk_with_existing_index',
    'select_for_update.tests.SelectForUpdateTests.test_for_update_after_from',
)

SECRET_KEY = "django_tests_secret_key"

# Use a fast hasher to speed up tests.
PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.MD5PasswordHasher',
]


================================================
FILE: testapp/tests/__init__.py
================================================


================================================
FILE: testapp/tests/test_constraints.py
================================================
from django.db.utils import IntegrityError
from django.test import TestCase, skipUnlessDBFeature

from ..models import (
    Author, Editor, Post,
    TestUniqueNullableModel, TestNullableUniqueTogetherModel,
)


@skipUnlessDBFeature('supports_nullable_unique_constraints')
class TestNullableUniqueColumn(TestCase):
    def test_multiple_nulls(self):
        # Issue #45 (case 1) - after field `x` has had its type changed, the filtered UNIQUE
        # INDEX which is implementing the nullable unique constraint should still be correctly
        # in place - i.e. allowing multiple NULLs but still enforcing uniqueness of non-NULLs

        # Allowed
        TestUniqueNullableModel.objects.create(x=None, test_field='randomness')
        TestUniqueNullableModel.objects.create(x=None, test_field='doesntmatter')

        # Disallowed
        TestUniqueNullableModel.objects.create(x="foo", test_field='irrelevant')
        with self.assertRaises(IntegrityError):
            TestUniqueNullableModel.objects.create(x="foo", test_field='nonsense')


@skipUnlessDBFeature('supports_partially_nullable_unique_constraints')
class TestPartiallyNullableUniqueTogether(TestCase):
    def test_partially_nullable(self):
        # Check basic behaviour of `unique_together` where at least 1 of the columns is nullable

        # It should be possible to have 2 rows both with NULL `alt_editor`
        author = Author.objects.create(name="author")
        Post.objects.create(title="foo", author=author)
        Post.objects.create(title="foo", author=author)

        # But `unique_together` is still enforced for non-NULL values
        editor = Editor.objects.create(name="editor")
        Post.objects.create(title="foo", author=author, alt_editor=editor)
        with self.assertRaises(IntegrityError):
            Post.objects.create(title="foo", author=author, alt_editor=editor)

    def test_after_type_change(self):
        # Issue #45 (case 2) - after one of the fields in the `unique_together` has had its
        # type changed in a migration, the constraint should still be correctly enforced

        # Multiple rows with a=NULL are considered different
        TestNullableUniqueTogetherModel.objects.create(a=None, b='bbb', c='ccc')
        TestNullableUniqueTogetherModel.objects.create(a=None, b='bbb', c='ccc')

        # Uniqueness still enforced for non-NULL values
        TestNullableUniqueTogetherModel.objects.create(a='aaa', b='bbb', c='ccc')
        with self.assertRaises(IntegrityError):
            TestNullableUniqueTogetherModel.objects.create(a='aaa', b='bbb', c='ccc')


================================================
FILE: testapp/tests/test_expressions.py
================================================
from unittest import skipUnless

from django import VERSION
from django.db.models import IntegerField
from django.db.models.expressions import Case, Exists, OuterRef, Subquery, Value, When
from django.test import TestCase

from ..models import Author, Comment, Post

DJANGO3 = VERSION[0] >= 3


class TestSubquery(TestCase):
    def setUp(self):
        self.author = Author.objects.create(name="author")
        self.post = Post.objects.create(title="foo", author=self.author)

    def test_with_count(self):
        newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
        Post.objects.annotate(
            post_exists=Subquery(newest.values('text')[:1])
        ).filter(post_exists=True).count()


class TestExists(TestCase):
    def setUp(self):
        self.author = Author.objects.create(name="author")
        self.post = Post.objects.create(title="foo", author=self.author)

    def test_with_count(self):
        Post.objects.annotate(
            post_exists=Exists(Post.objects.all())
        ).filter(post_exists=True).count()

    @skipUnless(DJANGO3, "Django 3 specific tests")
    def test_with_case_when(self):
        author = Author.objects.annotate(
            has_post=Case(
                When(Exists(Post.objects.filter(author=OuterRef('pk')).values('pk')), then=Value(1)),
                default=Value(0),
                output_field=IntegerField(),
            )
        ).get()
        self.assertEqual(author.has_post, 1)

    @skipUnless(DJANGO3, "Django 3 specific tests")
    def test_order_by_exists(self):
        author_without_posts = Author.objects.create(name="other author")
        authors_by_posts = Author.objects.order_by(Exists(Post.objects.filter(author=OuterRef('pk'))).desc())
        self.assertSequenceEqual(authors_by_posts, [self.author, author_without_posts])

        authors_by_posts = Author.objects.order_by(Exists(Post.objects.filter(author=OuterRef('pk'))).asc())
        self.assertSequenceEqual(authors_by_posts, [author_without_posts, self.author])


================================================
FILE: testapp/tests/test_fields.py
================================================
from django.test import TestCase

from ..models import UUIDModel


class TestUUIDField(TestCase):
    def test_create(self):
        UUIDModel.objects.create()


================================================
FILE: tox.ini
================================================
[tox]
envlist =
       {py36,py37}-django22,
       {py36,py37,py38}-django30,
       {py36,py37,py38}-django31,

[testenv]
passenv =
    DATABASE_URL
    DATABASE_URL_OTHER

whitelist_externals =
    /bin/bash

commands =
    python manage.py test --keepdb
    python manage.py install_regex_clr test_default
    bash test.sh

deps =
    django22: django==2.2.*
    django30: django>=3.0a1,<3.1
    django31: django>=3.1,<3.2
    dj-database-url==0.5.0
Download .txt
gitextract_g2cq4foq/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── MANIFEST.in
├── README.rst
├── docker/
│   ├── Dockerfile
│   └── docker-compose.yml
├── manage.py
├── setup.cfg
├── setup.py
├── sql_server/
│   ├── __init__.py
│   └── pyodbc/
│       ├── __init__.py
│       ├── base.py
│       ├── client.py
│       ├── compiler.py
│       ├── creation.py
│       ├── features.py
│       ├── functions.py
│       ├── introspection.py
│       ├── management/
│       │   ├── __init__.py
│       │   └── commands/
│       │       ├── __init__.py
│       │       └── install_regex_clr.py
│       ├── operations.py
│       └── schema.py
├── test.sh
├── testapp/
│   ├── __init__.py
│   ├── migrations/
│   │   ├── 0001_initial.py
│   │   ├── 0002_test_unique_nullable_part1.py
│   │   ├── 0003_test_unique_nullable_part2.py
│   │   ├── 0004_test_issue45_unique_type_change_part1.py
│   │   ├── 0005_test_issue45_unique_type_change_part2.py
│   │   ├── 0006_test_remove_onetoone_field_part1.py
│   │   ├── 0007_test_remove_onetoone_field_part2.py
│   │   └── __init__.py
│   ├── models.py
│   ├── runner.py
│   ├── settings.py
│   └── tests/
│       ├── __init__.py
│       ├── test_constraints.py
│       ├── test_expressions.py
│       └── test_fields.py
└── tox.ini
Download .txt
SYMBOL INDEX (216 symbols across 22 files)

FILE: sql_server/pyodbc/base.py
  function encode_connection_string (line 41) | def encode_connection_string(fields):
  function encode_value (line 55) | def encode_value(v):
  class DatabaseWrapper (line 64) | class DatabaseWrapper(BaseDatabaseWrapper):
    method __init__ (line 176) | def __init__(self, *args, **kwargs):
    method create_cursor (line 211) | def create_cursor(self, name=None):
    method _cursor (line 214) | def _cursor(self):
    method get_connection_params (line 229) | def get_connection_params(self):
    method get_new_connection (line 240) | def get_new_connection(self, conn_params):
    method init_connection_state (line 333) | def init_connection_state(self):
    method is_usable (line 375) | def is_usable(self):
    method get_system_datetime (line 383) | def get_system_datetime(self):
    method sql_server_version (line 392) | def sql_server_version(self, _known_versions={}):
    method to_azure_sql_db (line 412) | def to_azure_sql_db(self, _known_azures={}):
    method _execute_foreach (line 427) | def _execute_foreach(self, sql, table_names=None):
    method _get_trancount (line 434) | def _get_trancount(self):
    method _on_error (line 438) | def _on_error(self, e):
    method _savepoint (line 449) | def _savepoint(self, sid):
    method _savepoint_commit (line 457) | def _savepoint_commit(self, sid):
    method _savepoint_rollback (line 461) | def _savepoint_rollback(self, sid):
    method _set_autocommit (line 469) | def _set_autocommit(self, autocommit):
    method check_constraints (line 478) | def check_constraints(self, table_names=None):
    method disable_constraint_checking (line 482) | def disable_constraint_checking(self):
    method enable_constraint_checking (line 487) | def enable_constraint_checking(self):
  class CursorWrapper (line 492) | class CursorWrapper(object):
    method __init__ (line 498) | def __init__(self, cursor, connection):
    method close (line 506) | def close(self):
    method format_sql (line 511) | def format_sql(self, sql, params):
    method format_params (line 523) | def format_params(self, params):
    method execute (line 549) | def execute(self, sql, params=None):
    method executemany (line 560) | def executemany(self, sql, params_list=()):
    method format_rows (line 572) | def format_rows(self, rows):
    method format_row (line 575) | def format_row(self, row):
    method fetchone (line 589) | def fetchone(self):
    method fetchmany (line 599) | def fetchmany(self, chunk):
    method fetchall (line 602) | def fetchall(self):
    method __getattr__ (line 605) | def __getattr__(self, attr):
    method __iter__ (line 610) | def __iter__(self):

FILE: sql_server/pyodbc/client.py
  class DatabaseClient (line 7) | class DatabaseClient(BaseDatabaseClient):
    method runshell (line 10) | def runshell(self):

FILE: sql_server/pyodbc/compiler.py
  function _as_sql_agv (line 15) | def _as_sql_agv(self, compiler, connection):
  function _as_sql_chr (line 19) | def _as_sql_chr(self, compiler, connection):
  function _as_sql_concatpair (line 23) | def _as_sql_concatpair(self, compiler, connection):
  function _as_sql_count (line 31) | def _as_sql_count(self, compiler, connection):
  function _as_sql_greatest (line 35) | def _as_sql_greatest(self, compiler, connection):
  function _as_sql_least (line 43) | def _as_sql_least(self, compiler, connection):
  function _as_sql_length (line 51) | def _as_sql_length(self, compiler, connection):
  function _as_sql_lpad (line 55) | def _as_sql_lpad(self, compiler, connection):
  function _as_sql_repeat (line 73) | def _as_sql_repeat(self, compiler, connection):
  function _as_sql_rpad (line 77) | def _as_sql_rpad(self, compiler, connection):
  function _as_sql_stddev (line 91) | def _as_sql_stddev(self, compiler, connection):
  function _as_sql_strindex (line 98) | def _as_sql_strindex(self, compiler, connection):
  function _as_sql_substr (line 105) | def _as_sql_substr(self, compiler, connection):
  function _as_sql_trim (line 111) | def _as_sql_trim(self, compiler, connection):
  function _as_sql_variance (line 115) | def _as_sql_variance(self, compiler, connection):
  function _cursor_iter (line 122) | def _cursor_iter(cursor, sentinel, col_count, itersize):
  class SQLCompiler (line 151) | class SQLCompiler(compiler.SQLCompiler):
    method as_sql (line 153) | def as_sql(self, with_limits=True, with_col_aliases=False):
    method compile (line 356) | def compile(self, node, *args, **kwargs):
    method collapse_group_by (line 360) | def collapse_group_by(self, expressions, having):
    method _as_microsoft (line 364) | def _as_microsoft(self, node):
  class SQLInsertCompiler (line 402) | class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler):
    method get_returned_fields (line 403) | def get_returned_fields(self):
    method fix_auto (line 408) | def fix_auto(self, sql, opts, fields, qn):
    method as_sql (line 423) | def as_sql(self):
  class SQLDeleteCompiler (line 474) | class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler):
    method as_sql (line 475) | def as_sql(self):
  class SQLUpdateCompiler (line 482) | class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler):
    method as_sql (line 483) | def as_sql(self):
  class SQLAggregateCompiler (line 490) | class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler):

FILE: sql_server/pyodbc/creation.py
  class DatabaseCreation (line 8) | class DatabaseCreation(BaseDatabaseCreation):
    method cursor (line 10) | def cursor(self):
    method _destroy_test_db (line 16) | def _destroy_test_db(self, test_database_name, verbosity):
    method sql_table_creation_suffix (line 32) | def sql_table_creation_suffix(self):
    method enable_clr (line 41) | def enable_clr(self):
    method install_regex_clr (line 69) | def install_regex_clr(self, database_name):
    method get_regex_clr_assembly_hex (line 100) | def get_regex_clr_assembly_hex(self):

FILE: sql_server/pyodbc/features.py
  class DatabaseFeatures (line 5) | class DatabaseFeatures(BaseDatabaseFeatures):
    method has_bulk_insert (line 44) | def has_bulk_insert(self):
    method supports_nullable_unique_constraints (line 48) | def supports_nullable_unique_constraints(self):
    method supports_partially_nullable_unique_constraints (line 52) | def supports_partially_nullable_unique_constraints(self):
    method supports_partial_indexes (line 56) | def supports_partial_indexes(self):
    method supports_functions_in_partial_indexes (line 60) | def supports_functions_in_partial_indexes(self):
    method introspected_field_types (line 64) | def introspected_field_types(self):

FILE: sql_server/pyodbc/functions.py
  class TryCast (line 11) | class TryCast(Cast):
  function sqlserver_as_sql (line 15) | def sqlserver_as_sql(self, compiler, connection, template=None, **extra_...
  function sqlserver_atan2 (line 43) | def sqlserver_atan2(self, compiler, connection, **extra_context):
  function sqlserver_log (line 47) | def sqlserver_log(self, compiler, connection, **extra_context):
  function sqlserver_ln (line 53) | def sqlserver_ln(self, compiler, connection, **extra_context):
  function sqlserver_mod (line 57) | def sqlserver_mod(self, compiler, connection, **extra_context):
  function sqlserver_round (line 61) | def sqlserver_round(self, compiler, connection, **extra_context):
  function sqlserver_exists (line 65) | def sqlserver_exists(self, compiler, connection, template=None, **extra_...
  function sqlserver_lookup (line 74) | def sqlserver_lookup(self, compiler, connection):
  function sqlserver_orderby (line 88) | def sqlserver_orderby(self, compiler, connection):

FILE: sql_server/pyodbc/introspection.py
  class DatabaseIntrospection (line 15) | class DatabaseIntrospection(BaseDatabaseIntrospection):
    method get_field_type (line 48) | def get_field_type(self, data_type, description):
    method get_table_list (line 61) | def get_table_list(self, cursor):
    method _is_auto_field (line 72) | def _is_auto_field(self, cursor, table_name, column_name):
    method get_table_description (line 85) | def get_table_description(self, cursor, table_name, identity_check=True):
    method get_sequences (line 113) | def get_sequences(self, cursor, table_name, table_fields=()):
    method get_relations (line 124) | def get_relations(self, cursor, table_name):
    method get_key_columns (line 151) | def get_key_columns(self, cursor, table_name):
    method get_constraints (line 168) | def get_constraints(self, cursor, table_name):

FILE: sql_server/pyodbc/management/commands/install_regex_clr.py
  class Command (line 8) | class Command(BaseCommand):
    method add_arguments (line 15) | def add_arguments(self, parser):
    method handle (line 18) | def handle(self, *args, **options):

FILE: sql_server/pyodbc/operations.py
  class DatabaseOperations (line 17) | class DatabaseOperations(BaseDatabaseOperations):
    method _convert_field_to_tz (line 22) | def _convert_field_to_tz(self, field_name, tzname):
    method _get_utcoffset (line 28) | def _get_utcoffset(self, tzname):
    method bulk_batch_size (line 40) | def bulk_batch_size(self, fields, objs):
    method bulk_insert_sql (line 53) | def bulk_insert_sql(self, fields, placeholder_rows):
    method cache_key_culling_sql (line 58) | def cache_key_culling_sql(self):
    method combine_duration_expression (line 70) | def combine_duration_expression(self, connector, sub_expressions):
    method combine_expression (line 81) | def combine_expression(self, connector, sub_expressions):
    method convert_datetimefield_value (line 93) | def convert_datetimefield_value(self, value, expression, connection):
    method convert_floatfield_value (line 99) | def convert_floatfield_value(self, value, expression, connection):
    method convert_uuidfield_value (line 104) | def convert_uuidfield_value(self, value, expression, connection):
    method convert_booleanfield_value (line 109) | def convert_booleanfield_value(self, value, expression, connection):
    method date_extract_sql (line 112) | def date_extract_sql(self, lookup_type, field_name):
    method date_interval_sql (line 122) | def date_interval_sql(self, timedelta):
    method date_trunc_sql (line 132) | def date_trunc_sql(self, lookup_type, field_name):
    method datetime_cast_date_sql (line 149) | def datetime_cast_date_sql(self, field_name, tzname):
    method datetime_cast_time_sql (line 154) | def datetime_cast_time_sql(self, field_name, tzname):
    method datetime_extract_sql (line 159) | def datetime_extract_sql(self, lookup_type, field_name, tzname):
    method datetime_trunc_sql (line 163) | def datetime_trunc_sql(self, lookup_type, field_name, tzname):
    method for_update_sql (line 176) | def for_update_sql(self, nowait=False, skip_locked=False, of=()):
    method format_for_duration_arithmetic (line 184) | def format_for_duration_arithmetic(self, sql):
    method fulltext_search_sql (line 196) | def fulltext_search_sql(self, field_name):
    method get_db_converters (line 204) | def get_db_converters(self, expression):
    method last_insert_id (line 217) | def last_insert_id(self, cursor, table_name, pk_name):
    method lookup_cast (line 244) | def lookup_cast(self, lookup_type, internal_type=None):
    method max_name_length (line 249) | def max_name_length(self):
    method no_limit_value (line 252) | def no_limit_value(self):
    method prepare_sql_script (line 255) | def prepare_sql_script(self, sql, _allow_fallback=False):
    method quote_name (line 258) | def quote_name(self, name):
    method random_function_sql (line 267) | def random_function_sql(self):
    method regex_lookup (line 273) | def regex_lookup(self, lookup_type):
    method limit_offset_sql (line 285) | def limit_offset_sql(self, low_mark, high_mark):
    method last_executed_query (line 293) | def last_executed_query(self, cursor, sql, params):
    method savepoint_create_sql (line 305) | def savepoint_create_sql(self, sid):
    method savepoint_rollback_sql (line 313) | def savepoint_rollback_sql(self, sid):
    method _build_sequences (line 319) | def _build_sequences(self, sequences, cursor):
    method _sql_flush_new (line 333) | def _sql_flush_new(self, style, tables, *, reset_sequences=False, allo...
    method _sql_flush_old (line 342) | def _sql_flush_old(self, style, tables, sequences, allow_cascade=False):
    method sql_flush (line 345) | def sql_flush(self, style, tables, *args, **kwargs):
    method start_transaction_sql (line 404) | def start_transaction_sql(self):
    method subtract_temporals (line 410) | def subtract_temporals(self, internal_type, lhs, rhs):
    method tablespace_sql (line 423) | def tablespace_sql(self, tablespace, inline=False):
    method prep_for_like_query (line 430) | def prep_for_like_query(self, x):
    method prep_for_iexact_query (line 435) | def prep_for_iexact_query(self, x):
    method adapt_datetimefield_value (line 442) | def adapt_datetimefield_value(self, value):
    method time_trunc_sql (line 454) | def time_trunc_sql(self, lookup_type, field_name):
    method conditional_expression_supported_in_where_clause (line 470) | def conditional_expression_supported_in_where_clause(self, expression):

FILE: sql_server/pyodbc/schema.py
  class Statement (line 23) | class Statement(DjStatement):
    method __hash__ (line 24) | def __hash__(self):
    method __eq__ (line 27) | def __eq__(self, other):
  class DatabaseSchemaEditor (line 31) | class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
    method _alter_column_default_sql (line 72) | def _alter_column_default_sql(self, model, old_field, new_field, drop=...
    method _alter_column_null_sql (line 115) | def _alter_column_null_sql(self, model, old_field, new_field):
    method _alter_column_type_sql (line 137) | def _alter_column_type_sql(self, model, old_field, new_field, new_type):
    method alter_unique_together (line 141) | def alter_unique_together(self, model, old_unique_together, new_unique...
    method _model_indexes_sql (line 159) | def _model_indexes_sql(self, model):
    method _alter_many_to_many (line 184) | def _alter_many_to_many(self, model, old_field, new_field, strict):
    method _db_table_constraint_names (line 192) | def _db_table_constraint_names(self, db_table, column_names=None, uniq...
    method _db_table_delete_constraint_sql (line 222) | def _db_table_delete_constraint_sql(self, template, db_table, name):
    method alter_db_table (line 229) | def alter_db_table(self, model, old_db_table, new_db_table):
    method _alter_field (line 240) | def _alter_field(self, model, old_field, new_field, old_type, new_type,
    method _delete_indexes (line 574) | def _delete_indexes(self, model, old_field, new_field):
    method _delete_unique_constraints (line 593) | def _delete_unique_constraints(self, model, old_field, new_field, stri...
    method _rename_field_sql (line 615) | def _rename_field_sql(self, table, old_field, new_field, new_type):
    method _set_field_new_type_null_status (line 619) | def _set_field_new_type_null_status(self, field, new_type):
    method add_field (line 630) | def add_field(self, model, field):
    method _create_unique_sql (line 681) | def _create_unique_sql(self, model, columns, name=None, condition=None...
    method _create_index_sql (line 716) | def _create_index_sql(self, model, fields, *, name=None, suffix='', us...
    method create_model (line 745) | def create_model(self, model):
    method delete_model (line 830) | def delete_model(self, model):
    method execute (line 858) | def execute(self, sql, params=(), has_result=False):
    method prepare_default (line 892) | def prepare_default(self, value):
    method quote_value (line 895) | def quote_value(self, value):
    method remove_field (line 914) | def remove_field(self, model, field):

FILE: testapp/migrations/0001_initial.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: testapp/migrations/0002_test_unique_nullable_part1.py
  class Migration (line 4) | class Migration(migrations.Migration):

FILE: testapp/migrations/0003_test_unique_nullable_part2.py
  class Migration (line 4) | class Migration(migrations.Migration):

FILE: testapp/migrations/0004_test_issue45_unique_type_change_part1.py
  class Migration (line 4) | class Migration(migrations.Migration):

FILE: testapp/migrations/0005_test_issue45_unique_type_change_part2.py
  class Migration (line 4) | class Migration(migrations.Migration):

FILE: testapp/migrations/0006_test_remove_onetoone_field_part1.py
  class Migration (line 7) | class Migration(migrations.Migration):

FILE: testapp/migrations/0007_test_remove_onetoone_field_part2.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: testapp/models.py
  class Author (line 7) | class Author(models.Model):
  class Editor (line 11) | class Editor(models.Model):
  class Post (line 15) | class Post(models.Model):
    class Meta (line 21) | class Meta:
    method __str__ (line 26) | def __str__(self):
  class Comment (line 30) | class Comment(models.Model):
    method __str__ (line 35) | def __str__(self):
  class UUIDModel (line 39) | class UUIDModel(models.Model):
    method __str__ (line 42) | def __str__(self):
  class TestUniqueNullableModel (line 46) | class TestUniqueNullableModel(models.Model):
  class TestNullableUniqueTogetherModel (line 58) | class TestNullableUniqueTogetherModel(models.Model):
    class Meta (line 59) | class Meta:
  class TestRemoveOneToOneFieldModel (line 69) | class TestRemoveOneToOneFieldModel(models.Model):

FILE: testapp/runner.py
  class ExcludeTestSuiteRunner (line 9) | class ExcludeTestSuiteRunner(DiscoverRunner):
    method build_suite (line 10) | def build_suite(self, *args, **kwargs):

FILE: testapp/tests/test_constraints.py
  class TestNullableUniqueColumn (line 11) | class TestNullableUniqueColumn(TestCase):
    method test_multiple_nulls (line 12) | def test_multiple_nulls(self):
  class TestPartiallyNullableUniqueTogether (line 28) | class TestPartiallyNullableUniqueTogether(TestCase):
    method test_partially_nullable (line 29) | def test_partially_nullable(self):
    method test_after_type_change (line 43) | def test_after_type_change(self):

FILE: testapp/tests/test_expressions.py
  class TestSubquery (line 13) | class TestSubquery(TestCase):
    method setUp (line 14) | def setUp(self):
    method test_with_count (line 18) | def test_with_count(self):
  class TestExists (line 25) | class TestExists(TestCase):
    method setUp (line 26) | def setUp(self):
    method test_with_count (line 30) | def test_with_count(self):
    method test_with_case_when (line 36) | def test_with_case_when(self):
    method test_order_by_exists (line 47) | def test_order_by_exists(self):

FILE: testapp/tests/test_fields.py
  class TestUUIDField (line 6) | class TestUUIDField(TestCase):
    method test_create (line 7) | def test_create(self):
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (197K chars).
[
  {
    "path": ".editorconfig",
    "chars": 230,
    "preview": "# https://editorconfig.org/\n\nroot = true\n\n[*]\nindent_style = space\nindent_size = 4\ninsert_final_newline = true\ntrim_trai"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 3457,
    "preview": "name: Tests\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n\nenv:\n  DATABASE_URL:"
  },
  {
    "path": ".gitignore",
    "chars": 115,
    "preview": "*.py[co]\n*.sw[a-z]\n*.orig\n*~\n.DS_Store\nThumbs.db\n\n*.egg-info\n\ntests/local_settings.py\n\n# Virtual Env\n/venv/\n.idea/\n"
  },
  {
    "path": ".travis.yml",
    "chars": 3689,
    "preview": "sudo: required\nlanguage: python\ndist: xenial\ncache: pip\n\nbranches:\n  only:\n    - master\n\nenv:\n  global:\n    - PYTHONPATH"
  },
  {
    "path": "LICENSE",
    "chars": 1515,
    "preview": "BSD 3-Clause License\n\nCopyright (c) 2019, ES Solutions AB\nAll rights reserved.\n\nRedistribution and use in source and bin"
  },
  {
    "path": "MANIFEST.in",
    "chars": 116,
    "preview": "include LICENSE\ninclude MANIFEST.in\ninclude README.rst\nrecursive-include sql_server *.py\nrecursive-exclude docker *\n"
  },
  {
    "path": "README.rst",
    "chars": 6715,
    "preview": "django-mssql-backend\n====================\n\n.. image:: https://img.shields.io/pypi/v/django-mssql-backend.svg\n   :target:"
  },
  {
    "path": "docker/Dockerfile",
    "chars": 655,
    "preview": "FROM python:3.7\n\nENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn\n\nRUN apt-get update && apt-get install -y apt-transpo"
  },
  {
    "path": "docker/docker-compose.yml",
    "chars": 605,
    "preview": "version: \"3.3\"\n\nservices:\n  app:\n    build:\n      context: ..\n      dockerfile: docker/Dockerfile\n    volumes:\n      - ."
  },
  {
    "path": "manage.py",
    "chars": 250,
    "preview": "#!/usr/bin/env python\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE"
  },
  {
    "path": "setup.cfg",
    "chars": 122,
    "preview": "[flake8]\nexclude = .git,__pycache__,migrations\n# W504 is mutually exclusive with W503\nignore = W504\nmax-line-length = 11"
  },
  {
    "path": "setup.py",
    "chars": 1027,
    "preview": "from setuptools import find_packages, setup\n\nCLASSIFIERS = [\n    'License :: OSI Approved :: BSD License',\n    'Framewor"
  },
  {
    "path": "sql_server/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "sql_server/pyodbc/__init__.py",
    "chars": 43,
    "preview": "import sql_server.pyodbc.functions  # noqa\n"
  },
  {
    "path": "sql_server/pyodbc/base.py",
    "chars": 22862,
    "preview": "\"\"\"\nMS SQL Server database backend for Django.\n\"\"\"\nimport os\nimport re\nimport time\n\nfrom django.core.exceptions import I"
  },
  {
    "path": "sql_server/pyodbc/client.py",
    "chars": 1732,
    "preview": "import re\nimport subprocess\n\nfrom django.db.backends.base.client import BaseDatabaseClient\n\n\nclass DatabaseClient(BaseDa"
  },
  {
    "path": "sql_server/pyodbc/compiler.py",
    "chars": 21866,
    "preview": "import types\nfrom itertools import chain\n\nimport django\nfrom django.db.models.aggregates import Avg, Count, StdDev, Vari"
  },
  {
    "path": "sql_server/pyodbc/creation.py",
    "chars": 3606,
    "preview": "import binascii\nimport os\n\nimport django\nfrom django.db.backends.base.creation import BaseDatabaseCreation\n\n\nclass Datab"
  },
  {
    "path": "sql_server/pyodbc/features.py",
    "chars": 2424,
    "preview": "from django.db.backends.base.features import BaseDatabaseFeatures\nfrom django.utils.functional import cached_property\n\n\n"
  },
  {
    "path": "sql_server/pyodbc/functions.py",
    "chars": 4572,
    "preview": "from django import VERSION\nfrom django.db.models import BooleanField\nfrom django.db.models.functions import Cast\nfrom dj"
  },
  {
    "path": "sql_server/pyodbc/introspection.py",
    "chars": 14561,
    "preview": "import pyodbc as Database\nfrom collections import namedtuple\n\nfrom django.db.backends.base.introspection import (\n    Ba"
  },
  {
    "path": "sql_server/pyodbc/management/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "sql_server/pyodbc/management/commands/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "sql_server/pyodbc/management/commands/install_regex_clr.py",
    "chars": 776,
    "preview": "# Add regex support in SQLServer\n# Code taken from django-mssql (see https://bitbucket.org/Manfre/django-mssql)\n\nfrom dj"
  },
  {
    "path": "sql_server/pyodbc/operations.py",
    "chars": 20588,
    "preview": "import datetime\nimport uuid\nimport warnings\nimport django\n\nfrom django.conf import settings\nfrom django.db.backends.base"
  },
  {
    "path": "sql_server/pyodbc/schema.py",
    "chars": 48605,
    "preview": "import binascii\nimport datetime\nimport django\n\nfrom django.db.backends.base.schema import (\n    BaseDatabaseSchemaEditor"
  },
  {
    "path": "test.sh",
    "chars": 2198,
    "preview": "# TODO:\n#\n# * m2m_through_regress\n# * many_to_one_null\n\nset -e\n\nDJANGO_VERSION=\"$(python -m django --version)\"\n\ncd djang"
  },
  {
    "path": "testapp/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "testapp/migrations/0001_initial.py",
    "chars": 2392,
    "preview": "# Generated by Django 2.2.8.dev20191112211527 on 2019-11-15 01:38\n\nimport uuid\n\nfrom django.db import migrations, models"
  },
  {
    "path": "testapp/migrations/0002_test_unique_nullable_part1.py",
    "chars": 642,
    "preview": "from django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('testap"
  },
  {
    "path": "testapp/migrations/0003_test_unique_nullable_part2.py",
    "chars": 535,
    "preview": "from django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('testap"
  },
  {
    "path": "testapp/migrations/0004_test_issue45_unique_type_change_part1.py",
    "chars": 961,
    "preview": "from django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('testap"
  },
  {
    "path": "testapp/migrations/0005_test_issue45_unique_type_change_part2.py",
    "chars": 1349,
    "preview": "from django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('testap"
  },
  {
    "path": "testapp/migrations/0006_test_remove_onetoone_field_part1.py",
    "chars": 751,
    "preview": "# Generated by Django 3.0.4 on 2020-04-20 14:59\r\n\r\nfrom django.db import migrations, models\r\nimport django.db.models.del"
  },
  {
    "path": "testapp/migrations/0007_test_remove_onetoone_field_part2.py",
    "chars": 376,
    "preview": "# Generated by Django 3.0.4 on 2020-04-20 14:59\r\n\r\nfrom django.db import migrations\r\n\r\n\r\nclass Migration(migrations.Migr"
  },
  {
    "path": "testapp/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "testapp/models.py",
    "chars": 2338,
    "preview": "import uuid\n\nfrom django.db import models\nfrom django.utils import timezone\n\n\nclass Author(models.Model):\n    name = mod"
  },
  {
    "path": "testapp/runner.py",
    "chars": 738,
    "preview": "from unittest import skip\nfrom django.test.runner import DiscoverRunner\nfrom django.conf import settings\n\n\nEXCLUDED_TEST"
  },
  {
    "path": "testapp/settings.py",
    "chars": 11042,
    "preview": "import dj_database_url\n\nDATABASES = {\n    'default': dj_database_url.config(default='sqlite:///db.sqlite'),\n    'other':"
  },
  {
    "path": "testapp/tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "testapp/tests/test_constraints.py",
    "chars": 2596,
    "preview": "from django.db.utils import IntegrityError\nfrom django.test import TestCase, skipUnlessDBFeature\n\nfrom ..models import ("
  },
  {
    "path": "testapp/tests/test_expressions.py",
    "chars": 2041,
    "preview": "from unittest import skipUnless\n\nfrom django import VERSION\nfrom django.db.models import IntegerField\nfrom django.db.mod"
  },
  {
    "path": "testapp/tests/test_fields.py",
    "chars": 160,
    "preview": "from django.test import TestCase\n\nfrom ..models import UUIDModel\n\n\nclass TestUUIDField(TestCase):\n    def test_create(se"
  },
  {
    "path": "tox.ini",
    "chars": 454,
    "preview": "[tox]\nenvlist =\n       {py36,py37}-django22,\n       {py36,py37,py38}-django30,\n       {py36,py37,py38}-django31,\n\n[teste"
  }
]

About this extraction

This page contains the full source code of the ESSolutions/django-mssql-backend GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (184.3 KB), approximately 42.3k tokens, and a symbol index with 216 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!