Translate

Mostrar mensagens com a etiqueta bind. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta bind. Mostrar todas as mensagens

terça-feira, 24 de setembro de 2024

Fluxo de Compilação de um programa COBOL com DB2

 

Bellacosa Mainframe e o fluxo de compilação cobol com db2

☕ Um Café no Bellacosa Mainframe

O Caso do Programa que Precisava de Duas Identidades

O Fluxo de Compilação de um Programa COBOL com Db2

A chuva caía sobre as janelas do CPD como uma sequência interminável de registros sendo gravados em um arquivo sequencial.

Do lado de dentro, os monitores 3270 lançavam uma luz esverdeada sobre as mesas. O relógio marcava 23h47. Os operadores já falavam baixo, como se soubessem que, depois de certo horário, os programas começavam a revelar segredos que escondiam durante o expediente.

Foi quando encontrei o programa.

Estava abandonado em uma biblioteca de fontes, cercado por COPYBOOKs, comandos SQL e comentários escritos por programadores que provavelmente já haviam se aposentado.

Na primeira linha, ele parecia apenas mais um programa COBOL.

Mas havia alguma coisa diferente.

No meio da PROCEDURE DIVISION, encontrei a pista:

EXEC SQL
    SELECT NOME_CLIENTE,
           SALDO_CONTA
      INTO :WS-NOME-CLIENTE,
           :WS-SALDO-CONTA
      FROM CLIENTES
     WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.

Aquilo mudava tudo.

Um compilador COBOL comum não saberia o que fazer com aquelas instruções.

EXEC SQL não era COBOL.

Era SQL infiltrado dentro de um programa COBOL.

O programa possuía duas identidades: uma destinada ao compilador COBOL e outra destinada ao Db2.

Para transformar aquele fonte em um módulo executável, seria necessário conduzi-lo por uma cadeia de interrogatórios, traduções, compilações, ligações e registros.

No mundo COBOL com Db2, ninguém sai do fonte diretamente para a execução.

Antes de chegar ao CICS, ao batch ou ao ambiente de produção, o programa precisa atravessar o chamado fluxo de compilação COBOL–Db2.

E cada etapa produz uma nova pista.


1. A cena do crime: o programa-fonte

Tudo começa com um membro contendo o código-fonte COBOL.

Em um ambiente tradicional, ele poderia estar em uma biblioteca como:

BANCO.DESENV.COBOL(PROGCLI1)

Dentro desse programa encontramos instruções COBOL normais:

MOVE 1001 TO WS-COD-CLIENTE.
DISPLAY 'INICIANDO CONSULTA'.

Mas também encontramos comandos SQL embutidos:

EXEC SQL
    SELECT NOME_CLIENTE
      INTO :WS-NOME-CLIENTE
      FROM CLIENTES
     WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.

Esses comandos são chamados de SQL estático embutido, ou embedded static SQL.

O termo “estático” significa que, em linhas gerais, a instrução SQL já está conhecida antes da execução do programa.

O Db2 pode analisar essa instrução previamente, determinar como ela poderá acessar as tabelas e registrar essas informações durante o processo de BIND.

Mas existe um problema.

O compilador COBOL não entende diretamente:

EXEC SQL

Ele entende MOVE, PERFORM, IF, EVALUATE, READ, WRITE e outras instruções da linguagem.

SQL pertence ao território do Db2.

Portanto, antes da compilação COBOL, alguém precisa separar as duas identidades do programa.

Esse alguém é o pré-compilador Db2.


2. O primeiro interrogatório: o pré-compilador Db2

O pré-compilador recebe o programa-fonte como entrada.

Sua missão é localizar todas as instruções existentes entre:

EXEC SQL

e:

END-EXEC

Quando encontra uma instrução SQL, o pré-compilador não simplesmente a apaga.

Ele realiza duas operações fundamentais.

Primeiro, substitui o SQL por chamadas que poderão ser compiladas como parte do programa COBOL.

Segundo, extrai informações sobre as instruções SQL e as registra em um arquivo chamado DBRM.

Assim, de um único programa-fonte surgem duas evidências:

Fonte COBOL com SQL
        |
        v
Pré-compilador Db2
        |
        +--> Fonte COBOL modificado
        |
        +--> DBRM

Essa divisão é a chave de todo o caso.

O programa passa a ter dois caminhos paralelos.

Um caminho segue para o compilador COBOL.

O outro segue para o BIND do Db2.

Mais tarde, os dois caminhos precisarão se reencontrar durante a execução.


3. O fonte modificado

Depois do pré-processamento, o SQL original não permanece exatamente como foi escrito.

Uma instrução como:

EXEC SQL
    SELECT NOME_CLIENTE
      INTO :WS-NOME-CLIENTE
      FROM CLIENTES
     WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.

é transformada em estruturas e chamadas que o compilador COBOL consegue processar.

O resultado é conhecido como fonte modificado, fonte traduzido ou fonte expandido, dependendo da terminologia usada no ambiente.

Esse fonte contém lógica responsável por conversar com a interface do Db2 em tempo de execução.

O programador normalmente não precisa editar esse código gerado.

Ele existe para que o compilador COBOL consiga trabalhar com um programa que originalmente continha SQL.

É como se o pré-compilador retirasse o estrangeiro da sala, traduzisse seu depoimento e entregasse ao compilador apenas aquilo que ele consegue compreender.


4. A ficha que acompanha o suspeito: SQLCA

Programas COBOL que acessam Db2 normalmente precisam de uma área chamada SQLCA, SQL Communication Area.

Ela pode ser incluída com:

EXEC SQL
    INCLUDE SQLCA
END-EXEC.

A SQLCA contém informações sobre o resultado da última instrução SQL executada.

Entre seus campos, o mais famoso é:

SQLCODE

O SQLCODE informa se a operação terminou corretamente ou se algo inesperado aconteceu.

Alguns valores comuns são:

SQLCODE = 0
Operação concluída com sucesso.

SQLCODE = +100
Nenhuma linha encontrada ou fim do resultado.

SQLCODE negativo
Ocorreu algum erro.

Exemplo:

EXEC SQL
    SELECT NOME_CLIENTE
      INTO :WS-NOME-CLIENTE
      FROM CLIENTES
     WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.

EVALUATE TRUE
    WHEN SQLCODE = 0
         DISPLAY 'CLIENTE: ' WS-NOME-CLIENTE

    WHEN SQLCODE = 100
         DISPLAY 'CLIENTE NAO ENCONTRADO'

    WHEN OTHER
         DISPLAY 'ERRO DB2. SQLCODE: ' SQLCODE
END-EVALUATE.

Um programa COBOL–Db2 que ignora o SQLCODE é como um detetive que interroga uma testemunha e sai da sala sem ouvir a resposta.


5. O segundo interrogatório: o compilador COBOL

Depois do pré-compilador, o fonte modificado é enviado ao compilador COBOL.

Agora o compilador encontra apenas estruturas que consegue entender.

Ele verifica:

  • sintaxe COBOL;

  • definição de variáveis;

  • compatibilidade de tipos;

  • referências a parágrafos;

  • COPYBOOKs;

  • tamanho de campos;

  • opções de compilação;

  • regras da linguagem.

Se tudo estiver correto, o compilador gera um módulo objeto.

O módulo objeto ainda não é o programa final pronto para executar.

Ele contém código de máquina e referências que ainda precisam ser resolvidas.

Podemos representar essa fase assim:

Fonte COBOL modificado
          |
          v
Compilador COBOL
          |
          v
Módulo objeto

Durante essa etapa, também é produzido o listing de compilação.

Esse listing pode mostrar:

  • erros;

  • avisos;

  • opções utilizadas;

  • mapa de dados;

  • referências cruzadas;

  • estatísticas da compilação;

  • mensagens do compilador.

O retorno da compilação costuma ser avaliado por meio do condition code do step.

Uma interpretação frequente é:

RC 0
Compilação concluída sem mensagens relevantes.

RC 4
Compilação concluída com avisos.

RC 8 ou superior
Existem erros que normalmente impedem a geração válida do programa.

Os significados exatos dependem das mensagens e das políticas do ambiente.

Um RC=4 não deve ser tratado automaticamente como “está tudo bem”.

Aviso também é pista.


6. O dossiê secreto: DBRM

Enquanto o fonte modificado segue para o compilador COBOL, o DBRM toma outro caminho.

DBRM significa:

Database Request Module

Ele contém uma representação das instruções SQL estáticas extraídas do programa.

O DBRM não é um programa COBOL executável.

Ele também não é uma tabela do Db2.

É uma espécie de dossiê contendo os pedidos de acesso ao banco de dados.

Nesse dossiê, o Db2 encontra informações sobre instruções como:

SELECT
INSERT
UPDATE
DELETE
DECLARE CURSOR
OPEN
FETCH
CLOSE

O DBRM será usado mais tarde durante o processo chamado BIND.

Sem BIND, o Db2 sabe que o programa tem intenções.

Mas ainda não concedeu autorização operacional para que essas intenções sejam executadas.


7. O BIND: quando o Db2 monta o plano

O BIND é uma das etapas mais importantes do fluxo.

Durante o BIND, o Db2 examina as instruções SQL registradas no DBRM.

Ele verifica:

  • se os objetos referenciados existem;

  • se tabelas, views e colunas podem ser localizadas;

  • se os tipos são compatíveis;

  • se o usuário responsável possui os privilégios necessários;

  • quais caminhos de acesso podem ser utilizados;

  • quais opções de isolamento e validação foram definidas.

O resultado normalmente é a criação ou atualização de um PACKAGE.

Em arquiteturas mais antigas ou em determinados ambientes, também pode existir o conceito de PLAN associado à execução.

De forma simplificada:

DBRM
 |
 v
BIND PACKAGE
 |
 v
PACKAGE Db2

O PACKAGE contém informações que o Db2 utilizará para executar o SQL estático.

Entre essas informações está o access path, isto é, o caminho escolhido para alcançar os dados.

Por exemplo, o Db2 poderá decidir entre:

  • utilizar um índice;

  • realizar uma varredura da tabela;

  • acessar índices em determinada sequência;

  • executar joins em uma ordem específica;

  • utilizar mecanismos de ordenação;

  • aplicar predicados em etapas diferentes.

O BIND é o momento em que o Db2 estuda o mapa do bairro antes de mandar seus agentes à rua.


8. VALIDATE(BIND) e VALIDATE(RUN)

Durante o BIND, uma opção importante pode determinar quando determinadas verificações serão exigidas.

Com:

VALIDATE(BIND)

o Db2 tenta validar os objetos e privilégios durante o próprio BIND.

Caso algo necessário não esteja disponível, o BIND pode falhar.

Com:

VALIDATE(RUN)

algumas verificações podem ser adiadas até o momento da execução.

Isso pode ser útil em certos cenários, mas também transfere parte do risco para o ambiente de execução.

Em uma produção crítica, adiar problemas não significa eliminá-los.

Significa apenas permitir que eles apareçam quando o programa estiver diante do usuário, do fechamento contábil ou do lote de milhões de registros.


9. O PACKAGE

O PACKAGE é o objeto Db2 que representa o SQL preparado para execução.

Ele está associado a elementos como:

  • nome da collection;

  • nome do programa;

  • versão;

  • opções do BIND;

  • access paths;

  • consistência do programa;

  • nível de isolamento;

  • qualificador;

  • proprietário;

  • validação.

Um comando conceitual de BIND poderia lembrar:

BIND PACKAGE(COLLECT1)
     MEMBER(PROGCLI1)
     ACTION(REPLACE)
     ISOLATION(CS)
     VALIDATE(BIND)

A sintaxe real depende do utilitário, da versão, do padrão de nomenclatura e das práticas adotadas na instalação.

O ponto essencial é que o PACKAGE vive no Db2.

Ele não é armazenado dentro do load module COBOL.

Isso explica por que o programa executável e seu PACKAGE podem existir em lugares diferentes e, mesmo assim, precisar corresponder exatamente.


10. O elo invisível: consistency token

Aqui surge uma das pistas mais elegantes do processo.

O módulo executável COBOL e o PACKAGE Db2 precisam reconhecer um ao outro.

Para isso, o processo utiliza uma identificação de consistência frequentemente relacionada ao consistency token.

O pré-compilador e o BIND produzem elementos que permitem ao Db2 verificar se o código executável corresponde ao PACKAGE disponível.

Considere este cenário:

  1. O programa foi pré-compilado.

  2. O DBRM foi gerado.

  3. O COBOL foi compilado.

  4. O load module foi criado.

  5. Um novo BIND não foi executado corretamente.

  6. O programa antigo ou um PACKAGE incompatível permaneceu no ambiente.

Durante a execução, o Db2 pode detectar que o executável e o PACKAGE não combinam.

O famoso resultado pode ser:

SQLCODE -805

Em linguagem de romance policial:

O sujeito apresentado pelo load module não era o mesmo registrado nos arquivos do Db2.


11. O terceiro interrogatório: o link-edit

O módulo objeto criado pelo compilador ainda contém referências externas.

Ele pode precisar de rotinas de tempo de execução, interfaces do Db2 e bibliotecas do sistema.

Por isso, o módulo objeto passa pelo link-edit, atualmente frequentemente executado pelo Binder do z/OS.

Fluxo:

Módulo objeto
      |
      v
Binder / Link-edit
      |
      v
Load module ou program object

Durante essa etapa, referências externas são resolvidas.

O resultado é colocado em uma load library, por exemplo:

BANCO.DESENV.LOAD(PROGCLI1)

Esse membro é o programa que poderá ser carregado para execução.

Dependendo da tecnologia e das opções adotadas, ele poderá ser chamado de:

  • load module;

  • program object;

  • módulo de carga;

  • executável.

É importante não confundir o load module com o PACKAGE.

Load module
Código COBOL executável.

PACKAGE
Representação executável das instruções SQL estáticas dentro do Db2.

Os dois fazem parte do mesmo caso, mas vivem em delegacias diferentes.


12. A montagem completa do fluxo

O fluxo clássico pode ser representado assim:

+----------------------------------+
| Fonte COBOL com SQL embutido     |
| EXEC SQL ... END-EXEC            |
+----------------+-----------------+
                 |
                 v
+----------------------------------+
| Pré-compilador Db2               |
+----------------+-----------------+
                 |
        +--------+--------+
        |                 |
        v                 v
+---------------+   +---------------+
| Fonte COBOL   |   | DBRM          |
| modificado    |   | SQL estático  |
+-------+-------+   +-------+-------+
        |                   |
        v                   v
+---------------+   +---------------+
| Compilador    |   | BIND PACKAGE  |
| COBOL         |   | no Db2        |
+-------+-------+   +-------+-------+
        |                   |
        v                   v
+---------------+   +---------------+
| Módulo objeto |   | PACKAGE       |
+-------+-------+   +---------------+
        |
        v
+---------------+
| Binder /      |
| Link-edit     |
+-------+-------+
        |
        v
+---------------+
| Load module   |
| ou program    |
| object        |
+---------------+

Na execução, os dois lados finalmente se encontram:

Load module COBOL
        |
        | chamada SQL
        v
Subsistema Db2
        |
        v
PACKAGE correspondente
        |
        v
Tabelas, índices e dados

Esse é o fluxo essencial.

Mas, como em toda investigação, os detalhes podem mudar conforme as ferramentas utilizadas.


13. Pré-compilador tradicional ou coprocessador SQL

Em ambientes modernos, o fluxo pode usar um SQL coprocessor integrado à compilação COBOL.

Nesse modelo, a compilação e o tratamento do SQL podem parecer uma única operação dentro do JCL ou da ferramenta de build.

Isso não elimina os conceitos fundamentais.

Mesmo com automação, continuam existindo:

  • análise do SQL;

  • geração de informações para o Db2;

  • compilação COBOL;

  • criação do executável;

  • criação ou atualização do PACKAGE;

  • necessidade de correspondência entre código e PACKAGE.

A diferença é que as ferramentas modernas escondem parte do corredor escuro atrás de uma porta automática.

O corredor continua lá.


14. Exemplo simplificado de programa

Considere o seguinte programa:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. PROGCLI1.

       DATA DIVISION.

       WORKING-STORAGE SECTION.

       01  WS-COD-CLIENTE     PIC 9(09) COMP-3.
       01  WS-NOME-CLIENTE    PIC X(40).
       01  WS-SALDO-CONTA     PIC S9(11)V99 COMP-3.

           EXEC SQL
               INCLUDE SQLCA
           END-EXEC.

       PROCEDURE DIVISION.

       0000-PRINCIPAL.

           MOVE 1001 TO WS-COD-CLIENTE

           EXEC SQL
               SELECT NOME_CLIENTE,
                      SALDO_CONTA
                 INTO :WS-NOME-CLIENTE,
                      :WS-SALDO-CONTA
                 FROM CLIENTES
                WHERE COD_CLIENTE = :WS-COD-CLIENTE
           END-EXEC

           EVALUATE TRUE
               WHEN SQLCODE = 0
                    DISPLAY 'CLIENTE: ' WS-NOME-CLIENTE
                    DISPLAY 'SALDO  : ' WS-SALDO-CONTA

               WHEN SQLCODE = 100
                    DISPLAY 'CLIENTE NAO ENCONTRADO'

               WHEN OTHER
                    DISPLAY 'ERRO SQL: ' SQLCODE
           END-EVALUATE

           GOBACK.

Antes que o programa execute, várias condições precisam ser atendidas:

  1. A tabela CLIENTES precisa existir.

  2. As colunas precisam existir.

  3. Os tipos precisam ser compatíveis.

  4. O programa precisa ser pré-processado.

  5. O código COBOL precisa ser compilado.

  6. O executável precisa ser linkado.

  7. O PACKAGE precisa ser criado.

  8. O usuário de execução precisa ter os acessos necessários.

  9. O load module e o PACKAGE precisam corresponder.

  10. O subsistema Db2 correto precisa estar disponível.

Uma única instrução SELECT pode parecer simples no fonte.

Mas por trás dela existe uma organização inteira trabalhando durante a madrugada.


15. Host variables: os informantes do COBOL

As variáveis utilizadas pelo SQL são chamadas de host variables.

Elas pertencem ao programa COBOL, mas são apresentadas ao SQL com dois-pontos:

:WS-COD-CLIENTE

Exemplo:

WHERE COD_CLIENTE = :WS-COD-CLIENTE

A coluna COD_CLIENTE pertence à tabela.

A variável WS-COD-CLIENTE pertence ao programa COBOL.

Os dois-pontos avisam ao pré-compilador:

Este nome não é uma coluna do banco. É uma variável do programa.

No INTO:

INTO :WS-NOME-CLIENTE

o Db2 coloca o valor retornado dentro da variável COBOL.

As host variables fazem a ponte entre dois mundos:

Mundo COBOL               Mundo Db2

WS-COD-CLIENTE   ------>  COD_CLIENTE

WS-NOME-CLIENTE  <------  NOME_CLIENTE

Se os tipos forem incompatíveis, o caso pode terminar em erro, truncamento ou comportamento indesejado.

Por isso, o programador deve entender tanto o PIC COBOL quanto o tipo da coluna Db2.


16. Variáveis indicadoras e o mistério do NULL

COBOL tradicional não possui um conceito nativo idêntico ao NULL do banco de dados.

Por isso, quando uma coluna pode conter NULL, utiliza-se uma indicator variable.

Exemplo:

01  WS-TELEFONE        PIC X(20).
01  WS-IND-TELEFONE    PIC S9(04) COMP.

No SQL:

EXEC SQL
    SELECT TELEFONE
      INTO :WS-TELEFONE :WS-IND-TELEFONE
      FROM CLIENTES
     WHERE COD_CLIENTE = :WS-COD-CLIENTE
END-EXEC.

Depois da execução:

Indicator >= 0
O valor normalmente está presente.

Indicator = -1
A coluna retornou NULL.

Sem a variável indicadora, um SELECT que encontre NULL pode gerar erro.

O programador iniciante frequentemente acusa a coluna.

Mas o verdadeiro culpado foi a ausência da indicator variable.


17. O PLAN

Em muitos ambientes Db2 for z/OS, packages são associados a um PLAN ou acessados por meio de mecanismos como collection lists.

Historicamente, o PLAN representa uma estrutura utilizada para a execução de programas SQL.

Simplificando:

Programa
   |
   v
PLAN
   |
   v
PACKAGE
   |
   v
SQL e dados

Em arquiteturas atuais, o PACKAGE ganhou grande importância porque permite maior modularidade.

Vários programas podem possuir seus próprios packages.

O PLAN pode utilizar uma lista de collections por meio de PKLIST.

Isso evita a necessidade de colocar todo o SQL de uma aplicação dentro de um único objeto gigantesco.


18. Erros clássicos da investigação

SQLCODE -805

Normalmente indica que o PACKAGE necessário não foi encontrado ou que existe incompatibilidade de identificação.

Possíveis causas:

  • PACKAGE não bindado;

  • collection incorreta;

  • versão incorreta;

  • ambiente errado;

  • load module e PACKAGE incompatíveis;

  • PLAN sem acesso à collection adequada.


SQLCODE -818

É frequentemente associado a incompatibilidade de timestamp ou consistency token entre o módulo executável e o DBRM/PACKAGE.

Em termos práticos:

  • o código foi compilado;

  • o BIND foi feito com outro DBRM;

  • as peças pertencem a versões diferentes.

É como tentar abrir um cofre novo com a combinação do cofre antigo.


SQLCODE -204

Objeto não encontrado.

Exemplo:

Tabela, view, alias ou outro objeto não localizado.

Possíveis causas:

  • nome incorreto;

  • qualifier incorreto;

  • objeto inexistente;

  • ambiente incorreto;

  • uso de tabela de desenvolvimento em produção ou vice-versa.


SQLCODE -206

Coluna não encontrada ou inválida no contexto.

Possíveis causas:

  • nome digitado incorretamente;

  • coluna removida;

  • alias de tabela ausente;

  • SQL desatualizado em relação à estrutura do banco.


SQLCODE -551

Problema de autorização.

O usuário ou authid não possui privilégio suficiente para realizar a operação.

O programa pode estar perfeito.

O BIND pode existir.

A tabela pode existir.

Mas a porta permanece trancada.


SQLCODE +100

Nenhuma linha encontrada.

Não é necessariamente um erro.

Em um SELECT INTO, pode significar que nenhum registro correspondeu à condição.

Em um cursor, pode indicar fim das linhas.

O erro verdadeiro é tratar +100 como se nunca pudesse acontecer.


19. JCL conceitual do processo

Um JCL real varia muito entre instalações, mas conceitualmente o processo pode ter steps como:

STEP 1 - Pré-compilação Db2
STEP 2 - Compilação COBOL
STEP 3 - Link-edit
STEP 4 - BIND PACKAGE
STEP 5 - BIND PLAN, quando necessário

Ou, em outra organização:

STEP 1 - Compilação com SQL coprocessor
STEP 2 - Link-edit
STEP 3 - BIND PACKAGE

Pipelines modernos podem executar essas etapas por meio de:

  • JCLs padronizados;

  • procedures catalogadas;

  • Endevor;

  • ISPW;

  • DBB;

  • Jenkins;

  • Git;

  • scripts de automação;

  • ferramentas DevOps para IBM Z.

Mesmo que o programador clique em um botão chamado “Build”, o botão não faz magia.

Ele apenas dispara uma sequência semelhante à investigação que acabamos de seguir.


20. A ordem das etapas importa

Imagine que o programa tenha sido alterado.

O desenvolvedor adiciona uma coluna ao SELECT:

SELECT NOME_CLIENTE,
       SALDO_CONTA,
       LIMITE_CREDITO

O fonte é pré-processado e compilado.

O novo load module é promovido.

Mas o novo DBRM não é utilizado no BIND.

O resultado é um executável novo tentando conversar com um PACKAGE antigo.

Isso pode gerar incompatibilidade.

Agora imagine o contrário:

O PACKAGE novo é bindado, mas o load module antigo permanece na biblioteca de produção.

Mais uma vez, versões diferentes se encontram.

Por isso, uma promoção correta precisa tratar como uma unidade:

Fonte
DBRM
Load module
PACKAGE
Configuração de execução

Em ambientes controlados, o processo de change management deve garantir que todas as peças da mesma versão avancem juntas.


21. O que acontece em tempo de execução

Quando o programa é executado, o z/OS carrega o load module.

Ao alcançar uma instrução SQL, a lógica gerada durante o pré-processamento encaminha a solicitação ao Db2.

O Db2 identifica:

  • o subsistema;

  • o plano ou contexto de execução;

  • a collection;

  • o PACKAGE;

  • a seção SQL correspondente.

Depois, executa o access path registrado ou reavaliado conforme as características do ambiente e as opções utilizadas.

O resultado é devolvido às host variables.

O SQLCODE é atualizado.

O programa COBOL continua.

Fluxo simplificado:

Programa COBOL executando
          |
          v
Encontra instrução SQL
          |
          v
Interface com Db2
          |
          v
Localiza PACKAGE
          |
          v
Executa SQL
          |
          v
Acessa tabela ou índice
          |
          v
Retorna dados e SQLCODE
          |
          v
Programa COBOL prossegue

Para o usuário, tudo isso pode acontecer em milésimos de segundo.

Para o programador, são décadas de engenharia condensadas em um único EXEC SQL.


22. Compile não é BIND

Uma das confusões mais comuns entre iniciantes é pensar:

O programa compilou, então o SQL está correto.

Nem sempre.

A compilação COBOL valida o código COBOL e as estruturas geradas.

O BIND é que realiza boa parte da validação relacionada ao Db2.

Dependendo das opções usadas, alguns problemas só aparecerão durante o BIND ou até durante a execução.

Portanto:

Compilação bem-sucedida
não garante
BIND bem-sucedido.

E:

BIND bem-sucedido
não garante
execução funcionalmente correta.

Um SELECT pode executar perfeitamente e devolver o cliente errado porque a regra de negócio foi escrita de maneira incorreta.

Nenhum compilador consegue condenar uma lógica que é sintaticamente válida, mas conceitualmente equivocada.


23. BIND não é apenas burocracia

É comum enxergar o BIND apenas como uma etapa obrigatória.

Mas ele também está ligado à performance.

Durante o BIND ou REBIND, o Db2 pode determinar access paths com base em informações como:

  • índices disponíveis;

  • estatísticas de tabelas;

  • estatísticas de colunas;

  • cardinalidade;

  • distribuição dos dados;

  • custo estimado;

  • métodos de join;

  • quantidade de páginas;

  • seletividade dos predicados.

Se as estatísticas estiverem desatualizadas, o Db2 poderá tomar decisões baseadas em uma fotografia antiga da cena.

É por isso que operações como RUNSTATS possuem tanta importância.

O otimizador só pode investigar com as evidências que recebe.


24. REBIND

O REBIND permite reconstruir informações de um PACKAGE existente sem necessariamente recompilar o programa COBOL.

Ele pode ser utilizado quando:

  • estatísticas foram atualizadas;

  • índices foram criados ou alterados;

  • ocorreu mudança de versão;

  • deseja-se recalcular access paths;

  • políticas de performance exigem revisão;

  • objetos sofreram alterações.

Mas um REBIND deve ser tratado com cuidado.

Um novo access path pode melhorar a performance.

Também pode piorá-la.

Em ambientes críticos, equipes analisam EXPLAIN, histórico de access paths e comportamento anterior antes de aceitar mudanças.

Todo bom detetive sabe que reabrir um caso pode revelar a verdade.

Mas também pode destruir uma pista que ainda era útil.


25. COLLECTION, PACKAGE e versão

Packages podem ser organizados em collections.

Isso permite separar ambientes ou versões.

Exemplo conceitual:

Collection: DESENV
Package: PROGCLI1

Collection: HOMOLOG
Package: PROGCLI1

Collection: PRODUCAO
Package: PROGCLI1

O nome do programa pode ser o mesmo.

Mas cada collection representa um contexto diferente.

Também podem existir estratégias de versionamento:

PROGCLI1 versão V1
PROGCLI1 versão V2

Esses mecanismos ajudam em:

  • implantação;

  • rollback;

  • testes paralelos;

  • manutenção;

  • coexistência de versões.

Entretanto, quanto maior a flexibilidade, maior a necessidade de controle.

Sem governança, uma collection se transforma em uma rua escura cheia de packages com identidades falsas.


26. Static SQL e Dynamic SQL

O fluxo descrito é principalmente associado ao SQL estático.

No SQL estático, a instrução é conhecida antes da execução:

EXEC SQL
    SELECT NOME_CLIENTE
      INTO :WS-NOME
      FROM CLIENTES
     WHERE COD_CLIENTE = :WS-COD
END-EXEC.

No SQL dinâmico, o texto da instrução pode ser montado durante a execução.

Exemplo conceitual:

MOVE 'SELECT NOME_CLIENTE FROM CLIENTES'
  TO WS-COMANDO-SQL.

Depois, o programa pode usar comandos como:

PREPARE
EXECUTE
OPEN

O SQL dinâmico oferece flexibilidade.

Mas pode aumentar a complexidade relacionada a:

  • segurança;

  • autorização;

  • performance;

  • cache;

  • validação;

  • construção de comandos;

  • risco de SQL injection, quando entradas são tratadas incorretamente.

O SQL estático é como uma operação planejada.

O SQL dinâmico é como receber uma missão enquanto o carro já está em movimento.


27. O papel do programador COBOL

O programador COBOL–Db2 precisa enxergar além do fonte.

Ele deve saber responder:

  • Qual pré-processador está sendo usado?

  • Onde o DBRM é gerado?

  • Em qual biblioteca o load module é gravado?

  • Qual collection contém o PACKAGE?

  • Qual PLAN ou PKLIST participa da execução?

  • Qual subsistema Db2 será acessado?

  • Qual qualifier está sendo utilizado?

  • Qual authid realiza o BIND?

  • Quem executa o programa?

  • Qual é o nível de isolamento?

  • O programa verifica SQLCODE?

  • Existem colunas nullable?

  • As host variables são compatíveis?

  • O BIND acompanha a promoção do load module?

Essas perguntas separam o programador que apenas altera linhas daquele que compreende o ciclo de vida da aplicação.


28. Checklist para o iniciante

Antes de declarar o caso encerrado, verifique:

[ ] O fonte COBOL está correto?

[ ] Todas as instruções EXEC SQL possuem END-EXEC?

[ ] As host variables estão declaradas?

[ ] Os tipos COBOL combinam com as colunas Db2?

[ ] Colunas nullable possuem indicator variables?

[ ] A SQLCA foi incluída?

[ ] O programa testa SQLCODE?

[ ] O pré-processamento terminou corretamente?

[ ] O DBRM foi gerado?

[ ] A compilação COBOL terminou sem erros?

[ ] O link-edit criou o load module?

[ ] O BIND PACKAGE foi executado?

[ ] A collection está correta?

[ ] O PLAN ou PKLIST encontra o PACKAGE?

[ ] O executável e o PACKAGE pertencem à mesma versão?

[ ] O usuário possui autorização?

[ ] A load library correta está sendo utilizada?

[ ] O subsistema Db2 correto está ativo?

Esse checklist não evita todos os crimes.

Mas reduz bastante o número de suspeitos.


29. O fluxo resumido em uma frase

Um programa COBOL com Db2 passa pelo pré-processamento para separar COBOL e SQL, pela compilação para gerar o código objeto, pelo link-edit para criar o executável e pelo BIND para transformar o SQL estático em um PACKAGE reconhecido pelo Db2.

Ou, em linguagem de rua:

O pré-compilador separa.
O compilador traduz.
O Binder monta.
O BIND registra.
O Db2 executa.

30. Conclusão: dois caminhos, uma única execução

Às 3h12 da manhã, o caso finalmente estava resolvido.

O programa não era apenas COBOL.

Também não era apenas SQL.

Ele era uma aliança entre dois mundos.

O lado COBOL cuidava da lógica, dos campos, dos arquivos, dos cálculos e das decisões.

O lado Db2 cuidava das tabelas, dos índices, dos access paths, dos locks e da persistência dos dados.

Entre os dois, o pré-compilador atuava como intérprete.

O DBRM carregava o depoimento das instruções SQL.

O compilador transformava COBOL em código objeto.

O Binder criava o módulo executável.

O BIND registrava o PACKAGE no submundo do Db2.

Na execução, todas essas peças precisavam apresentar os mesmos documentos.

Quando tudo correspondia, o SELECT retornava seus dados e o programa continuava tranquilamente.

Quando alguma peça pertencia à versão errada, surgiam os suspeitos habituais:

-805
-818
-204
-206
-551

Apaguei a última luz do CPD e deixei o programa executando.

Lá fora, a chuva ainda caía.

Dentro do mainframe, milhões de instruções SQL atravessavam o mesmo caminho sem que ninguém percebesse.

Porque esta é uma das grandes verdades do IBM Z:

quando o fluxo de compilação funciona, ninguém nota.

Mas quando o BIND desaparece, o DBRM não combina ou o PACKAGE está na collection errada, sempre haverá um programador COBOL caminhando pelos corredores da madrugada, seguindo as pistas deixadas no spool.

E pedindo mais um café.

Posso também transformar esse conteúdo em uma versão ampliada com JCL completo de pré-compilação, compilação, link-edit e BIND PACKAGE.




Infografico demonstrando o fluxo de compilação de um programa mainframe COBOL com acesso ao Banco de Dados DB2. 

 

terça-feira, 6 de agosto de 2024

SQLCODE sem Mistérios : O Guia de Sobrevivência do Programador COBOL Padawan diante dos Principais Erros do Db2

 

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 INTO sem linha correspondente;

  • FETCH apó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

  1. Verifique se os valores das host variables estão corretos.

  2. Confirme se a linha realmente existe na tabela.

  3. Verifique espaços, zeros à esquerda e formatos de data.

  4. Confirme se o predicado WHERE não está restritivo demais.

  5. Em cursores, trate +100 como fim normal da leitura.

  6. 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

  1. Capture o conteúdo de SQLERRMC.

  2. Identifique o nome exato do objeto mencionado.

  3. Confirme o subsistema Db2 em que o programa executou.

  4. Pesquise o catálogo Db2.

  5. Verifique o schema ou creator.

  6. Compare o DDL entre os ambientes.

  7. Verifique os parâmetros de qualificação usados no BIND.

  8. 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

  1. Identifique a coluna em SQLERRMC.

  2. Consulte a definição atual da tabela.

  3. Compare o SQL com a DCLGEN.

  4. Confirme se o alias da tabela foi usado corretamente.

  5. Verifique se a coluna pertence à tabela esperada.

  6. 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

  1. Descubra qual coluna permite NULL.

  2. Adicione uma variável indicadora compatível.

  3. Associe o indicador à host variable.

  4. Verifique o indicador após a instrução.

  5. Defina a regra de negócio para valores nulos.

  6. Não confunda NULL com 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

  1. Exiba o valor da host variable antes do SQL.

  2. Verifique o tipo da coluna no catálogo.

  3. Compare PIC, USAGE, comprimento, precisão e escala.

  4. Valide dados recebidos de arquivo, tela ou API.

  5. Verifique sinais e casas decimais.

  6. Utilize DCLGEN atualizada.

  7. 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

  1. Identifique a coluna envolvida.

  2. Verifique os indicadores.

  3. Consulte a definição NULL/NOT NULL.

  4. Confirme se existe valor default.

  5. Valide os campos obrigatórios antes do SQL.

  6. 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

  1. Identifique a constraint ou índice envolvido.

  2. Verifique quais colunas formam a chave única.

  3. Consulte o registro existente.

  4. Descubra se é duplicidade real ou reprocessamento.

  5. Verifique a origem da chave.

  6. Avalie o uso de sequence ou identity.

  7. Torne o processamento idempotente quando necessário.

  8. 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

  1. Capture todo o conteúdo de SQLERRMC.

  2. Identifique location, collection, package e consistência.

  3. Confirme qual load module foi executado.

  4. Verifique a STEPLIB ou JOBLIB.

  5. Confirme o subsistema Db2.

  6. Consulte o catálogo para verificar se o package existe.

  7. Confira collection e versão.

  8. Verifique o PKLIST do plano.

  9. Execute ou solicite o BIND correto.

  10. 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

  1. Programa é pré-compilado.

  2. Um novo DBRM é produzido.

  3. O programa é compilado e linkeditado.

  4. O BIND usa um DBRM antigo.

Ou:

  1. O package foi atualizado.

  2. O load module antigo continua na load library.

Solução passo a passo

  1. Identifique o load module carregado.

  2. Confirme a data e versão do módulo.

  3. Identifique o DBRM usado no último BIND.

  4. Refaça toda a cadeia de construção.

  5. Pré-compile novamente.

  6. Compile novamente.

  7. Faça o link-edit novamente.

  8. Execute o BIND novamente.

  9. Promova load module e package como uma unidade.

  10. 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

  1. Capture o reason code.

  2. Capture o resource type.

  3. Capture o resource name.

  4. Consulte a documentação do reason code.

  5. Verifique mensagens Db2 no log.

  6. Consulte o estado do objeto.

  7. Verifique utilitários ativos.

  8. Acione o DBA ou suporte de produção com os dados completos.

  9. 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

  1. Reduza o tempo entre commits.

  2. Não mantenha cursor ou unidade de trabalho aberta desnecessariamente.

  3. Acesse tabelas na mesma ordem em todos os programas.

  4. Atualize somente as linhas necessárias.

  5. Garanta bons índices.

  6. Evite varreduras extensas durante updates.

  7. Analise isolamento e concorrência.

  8. Implemente retry controlado quando permitido.

  9. Não faça retry infinito.

  10. 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

  1. Identifique o authorization ID em uso.

  2. Capture os tokens da SQLCA.

  3. Verifique o privilégio exigido.

  4. Confirme quem é o owner do package.

  5. Verifique autorização de EXECUTE.

  6. Confira plano, collection e contexto de execução.

  7. Analise mensagens SAF/RACF quando aplicável.

  8. Solicite o GRANT correto.

  9. 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 FOUND corresponde ao +100;

  • SQLERROR corresponde a SQLCODE negativo;

  • SQLWARNING cobre 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:

  1. pare;

  2. identifique o SQL;

  3. capture a SQLCA;

  4. leia o SQLCODE;

  5. consulte o SQLSTATE;

  6. analise os tokens;

  7. identifique objetos e reason codes;

  8. verifique host variables;

  9. confirme package, plano e ambiente;

  10. corrija a causa;

  11. 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.

 


quinta-feira, 23 de junho de 2022

DB2I sem Mistérios: o Portal Clássico que Leva o Programador COBOL Padawan do Primeiro SELECT ao BIND de Produção

 

Bellacosa Mainframe apresenta o db2i

☕ Um Café no Bellacosa Mainframe

DB2I sem Mistérios: o Portal Clássico que Leva o Programador COBOL Padawan do Primeiro SELECT ao BIND de Produção

Imagine a seguinte cena.

Você acabou de entrar no TSO. A tela preta surgiu diante de seus olhos como a entrada de uma antiga fortaleza digital. Depois de informar seu usuário, sua senha e atravessar os corredores do ISPF, você finalmente executa o comando que abre uma das áreas mais tradicionais do universo IBM Z.

Na tela aparece:

DB2I PRIMARY OPTION MENU

No canto superior direito:

SSID: DB9G

E logo abaixo, um conjunto de opções aparentemente simples:

1  SPUFI
2  DCLGEN
3  PROGRAM PREPARATION
4  PRECOMPILE
5  BIND/REBIND/FREE
6  RUN
7  DB2 COMMANDS
8  UTILITIES
D  DB2I DEFAULTS
X  EXIT

Para um iniciante, isso pode parecer apenas mais um menu antigo em modo texto.

Mas não se engane, jovem padawan.

Essa tela é uma verdadeira central de comando para o desenvolvimento de aplicações COBOL com Db2 no mainframe. Ela reúne, em um único lugar, grande parte da jornada que transforma uma instrução SQL escrita dentro de um programa COBOL em uma operação real, autorizada, otimizada e executada contra um banco de dados corporativo.

Estamos diante do DB2I, sigla para Db2 Interactive.

Ele é um dos portais clássicos do desenvolvimento no IBM Z.

Neste café, vamos atravessar cada porta desse menu, entender sua história, observar como ele funciona, descobrir o que acontece nos bastidores e acompanhar, passo a passo, o nascimento de um programa COBOL com SQL embutido.

Prepare sua caneca.

O Db2 está acordado.


Bellacosa Mainframe e o db2i no emulador 3270

1. O que é o DB2I?

O DB2I é uma interface interativa integrada ao ISPF que permite acessar diversas funções relacionadas ao Db2 for z/OS.

Ele não é o banco de dados propriamente dito.

Também não é o compilador COBOL.

Ele funciona como um grande painel de controle que organiza diferentes ferramentas, processos e utilitários do ecossistema Db2.

Por meio dele, o usuário pode:

  • executar comandos SQL;

  • gerar declarações de tabelas;

  • preparar programas para execução;

  • realizar precompile;

  • executar BIND e REBIND;

  • rodar programas;

  • emitir comandos administrativos;

  • executar utilitários;

  • configurar parâmetros pessoais.

Sua grande virtude é a integração.

Em vez de o programador precisar decorar vários comandos, jobs e programas utilitários, o DB2I apresenta painéis que solicitam os parâmetros necessários e, em muitos casos, gera ou submete o JCL correspondente.

É importante entender que o DB2I não eliminou o JCL.

Ele apenas oferece uma interface mais amigável para preparar ou executar processos que, por baixo da superfície, continuam dependendo de datasets, procedimentos catalogados, módulos de carga, bibliotecas, parâmetros, planos e packages.

O DB2I é, portanto, uma espécie de ponte entre o usuário e a complexidade da infraestrutura.


2. Em que ambiente estamos trabalhando?

A tela mostrada é acessada por meio de um emulador TN3270.

A arquitetura normalmente segue este caminho:

Computador do usuário
        |
        v
Emulador TN3270
        |
        v
TSO/E
        |
        v
ISPF
        |
        v
DB2I
        |
        v
Subsistema Db2

Cada camada possui uma função.

O TN3270 permite que o computador moderno se comporte como um terminal IBM 3270.

O TSO/E oferece a sessão interativa no z/OS.

O ISPF fornece os painéis, menus, editores e serviços de produtividade.

O DB2I organiza as funções relacionadas ao Db2.

Finalmente, o subsistema Db2 executa o trabalho real de gerenciamento de dados, SQL, locks, buffer pools, logs, recuperação, autorização e otimização.

O programador enxerga uma tela.

O sistema enxerga uma cadeia inteira de componentes.


3. O significado de SSID

No canto superior direito aparece:

SSID: DB9G

SSID significa:

Subsystem Identifier

É o identificador do subsistema Db2 ao qual a sessão está associada.

Em um mesmo ambiente z/OS podem existir vários subsistemas Db2.

Por exemplo:

DB2D = desenvolvimento
DB2T = testes
DB2H = homologação
DB2P = produção

Também podem existir subsistemas diferentes por aplicação, unidade de negócio, versão, data sharing group ou finalidade técnica.

O nome não precisa obrigatoriamente indicar o ambiente. Cada empresa define sua convenção.

O ponto essencial é este:

Sempre confirme em qual SSID você está trabalhando antes de executar comandos.

Essa é uma regra de ouro.

Um SELECT executado no ambiente errado pode causar apenas confusão.

Um DELETE executado no ambiente errado pode causar uma reunião de emergência com vinte pessoas, três gerentes, dois DBAs e um café que já perdeu a temperatura.


4. Opção 1 — SPUFI

A primeira opção é:

1 SPUFI

SPUFI significa:

SQL Processor Using File Input

Em muitas documentações antigas, também é descrito como uma interface para processar SQL armazenado em um dataset de entrada.

Na prática, ele permite escrever instruções SQL em um arquivo, executá-las e armazenar os resultados em outro arquivo.

É uma das ferramentas mais tradicionais do Db2 for z/OS.


4.1 Como o SPUFI funciona?

O fluxo básico é:

Dataset de entrada
       |
       v
Instruções SQL
       |
       v
SPUFI
       |
       v
Db2
       |
       v
Dataset de saída

O usuário informa:

  • o dataset que contém o SQL;

  • o dataset em que deseja receber o resultado;

  • parâmetros de execução;

  • formato da saída;

  • número máximo de linhas;

  • opções de commit;

  • isolamento.

Um exemplo de dataset de entrada:

SELECT EMPNO,
       FIRSTNME,
       LASTNAME,
       SALARY
FROM DSN8C10.EMP
ORDER BY LASTNAME;

O SPUFI envia a instrução ao Db2 e grava a resposta no dataset de saída.


4.2 Primeiro passo a passo com SPUFI

Suponha que você queira consultar uma tabela chamada CLIENTE.

Entre na opção 1.

Informe um dataset de entrada, por exemplo:

VAGNER.SQL.CONSULTA

Caso o dataset não exista, o DB2I poderá permitir sua alocação, dependendo das configurações.

No editor ISPF, escreva:

SELECT ID_CLIENTE,
       NOME_CLIENTE,
       LIMITE_CREDITO
FROM APP.CLIENTE
FETCH FIRST 20 ROWS ONLY;

Salve o membro ou dataset.

Retorne ao painel do SPUFI.

Informe o dataset de saída:

VAGNER.SQL.RESULTADO

Execute.

Depois, abra o resultado.

Você poderá ver algo semelhante a:

---------+---------+---------+---------+
ID_CLIENTE NOME_CLIENTE          LIMITE_CREDITO
---------+---------+---------+---------+
000001     ANA SILVA                    5000.00
000002     JOAO SOUZA                   3500.00
000003     MARIA COSTA                  8000.00
DSNE610I NUMBER OF ROWS DISPLAYED IS 3
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL

O formato real varia conforme parâmetros, versão e configuração do ambiente.


4.3 Cuidados com SPUFI

O SPUFI não é apenas uma ferramenta de consulta.

Ele também pode executar:

INSERT
UPDATE
DELETE
CREATE
ALTER
DROP
GRANT
REVOKE

Portanto, trate-o com respeito.

Antes de executar:

DELETE FROM APP.CLIENTE;

verifique se faltou uma cláusula WHERE.

Uma pequena ausência pode transformar uma manutenção de um registro em uma limpeza completa da tabela.

Uma boa prática é primeiro executar:

SELECT COUNT(*)
FROM APP.CLIENTE
WHERE STATUS = 'I';

Depois:

SELECT *
FROM APP.CLIENTE
WHERE STATUS = 'I'
FETCH FIRST 50 ROWS ONLY;

Somente após validar os dados, executar:

DELETE FROM APP.CLIENTE
WHERE STATUS = 'I';

O padawan prudente consulta antes de alterar.


5. Opção 2 — DCLGEN

A segunda opção é:

2 DCLGEN

DCLGEN significa:

Declarations Generator

Sua finalidade é gerar declarações de tabela e estruturas de host variables para linguagens como COBOL.

Suponha que exista a tabela:

CREATE TABLE APP.CLIENTE
(
    ID_CLIENTE      INTEGER       NOT NULL,
    NOME_CLIENTE    VARCHAR(80)   NOT NULL,
    LIMITE_CREDITO  DECIMAL(11,2),
    DATA_CADASTRO   DATE,
    STATUS          CHAR(1)
);

O programa COBOL precisa conhecer a estrutura dos campos que serão usados nas instruções SQL.

O DCLGEN pode gerar algo semelhante a:

       EXEC SQL DECLARE APP.CLIENTE TABLE
       ( ID_CLIENTE      INTEGER NOT NULL,
         NOME_CLIENTE    VARCHAR(80) NOT NULL,
         LIMITE_CREDITO  DECIMAL(11,2),
         DATA_CADASTRO   DATE,
         STATUS          CHAR(1)
       ) END-EXEC.

Também gera a estrutura COBOL:

       01  DCLCLIENTE.
           10  ID-CLIENTE          PIC S9(9) COMP.
           10  NOME-CLIENTE.
               49 NOME-CLIENTE-LEN PIC S9(4) COMP.
               49 NOME-CLIENTE-TEXT PIC X(80).
           10  LIMITE-CREDITO      PIC S9(9)V99 COMP-3.
           10  DATA-CADASTRO       PIC X(10).
           10  STATUS-CLIENTE      PIC X(1).

Os nomes e formatos podem variar de acordo com as opções escolhidas.


5.1 Por que o DCLGEN é tão importante?

Sem ele, o programador teria que converter manualmente cada tipo SQL em um formato COBOL.

Exemplos:

INTEGER       -> PIC S9(9) COMP
SMALLINT      -> PIC S9(4) COMP
DECIMAL(9,2)  -> PIC S9(7)V99 COMP-3
CHAR(10)      -> PIC X(10)
DATE          -> PIC X(10)
VARCHAR       -> campo de tamanho + texto

Essa conversão manual pode gerar erros.

Um campo definido incorretamente pode resultar em:

  • truncamento;

  • dados corrompidos;

  • SQLCODE negativo;

  • valores numéricos inválidos;

  • ABEND S0C7;

  • comportamento imprevisível.

O DCLGEN reduz essa possibilidade.


5.2 DCLGEN não substitui governança

Há um detalhe importante.

Gerar o DCLGEN é apenas o começo.

A empresa precisa controlar:

  • onde o copybook será armazenado;

  • qual versão está em produção;

  • quais programas usam aquela estrutura;

  • o que acontece quando a tabela muda;

  • se os programas precisam ser recompilados;

  • se o BIND precisa ser renovado.

Em ambientes maduros, alterações de tabela seguem processos rigorosos.

Não basta alterar uma coluna e esperar que todos os programas se adaptem magicamente.

No mainframe, magia sem controle costuma receber outro nome: incidente.


6. Opção 3 — Program Preparation

A opção 3 é:

3 PROGRAM PREPARATION

Ela reúne etapas necessárias para preparar uma aplicação Db2 para execução.

Um programa COBOL com SQL embutido precisa passar por várias fases:

Fonte COBOL com EXEC SQL
          |
          v
Precompile
          |
          +----> DBRM
          |
          v
Fonte COBOL transformado
          |
          v
Compilação
          |
          v
Objeto
          |
          v
Link-edit
          |
          v
Load module
          |
          v
BIND
          |
          v
Package ou plan

A opção Program Preparation tenta coordenar essas etapas.

É excelente para laboratórios, ambientes educacionais e processos padronizados.

Em grandes empresas, porém, muitas dessas fases são executadas por pipelines, ferramentas de change management ou JCLs corporativos.

Entre as ferramentas modernas ou tradicionais podem aparecer:

  • Endevor;

  • ISPW;

  • Changeman;

  • DBB;

  • Jenkins;

  • GitLab;

  • GitHub Actions;

  • IBM Developer for z/OS;

  • zBuilder.

Mesmo assim, o conceito permanece exatamente o mesmo.


7. Opção 4 — Precompile

A opção 4 chama o precompiler do Db2.

Essa é uma das etapas mais fascinantes.

O compilador COBOL não compreende diretamente uma instrução como:

       EXEC SQL
           SELECT NOME_CLIENTE,
                  LIMITE_CREDITO
             INTO :WS-NOME,
                  :WS-LIMITE
             FROM APP.CLIENTE
            WHERE ID_CLIENTE = :WS-ID
       END-EXEC.

O SQL embutido precisa ser tratado antes da compilação COBOL.

O precompiler percorre o fonte e identifica blocos entre:

EXEC SQL

e:

END-EXEC

Ele separa as instruções SQL e gera dois resultados principais:

  1. Um fonte COBOL modificado.

  2. Um DBRM.


7.1 O que é o DBRM?

DBRM significa:

Database Request Module

Ele contém representações das instruções SQL extraídas do programa.

O DBRM não é o executável.

Ele também não é uma tabela.

Ele é um artefato intermediário utilizado posteriormente no BIND.

Pense nele como um dossiê contendo os pedidos de acesso ao banco feitos pelo programa.

Exemplo conceitual:

Programa: PGMCAD01

SQL 1:
SELECT NOME_CLIENTE
FROM APP.CLIENTE
WHERE ID_CLIENTE = ?

SQL 2:
UPDATE APP.CLIENTE
SET STATUS = ?
WHERE ID_CLIENTE = ?

Esse conjunto de solicitações será analisado pelo Db2 durante o BIND.


7.2 O que acontece com o fonte COBOL?

O SQL é substituído ou acompanhado por chamadas apropriadas à interface do Db2.

O fonte resultante pode conter referências a módulos e estruturas necessárias para a comunicação com o banco.

Depois disso, o compilador COBOL consegue processar o programa.

O fluxo é:

COBOL + SQL
    |
    v
Precompiler Db2
    |
    +----> DBRM
    |
    v
COBOL sem SQL nativo
    |
    v
Compiler

8. SQLCA: o mensageiro do Db2

Quase todo programa COBOL com Db2 possui:

       EXEC SQL
           INCLUDE SQLCA
       END-EXEC.

SQLCA significa:

SQL Communication Area

É uma estrutura usada para receber informações sobre a execução da instrução SQL.

O campo mais famoso é:

SQLCODE

Exemplos:

SQLCODE = 0      sucesso
SQLCODE = 100    nenhuma linha encontrada
SQLCODE = -811   mais de uma linha retornada
SQLCODE = -904   recurso indisponível
SQLCODE = -911   deadlock ou timeout com rollback
SQLCODE = -913   deadlock ou timeout
SQLCODE = -805   package não encontrado
SQLCODE = -818   timestamp inconsistente

Um programa sério deve testar o SQLCODE após cada operação relevante.

Exemplo:

       EXEC SQL
           SELECT NOME_CLIENTE
             INTO :WS-NOME
             FROM APP.CLIENTE
            WHERE ID_CLIENTE = :WS-ID
       END-EXEC.

       EVALUATE SQLCODE
           WHEN 0
               DISPLAY 'CLIENTE ENCONTRADO: ' WS-NOME
           WHEN 100
               DISPLAY 'CLIENTE NAO ENCONTRADO'
           WHEN OTHER
               DISPLAY 'ERRO SQLCODE: ' SQLCODE
       END-EVALUATE.

Ignorar o SQLCODE é como pilotar uma nave sem olhar o painel.

Talvez ela continue voando.

Talvez o motor já esteja em chamas.


9. Opção 5 — BIND, REBIND e FREE

A opção 5 é uma das mais importantes do menu:

5 BIND/REBIND/FREE

Esses três comandos controlam packages e plans.


10. O que é BIND?

O BIND pega o DBRM e cria uma estrutura executável pelo Db2, geralmente um package.

Durante o BIND, o Db2:

  • valida as instruções SQL;

  • verifica objetos referenciados;

  • avalia autorizações;

  • analisa estatísticas;

  • escolhe caminhos de acesso;

  • registra dependências;

  • cria o package;

  • armazena informações no catálogo.

O otimizador decide como acessar os dados.

Ele pode escolher:

  • table space scan;

  • index scan;

  • index-only access;

  • nested loop join;

  • merge scan join;

  • hybrid join;

  • acesso por particionamento;

  • paralelismo.

Duas instruções SQL textualmente iguais podem receber caminhos de acesso diferentes dependendo de:

  • índices;

  • cardinalidade;

  • distribuição de dados;

  • estatísticas;

  • parâmetros de BIND;

  • versão do Db2;

  • nível de função;

  • configuração do subsistema.


10.1 Package e plan

Um package contém a forma preparada das instruções SQL de um programa ou unidade lógica.

Um plan organiza a execução e pode referenciar collections e packages.

No modelo moderno, é comum trabalhar principalmente com packages.

Fluxo simplificado:

Programa COBOL
      |
      v
Package
      |
      v
Collection
      |
      v
Plan
      |
      v
Db2

Nem todas as empresas usam exatamente a mesma convenção, mas o conceito geral permanece.


11. O que é REBIND?

O REBIND recria o package ou plan sem precisar gerar um novo DBRM.

Ele é útil quando:

  • estatísticas foram atualizadas;

  • índices foram criados;

  • índices foram removidos;

  • o volume de dados mudou;

  • houve alteração de parâmetros;

  • o Db2 foi atualizado;

  • deseja-se obter um novo access path.

Exemplo clássico:

RUNSTATS
   |
   v
Novas estatísticas
   |
   v
REBIND
   |
   v
Novo caminho de acesso

O programa COBOL pode permanecer o mesmo.

O executável pode permanecer o mesmo.

Mas o Db2 pode escolher uma estratégia diferente para acessar os dados.

Esse desacoplamento é uma das maiores forças da arquitetura Db2.


12. O que é FREE?

FREE remove packages ou plans do catálogo.

É uma operação poderosa e potencialmente perigosa.

Se você remover um package necessário, o programa poderá falhar com erro semelhante ao:

SQLCODE -805

Esse erro normalmente indica que o package esperado não foi encontrado, não está disponível na collection correta ou não corresponde ao que o programa está tentando usar.

Nunca execute FREE por curiosidade em ambiente corporativo.

Curiosidade é excelente para estudar.

Em produção, curiosidade sem mudança aprovada pode virar RCA.


13. Opção 6 — RUN

A opção 6 permite executar um programa SQL.

Dependendo da instalação, o painel solicita:

  • nome do programa;

  • plan;

  • parâmetros;

  • bibliotecas de carga;

  • datasets;

  • ambiente;

  • opções de execução.

Essa função é bastante útil para testes.

Em ambientes reais, programas batch normalmente são executados por JCL.

Um exemplo conceitual:

//RUNDB2   JOB ...
//STEP01   EXEC PGM=IKJEFT01
//STEPLIB  DD DISP=SHR,DSN=APP.LOADLIB
//SYSTSPRT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSTSIN  DD *
  DSN SYSTEM(DB9G)
  RUN PROGRAM(PGMCAD01) PLAN(PLANAPP) -
      LIB('APP.LOADLIB')
  END
/*

O exemplo exato varia conforme o ambiente.

O programa pode também ser executado em:

  • CICS;

  • IMS;

  • stored procedure;

  • WLM;

  • batch;

  • TSO;

  • z/OS Unix;

  • aplicações distribuídas.


14. Opção 7 — Db2 Commands

A opção 7 permite emitir comandos administrativos do Db2.

Exemplos:

-DISPLAY DATABASE
-DISPLAY THREAD
-DISPLAY UTILITY
-DISPLAY BUFFERPOOL
-START DATABASE
-STOP DATABASE
-RECOVER INDOUBT

Esses comandos não são SQL.

Eles são comandos do subsistema Db2.

Por exemplo:

-DISPLAY DATABASE(APPDB)

Pode mostrar o estado dos objetos relacionados ao banco.

Outro exemplo:

-DISPLAY THREAD(*)

Pode exibir threads conectadas.

Essas funções geralmente são controladas por autorização.

Um programador comum talvez possa executar alguns comandos de consulta, mas não terá autoridade para iniciar, parar ou alterar recursos críticos.

E isso é saudável.

Segurança não é um obstáculo.

É o cinto de segurança da operação.


15. Opção 8 — Utilities

Os utilitários do Db2 são responsáveis por diversas tarefas essenciais de manutenção.

Entre os principais:

LOAD
UNLOAD
REORG
RUNSTATS
COPY
RECOVER
CHECK DATA
CHECK INDEX
REBUILD INDEX
QUIESCE
MODIFY RECOVERY

15.1 RUNSTATS

Coleta estatísticas sobre:

  • quantidade de linhas;

  • cardinalidade;

  • distribuição;

  • frequência;

  • índices;

  • colunas;

  • partições.

O otimizador usa essas informações para escolher access paths.

Estatística desatualizada pode levar a decisões ruins.

É como usar um mapa de uma cidade de 1995 para dirigir em 2026.

Algumas ruas ainda existem.

Outras viraram avenidas, túneis, condomínios e rotatórias criadas por alguém que parecia gostar muito de rotatórias.


15.2 REORG

Reorganiza os dados fisicamente.

Pode ajudar a:

  • reduzir fragmentação;

  • recuperar espaço;

  • melhorar clustering;

  • restaurar organização física;

  • tratar estados pendentes;

  • melhorar acesso.


15.3 COPY

Cria cópias de imagem para recuperação.

Sem cópias adequadas, uma falha pode se tornar uma tragédia operacional.


15.4 RECOVER

Restaura objetos após falhas ou perda de dados.

Pode utilizar:

  • image copies;

  • logs;

  • pontos de recuperação;

  • informações do catálogo.


15.5 LOAD

Carrega grandes volumes de dados com eficiência.

É muito mais apropriado para cargas massivas do que executar milhões de INSERTs individuais.


16. Opção D — DB2I Defaults

A opção D permite configurar padrões utilizados pelo DB2I.

Podem existir parâmetros para:

  • nomes de datasets;

  • classes de job;

  • opções de saída;

  • SQL terminator;

  • parâmetros de execução;

  • bibliotecas;

  • identificadores;

  • formato dos resultados.

Esses defaults economizam tempo.

Em vez de digitar os mesmos valores em todos os painéis, o usuário configura uma vez e reaproveita.

Porém, sempre revise os parâmetros antes de executar.

Um default antigo pode apontar para:

  • SSID incorreto;

  • biblioteca obsoleta;

  • plan antigo;

  • collection inadequada;

  • dataset inexistente.

Automação ajuda.

Automação desatualizada ajuda a errar mais rápido.


17. Passo a passo completo: criando um programa COBOL com Db2

Agora vamos juntar tudo.

Imagine um programa que consulta o nome de um cliente.


Passo 1 — Criar o DCLGEN

Use a opção 2.

Informe:

TABLE OWNER: APP
TABLE NAME: CLIENTE

Defina o dataset de saída:

VAGNER.COBOL.COPYLIB(DCLCLI)

O DCLGEN será gerado.


Passo 2 — Escrever o programa COBOL

Exemplo simplificado:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. PGCLI001.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       EXEC SQL
           INCLUDE SQLCA
       END-EXEC.

       EXEC SQL
           INCLUDE DCLCLI
       END-EXEC.

       01  WS-ID-CLIENTE      PIC S9(9) COMP VALUE 100.
       01  WS-NOME-CLIENTE    PIC X(80).

       PROCEDURE DIVISION.

           EXEC SQL
               SELECT NOME_CLIENTE
                 INTO :WS-NOME-CLIENTE
                 FROM APP.CLIENTE
                WHERE ID_CLIENTE = :WS-ID-CLIENTE
           END-EXEC

           EVALUATE SQLCODE
               WHEN 0
                   DISPLAY 'CLIENTE: ' WS-NOME-CLIENTE
               WHEN 100
                   DISPLAY 'CLIENTE NAO ENCONTRADO'
               WHEN OTHER
                   DISPLAY 'ERRO SQL: ' SQLCODE
           END-EVALUATE

           GOBACK.

Passo 3 — Precompile

Use a opção 4 ou Program Preparation.

Entradas:

Fonte COBOL
DBRM library
Copy library
Parâmetros SQL

Saídas:

Fonte COBOL modificado
DBRM
Listing
Mensagens

Verifique erros de sintaxe SQL.


Passo 4 — Compilar

O fonte modificado segue para o Enterprise COBOL.

O compilador gera:

Object deck
Compiler listing
Mensagens

Corrija qualquer erro COBOL.


Passo 5 — Link-edit

O objeto é transformado em load module ou program object.

Ele será armazenado em uma biblioteca de carga.

Exemplo:

VAGNER.APP.LOADLIB

Passo 6 — BIND PACKAGE

Use a opção 5.

Informe:

DBRM: PGCLI001
COLLECTION: APPDEV
PACKAGE: PGCLI001
OWNER: VAGNER
QUALIFIER: APP

Parâmetros comuns podem incluir:

ACTION(REPLACE)
ISOLATION(CS)
VALIDATE(BIND)
RELEASE(COMMIT)
CURRENTDATA(NO)

Os parâmetros exatos dependem dos padrões da empresa.


Passo 7 — BIND PLAN

Caso o ambiente utilize plan explícito para a execução, associe a package list ou collection.

Exemplo conceitual:

PLAN: PLANAPP
PKLIST: APPDEV.*

Passo 8 — Executar

Use a opção 6 ou submeta o JCL.

Observe:

  • retorno do job;

  • SQLCODE;

  • mensagens;

  • dumps;

  • saídas;

  • tempo de CPU;

  • quantidade de linhas.


18. Erros clássicos do padawan

SQLCODE -805

Package não encontrado.

Possíveis causas:

  • BIND não executado;

  • collection errada;

  • plan incorreto;

  • package removido;

  • versão incompatível.


SQLCODE -818

Incompatibilidade de timestamp entre programa e package.

Pode acontecer quando o programa foi recompilado, mas o package não foi gerado de forma correspondente.

A solução geralmente envolve sincronizar:

Precompile
Compile
Link-edit
Bind

SQLCODE -811

Um SELECT INTO retornou mais de uma linha.

Exemplo perigoso:

SELECT NOME_CLIENTE
INTO :WS-NOME
FROM APP.CLIENTE
WHERE STATUS = 'A';

Se existem mil clientes ativos, o Db2 não sabe qual retornar.

Use chave única, agregação ou cursor.


SQLCODE +100

Nenhuma linha encontrada.

Não é necessariamente erro.

Pode ser uma condição normal de negócio.


SQLCODE -911

Deadlock ou timeout com rollback.

O programa perdeu uma disputa por recurso e a unidade de trabalho foi desfeita.

É necessário avaliar:

  • ordem de acesso;

  • tempo entre commits;

  • índices;

  • isolamento;

  • concorrência;

  • volume de processamento.


19. Curiosidades históricas

O DB2I carrega a filosofia de uma época em que memória, largura de banda e espaço de tela eram recursos valiosos.

Por isso, seus painéis são diretos.

Não existem animações.

Não existem botões brilhantes.

Não existem notificações perguntando se você gostaria de conhecer cinco novidades.

Existe uma linha de comando, campos objetivos e uma tecla Enter.

Essa simplicidade ajudou o ambiente a permanecer produtivo por décadas.

Outra curiosidade é que muitos profissionais que começaram no Db2 em versões antigas ainda reconhecem imediatamente o menu.

Os detalhes evoluíram.

O banco ganhou novos tipos, novos níveis de função, novas capacidades e otimizações.

Mas a lógica fundamental continua familiar.

Isso é compatibilidade cultural.

Não apenas compatibilidade técnica.


20. Easter egg Bellacosa Mainframe

Vamos transformar a jornada em uma aventura galáctica.

O programa COBOL é um jovem Jedi.

O DCLGEN entrega o mapa da estrutura do planeta-tabela.

O precompiler é C-3PO, traduzindo SQL para uma linguagem compreendida pela infraestrutura.

O DBRM é o pergaminho contendo todas as missões de acesso ao banco.

O compilador COBOL treina o guerreiro.

O link-editor entrega o sabre de luz.

O BIND apresenta a missão ao Conselho Jedi.

O otimizador decide a rota: índice, scan, join, paralelismo.

O package é a autorização oficial.

O plan é o plano de batalha.

O SQLCA é o comunicador preso ao cinto.

E o SQLCODE informa se a missão foi cumprida ou se o grupo acabou preso em um compactador de lixo da Estrela da Morte.

O mais importante é compreender que nenhuma etapa existe por acaso.

O mainframe não gosta de improviso.

Ele gosta de processos repetíveis, auditáveis e previsíveis.

Essa disciplina é uma das razões pelas quais sistemas IBM Z sustentam bancos, governos, seguradoras, companhias aéreas, indústrias e cadeias globais de negócios.


Conclusão

A tela do DB2I pode parecer modesta, mas ela concentra uma quantidade impressionante de conhecimento.

Por trás de suas opções existem:

  • linguagens;

  • compiladores;

  • catálogos;

  • packages;

  • plans;

  • access paths;

  • estatísticas;

  • segurança;

  • recuperação;

  • concorrência;

  • utilitários;

  • JCL;

  • datasets;

  • décadas de engenharia.

Dominar o DB2I não significa apenas aprender a navegar em um menu.

Significa compreender o ciclo de vida de uma aplicação Db2 no z/OS.

O programador COBOL padawan que aprende apenas a escrever SELECT conhece a superfície.

O profissional que compreende precompile, DBRM, BIND, package, plan, SQLCA, utilitários e access path começa a enxergar o sistema inteiro.

E é nesse momento que a velha tela preta deixa de parecer antiga.

Ela passa a parecer aquilo que realmente é:

Um painel de controle compacto para uma das plataformas de dados mais robustas já construídas pela indústria da computação.

Portanto, na próxima vez que você entrar no DB2I e enxergar suas opções em ciano, não veja apenas números.

Veja uma linha de produção.

Veja o SQL sendo extraído.

Veja o DBRM sendo criado.

Veja o compilador trabalhando.

Veja o otimizador avaliando caminhos.

Veja o package sendo autorizado.

Veja o programa entrando em execução.

Porque, no IBM Z, quase sempre existe muito mais acontecendo por trás da tela do que o terminal permite enxergar.

E essa, jovem padawan, é parte da beleza do mainframe.


Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...