Gestão de erros e códigos SQLSTATE para mssql-python

O driver mssql-python define uma hierarquia padrão de exceções, padrões comuns de tratamento de erros e mapeamentos de código SQLSTATE para SQL Server e SQL do Azure.

Hierarquia de exceção

O driver mssql-python segue a hierarquia de exceções DB-API 2.0 (PEP 249):

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

ConnectionStringParseError (standalone, not part of hierarchy)

Descrições de exceções

Apanha a exceção mais específica que corresponda à sua situação. Por exemplo, apanhar IntegrityError violações de restrições em INSERToperações/UPDATE , e ProgrammingError para problemas de sintaxe SQL durante o desenvolvimento. Apanhar a classe base Error apenas como plano B.

Exception Quando levantado
Warning Avisos não fatais da base de dados.
Error Classe base para todos os erros da base de dados.
InterfaceError Erros relacionados com a interface da base de dados (driver), não com a base de dados em si.
DatabaseError Erros relacionados com a base de dados.
DataError Erros devido a problemas com dados processados (divisão por zero, valor fora do intervalo).
OperationalError Erros relacionados com a operação da base de dados (perda de ligação, alocação de memória, erros de transação).
IntegrityError Erros quando a integridade da base de dados é afetada (violação de chave estrangeira, restrição única).
InternalError Erros internos da base de dados (cursor não válido, transação fora de sincronização).
ProgrammingError Erros de programação (erros de sintaxe, tabela não encontrada, número errado de parâmetros).
NotSupportedError Funcionalidade não suportada pela base de dados ou pelo driver.
ConnectionStringParseError Sintaxe de cadeia de ligação inválida ou palavras-chave desconhecidas.

Gestão básica de erros

Use blocos try-except para lidar com erros na base de dados:

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()

Exceções de acesso através da ligação

Pode detetar exceções através da instância de ligação:

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

Estrutura da mensagem de erro

Os objetos de exceção mssql-python expõem três atributos que provêm da classe base doException driver:

Attribute Source Descrição
driver_error Driver Python O texto inglês padronizado escolhido pelo SQLSTATE devolveu do ODBC (por exemplo, "Communication link failure", "Invalid authorization specification", "Syntax error or access violation"). Estável entre lançamentos; Seguro para fazer substring match.
ddbc_error Conectividade Direta de Bases de Dados (DDBC) A mensagem do lado do servidor, normalmente com o prefixo [Microsoft][SQL Server]de . O formato não é um contrato estável.
message Composição f"Driver Error: {driver_error}; DDBC Error: {ddbc_error}". É isto que str(exc) regressa.
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: ...

O número de erro do motor do SQL Server (como 208 ou 40501) não é exposto como um atributo e não está embutido de forma fiável em nenhuma das strings. Classificar erros por subclasse de exceção mais driver_error texto. Para o throttling do SQL do Azure, veja Retry logic.

Classificação SQLSTATE

mssql-python usa o SQLSTATE devolvido pelo ODBC para escolher tanto a subclasse de exceção Python como o driver_error texto. O mapeamento completo de SQLSTATE → exceções está no exceptions.py código-fonte do driver. A secção seguinte lista os SQLSTATEs que aparecem com mais frequência no SQL Server e no SQL do Azure.

Erros de ligação

Falhas de ligação do mssql_python.connect() raise mssql_python.OperationalError, iguais a outras falhas de conectividade:

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"

Erros na cadeia de ligação

Erros de análise sintática de stringas de ligação aumentam 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'

Referência de código SQLSTATE

Os códigos SQLSTATE são códigos de cinco caracteres que identificam condições de erro. Os dois primeiros caracteres indicam a classe, e os últimos três indicam a subclasse. Raramente precisa de inspecionar estes códigos diretamente. Em vez disso, escolha o tipo de exceção Python apropriado (listado na coluna "Exceção"). Use códigos SQLSTATE quando precisar de distinguir entre condições de erro específicas dentro do mesmo tipo de exceção, por exemplo, para diferenciar um deadlock (40001) de uma falha geral de ligação (08S01).

Classe 00 - Conclusão bem-sucedida

SQLSTATE Exception Descrição
00000 None Êxito

Classe 01 - Aviso

SQLSTATE Exception Descrição
01000 Warning Aviso geral
01001 Warning Conflito de operação de cursor
01002 Warning Erro de desconexão
01003 DataError Valor NULL eliminado na função de conjunto
01004 DataError Dados de cadeia, truncagem à direita
01006 Warning Privilégio não revogado
01007 Warning Privilégio não concedido
01S00 Warning Atributo de cadeia de ligação inválido
01S01 Warning Erro em linha
01S02 Warning Valor da opção alterado

Classe 07 - Erro SQL dinâmico

SQLSTATE Exception Descrição
07001 ErrorProgrammingError Número errado de parâmetros
07002 ErrorProgrammingError Campo COUNT incorreto
07005 ErrorProgrammingError Instrução preparada, não uma especificação de cursor
07006 ErrorProgrammingError Violação de atributo de tipo de dado restrito
07009 ErrorProgrammingError Índice de descritores inválido
07S01 ErrorProgrammingError Uso inválido do parâmetro padrão

Classe 08 - Exceção de ligação

SQLSTATE Exception Descrição
08001 OperationalError Cliente incapaz de estabelecer ligação
08002 OperationalError Nome da ligação em uso
08003 OperationalError A ligação não existe
08004 OperationalError O servidor rejeitou a ligação
08007 OperationalError Falha de ligação durante a transação
08S01 OperationalError Falha da ligação de comunicação

Classe 21 - Violação de cardinalidade

SQLSTATE Exception Descrição
21S01 ErrorProgrammingError Inserir lista de valores não corresponde à lista de colunas
21S02 ErrorProgrammingError O grau da tabela derivada não corresponde à lista de colunas

Classe 22 - Exceção de dados

SQLSTATE Exception Descrição
22001 DataError Dados de cadeia, truncagem à direita
22002 DataError Variável indicadora necessária, mas não fornecida
22003 DataError Valor numérico fora do intervalo
22007 DataError Formato de data-hora inválido
22008 DataError Excesso de campo data-hora
22012 DataError Divisão por zero
22015 DataError Excesso de campo de intervalo
22018 DataError Valor de personagem inválido para especificação de elenco
22019 DataError Carácter de fuga inválido
22025 DataError Sequência de fuga inválida
22026 DataError Dados de cadeia de caracteres, incompatibilidade de comprimento

Classe 23 - Violação de restrições de integridade

SQLSTATE Exception Descrição
23000 IntegrityError Violação de restrições de integridade (geral)

Classe 24 - Estado do cursor inválido

SQLSTATE Exception Descrição
24000 Erro interno Estado do cursor inválido

Classe 25 - Estado de transação inválido

SQLSTATE Exception Descrição
25000 OperationalError Estado inválido da transação
25S01 OperationalError Estado da transação desconhecido
25S02 OperationalError A transação continua ativa
25S03 OperationalError A transação é revertida

Classe 28 - Especificação de autorização inválida

SQLSTATE Exception Descrição
28000 OperationalError Especificação de autorização inválida (falha no início de sessão)

Classe 34 - Nome do cursor inválido

SQLSTATE Exception Descrição
34000 ErrorProgrammingError Nome do cursor inválido

Classe 3C - Nome duplicado do cursor

SQLSTATE Exception Descrição
3C000 ErrorProgrammingError Nome do cursor duplicado

Classe 3D - Nome inválido do catálogo

SQLSTATE Exception Descrição
3D000 ErrorProgrammingError Nome do catálogo inválido

Classe 3F - Nome inválido do esquema

SQLSTATE Exception Descrição
3F000 ErrorProgrammingError Nome de esquema inválido

Classe 40 - Reversão de transações

SQLSTATE Exception Descrição
40001 OperationalError Falha de serialização (deadlock)
40002 OperationalError A violação de restrições de integridade causou recuo
40003 OperationalError Conclusão da afirmação desconhecida

Classe 42 - Erro de sintaxe ou violação da regra de acesso

SQLSTATE Exception Descrição
42000 ErrorProgrammingError Erro de sintaxe ou violação de acesso
42S01 ErrorProgrammingError A tabela base ou vista já existe
42S02 ErrorProgrammingError Tabela base ou vista não encontrada
42S11 ErrorProgrammingError O índice já existe
42S12 ErrorProgrammingError Índice não encontrado
42S21 ErrorProgrammingError A coluna já existe
42S22 ErrorProgrammingError Coluna não encontrada

Classe 44 - VIOLAÇÃO DA OPÇÃO DE VERIFICAÇÃO

SQLSTATE Exception Descrição
44000 IntegrityError COM VIOLAÇÃO DA OPÇÃO DE VERIFICAÇÃO

Classe HY - condição específica de CLI

SQLSTATE Exception Descrição
HY000 DatabaseError Erro geral
HY001 OperationalError Erro de alocação de memória
HY003 ErrorProgrammingError Tipo de buffer de aplicação inválido
HY004 ErrorProgrammingError Tipo de dado SQL inválido
HY007 ErrorProgrammingError A declaração associada não está preparada
HY008 OperationalError Operação cancelada
HY009 ErrorProgrammingError Uso inválido do ponteiro nulo
HY010 ErrorProgrammingError Erro de sequência de funções
HY011 ErrorProgrammingError O atributo não pode ser definido agora
HY012 ErrorProgrammingError Código de operação de transação inválido
HY013 OperationalError Erro de gestão de memória
HY014 OperationalError Limite para o número de alças ultrapassado
HY015 ErrorProgrammingError Não há nome de cursor disponível
HY016 ErrorProgrammingError Não pode modificar um descritor de linha de implementação
HY017 ErrorProgrammingError Uso inválido do handle de descriptor automaticamente alocado
HY018 OperationalError Pedido de cancelamento do servidor recusado
HY019 ErrorProgrammingError Dados não-caracteres e não-binários enviados em pedaços
HY020 DataError Tentativa de concatenar um valor nulo
HY021 ErrorProgrammingError Informação inconsistente do descritor
HY024 ErrorProgrammingError Valor de atributo inválido
HY090 ErrorProgrammingError Comprimento inválido da corda ou do buffer
HY091 ErrorProgrammingError Identificador de campo descritor inválido
HY092 ErrorProgrammingError Identificador de atributo/opção inválido
HY095 ErrorProgrammingError Tipo de função fora do alcance
HY096 ErrorProgrammingError Tipo de informação inválido
HY097 ErrorProgrammingError Tipo de coluna fora do alcance
HY098 ErrorProgrammingError Tipo de mira fora do alcance
HY099 ErrorProgrammingError Tipo anulável fora do alcance
HY100 ErrorProgrammingError Opção de unicidade fora do intervalo
HY101 ErrorProgrammingError Tipo de opção de precisão fora do alcance
HY103 ErrorProgrammingError Código de recuperação inválido
HY104 ErrorProgrammingError Precisão ou valor de escala inválidos
HY105 ErrorProgrammingError Tipo de parâmetro inválido
HY106 ErrorProgrammingError Tipo de busca fora do alcance
HY107 ErrorProgrammingError Valor da linha fora do intervalo
HY109 ErrorProgrammingError Posição inválida do cursor
HY110 ErrorProgrammingError Completação inválida do driver
HY111 ErrorProgrammingError Valor de marcador inválido
HYC00 NotSupportedError Funcionalidade opcional não implementada
HYT00 OperationalError O tempo expirou
HYT01 OperationalError Expirou o tempo limite de ligação

Classe IM - Erro do gestor do piloto

SQLSTATE Exception Descrição
IM001 InterfaceError O driver não suporta esta função
IM002 InterfaceError Nome da fonte de dados não encontrado
IM003 InterfaceError O driver especificado não podia ser carregado
IM004 InterfaceError O SQLAllocHandle do driver no SQL_HANDLE_ENV falhou
IM005 InterfaceError O SQLAllocHandle do driver no SQL_HANDLE_DBC falhou
IM006 InterfaceError O SQLSetConnectAttr do driver falhou
IM007 InterfaceError Sem fonte de dados ou driver especificado
IM008 InterfaceError Diálogo falhado
IM009 InterfaceError Não é possível carregar DLL de tradução
IM010 InterfaceError Nome da fonte de dados demasiado longo
IM011 InterfaceError Nome do piloto demasiado longo
IM012 InterfaceError Erro de sintaxe da palavra-chave DRIVER
IM014 InterfaceError DSN inválido
IM015 InterfaceError Corromper a fonte de dados do ficheiro

Números de erro comuns do SQL Server

Para além do SQLSTATE, o SQL Server fornece números de erro nativos entre parênteses. Estes são os erros que é mais provável de encontrar no código da aplicação. Construir a lógica de retentativa em torno do erro 1205 (deadlock) e erros de ligação transitória (ver lógica de retentação).

Erro Padrão de mensagens Resolução
208 Nome do objeto inválido Verifique se a tabela ou vista existe e verifique a qualificação do esquema.
547 Violação de restrições Uma restrição de chave estrangeira ou de verificação falhou.
2627 Violação única de restrição Foi inserido um valor duplicado da chave.
2601 Violação de índice único Existe uma chave duplicada no índice.
4060 Não é possível abrir a base de dados A base de dados não existe ou o acesso é negado.
18456 Início de sessão falhado Falha de autenticação. Verifica as credenciais.
1205 Vítima do impasse A transação foi revertida. Repita a operação.

Referência rápida de sintomas para exceções

Use esta tabela para mapear os sintomas comuns ao tipo de exceção que deverá detetar:

Symptom Exception Causa provável
"Login falhado para o utilizador" OperationalError Credenciais erradas ou utilizador não mapeado para a base de dados.
"Cliente incapaz de estabelecer ligação" OperationalError Servidor inacessível, firewall ou problema de DNS.
"Tempo expirado" OperationalError Tempo limite de consulta ou ligação. Aumenta o timeout ou otimiza a consulta.
"Nome do objeto inválido" ProgrammingError A tabela não existe nem o esquema não está especificado.
"Sintaxe incorreta" ProgrammingError Erro de sintaxe SQL. Consulta de teste no SSMS.
"Número errado de parâmetros" ProgrammingError A contagem de parâmetros não corresponde aos marcadores de posição.
"Violação da CHAVE PRIMÁRIA" IntegrityError Duplicar a chave. Use MERGE ou verifique antes de inserir.
"Violação da CHAVE ESTRANGEIRA" IntegrityError A linha referenciada não existe. Insira primeiro o pai.
"Transação bloqueada" OperationalError (erro 1205) Contenda de fechadura. Implemente lógica de reintento.
"Os dados da cadeia ou binários seriam truncados" DataError O valor excede o comprimento da coluna. Verifique os dados ou aumente o tamanho da coluna.
"Conversão falhada" DataError Incompatibilidade de tipo. Use o tipo correto de Python para a coluna.
"Palavra-chave desconhecida" ConnectionStringParseError Erro tipográfico na palavra-chave da cadeia de ligação.
"O CallProc não é suportado" NotSupportedError Utilize cursor.execute("EXECUTE ...") em substituição.

Melhores práticas

  • Apanha exceções específicas antes das genéricas. Ordem do mais específico (IntegrityError) ao menos específico (Error).
  • Manusei sempre o IntegrityError para operações de modificação de dados. Violações de restrições são esperadas em funcionamento normal (por exemplo, um utilizador a tentar criar um nome de utilizador duplicado).
  • Regista o contexto completo do erro para a resolução de problemas. A exceção expõe driver_error (texto estável, derivado do SQLSTATE) e ddbc_error (mensagem do lado do servidor). Regista ambos; classificar em driver_error.
  • Implementar lógica de retentativa para erros transitórios (falhas de ligação, bloqueios). Veja Lógica de Retentar.
  • Use rollback() nos tratadores de exceções para limpar transações falhadas. Sem um rollback explícito, a ligação permanece num estado de transação falhada.