| Bellacosa Mainframe e o sqlcode sem misterios |
☕ Um Café no Bellacosa Mainframe
SQLCODE sem Mistérios
O Guia de Sobrevivência do Programador COBOL Padawan diante dos Principais Erros do Db2
Imagine a seguinte cena.
Você acabou de escrever seu primeiro programa COBOL acessando uma tabela Db2. O código compilou. O pré-compilador não reclamou. O BIND terminou aparentemente bem. O JCL foi submetido. O job entrou no JES2, executou alguns segundos e terminou com uma mensagem misteriosa:
SQLCODE = -805
O jovem Padawan olha para o número e pensa:
“Meu programa abendou?”
Talvez sim. Talvez não.
Um SQLCODE negativo não é necessariamente um ABEND do sistema operacional. Ele é uma resposta do Db2 informando que não conseguiu executar determinada instrução SQL. É como se o banco de dados dissesse:
“Recebi sua solicitação, mas existe alguma coisa errada. Aqui está o código que explica o motivo.”
O segredo não é decorar centenas de números. O verdadeiro conhecimento está em aprender a interpretar o contexto, capturar as informações do SQLCA, identificar a instrução que falhou e seguir uma sequência organizada de diagnóstico.
É exatamente isso que faremos neste artigo.
Prepare a caneca, abra o SDSF e venha conhecer o lado Jedi do tratamento de erros SQL em COBOL.
1. Antes do SQLCODE: como COBOL e Db2 conversam?
Um programa COBOL não entende SQL nativamente da mesma maneira que entende comandos como:
MOVE
ADD
PERFORM
READ
WRITE
As instruções SQL aparecem dentro do programa como SQL embutido:
EXEC SQL
SELECT NOME_CLIENTE
INTO :WS-NOME-CLIENTE
FROM CLIENTE
WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.
Durante a preparação do programa, um pré-compilador ou coprocessador Db2 identifica os blocos delimitados por EXEC SQL e END-EXEC, separa o SQL do código COBOL e prepara as estruturas necessárias para a execução. A documentação da IBM estabelece justamente esse formato para aplicações COBOL que emitem comandos SQL. (IBM)
Quando o programa executa uma instrução SQL, o Db2 precisa devolver uma resposta.
Essa resposta inclui, entre outras informações:
se a instrução funcionou;
se ocorreu um aviso;
se nenhum registro foi localizado;
se houve erro;
qual objeto estava envolvido;
quais tokens complementam a mensagem;
qual estado SQL representa a situação.
É nesse momento que entra o SQLCA.
2. O que é SQLCA?
SQLCA significa:
SQL Communication Area
Em português:
Área de Comunicação SQL
Ela é uma estrutura de dados usada para transportar informações entre o mecanismo SQL e o programa hospedeiro, como COBOL, PL/I, C ou Assembler.
No COBOL, normalmente incluímos essa estrutura assim:
EXEC SQL
INCLUDE SQLCA
END-EXEC.
Durante o processo de pré-compilação, essa instrução é substituída pela definição correspondente da estrutura SQLCA. A IBM documenta a composição gerada pelo INCLUDE SQLCA para as diferentes linguagens hospedeiras. (IBM)
Conceitualmente, a origem do SQLCA está ligada à necessidade criada pelo SQL embutido: o banco precisava de uma área padronizada para devolver o resultado de cada operação ao programa que o chamou.
Pense nela como uma pequena central de mensagens.
O COBOL envia:
SELECT este cliente.
O Db2 responde através da SQLCA:
Encontrei.
Não encontrei.
Encontrei, mas houve aviso.
Não consegui porque a tabela não existe.
Não consegui porque o package não foi localizado.
Não consegui porque outro processo está segurando o recurso.
O SQLCODE é apenas o campo mais famoso dessa estrutura.
3. Anatomia básica do SQLCA
Uma representação simplificada da SQLCA em COBOL seria semelhante a esta:
01 SQLCA.
05 SQLCAID PIC X(8).
05 SQLCABC PIC S9(9) COMP-5.
05 SQLCODE PIC S9(9) COMP-5.
05 SQLERRM.
49 SQLERRML PIC S9(4) COMP-5.
49 SQLERRMC PIC X(70).
05 SQLERRP PIC X(8).
05 SQLERRD OCCURS 6 TIMES
PIC S9(9) COMP-5.
05 SQLWARN.
10 SQLWARN0 PIC X.
10 SQLWARN1 PIC X.
10 SQLWARN2 PIC X.
10 SQLWARN3 PIC X.
10 SQLWARN4 PIC X.
10 SQLWARN5 PIC X.
10 SQLWARN6 PIC X.
10 SQLWARN7 PIC X.
10 SQLWARN8 PIC X.
10 SQLWARN9 PIC X.
10 SQLWARNA PIC X.
05 SQLSTATE PIC X(5).
A definição exata pode variar conforme plataforma, compilador e versão, mas os conceitos permanecem.
SQLCODE
É o código numérico principal retornado pelo Db2.
0 Operação bem-sucedida
+100 Nenhum dado encontrado
positivo diferente de +100
Operação concluída com aviso
negativo
Erro
A IBM define que SQLCODE 0 representa sucesso, +100 indica ausência de dados e valores negativos indicam que a execução não foi bem-sucedida. (IBM)
SQLSTATE
É um código de cinco caracteres que classifica a condição de maneira mais padronizada.
Exemplo:
02000
Representa a condição “nenhum dado encontrado”, equivalente ao SQLCODE +100.
SQLCODE é muito usado historicamente em ambientes Db2 e mainframe. SQLSTATE é útil por apresentar uma categorização mais padronizada entre diferentes sistemas gerenciadores de bancos de dados.
SQLERRMC
Contém tokens associados à mensagem.
Se o erro envolver o nome de uma tabela, coluna, package, plano ou autorização, essa área pode trazer justamente a informação que faltava para entender o problema.
SQLERRML
Informa o comprimento válido do conteúdo de SQLERRMC.
Portanto, não é uma boa prática exibir os 70 bytes de SQLERRMC indiscriminadamente. O ideal é considerar a quantidade indicada por SQLERRML.
SQLERRP
Pode identificar o módulo ou componente que detectou a condição. No Db2 for z/OS, os primeiros caracteres normalmente trazem a assinatura DSN. (IBM)
SQLERRD
É um conjunto de campos numéricos com informações complementares.
Dependendo da instrução e do SQLCODE, eles podem indicar:
quantidade de linhas afetadas;
códigos internos;
informações relacionadas ao processamento;
razão complementar de determinadas condições.
A interpretação dos campos SQLERRD depende do contexto. Portanto, nunca conclua que um determinado índice possui sempre o mesmo significado em qualquer SQLCODE.
SQLWARN
É um conjunto de indicadores de aviso.
Quando SQLWARN0 contém W, pelo menos uma condição de warning foi identificada. Outros campos mostram categorias específicas de aviso, como truncamento ou situações relacionadas aos dados retornados. A SQLCA utiliza esse conjunto de indicadores para comunicar warnings ao programa. (IBM)
4. A primeira regra Jedi: sempre teste o SQLCODE
Um dos erros mais perigosos não é receber um SQLCODE negativo.
É ignorá-lo.
Observe este código:
EXEC SQL
SELECT SALDO
INTO :WS-SALDO
FROM CONTA
WHERE NUM_CONTA = :WS-NUM-CONTA
END-EXEC.
DISPLAY 'SALDO: ' WS-SALDO.
O que acontecerá se a conta não existir?
O Db2 retornará +100. Entretanto, se o programa não verificar o resultado, WS-SALDO poderá continuar contendo um valor anterior, zeros, espaços ou dados residuais.
O programa poderá apresentar um saldo incorreto como se fosse válido.
O padrão correto é:
EXEC SQL
SELECT SALDO
INTO :WS-SALDO
FROM CONTA
WHERE NUM_CONTA = :WS-NUM-CONTA
END-EXEC.
EVALUATE TRUE
WHEN SQLCODE = 0
PERFORM 3000-PROCESSAR-SALDO
WHEN SQLCODE = +100
PERFORM 3100-CONTA-NAO-ENCONTRADA
WHEN OTHER
PERFORM 9000-TRATAR-ERRO-SQL
END-EVALUATE.
Esse modelo deixa explícitos três caminhos:
sucesso;
ausência de dados;
erro inesperado.
5. SQLCODE 0 — sucesso, mas continue atento
SQLCODE = 0 significa que a instrução foi executada com sucesso.
Exemplo:
EXEC SQL
UPDATE CONTA
SET SALDO = SALDO - :WS-VALOR
WHERE NUM_CONTA = :WS-NUM-CONTA
END-EXEC.
Entretanto, existe uma armadilha.
Um UPDATE pode retornar SQLCODE zero e ainda assim não ter atualizado a quantidade de linhas que sua regra de negócio esperava.
Imagine uma rotina que deveria alterar exatamente uma linha.
Mesmo após SQLCODE zero, pode ser importante verificar a quantidade de linhas afetadas usando as informações apropriadas da SQLCA, de acordo com a instrução e o ambiente.
A pergunta profissional não é apenas:
“Funcionou?”
É também:
“Funcionou exatamente como a regra de negócio esperava?”
6. SQLCODE +100 — nenhum dado encontrado
O +100 é provavelmente o SQLCODE positivo mais conhecido.
Ele significa:
No data found.
Nenhum dado foi encontrado.
Isso pode ocorrer em situações como:
SELECT INTOsem linha correspondente;FETCHapós o final do cursor;determinadas operações que esperavam encontrar um registro;
exclusão ou atualização sem correspondência, conforme a instrução e o contexto.
A IBM associa o SQLCODE +100 e o SQLSTATE 02000 à condição NOT FOUND. (IBM)
Exemplo com SELECT
EXEC SQL
SELECT NOME
INTO :WS-NOME
FROM CLIENTE
WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.
IF SQLCODE = +100
DISPLAY 'CLIENTE NAO ENCONTRADO'
END-IF.
Exemplo com cursor
PERFORM UNTIL WS-FIM-CURSOR = 'S'
EXEC SQL
FETCH C1
INTO :WS-CODIGO,
:WS-NOME
END-EXEC
EVALUATE TRUE
WHEN SQLCODE = 0
PERFORM 4000-PROCESSAR-CLIENTE
WHEN SQLCODE = +100
MOVE 'S' TO WS-FIM-CURSOR
WHEN OTHER
PERFORM 9000-TRATAR-ERRO-SQL
END-EVALUATE
END-PERFORM.
Possíveis soluções
Verifique se os valores das host variables estão corretos.
Confirme se a linha realmente existe na tabela.
Verifique espaços, zeros à esquerda e formatos de data.
Confirme se o predicado
WHEREnão está restritivo demais.Em cursores, trate
+100como fim normal da leitura.Inicialize as variáveis de saída antes do
SELECT.
Dica Bellacosa
Não trate todo +100 como erro técnico.
Em muitos programas, “cliente não encontrado” é uma condição normal de negócio. Em um cursor, +100 é praticamente o equivalente SQL ao fim de arquivo.
7. SQLCODE -204 — objeto não definido
O -204 informa que o objeto referenciado não está definido no subsistema ou contexto em que a instrução está sendo executada. A documentação da IBM cita essa condição para diferentes tipos de objetos Db2. (IBM)
Exemplo:
SELECT *
FROM CLIENTES
Mas a tabela correta é:
SISTEMA1.CLIENTE
Causas comuns
nome da tabela digitado incorretamente;
creator ou schema ausente;
tabela existente em outro ambiente;
synonym, alias ou view inexistente;
programa executando em outro subsistema Db2;
objeto ainda não criado;
qualificador definido incorretamente no BIND;
diferença entre desenvolvimento, homologação e produção.
Passo a passo
Capture o conteúdo de
SQLERRMC.Identifique o nome exato do objeto mencionado.
Confirme o subsistema Db2 em que o programa executou.
Pesquise o catálogo Db2.
Verifique o schema ou creator.
Compare o DDL entre os ambientes.
Verifique os parâmetros de qualificação usados no BIND.
Corrija o nome ou solicite a criação do objeto.
Exemplo de correção
Antes:
EXEC SQL
SELECT NOME
INTO :WS-NOME
FROM CLIENTE
WHERE CODIGO = :WS-CODIGO
END-EXEC.
Depois:
EXEC SQL
SELECT NOME
INTO :WS-NOME
FROM CADASTRO.CLIENTE
WHERE CODIGO = :WS-CODIGO
END-EXEC.
8. SQLCODE -206 — coluna não encontrada ou inválida
O -206 geralmente indica que o nome de uma coluna não é válido no contexto da instrução.
Exemplo:
SELECT NOME_COMPLETO
FROM CLIENTE
Mas a coluna real se chama:
NOME_CLIENTE
Causas comuns
erro de digitação;
coluna removida ou renomeada;
referência incorreta a alias de tabela;
SQL dinâmico montado de maneira errada;
DCLGEN desatualizada;
programa compilado com uma versão antiga do layout;
promoção incompleta entre ambientes.
Diagnóstico
Identifique a coluna em
SQLERRMC.Consulte a definição atual da tabela.
Compare o SQL com a DCLGEN.
Confirme se o alias da tabela foi usado corretamente.
Verifique se a coluna pertence à tabela esperada.
Atualize e regenere as estruturas, se necessário.
Armadilha clássica
SELECT C.NOME
FROM CLIENTE X
A tabela recebeu o alias X, mas a coluna foi qualificada com C.
A correção seria:
SELECT X.NOME
FROM CLIENTE X
9. SQLCODE -305 — valor NULL sem indicador
O -305 é um dos primeiros grandes encontros do programador COBOL com a diferença entre o mundo COBOL e o mundo relacional.
No Db2, uma coluna pode possuir valor NULL.
No COBOL tradicional, uma variável hospedeira comum não possui, sozinha, um terceiro estado que signifique “valor desconhecido ou ausente”.
Por isso usamos uma variável indicadora.
Exemplo incorreto:
EXEC SQL
SELECT COMPLEMENTO
INTO :WS-COMPLEMENTO
FROM ENDERECO
WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.
Se COMPLEMENTO for NULL, o programa poderá receber -305.
Correção
01 WS-COMPLEMENTO PIC X(30).
01 IND-COMPLEMENTO PIC S9(4) COMP-5.
EXEC SQL
SELECT COMPLEMENTO
INTO :WS-COMPLEMENTO
:IND-COMPLEMENTO
FROM ENDERECO
WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.
Depois:
IF IND-COMPLEMENTO < 0
MOVE 'NAO INFORMADO' TO WS-COMPLEMENTO
END-IF.
Regra prática
Indicador negativo:
o valor recebido é NULL.
Indicador zero:
o valor não é NULL.
Certas condições positivas podem representar informações adicionais, como truncamento, dependendo da operação.
Passo a passo
Descubra qual coluna permite NULL.
Adicione uma variável indicadora compatível.
Associe o indicador à host variable.
Verifique o indicador após a instrução.
Defina a regra de negócio para valores nulos.
Não confunda
NULLcom espaços ou zeros.
10. SQLCODE -302 — valor incompatível ou grande demais
O -302 costuma indicar que uma variável de entrada possui um valor incompatível com o tipo ou tamanho esperado.
Exemplo:
01 WS-CODIGO PIC X(20).
A coluna Db2 espera um número pequeno, mas o programa envia:
ABC123
Também pode haver problemas de comprimento, precisão, escala ou representação.
Causas comuns
conteúdo alfanumérico enviado para coluna numérica;
número maior do que a coluna suporta;
escala decimal incompatível;
data em formato inválido;
host variable com definição incorreta;
estrutura COBOL divergente do DCLGEN;
indicador ou comprimento incorreto.
Passo a passo
Exiba o valor da host variable antes do SQL.
Verifique o tipo da coluna no catálogo.
Compare PIC, USAGE, comprimento, precisão e escala.
Valide dados recebidos de arquivo, tela ou API.
Verifique sinais e casas decimais.
Utilize DCLGEN atualizada.
Não corrija apenas aumentando o campo sem entender a origem do valor.
Exemplo
Coluna:
VALOR DECIMAL(9,2)
Host variable recomendada:
01 WS-VALOR PIC S9(7)V99 COMP-3.
Um erro de definição poderia fazer o programa enviar uma representação incompatível.
11. SQLCODE -303 — tipos incompatíveis na atribuição
O -303 aparece quando o Db2 não consegue atribuir um valor à variável hospedeira devido à incompatibilidade de tipos.
Exemplo conceitual:
SELECT DATA_NASCIMENTO
INTO :WS-VALOR-NUMERICO
Se WS-VALOR-NUMERICO não possuir definição compatível com uma data, haverá problema.
Solução
compare o tipo da coluna com a PIC da host variable;
use DCLGEN;
faça conversões explícitas quando justificadas;
evite depender de conversões implícitas;
verifique CCSID e codificação quando o erro envolver caracteres;
confira precisão e escala em campos decimais.
12. SQLCODE -407 — tentativa de gravar NULL em coluna NOT NULL
O -407 representa a tentativa de atribuir NULL a uma coluna que não aceita valores nulos.
Isso pode ocorrer em:
INSERT;UPDATE;processamento de indicadores;
triggers;
valores omitidos sem default apropriado.
Exemplo
INSERT INTO CLIENTE
(CODIGO, NOME)
VALUES (:HV-CODIGO, :HV-NOME)
Se o indicador associado a HV-NOME estiver negativo, o programa estará tentando inserir NULL.
Caso NOME seja NOT NULL, a operação falhará.
Passo a passo
Identifique a coluna envolvida.
Verifique os indicadores.
Consulte a definição
NULL/NOT NULL.Confirme se existe valor default.
Valide os campos obrigatórios antes do SQL.
Não substitua NULL por espaços sem autorização da regra de negócio.
13. SQLCODE -803 — chave duplicada
O -803 é o guardião da unicidade.
Ele geralmente ocorre quando um INSERT ou UPDATE tenta gerar um valor que viola um índice único ou uma restrição de unicidade.
Exemplo:
INSERT INTO CLIENTE
(COD_CLIENTE, NOME)
VALUES (100, 'ANA')
Mas já existe um cliente com código 100.
Causas comuns
chave primária já existente;
índice único violado;
contador ou sequência mal controlada;
reprocessamento do mesmo arquivo;
mensagem MQ processada duas vezes;
reinício de job sem checkpoint;
concorrência entre processos;
lógica “consultar e depois inserir” sujeita a corrida.
Passo a passo
Identifique a constraint ou índice envolvido.
Verifique quais colunas formam a chave única.
Consulte o registro existente.
Descubra se é duplicidade real ou reprocessamento.
Verifique a origem da chave.
Avalie o uso de sequence ou identity.
Torne o processamento idempotente quando necessário.
Não resolva apagando o registro anterior sem análise.
Dica de produção
Em sistemas distribuídos, o -803 pode ser sintoma de uma mensagem repetida, não de um erro humano.
A pergunta correta pode ser:
“Por que esta transação chegou duas vezes?”
14. SQLCODE -805 — package não encontrado
O -805 é um clássico do Db2 for z/OS.
Ele normalmente informa que o Db2 não encontrou o package necessário para executar a instrução SQL.
Seu programa foi compilado, linkeditado e executado, mas o componente Db2 correspondente não foi localizado na collection esperada.
Causas comuns
DBRM não foi bindado;
BIND PACKAGE não foi executado;
collection incorreta;
versão incorreta;
package removido;
plano não possui PKLIST adequado;
programa executando em subsistema diferente;
promoção incompleta;
load module novo com package antigo;
package novo com load module antigo.
Passo a passo de diagnóstico
Capture todo o conteúdo de
SQLERRMC.Identifique location, collection, package e consistência.
Confirme qual load module foi executado.
Verifique a STEPLIB ou JOBLIB.
Confirme o subsistema Db2.
Consulte o catálogo para verificar se o package existe.
Confira collection e versão.
Verifique o PKLIST do plano.
Execute ou solicite o BIND correto.
Confirme se programa e package pertencem à mesma construção.
Analogia Bellacosa
O load module é o guerreiro.
O package é o pergaminho com a estratégia SQL.
O plano ou contexto de execução é a autorização para usar determinados pergaminhos.
No -805, o guerreiro chegou ao campo de batalha, mas o pergaminho correto não estava na biblioteca.
15. SQLCODE -818 — incompatibilidade de timestamp
O -818 normalmente indica que o módulo executável e o DBRM/package associado não pertencem à mesma preparação.
Em termos simples:
o código COBOL e o código SQL ficaram fora de sincronia.
Cenário clássico
Programa é pré-compilado.
Um novo DBRM é produzido.
O programa é compilado e linkeditado.
O BIND usa um DBRM antigo.
Ou:
O package foi atualizado.
O load module antigo continua na load library.
Solução passo a passo
Identifique o load module carregado.
Confirme a data e versão do módulo.
Identifique o DBRM usado no último BIND.
Refaça toda a cadeia de construção.
Pré-compile novamente.
Compile novamente.
Faça o link-edit novamente.
Execute o BIND novamente.
Promova load module e package como uma unidade.
Verifique se a execução está lendo a biblioteca correta.
Dica DevOps
Nunca trate o package e o executável como artefatos independentes.
Eles são partes da mesma entrega.
16. SQLCODE -811 — SELECT retornou mais de uma linha
Um SELECT INTO espera, normalmente, uma única linha.
Exemplo:
EXEC SQL
SELECT NOME
INTO :WS-NOME
FROM CLIENTE
WHERE CIDADE = :WS-CIDADE
END-EXEC.
Se existirem cem clientes na cidade, o Db2 não poderá decidir qual nome devolver.
Resultado:
SQLCODE -811
Causas
predicado incompleto;
premissa errada de unicidade;
dados duplicados;
constraint ausente;
chave incorreta;
regra de negócio mudou;
SELECT deveria utilizar cursor.
Soluções
Quando deveria existir apenas uma linha
corrija o
WHERE;consulte pela chave correta;
elimine duplicidades de forma controlada;
implemente constraint única quando fizer sentido.
Quando várias linhas são válidas
Use cursor:
EXEC SQL
DECLARE C1 CURSOR FOR
SELECT NOME
FROM CLIENTE
WHERE CIDADE = :WS-CIDADE
END-EXEC.
Cuidado com a falsa solução
Adicionar algo equivalente a “pegue apenas a primeira linha” pode esconder um problema de dados.
Antes de limitar o resultado, pergunte:
“Qual linha é realmente a correta?”
17. SQLCODE -904 — recurso indisponível
O -904 indica que a instrução não foi executada porque um recurso necessário estava indisponível. A mensagem traz informações como reason code, tipo do recurso e nome do recurso. (IBM)
Possíveis causas
tablespace parado;
objeto em estado restritivo;
partição indisponível;
utilitário em execução;
recurso não iniciado;
problema de comunicação;
recurso auxiliar indisponível;
condição de recuperação pendente.
Passo a passo
Capture o reason code.
Capture o resource type.
Capture o resource name.
Consulte a documentação do reason code.
Verifique mensagens Db2 no log.
Consulte o estado do objeto.
Verifique utilitários ativos.
Acione o DBA ou suporte de produção com os dados completos.
Não tente repetir indefinidamente sem entender a indisponibilidade.
Dica importante
-904 sem reason code é apenas metade do diagnóstico.
Dizer ao DBA:
“Deu menos novecentos e quatro”
é pouco útil.
Dizer:
“SQLCODE -904, reason 00C9..., resource type ..., resource name ...”
transforma um pedido genérico em uma investigação objetiva.
18. SQLCODE -911 e -913 — deadlock ou timeout
Esses códigos aparecem em situações de contenção, timeout ou deadlock.
Deadlock
Dois processos ficam esperando recursos mantidos um pelo outro.
Exemplo:
Programa A atualiza CLIENTE e espera CONTA.
Programa B atualiza CONTA e espera CLIENTE.
Nenhum consegue continuar.
O Db2 escolhe uma das unidades de trabalho como vítima para liberar o impasse.
Timeout
Um processo aguarda um recurso por mais tempo do que o limite permitido.
Diferença prática
A interpretação exata deve considerar:
SQLCODE;
reason code;
mensagens;
rollback executado;
ambiente e parâmetros;
informações de trace.
Em muitos cenários, -911 aparece quando a unidade de trabalho sofre rollback, enquanto -913 pode indicar uma condição semelhante sem o mesmo comportamento automático de rollback. A confirmação deve ser feita pelos dados complementares, especialmente reason code e SQLERRD. (Comunidade IBM)
Possíveis soluções
Reduza o tempo entre commits.
Não mantenha cursor ou unidade de trabalho aberta desnecessariamente.
Acesse tabelas na mesma ordem em todos os programas.
Atualize somente as linhas necessárias.
Garanta bons índices.
Evite varreduras extensas durante updates.
Analise isolamento e concorrência.
Implemente retry controlado quando permitido.
Não faça retry infinito.
Registre tentativa, horário e chave processada.
Exemplo de retry controlado
MOVE 0 TO WS-TENTATIVAS.
PERFORM UNTIL WS-SUCESSO = 'S'
OR WS-TENTATIVAS >= 3
ADD 1 TO WS-TENTATIVAS
PERFORM 5000-EXECUTAR-TRANSACAO
EVALUATE SQLCODE
WHEN 0
MOVE 'S' TO WS-SUCESSO
WHEN -911
PERFORM 5100-PREPARAR-NOVA-TENTATIVA
WHEN -913
PERFORM 5100-PREPARAR-NOVA-TENTATIVA
WHEN OTHER
PERFORM 9000-TRATAR-ERRO-SQL
MOVE 'S' TO WS-ENCERRAR
END-EVALUATE
END-PERFORM.
O retry precisa respeitar a arquitetura da aplicação. Em alguns casos, repetir a operação automaticamente pode duplicar efeitos externos.
19. SQLCODE -922 — falha de autorização
O -922 normalmente está relacionado à autorização, conexão ou acesso a recursos do Db2.
Possíveis causas
usuário sem privilégio;
plano sem autorização;
package sem autorização de execução;
falha na conexão;
contexto de segurança incorreto;
autorização RACF ou Db2 ausente;
ambiente executando com outro ID;
mudança de owner ou qualifier.
Passo a passo
Identifique o authorization ID em uso.
Capture os tokens da SQLCA.
Verifique o privilégio exigido.
Confirme quem é o owner do package.
Verifique autorização de
EXECUTE.Confira plano, collection e contexto de execução.
Analise mensagens SAF/RACF quando aplicável.
Solicite o
GRANTcorreto.Nunca peça privilégios excessivos apenas para “fazer funcionar”.
20. SQLCODE -501, -502 e -514 — problemas com cursor
-501
Tentativa de executar FETCH ou CLOSE em cursor que não está aberto.
-502
Tentativa de abrir um cursor que já está aberto.
-514
O cursor não está em estado adequado para a operação, frequentemente por não estar preparado corretamente em cenários de SQL dinâmico.
Checklist de cursor
A sequência esperada é:
DECLARE
OPEN
FETCH
FETCH
FETCH
...
+100
CLOSE
No COBOL:
EXEC SQL
OPEN C1
END-EXEC.
IF SQLCODE NOT = 0
PERFORM 9000-TRATAR-ERRO-SQL
END-IF.
PERFORM UNTIL WS-FIM = 'S'
EXEC SQL
FETCH C1
INTO :WS-CODIGO,
:WS-NOME
END-EXEC
EVALUATE SQLCODE
WHEN 0
PERFORM 4000-PROCESSAR
WHEN +100
MOVE 'S' TO WS-FIM
WHEN OTHER
PERFORM 9000-TRATAR-ERRO-SQL
MOVE 'S' TO WS-FIM
END-EVALUATE
END-PERFORM.
EXEC SQL
CLOSE C1
END-EXEC.
Dica
Use flags explícitas:
01 WS-CURSOR-ABERTO PIC X VALUE 'N'.
01 WS-FIM-CURSOR PIC X VALUE 'N'.
Elas ajudam a impedir OPEN duplicado ou FETCH após fechamento.
21. WHENEVER: útil, mas não mágico
O Db2 permite instruções como:
EXEC SQL
WHENEVER SQLERROR
GO TO 9000-ERRO-SQL
END-EXEC.
Também existem:
EXEC SQL
WHENEVER NOT FOUND
GO TO 8000-NAO-ENCONTRADO
END-EXEC.
EXEC SQL
WHENEVER SQLWARNING
GO TO 8500-WARNING-SQL
END-EXEC.
A IBM documenta que:
NOT FOUNDcorresponde ao+100;SQLERRORcorresponde a SQLCODE negativo;SQLWARNINGcobre warnings e códigos positivos diferentes de+100. (IBM)
Entretanto, existe uma característica importante:
WHENEVER é uma diretiva tratada durante a preparação do SQL embutido. Seu efeito depende da posição em que aparece no fonte.
Ela não funciona exatamente como uma configuração dinâmica COBOL tradicional.
Risco
Um programador pode colocar:
EXEC SQL
WHENEVER SQLERROR GO TO 9000-ERRO
END-EXEC.
e depois esquecer que todas as instruções SQL seguintes estarão sujeitas a esse desvio, até que outra diretiva altere o comportamento.
Alternativa explícita
Muitas equipes preferem:
EXEC SQL
WHENEVER SQLERROR CONTINUE
END-EXEC.
E verificam o SQLCODE após cada comando:
EXEC SQL
DELETE FROM TEMPORARIA
WHERE CHAVE = :WS-CHAVE
END-EXEC.
PERFORM 9100-VERIFICAR-SQL.
Isso pode tornar o fluxo mais previsível.
22. Uma rotina COBOL centralizada de tratamento
Uma boa aplicação não deveria espalhar dezenas de DISPLAY SQLCODE improvisados.
Crie uma rotina padronizada:
9000-TRATAR-ERRO-SQL.
DISPLAY '**************************************'
DISPLAY '* ERRO DB2 *'
DISPLAY '**************************************'
DISPLAY 'PROGRAMA : ' WS-NOME-PROGRAMA
DISPLAY 'PARAGRAFO: ' WS-PARAGRAFO-ATUAL
DISPLAY 'OPERACAO : ' WS-OPERACAO-SQL
DISPLAY 'SQLCODE : ' SQLCODE
DISPLAY 'SQLSTATE : ' SQLSTATE
DISPLAY 'SQLERRP : ' SQLERRP
DISPLAY 'SQLERRML : ' SQLERRML
DISPLAY 'SQLERRMC : ' SQLERRMC
DISPLAY 'SQLERRD1 : ' SQLERRD (1)
DISPLAY 'SQLERRD2 : ' SQLERRD (2)
DISPLAY 'SQLERRD3 : ' SQLERRD (3)
DISPLAY 'SQLERRD4 : ' SQLERRD (4)
DISPLAY 'SQLERRD5 : ' SQLERRD (5)
DISPLAY 'SQLERRD6 : ' SQLERRD (6)
DISPLAY '**************************************'
MOVE 12 TO RETURN-CODE.
Em produção, avalie cuidados com dados sensíveis. Não exiba:
senhas;
tokens;
informações pessoais desnecessárias;
números completos de documentos;
dados financeiros sigilosos;
comandos SQL contendo informações protegidas.
A observabilidade deve ajudar o diagnóstico sem criar uma nova vulnerabilidade.
23. O passo a passo universal de diagnóstico
Quando aparecer um SQLCODE inesperado, siga esta sequência.
Passo 1 — identifique a instrução
Não procure apenas pelo número.
Descubra:
qual programa;
qual parágrafo;
qual instrução SQL;
qual tabela;
qual chave;
qual operação.
Passo 2 — registre a SQLCA
Capture:
SQLCODE;
SQLSTATE;
SQLERRMC;
SQLERRML;
SQLERRP;
SQLERRD;
SQLWARN.
Passo 3 — descubra a categoria
Pergunte:
É sucesso?
É +100?
É warning?
É erro de dados?
É erro de objeto?
É erro de package?
É erro de autorização?
É indisponibilidade?
É concorrência?
Passo 4 — leia os tokens
Muitos SQLCODEs só ficam claros quando analisamos SQLERRMC, reason code, nome do recurso ou nome do objeto.
Passo 5 — reproduza com os mesmos dados
Tente identificar:
chave;
conteúdo das host variables;
ambiente;
versão do programa;
package;
plano;
horário;
unidade de trabalho.
Passo 6 — compare estruturas
Verifique:
DCLGEN;
catálogo;
copybooks;
tipos;
comprimentos;
indicadores;
nullabilidade;
índices;
constraints.
Passo 7 — corrija a causa, não apenas o sintoma
Exemplo:
Sintoma: -803.
Correção ruim: ignorar toda duplicidade.
Correção real: descobrir por que a transação foi processada novamente.
Passo 8 — crie proteção contra recorrência
Depois de corrigir:
adicione validação;
melhore o log;
crie teste;
atualize documentação;
ajuste pipeline;
implemente monitoramento;
reveja commit e rollback.
24. COMMIT e ROLLBACK: a responsabilidade do Padawan
Uma transação Db2 não é apenas uma sequência de comandos.
Ela é uma unidade lógica de trabalho.
Exemplo:
Debitar conta A.
Creditar conta B.
Registrar movimentação.
Essas três ações precisam ser tratadas como um conjunto.
Se a primeira funcionar e a segunda falhar, você não pode simplesmente continuar.
EXEC SQL
COMMIT
END-EXEC.
confirma a unidade de trabalho.
EXEC SQL
ROLLBACK
END-EXEC.
desfaz alterações ainda não confirmadas, dentro das regras e do contexto da aplicação.
Cuidado
Não espalhe commits aleatórios apenas para reduzir locks.
Um commit mal posicionado pode quebrar a atomicidade da transação.
O ponto de commit deve refletir a regra de negócio, não apenas uma tentativa de silenciar problemas de concorrência.
25. Dicas de veterano para o COBOL Padawan
Use DCLGEN
A DCLGEN ajuda a alinhar as colunas Db2 com as variáveis COBOL.
Mas lembre-se:
DCLGEN não é um artefato eterno.
Se a tabela mudar, a declaração precisa ser revisada e regenerada.
Inicialize variáveis
Antes de um SELECT INTO, inicialize as variáveis de saída quando isso fizer sentido.
Isso evita o uso acidental de conteúdo anterior após um +100.
Registre o ponto da falha
Antes da instrução:
MOVE 'SELECT-CLIENTE'
TO WS-OPERACAO-SQL.
Assim a rotina central sabe exatamente qual comando falhou.
Não use apenas DISPLAY
Em aplicações maduras, prefira uma estratégia padronizada de logging, mensagens de aplicação, códigos de retorno e integração com observabilidade.
Diferencie erro técnico de erro de negócio
+100 procurando cliente opcional:
condição de negócio.
-805:
erro técnico de implantação.
-803 ao reprocessar mensagem:
pode representar condição funcional de idempotência.
-911:
condição técnica de concorrência que talvez permita retry.
Conheça o ambiente
Em Db2 for z/OS, o diagnóstico frequentemente envolve muito mais do que o fonte:
subsistema Db2;
catálogo;
package;
collection;
plan;
DBRM;
BIND;
load library;
RACF;
JES2;
SDSF;
logs;
utilitários;
locks.
26. Curiosidade: SQLCODE não é ABEND
Um SQLCODE negativo indica que uma instrução SQL falhou.
Um ABEND indica encerramento anormal de uma task, job step ou programa.
Os dois podem aparecer juntos, mas não são a mesma coisa.
Um programa bem escrito pode receber -803, tratar a duplicidade e continuar.
Outro programa pode receber +100, ignorar a condição e mais tarde causar um S0C7 porque tentou usar dados inválidos.
Portanto:
SQLCODE negativo não significa automaticamente ABEND.
SQLCODE positivo não significa automaticamente que tudo está correto.
O resultado depende da maneira como o programa reage.
27. Easter egg do Bellacosa Mainframe
Nos filmes, o jovem Jedi pergunta:
“Mestre, como saberei qual caminho seguir?”
O mestre responde:
“Observe a Força.”
No Db2, a resposta seria:
“Observe a SQLCA.”
O SQLCODE mostra a direção geral.
O SQLSTATE mostra a categoria.
O SQLERRMC revela os personagens envolvidos.
O reason code explica a motivação do vilão.
O SQLERRD guarda pistas escondidas.
O log do Db2 conta o que aconteceu fora da câmera.
E o programa COBOL decide se deve:
continuar;
encerrar;
repetir;
fazer rollback;
informar o usuário;
acionar o suporte.
O verdadeiro Sith não é o SQLCODE negativo.
O verdadeiro Sith é o programa que recebe uma mensagem de erro, ignora a SQLCA e continua processando dados como se nada tivesse acontecido.
28. Tabela de bolso do Padawan
SQLCODE SIGNIFICADO PRINCIPAL
------- ----------------------------------------------
0 Execução bem-sucedida
+100 Nenhum dado encontrado / fim do cursor
-204 Objeto não definido
-206 Coluna inválida ou não encontrada
-302 Valor de entrada incompatível ou excessivo
-303 Tipos incompatíveis
-305 NULL recebido sem variável indicadora
-407 NULL enviado para coluna NOT NULL
-501 Cursor não aberto
-502 Cursor já aberto
-514 Cursor em estado inadequado
-803 Violação de chave ou índice único
-805 Package não encontrado
-811 SELECT INTO retornou mais de uma linha
-818 Incompatibilidade entre módulo e DBRM/package
-904 Recurso indisponível
-911 Timeout/deadlock com impacto na unidade de trabalho
-913 Timeout/deadlock; analisar rollback e reason code
-922 Falha de autorização ou conexão
Essa tabela é um mapa inicial, não substitui a documentação completa. O catálogo de códigos Db2 fornece explicações, ações do sistema e respostas recomendadas para cada condição. (IBM)
Conclusão: o erro é uma mensagem, não uma sentença
Aprender Db2 com COBOL não significa decorar uma enciclopédia de SQLCODEs.
Significa construir um método.
Quando uma instrução falhar:
pare;
identifique o SQL;
capture a SQLCA;
leia o SQLCODE;
consulte o SQLSTATE;
analise os tokens;
identifique objetos e reason codes;
verifique host variables;
confirme package, plano e ambiente;
corrija a causa;
proteja o sistema contra recorrência.
Com o tempo, os números deixam de parecer mensagens alienígenas.
O +100 passa a significar fim normal de cursor.
O -305 lembra imediatamente uma variável indicadora esquecida.
O -803 aponta para unicidade ou reprocessamento.
O -805 faz você olhar para package, collection e BIND.
O -818 lembra que load module e DBRM precisam caminhar juntos.
O -911 acende o alerta de concorrência, commit e retry.
O -904 exige reason code, resource type e resource name.
Nesse momento, o Padawan deixa de perguntar:
“Por que o Db2 quebrou?”
E começa a perguntar:
“Qual condição o Db2 está comunicando, quais evidências ele forneceu e qual é a resposta correta da aplicação?”
Essa mudança de postura é o nascimento de um verdadeiro programador de sistemas corporativos.
Porque no Bellacosa Mainframe, cada SQLCODE é uma pista, cada SQLCA é um mapa e cada erro corretamente tratado é mais uma transação protegida no coração do IBM Z.
Sem comentários:
Enviar um comentário