 |
| 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:
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:
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:
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:
O programa foi pré-compilado.
O DBRM foi gerado.
O COBOL foi compilado.
O load module foi criado.
Um novo BIND não foi executado corretamente.
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:
A tabela CLIENTES precisa existir.
As colunas precisam existir.
Os tipos precisam ser compatíveis.
O programa precisa ser pré-processado.
O código COBOL precisa ser compilado.
O executável precisa ser linkado.
O PACKAGE precisa ser criado.
O usuário de execução precisa ter os acessos necessários.
O load module e o PACKAGE precisam corresponder.
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:
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:
É 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:
SQLCODE -206
Coluna não encontrada ou inválida no contexto.
Possíveis causas:
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:
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:
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:
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:
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.