Обработка ошибок и коды SQLSTATE для mssql-python

Драйвер mssql-python определяет стандартную иерархию исключений, распространённые шаблоны обработки ошибок и отображения кода SQLSTATE для SQL Server и Azure SQL.

Иерархия исключений

Драйвер mssql-python следует иерархии исключений DB-API 2.0 (PEP 249):

Exception (builtins)
├── Warning
└── Error
    ├── InterfaceError
    └── DatabaseError
        ├── DataError
        ├── OperationalError
        ├── IntegrityError
        ├── InternalError
        ├── ProgrammingError
        └── NotSupportedError

ConnectionStringParseError (standalone, not part of hierarchy)

Описания исключений

Выберите самое конкретное исключение, которое соответствует вашей ситуации. Например, catch IntegrityError на нарушения ограничений на INSERT/UPDATE операциях и ProgrammingError для проблем с синтаксисом SQL во время разработки. Ловите базовый Error класс только как запасной вариант.

Исключение При поднятии
Warning Нефатальные предупреждения из базы данных.
Error Базовый класс для всех ошибок базы данных.
InterfaceError Ошибки касаются интерфейса базы данных (драйвера), а не самой базы данных.
DatabaseError Ошибки, связанные с базой данных.
DataError Ошибки, вызванные проблемами с обработанными данными (деление на ноль, значение вне диапазона).
OperationalError Ошибки, связанные с работой с базой данных (потеря соединения, выделение памяти, ошибки транзакций).
IntegrityError Ошибки при нарушении целостности базы данных (нарушение внешних ключей, уникальное ограничение).
InternalError Внутренние ошибки базы данных (курсор некорректный, транзакция не синхронизирована).
ProgrammingError Ошибки программирования (синтаксические ошибки, таблица не найдена, неправильное количество параметров).
NotSupportedError Функция не поддерживается базой данных или драйвером.
ConnectionStringParseError Некорректный синтаксис строка подключения или неизвестные ключевые слова.

Базовая обработка ошибок

Используйте блоки try-except для обработки ошибок базы данных:

import mssql_python

try:
    conn = mssql_python.connect(connection_string)
    cursor = conn.cursor()
    cursor.execute("INSERT INTO Production.Product (Name) VALUES (%(name)s)", {"name": "Test"})
    conn.commit()
except mssql_python.IntegrityError as e:
    print(f"Constraint violation: {e}")
    conn.rollback()
except mssql_python.ProgrammingError as e:
    print(f"SQL syntax error: {e}")
except mssql_python.OperationalError as e:
    print(f"Connection or operational error: {e}")
except mssql_python.Error as e:
    print(f"Database error: {e}")
finally:
    if 'conn' in locals():
        conn.close()

Исключения доступа через соединение

Вы можете обназначить исключения через экземпляр соединения:

try:
    cursor.execute("INVALID SQL")
except conn.ProgrammingError as e:
    print(f"Caught via connection: {e}")

Структура сообщений об ошибке

Объекты исключений MSSQL-Python предоставляют три атрибута, полученные из базового классаException драйвера:

Атрибут Source Описание
driver_error Python-драйвер Стандартизированный английский текст, выбранный SQLSTATE, возвращался из ODBC (например, "Communication link failure", "Invalid authorization specification", "Syntax error or access violation"). Стабильно на всех релизах; безопасно сопоставлять субструны.
ddbc_error Прямое подключение к базе данных (DDBC) Серверное сообщение, обычно с префиксом [Microsoft][SQL Server]. Формат — это нестабильный контракт.
message Сформирован f"Driver Error: {driver_error}; DDBC Error: {ddbc_error}". Вот что str(exc) возвращается.
try:
    cursor.execute("SELECT * FROM no_such_table;")
except mssql_python.ProgrammingError as exc:
    print(exc.driver_error)  # Base table or view not found
    print(exc.ddbc_error)    # [Microsoft][SQL Server]Invalid object name 'no_such_table'.
    print(exc)               # Driver Error: Base table or view not found; DDBC Error: ...

Номер ошибки движка SQL Server (например208, или 40501) не отображается как атрибут и не надёжно встроен ни в одну строку. Классифицируйте ошибки по подклассу исключений плюс driver_error тексту. Для Azure SQL throttling см. Retry logic.

Классификация SQLSTATE

mssql-python использует SQLSTATE, возвращаемый ODBC, для выбора как подкласса исключений Python, так и текстаdriver_error. Полное отображение исключений → SQLSTATE находится exceptions.py в исходном коде драйвера. В следующем разделе перечислены SQLSTATE, которые чаще всего встречаются с SQL Server и Azure SQL.

Ошибки подключения

Сбои соединения из-за mssql_python.connect() повышения mssql_python.OperationalError, такие же, как и при других сбоях подключения:

import mssql_python

try:
    conn = mssql_python.connect(
        "Server=unreachable-server.database.windows.net;"
        "Database=<database>;"
        "Authentication=ActiveDirectoryDefault;"
        "Encrypt=yes"
    )
except mssql_python.OperationalError as e:
    print(f"Connection failed: {e.driver_error}")
    # e.driver_error: "Client unable to establish connection"

Ошибки строки подключения

Ошибки разбора строк соединения вызывают ConnectionStringParseError:

try:
    conn = mssql_python.connect("Servr=localhost;")  # Typo
except mssql_python.ConnectionStringParseError as e:
    print(f"Invalid connection string: {e}")
    # Output: Unknown keyword 'Servr'

Ссылка на код SQLSTATE

Коды SQLSTATE — это пятисимвольные коды, которые определяют условия ошибок. Первые два символа обозначают класс, а последние три — подкласс. Редко приходится проверять эти коды напрямую. Вместо этого зафиксируйте соответствующий тип исключения Python (указанный в столбце «Исключение»). Используйте коды SQLSTATE, когда нужно различать конкретные ошибки внутри одного типа исключения, например, чтобы отличить тупиковую блокировку (40001) от общего сбоя соединения (08S01).

Класс 00 — успешное завершение

SQLSTATE Исключение Описание
00000 Нет Success

Класс 01 — Предупреждение

SQLSTATE Исключение Описание
01000 Предупреждение Общее предупреждение
01001 Предупреждение Конфликт операций курсора
01002 Предупреждение Ошибка отключения
01003 DataError Значение NULL, устраненное в функции set
01004 DataError Строковые данные, усечение справа
01006 Предупреждение Привилегии не отозваны
01007 Предупреждение Привилегии не предоставлены
01S00 Предупреждение Недопустимый атрибут строка подключения
01S01 Предупреждение Ошибка в строке
01S02 Предупреждение Изменено значение параметра

Класс 07 — Динамическая ошибка SQL

SQLSTATE Исключение Описание
07001 ProgrammingError Неправильное количество параметров
07002 ProgrammingError Неправильное поле COUNT
07005 ProgrammingError Подготовленный оператор, а не курсорная спецификация
07006 ProgrammingError Нарушение атрибута ограниченного типа данных
07009 ProgrammingError Индекс некорректного дескриптора
07S01 ProgrammingError Недопустимое использование параметра по умолчанию

Класс 08 — исключение при соединении

SQLSTATE Исключение Описание
08001 OperationalError Клиенту не удается установить подключение
08002 OperationalError Имя подключения, используемое
08003 OperationalError Связи отсутствует
08004 OperationalError Сервер отклонил подключение
08007 OperationalError Сбой соединения во время транзакции
08S01 OperationalError Сбой связи

Класс 21 — нарушение кардинальности

SQLSTATE Исключение Описание
21S01 ProgrammingError Список значений не соответствует списку столбцов
21S02 ProgrammingError Степень производной таблицы не соответствует списку столбцов

Класс 22 — исключение данных

SQLSTATE Исключение Описание
22001 DataError Строковые данные, усечение справа
22002 DataError Переменная индикатора, требуемая, но не указанная
22003 DataError Числовое значение вне диапазона
22007 DataError Недопустимый формат datetime
22008 DataError Переполнение поля Datetime
22012 DataError Деление по нулю
22015 DataError Переполнение поля интервала
22018 DataError Недопустимое значение символа для спецификации приведения
22019 DataError Недопустимый escape-символ
22025 DataError Недопустимая последовательность escape-адресов
22026 DataError Строковые данные, несовпадение длины

Класс 23 — нарушение ограничений целостности

SQLSTATE Исключение Описание
23000 IntegrityError Нарушение ограничения целостности (общее)

Класс 24 — недопустимое состояние курсора

SQLSTATE Исключение Описание
24000 Внутренняя ошибка Недопустимое состояние курсора

Класс 25 — недопустимое состояние транзакции

SQLSTATE Исключение Описание
25000 OperationalError Недопустимое состояние транзакции
25S01 OperationalError Состояние транзакции неизвестно
25S02 OperationalError Транзакция всё ещё активна
25S03 OperationalError Транзакция откатывается

Класс 28 — Недействительная спецификация авторизации

SQLSTATE Исключение Описание
28000 OperationalError Неверная спецификация авторизации (вход не выполнен)

Класс 34 — неверное имя курсора

SQLSTATE Исключение Описание
34000 ProgrammingError Недопустимое имя курсора

Класс 3C — дублирует имя курсора

SQLSTATE Исключение Описание
3C000 ProgrammingError Повторяющееся имя курсора

Класс 3D — неверное название каталога

SQLSTATE Исключение Описание
3D000 ProgrammingError Недопустимое имя каталога

Класс 3F — неверное имя схемы

SQLSTATE Исключение Описание
3F000 ProgrammingError Недопустимое имя схемы

Класс 40 — откат транзакций

SQLSTATE Исключение Описание
40001 OperationalError Сбой сериализации (тупик)
40002 OperationalError Нарушение ограничения целостности вызывало откат
40003 OperationalError Неизвестное завершение инструкции

Класс 42 — ошибка в синтаксисе или нарушение правил доступа

SQLSTATE Исключение Описание
42000 ProgrammingError Синтаксическая ошибка или нарушение доступа
42S01 ProgrammingError Базовая таблица или представление уже существует
42S02 ProgrammingError Базовая таблица или представление не найдено
42S11 ProgrammingError Индекс уже существует
42S12 ProgrammingError Индекс не найден
42S21 ProgrammingError Столбец уже существует
42S22 ProgrammingError Столбец не найден

Класс 44 — С НАРУШЕНИЕМ ОПЦИИ CHECK

SQLSTATE Исключение Описание
44000 IntegrityError Нарушение параметра WITH CHECK OPTION

Класс HY — специфическое для CLI состояние

SQLSTATE Исключение Описание
HY000 DatabaseError Общая ошибка
HY001 OperationalError Ошибка выделения памяти
HY003 ProgrammingError Недопустимый тип буфера приложения
HY004 ProgrammingError Недопустимый тип данных SQL
HY007 ProgrammingError Связанная инструкция не подготовлена
HY008 OperationalError Операция отменена
HY009 ProgrammingError Недопустимое использование указателя NULL
HY010 ProgrammingError Ошибка последовательности функций
HY011 ProgrammingError Атрибут не может быть задан сейчас
HY012 ProgrammingError Некорректный код операции транзакции
HY013 OperationalError Ошибка управления памятью
HY014 OperationalError Лимит на превышение количества ручок
HY015 ProgrammingError Имя курсора недоступно
HY016 ProgrammingError Нельзя изменить дескриптор строки реализации
HY017 ProgrammingError Некорректное использование автоматически выделенного дескриптора
HY018 OperationalError Сервер отклонил запрос на отмену
HY019 ProgrammingError Несимвольные и небинарные данные, передаваемые частями
HY020 DataError Попытка конкатенировать нулевое значение
HY021 ProgrammingError Несогласованная информация о описаниях
HY024 ProgrammingError Недопустимое значение атрибута
HY090 ProgrammingError Недопустимая длина строки или буфера
HY091 ProgrammingError Идентификатор поля некорректного дескриптора
HY092 ProgrammingError Некорректный идентификатор атрибута/опции
HY095 ProgrammingError Тип функции вне зоны действия
HY096 ProgrammingError Некорректный тип информации
HY097 ProgrammingError Тип колонки вне зоны действия
HY098 ProgrammingError Тип прицела вне зоны действия
HY099 ProgrammingError Обнулируемый тип вне зоны действия
HY100 ProgrammingError Тип параметра Uniqueness вне диапазона
HY101 ProgrammingError Тип параметра точности вне диапазона
HY103 ProgrammingError Некорректный код поиска
HY104 ProgrammingError Недопустимое значение точности или масштабирования
HY105 ProgrammingError Недопустимый тип параметра
HY106 ProgrammingError Тип апорта вне зоны действия
HY107 ProgrammingError Значение строки вне зоны действия
HY109 ProgrammingError Недопустимое положение курсора
HY110 ProgrammingError Неверное завершение драйвера
HY111 ProgrammingError Неверное значение закладок
HYC00 NotSupportedError Необязательный компонент не реализован
HYT00 OperationalError Время ожидания истекло.
HYT01 OperationalError Время ожидания для подключения истекло

Класс IM — ошибка менеджера водителя

SQLSTATE Исключение Описание
IM001 InterfaceError Драйвер не поддерживает эту функцию
IM002 InterfaceError Имя источника данных не найдено
IM003 InterfaceError Не удалось загрузить указанный драйвер
IM004 InterfaceError SQLAllocHandle драйвера на SQL_HANDLE_ENV неудача
IM005 InterfaceError Драйвер SQLAllocHandle на SQL_HANDLE_DBC не сработал
IM006 InterfaceError SQLSetConnectAttr драйвера не сработал
IM007 InterfaceError Источник данных или драйвер не указаны
IM008 InterfaceError Диалог провалился
IM009 InterfaceError Не удалось загрузить библиотеку DLL перевода
IM010 InterfaceError Слишком длинное имя источника данных
IM011 InterfaceError Слишком длинное имя драйвера
IM012 InterfaceError Ошибка синтаксиса ключевого слова DRIVER
IM014 InterfaceError Неверный DSN
IM015 InterfaceError Повреждённый источник данных файлов

Распространённые номера ошибок SQL Server

Помимо SQLSTATE, SQL Server предоставляет нативные номера ошибок в скобках. Это те ошибки, с которыми вы чаще всего столкнётесь в коде приложений. Постройте логику повторных попыток вокруг ошибки 1205 (тупик) и временных ошибок соединения (см. логику повторного использования).

Ошибка Шаблон сообщения Разрешение
208 Недопустимое имя объекта Проверьте, существует ли таблица или представление, и проверьте квалификацию схемы.
547 Нарушение ограничений Внешний ключ или ограничение проверки не сработали.
2627 Нарушение уникального ограничения Вставлялось дублирующее значение ключа.
2601 Нарушение уникального индекса В индексе существует дублирующий ключ.
4060 Нельзя открыть базу данных База данных не существует, или доступ запрещён.
18456 Сбой входа Ошибка аутентификации. Проверьте учетные данные.
1205 Жертва взаимоблокировки Выполнен откат этой транзакции. Повторите операцию.

Краткая справка по принципу «симптом к исключению»

Используйте эту таблицу, чтобы сопоставить распространённые симптомы с типом исключения, которые вам следует заметить:

Симптом Исключение Вероятная причина
«Неудачный вход для пользователя» OperationalError Неправильные учетные данные или пользователь не связан с базой данных.
"Клиент не может установить соединение" OperationalError Сервер недоступен, файрвол или проблема с DNS.
«Тайм-аут истек» OperationalError Тайм-аут запроса или соединения. Увеличьте тайм-аут или оптимизируйте запросы.
«Неверное имя объекта» ProgrammingError Таблица не существует, или схема не указана.
«Неправильный синтаксис» ProgrammingError Ошибка в синтаксисе SQL. Тестовый запрос в SSMS.
«Неправильное количество параметров» ProgrammingError Количество параметров не совпадает с заглушками.
"Нарушение ПЕРВИЧНОГО КЛЮЧА" IntegrityError Дубликат ключа. Используйте MERGE или проверьте перед введением.
«Нарушение ИНОСТРАННОГО КЛЮЧА» IntegrityError Упомянутый ряд не существует. Сначала вставьте родителя.
«Сделка была заблокирована» OperationalError (ошибка 1205) Спор на замок. Реализуйте логику повторных попыток.
«Строковые или двоичные данные будут усечаны» DataError Значение превышает длину столбца. Проверьте данные или увеличите размер столбцов.
«Конверсия не удалась» DataError Несоответствие типов. Используйте правильный тип Python для столбца.
«Неизвестное ключевое слово» ConnectionStringParseError Опечатка в ключевом слове строка подключения.
«callproc не поддерживается» NotSupportedError Вместо этого используйте cursor.execute("EXECUTE ...").

Лучшие практики

  • Ловите конкретные исключения перед обычными. Порядок от самого конкретного (IntegrityError) к наименее конкретному (Error).
  • Всегда обрабатывайте IntegrityError для операций модификации данных. Нарушения ограничений ожидаются в обычной работе (например, если пользователь пытается создать дублирующееся имя пользователя).
  • Запишите полный контекст ошибок для устранения неполадок. Исключение включает driver_error (стабильный, SQLSTATE-производный текст) и ddbc_error (серверное сообщение). Записывайте оба; классифицировать на driver_error.
  • Реализуйте повторную логику для временных ошибок (сбои соединения, тупиковые блокировки). См. логику повторного попытки.
  • Используйте rollback() в обработчиках exception для очистки неудачных транзакций. Без явного отката соединение остаётся в состоянии неудачной транзакции.