☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

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

segunda-feira, 4 de maio de 2026

🔥☕ O SUBMUNDO DO Db2 z/OS — LOGS, RECOVERY E O QUE ACONTECE QUANDO O BANCO “MORRE” ☕🔥

 

Bellacosa Mainframe em uma visão sobre o LOG do DB2

🔥☕ O SUBMUNDO DO Db2 z/OS — LOGS, RECOVERY E O QUE ACONTECE QUANDO O BANCO “MORRE” ☕🔥

Existe um momento na vida de todo programador COBOL/Db2 em que ele descobre uma verdade assustadora:

O Db2 nunca esquece nada.

Cada:

  • INSERT,
  • UPDATE,
  • DELETE,
  • COMMIT,
  • ROLLBACK,
  • ALTER,
  • REORG,

deixa rastros.

E esses rastros vivem dentro de uma das estruturas mais importantes do ecossistema mainframe:

🔥 O LOG DO Db2.

Se você é programador COBOL pleno e acha que recovery é “coisa de DBA”, cuidado.

Porque no dia em que um:

-904
-911
-803
00C90084
RESOURCE UNAVAILABLE

explodir produção às 3h da manhã…

você vai descobrir que entender o log do Db2 muda completamente sua carreira.


☕ O QUE É O LOG DO Db2?

O log do Db2 é o “diário transacional” do banco.

Tudo que altera dados gera registros de log.

O Db2 escreve:

  • before image,
  • after image,
  • controle transacional,
  • checkpoints,
  • unidades de recuperação.

Basicamente:

ALTERAÇÃO → LOG → DISCO

Antes mesmo da página ser gravada no tablespace.


🔥 ACTIVE LOGS vs ARCHIVE LOGS

Aqui começa uma das maiores confusões dos iniciantes.

🔹 Active Logs

São os logs online e ativos.

Ficam sendo usados continuamente.

Eles armazenam:

  • alterações recentes,
  • transações em andamento,
  • recovery imediato.

São críticos.

Perder active log é pesadelo nível apocalipse.


🔹 Archive Logs

Quando active logs ficam cheios:

  • Db2 descarrega,
  • copia,
  • arquiva.

Esses logs históricos viram:

ARCHIVE LOGS

Eles são usados para:

  • PIT recovery,
  • auditoria,
  • rollback histórico,
  • disaster recovery.

☕ COMO O Db2 ESCREVE NO LOG?

Muita gente acha que Db2 grava direto no disco.

Não.

Primeiro ele grava em:

🔥 LOG BUFFERS

na memória.

Depois:

  • COMMIT,
  • checkpoint,
  • buffer cheio,
  • sync I/O,

forçam gravação nos:

ACTIVE LOG DATASETS

🔥 WRITE AHEAD LOGGING (WAL)

Aqui está o segredo do recovery moderno.

O Db2 segue:

🔥 WAL — Write Ahead Logging

Regra:

“O log precisa ser gravado ANTES da página do banco.”

Isso garante:

  • rollback,
  • redo,
  • recuperação consistente.

Sem isso:
💀 corrupção.


☕ O QUE ACONTECE NUM COMMIT?

Quando o programa COBOL faz:

EXEC SQL COMMIT END-EXEC

o Db2:

  1. sincroniza logs,
  2. confirma UOW,
  3. libera locks,
  4. torna alterações permanentes.

O COMMIT é basicamente:

🔥 “Agora isso virou verdade oficial.”


☕ E NUM ABEND?

Aqui entra o terror psicológico do DBA.

Se ocorre:

  • S0C7,
  • S878,
  • timeout,
  • deadlock,
  • cancel,
  • crash,
  • queda de LPAR,

o Db2 usa os logs para:

🔥 ROLLBACK

Ele desfaz tudo desde o último COMMIT.


🔥 TIPOS DE ERRO MAIS COMUNS


⚠️ SQLCODE -911 / -913

Deadlock ou timeout

Dois programas querem recursos incompatíveis.

Exemplo clássico:

  • batch segurando tabela,
  • online tentando atualizar.

DBA/Sysprog:

  • analisar locking,
  • IFCID,
  • traces,
  • IRLM,
  • timeout values.

Programador COBOL:

  • reduzir tempo entre commits,
  • melhorar SQL,
  • evitar scan gigante.

⚠️ SQLCODE -904

Resource unavailable

Tablespace parado.
Utility rodando.
Objeto indisponível.

DBA:

  • verificar STOP status,
  • utilities,
  • claim/drain,
  • locks.

Sysprog:

  • investigar subsystem,
  • storage,
  • I/O,
  • coupling facility.

⚠️ SQLCODE -803

Duplicate key

Programador tentou inserir chave já existente.

Programador:

  • validar lógica,
  • tratar concorrência,
  • revisar sequence/identity.

DBA:

  • verificar índice,
  • constraints,
  • integridade.

⚠️ SQLCODE -805

Package não encontrado

Clássico inferno de deploy.

DBA:

  • verificar BIND,
  • PLAN/PACKAGE,
  • consistency token.

Sysprog:

  • SDSNLOAD,
  • STEPLIB,
  • DBRM libraries.

Programador:

  • garantir promote correto.

⚠️ 00C90084

Log full

Aqui o DBA começa a envelhecer rapidamente.

O active log lotou.

Possíveis causas:

  • UOW gigante,
  • commit inexistente,
  • archive parado.

DBA:

  • verificar ARCHIVE process,
  • aumentar logs,
  • cancelar job problemático.

Programador:

  • COMMIT frequente,
  • evitar transação monstruosa.

☕ COMO FUNCIONA O RECOVERY?

Aqui mora a mágica do Db2.


🔥 FORWARD RECOVERY

Db2:

  1. restaura image copy,
  2. reaplica logs.

Resultado:
✅ banco volta até ponto desejado.


🔥 BACKOUT / ROLLBACK

Db2 usa:

  • before images,
  • undo records.

E desfaz alterações.


🔥 RESTART RECOVERY

Após crash do subsystem:

Db2:

  • lê logs,
  • identifica UOW incompletas,
  • faz undo/redo automático.

Muitas vezes o usuário nem percebe.


☕ O PAPEL DO DBA

O DBA é o “cirurgião do banco”.

Ele:

  • monitora logs,
  • executa RECOVER,
  • controla utilities,
  • administra image copies,
  • resolve locking,
  • acompanha catalog,
  • analisa performance.

Ferramentas clássicas:

  • DSN1LOGP,
  • RECOVER,
  • COPY,
  • REORG,
  • DISPLAY DATABASE,
  • DISPLAY LOG.

☕ O PAPEL DO SYSPROG

O Sysprog atua na infraestrutura pesada.

Ele cuida:

  • do subsystem Db2,
  • IRLM,
  • z/OS,
  • JES,
  • storage,
  • coupling facility,
  • datasets de log,
  • BSDS,
  • bootstrap datasets.

Se o DBA é cirurgião…
o Sysprog é engenheiro nuclear.


☕ O QUE O PROGRAMADOR COBOL PRECISA ENTENDER?

Muito mais do que imaginam.

Porque SQL ruim gera:

  • lock,
  • timeout,
  • log storm,
  • escalation,
  • crash recovery lento.

🔥 Um bom programador Db2:

✅ faz commit racional
✅ evita cursor infinito
✅ reduz scans
✅ trata SQLCODE corretamente
✅ entende UOW
✅ sabe impacto do rollback
✅ evita transações gigantes


☕ O MAIOR ERRO DOS INICIANTES

Achar que:

COMMIT é só “salvar”.

Não.

COMMIT é:

  • sincronização,
  • liberação de lock,
  • persistência,
  • checkpoint lógico,
  • controle de recovery.

É o coração do Db2 transacional.


🔥 CONCLUSÃO

O log do Db2 é praticamente:

🔥 a memória do banco.

Sem ele:

  • não existe rollback,
  • recovery,
  • integridade,
  • restart,
  • consistência.

Quando você entende:

  • active log,
  • archive log,
  • WAL,
  • UOW,
  • rollback,
  • recovery,

você deixa de ser apenas “quem escreve SELECT”.

E começa a pensar como:

  • DBA,
  • sysprog,
  • arquiteto transacional.

E no universo mainframe…

isso muda tudo. ☕🔥

sexta-feira, 28 de novembro de 2025

💣🔥 TPS NÃO É THROUGHPUT — É O SEU “COMMIT FINANCEIRO” PASSANDO NO CICS 🔥💣

 

Bellacosa Mainframe CICS e throughput

💣🔥 TPS NÃO É THROUGHPUT — É O SEU “COMMIT FINANCEIRO” PASSANDO NO CICS 🔥💣

Se você entrou numa discussão de arquitetura falando de fila, banco NoSQL e multi-região antes de entender o que é dinheiro sendo movimentado, já começou igual job com JCL errado: vai rodar… mas vai dar abend.


⚙️ TPS vs Throughput — visão Bellacosa Mainframe

No mundo raiz (sim, aquele do CICS + DB2 + commit de verdade):

  • TPS (Transactions Per Second)
    👉 É o COMMIT EXECUTADO
    👉 É o dinheiro que mudou de dono
    👉 É o ponto sem volta
  • Throughput
    👉 É o volume de processamento
    👉 Inclui request, fila, validação, retry
    👉 Muito barulho… nem sempre dinheiro

💥 Tradução brutal:

Throughput é fila cheia.
TPS é saldo alterado com sucesso.

Se você tem:

  • 20k req/s entrando
  • 3k virando transação

👉 Você NÃO tem um sistema de 20k.
👉 Você tem um sistema de 3k TPS financeiro.


🌍 Multi-região — quando o sistema vira “sysplex global sem JES”

Quando você sai de uma região…

Você não escalou.
Você entrou em guerra.

Agora você tem:

  • 🌐 Latência: 100–200ms (no mínimo)
  • 🔄 Consistência distribuída
  • ⚠️ Conflito de escrita
  • 🔁 Failover real (não o de slide de PowerPoint)

💣 E aqui vem o ponto que derruba sistema:

TPS deixa de ser capacidade e vira problema de coordenação global.


💥 Onde TODO mundo quebra (sem exceção)

1. Consistência forte global

👉 “Vamos manter saldo sincronizado em todas regiões”

Resultado:

  • Lock distribuído
  • Round-trip global
  • TPS despenca mais rápido que job mal indexado

💣 Isso aqui mata performance.


2. Dependência síncrona entre regiões

👉 API Brasil → chama EUA → espera resposta

Resultado:

  • Cada request carrega latência global
  • Você virou refém da pior região

💣 É o equivalente moderno de:

“esperar fita montar pra continuar o batch”


3. Hotspot de dados

👉 Conta sendo acessada globalmente

Resultado:

  • Contenção
  • Locking
  • Throughput artificialmente alto… TPS real baixo

💣 Clássico erro de modelagem.


☠️ O ERRO RAIZ (o mais perigoso)

“Vamos usar Kafka”
“Vamos usar Cassandra”
“Vamos fazer active-active”

🚫 Errado.

Isso é igual dizer:

“Vamos usar DFSORT” antes de saber o layout do arquivo.


🧠 Modelo mental Bellacosa (nível arquiteto de guerra)

Antes de falar de tecnologia, responda:

1. Tipo de operação

  • 💰 Financeira crítica?
  • 🔁 Pode reprocessar?
  • ♻️ É idempotente?

2. Consistência

  • 🔒 Forte → saldo, ledger
  • 📊 Eventual → extrato, notificação

💣 Regra de ouro:

Quanto mais consistência, menor o TPS possível.


3. Latência aceitável

  • ⚡ 100ms?
  • 🕒 500ms?
  • 🔁 segundos com retry?

👉 Isso define TUDO.


4. Distribuição geográfica

  • Usuário local?
  • Cross-border?

👉 Se for global, esqueça sonho de consistência forte em tudo.


5. Perfil de carga

  • 📈 Constante?
  • 🚀 Pico violento?

👉 Sistema que aguenta pico não nasce por acidente.


🏦 Caso real (estilo “produção sem desculpa”)

Cenário:

  • 10k TPS global
  • Brasil + México
  • Transferência financeira

Estratégia inteligente

👉 Saldo = consistente localmente
👉 Cross-region = assíncrono

Fluxo mental:

  • Região BR resolve BR rápido
  • Região MX resolve MX rápido
  • Entre regiões → evento + reconciliação

⚖️ O trade-off que ninguém escapa

Você sempre escolhe entre:

  • 🔒 Consistência
  • ⚡ Latência
  • 🚀 Throughput

💣 Não existe arquitetura perfeita.
Existe arquitetura assumida com responsabilidade.


🔥 Conclusão estilo Bellacosa

Sistema financeiro não é sobre tecnologia.

É sobre decisão sob restrição real.

💣 Engenheiro júnior:

“Qual tecnologia usar?”

🔥 Engenheiro sênior:

“Qual risco eu posso aceitar?”


☕ Verdade final (nível mainframe raiz)

Se o seu TPS depende de coordenação global síncrona…

👉 você não construiu escala
👉 você construiu um gargalo distribuído

quinta-feira, 12 de setembro de 2024

Kojak Entra no CPD — O Dia em que um SQLCODE -911 Virou Suspeito e o Db2 Foi Chamado para Depor

 

Bellacosa Mainframe apresenta cobol e db2

☕ Um Café no Bellacosa Mainframe

Kojak Entra no CPD — O Dia em que um SQLCODE -911 Virou Suspeito e o Db2 Foi Chamado para Depor

Ou: como COBOL, SQL, DBRM, BIND, PACKAGE, access path, COMMIT, ROLLBACK, locking, CICS e um programador iniciante descobriram que, no mainframe, até um SELECT tem antecedentes

Nova York, 1973.

Um policial careca, impecavelmente vestido, andando pelas ruas com um pirulito na boca começa a resolver crimes enquanto solta ironias e uma pergunta que se tornaria inseparável do personagem:

“Who loves ya, baby?”

Era o tenente Theo Kojak.

A série Kojak, criada por Abby Mann e protagonizada por Telly Savalas, estreou na CBS em 24 de outubro de 1973 e permaneceu originalmente no ar até 1978. (Paramount Press Express)

Curiosamente, Kojak surgiu antes da série: Telly Savalas interpretou o personagem no telefilme The Marcus-Nelson Murders, de 1973, que funcionou como origem do programa. (Los Angeles Times)

E existe algo profundamente mainframe em Kojak.

Ele não olha apenas para o cadáver.

Olha para quem entrou, quem saiu, quem tinha autorização, quem estava segurando o recurso, quem alterou o registro e por que aquela história aparentemente perfeita não combina com as evidências.

Troque a delegacia por um CPD.

Troque o assassinato por uma transação travada.

Troque as testemunhas por logs.

E dê ao tenente um terminal 3270.

Temos nosso novo investigador Db2.



Prólogo — 03:17, alguma coisa morreu em produção

O telefone toca.

O programador COBOL iniciante atende.

— Produção está parada.

Cinco palavras capazes de transformar café em combustível nuclear.

Ele abre o fonte.

EXEC SQL
    SELECT SALDO
      INTO :WS-SALDO
      FROM CONTA
     WHERE NUMERO = :WS-CONTA
END-EXEC.

Olha novamente.

Nada parece errado.

Compilou.

Ontem funcionava.

O programador conclui:

— Deve ser o banco.

A porta do CPD abre.

Um homem careca entra lentamente, coloca um pirulito na boca e observa o terminal.

— O banco, baby?

Silêncio.

— Vamos começar novamente. Quem executou o SQL?

E aí descobrimos nosso primeiro problema.



1. COBOL não executa SQL sozinho

Quando vemos:

EXEC SQL
    SELECT ...
END-EXEC

é fácil imaginar que SELECT seja uma instrução COBOL.

Não é.

COBOL e SQL são linguagens diferentes trabalhando juntas.

Podemos imaginar três responsabilidades:

COBOL
   │
   ├── lógica da aplicação
   ├── cálculos
   ├── decisões
   └── fluxo
          │
          ▼
         SQL
          │
          └── declara quais dados queremos
                    │
                    ▼
                   Db2
                    │
                    └── determina como obtê-los

O COBOL pode dizer:

“Preciso consultar o saldo desta conta.”

O SQL expressa:

SELECT SALDO
FROM CONTA
WHERE NUMERO = :WS-CONTA

E o Db2 precisa resolver como encontrar aquele registro eficientemente.

Kojak tira o pirulito da boca.

— Então temos três testemunhas. COBOL diz uma coisa, SQL pede outra e Db2 faz o trabalho pesado.

Exatamente.



2. O primeiro interrogatório: as Host Variables

Observe:

WHERE NUMERO = :WS-CONTA

Por que existe aquele :?

Porque WS-CONTA pertence ao programa hospedeiro.

É uma host variable.

Temos uma fronteira:

       COBOL                     SQL

    WS-CONTA ───────────────► :WS-CONTA

    WS-SALDO ◄─────────────── :WS-SALDO

No comando:

EXEC SQL
    SELECT SALDO
      INTO :WS-SALDO
      FROM CONTA
     WHERE NUMERO = :WS-CONTA
END-EXEC

WS-CONTA fornece informação.

WS-SALDO recebe informação.

Parece simples.

Até aparecerem:

  • tipos incompatíveis;

  • valores NULL;

  • indicator variables;

  • truncamentos;

  • conversões;

  • nenhuma linha;

  • múltiplas linhas.

Kojak aponta para WS-CONTA.

— Interrogue esse sujeito primeiro. Todo mundo culpa o Db2 antes de perguntar o que mandou para ele.

Primeira regra da investigação:

entrada errada produz investigação errada.


3. O crime aconteceu antes da execução

Nosso iniciante acredita que o fonte vai diretamente para o compilador COBOL.

Kojak balança a cabeça.

— Baby... tem alguém faltando nessa história.

Quando existe SQL embutido, o SQL precisa ser processado.

No fluxo tradicional, podemos representar:

COBOL + SQL
     │
     ▼
PRECOMPILE
     │
     ├────────────► DBRM
     │
     ▼
COBOL modificado
     │
     ▼
COBOL COMPILER
     │
     ▼
OBJECT
     │
     ▼
LINK-EDIT
     │
     ▼
LOAD MODULE

O processamento SQL e o processamento COBOL são coisas distintas.

E acabamos de encontrar nosso primeiro suspeito misterioso.

DBRM.


4. DBRM — o dossiê policial do SQL

DBRM significa Database Request Module.

Não é o executável COBOL.

Não é a tabela.

Não é o banco.

Não é o programa completo.

Uma maneira didática de imaginá-lo é como o dossiê contendo informações sobre as requisições SQL extraídas do programa para uso posterior pelo Db2.

A documentação IBM descreve o DBRM dentro justamente desse processo de preparação das instruções SQL para o bind. (Wikipedia)

Imagine:

PROGRAMA ABC123

SQL 001
SELECT SALDO...

SQL 002
UPDATE CONTA...

SQL 003
INSERT MOVIMENTO...

O Db2 precisará conhecer essas requisições.

O DBRM entra nessa história.

Kojak pega a pasta.

— Agora temos antecedentes.


5. BIND — agora leve o suspeito para a delegacia

Aqui aparece uma palavra que todo programador COBOL/Db2 precisa conhecer:

BIND.

Simplificando bastante, durante o bind o Db2 trabalha com as informações SQL preparadas anteriormente e produz aquilo que será necessário para executar o SQL estático.

Temos:

DBRM
  │
  ▼
BIND PACKAGE
  │
  ▼
PACKAGE

Agora nossa investigação começa a ficar interessante.

Porque significa que existem dois universos relacionados:

             APLICAÇÃO

        ┌───────────────┐
        │               │
        ▼               ▼
      COBOL            SQL
        │               │
        ▼               ▼
 LOAD MODULE          DBRM
                        │
                        ▼
                      BIND
                        │
                        ▼
                     PACKAGE

É perfeitamente possível que alguém diga:

“Mas o COBOL compilou!”

Ótimo.

Isso prova apenas uma parte da história.

Kojak sorri.

— Compilou? Muito bonito. Agora me mostre o package.


6. PACKAGE — o personagem que o iniciante quase nunca conhece

O package contém informações necessárias para a execução das instruções SQL estáticas associadas à aplicação.

E aqui ocorre uma mudança mental importante.

O programa executável e o SQL preparado possuem processos relacionados, mas distintos.

Portanto:

SOURCE
  │
  ├──────── COBOL ────────► LOAD MODULE
  │
  └──────── SQL ─► DBRM ─► BIND ─► PACKAGE

Na execução, esses mundos precisam conversar corretamente.

É por isso que um problema de Db2 pode existir mesmo quando o compilador COBOL não reclamou.

O compilador não é Sherlock Holmes.

Muito menos Kojak.


7. “Mas quem decidiu usar aquele índice?”

Chegamos ao grande interrogatório.

Considere:

SELECT NOME,
       LIMITE,
       SALDO
FROM CLIENTE
WHERE CPF = :WS-CPF

O programador declarou o que deseja.

Não escreveu:

vá para cilindro X
abra página Y
ande 37 posições
leia registro Z

Essa é uma das grandes diferenças entre programação procedural e acesso relacional.

O Db2 possui um optimizer.

Conceitualmente:

             SQL
              │
              ▼
          OPTIMIZER
              │
       ┌──────┼──────┐
       │      │      │
       ▼      ▼      ▼
   índices estatísticas cardinalidade
       │      │      │
       └──────┼──────┘
              ▼
         ACCESS PATH
              │
              ▼
          EXECUÇÃO

O optimizer avalia alternativas e custos.

Pode considerar índices.

Pode considerar outras estratégias.

O resultado dessa decisão é fundamental para performance.

Kojak olha para o programador:

— Você escreveu o SELECT. Mas não decidiu necessariamente como ele encontraria o sujeito.

Perfeito.


8. RUNSTATS — quando a testemunha está dizendo a verdade de 2019

Agora temos uma situação deliciosa.

O programa não mudou.

O SQL não mudou.

A tabela não mudou estruturalmente.

Mas o desempenho ficou horrível.

Como?

Imagine que o Db2 esteja tomando decisões baseado em informações estatísticas inadequadas ou desatualizadas.

É como Kojak perguntar:

— Quantas pessoas vivem neste prédio?

E alguém responder:

— Doze.

— Quando você contou?

— Em 1997.

Temos um problema.

As estatísticas ajudam o optimizer a compreender características dos dados.

Daí a importância de operações como RUNSTATS.

Isso nos ensina uma lição extraordinária:

Performance SQL não está inteiramente dentro do fonte SQL.

Ela depende do ecossistema.


9. Índice não é pó mágico

O iniciante aprende:

Índice deixa SELECT rápido.

Depois cria índice para tudo.

Parabéns.

Acabamos de transformar uma boa ideia em um novo incidente.

Índices possuem custo.

Precisam ser mantidos.

INSERT, UPDATE e DELETE podem ter trabalho adicional quando índices associados precisam ser atualizados.

Portanto:

MAIS ÍNDICES

      não significa automaticamente

MAIS PERFORMANCE

A pergunta é:

qual índice atende quais padrões reais de acesso?

Kojak provavelmente perguntaria:

— Esse índice estava onde na noite do crime?


10. O SQLCODE chega para depor

Executamos:

EXEC SQL
    SELECT SALDO
      INTO :WS-SALDO
      FROM CONTA
     WHERE NUMERO = :WS-CONTA
END-EXEC

E agora?

Precisamos saber o resultado.

Entra o SQLCODE.

Didaticamente:

SQLCODE = 0
     │
     └── sucesso

SQLCODE positivo
     │
     └── condição/warning

SQLCODE negativo
     │
     └── erro

Um programador iniciante pode fazer:

IF SQLCODE NOT = ZERO
    DISPLAY 'ERRO DB2'
END-IF.

Kojak quase engole o pirulito.

Porque os códigos precisam ser interpretados, não simplesmente classificados como “deu certo/deu errado”.

O famoso +100, por exemplo, normalmente indica ausência de linha correspondente ou fim do conjunto de resultados conforme a operação.

Isso pode ser perfeitamente normal.

Pesquisar cliente inexistente não significa necessariamente que o banco “quebrou”.


11. Até que aparece o cadáver: SQLCODE -911

Agora temos drama.

O programa retorna:

SQLCODE = -911

E alguém grita:

— Db2 caiu!

Não necessariamente.

Temos uma pista ligada a situações envolvendo rollback provocado por deadlock ou timeout, conforme o contexto e reason code.

Kojak sorri.

Finalmente um crime digno dele.

Imagine:

TRANSAÇÃO A

LOCK RECURSO 1
      │
      ▼
PRECISA RECURSO 2


TRANSAÇÃO B

LOCK RECURSO 2
      │
      ▼
PRECISA RECURSO 1

Temos:

A espera B

B espera A

Os dois poderiam esperar até a aposentadoria do programador.

O sistema precisa resolver a situação.

Bem-vindo ao mundo de locking, timeout e deadlock.


12. ACID — a divisão de crimes financeiros

Imagine uma transferência:

CONTA A = 1000
CONTA B =  500

TRANSFERÊNCIA = 100

Queremos terminar:

A = 900
B = 600

Não queremos:

A = 900
B = 500

porque o sistema caiu no meio.

É aqui que as propriedades ACID entram em cena:

Atomicity — a unidade lógica precisa ser tratada de maneira indivisível quanto ao resultado transacional.

Consistency — regras de consistência devem permanecer válidas.

Isolation — transações concorrentes precisam coexistir sob regras controladas.

Durability — depois da confirmação, os resultados precisam possuir as garantias de persistência esperadas.

Esse não é detalhe acadêmico.

É o motivo pelo qual você consegue dormir depois de transferir dinheiro pelo banco.


13. COMMIT — pode liberar os suspeitos

Considere:

UPDATE CONTA A
       │
       ▼
UPDATE CONTA B
       │
       ▼
INSERT MOVIMENTO
       │
       ▼
     COMMIT

O COMMIT delimita a confirmação apropriada daquela unidade de trabalho.

Mas imagine:

UPDATE A       OK
UPDATE B       OK
INSERT         ERRO

Dependendo da lógica e do contexto transacional, podemos precisar desfazer alterações.

Entra:

ROLLBACK

Portanto:

        UNIT OF WORK

UPDATE
   │
UPDATE
   │
INSERT
   │
   ├──── tudo correto ───► COMMIT
   │
   └──── problema ───────► ROLLBACK

Essa dupla é parte central da engenharia transacional.


14. COMMIT também é performance

Agora vem uma sutileza importante.

Alguns iniciantes imaginam COMMIT apenas como:

salvar alterações.

Mas unidades de trabalho também estão relacionadas à utilização e liberação de determinados recursos e locks.

Imagine um batch processando:

10 registros
100 registros
10.000 registros
10.000.000 registros

sem pensar adequadamente na estratégia de commit.

Ele pode manter recursos por períodos indesejáveis, afetar concorrência e complicar recuperação.

Logo, frequência de commit não deveria ser escolhida com:

COMMIT a cada 1000

simplesmente porque alguém encontrou esse número num programa de 1987.

A estratégia depende da aplicação.


15. Então chega o CICS à delegacia

Até agora poderíamos estar pensando em batch.

Mas coloque a aplicação em ambiente transacional:

CLIENTE
   │
   ▼
CICS
   │
   ▼
PROGRAMA COBOL
   │
   ▼
SQL
   │
   ▼
DB2

Agora milhares de usuários podem executar transações.

Temos simultaneamente:

CICS transaction 001 ──┐
CICS transaction 002 ──┤
CICS transaction 003 ──┼──► Db2
CICS transaction 004 ──┤
CICS transaction 005 ──┘

Nesse momento, locking deixa de ser um capítulo de apostila.

Vira sobrevivência.


16. COBOL + Db2 Connect? Cuidado com essa simplificação

O infográfico original apresenta conceitualmente uma camada intermediária chamada Db2 Connect.

Aqui Kojak levantaria uma sobrancelha.

Db2 Connect não deve ser ensinado como passagem obrigatória de todo programa COBOL local no z/OS para Db2.

Dependendo do ambiente, temos diferentes mecanismos de attachment e execução.

Batch, CICS, IMS, TSO e aplicações distribuídas podem envolver arquiteturas diferentes.

Portanto:

COBOL → DB2 Connect → Db2

não é uma representação universal.

Esse é exatamente o tipo de simplificação que funciona num infográfico 101, mas precisa ser desmontada quando o aluno chega ao nível 201.


17. “COBOL cuida da regra; Db2 cuida dos dados”

Boa explicação.

Mas incompleta.

No mundo real, Db2 também possui recursos relacionados a:

  • constraints;

  • integridade referencial;

  • views;

  • triggers;

  • stored procedures;

  • functions.

Então podemos pensar:

COBOL
 │
 ├── fluxo
 ├── cálculo
 ├── regras da aplicação
 └── orquestração

DB2
 │
 ├── persistência
 ├── integridade
 ├── concorrência
 ├── recuperação
 ├── otimização
 └── acesso relacional

As responsabilidades precisam ser projetadas.

Não simplesmente presumidas.


18. Static SQL e Dynamic SQL entram na sala

Nosso exemplo:

EXEC SQL
    SELECT SALDO
    ...
END-EXEC

é um exemplo clássico de SQL embutido estático.

Conceitualmente:

STATIC SQL

conhecido durante
preparação/deployment
       │
       ▼
processamento
       │
       ▼
DBRM
       │
       ▼
BIND
       │
       ▼
PACKAGE

Mas existe SQL dinâmico.

Podemos ter situações nas quais a instrução é preparada durante a execução usando mecanismos como PREPARE e EXECUTE.

Isso oferece flexibilidade, mas muda aspectos da preparação e execução.

Novamente:

não existe “um é sempre melhor”.

Existe:

qual mecanismo atende melhor ao problema?


19. O crime perfeito: SELECT *

Kojak encontra:

SELECT *
FROM CLIENTE

Olha para o programador.

Olha novamente para a tela.

— Você precisa de todas essas colunas?

— Não.

— Então por que pediu?

Silêncio.

Essa pergunta vale ouro.

Evite transportar dados desnecessários.

Se precisa de:

NOME
SALDO

não peça quarenta colunas simplesmente porque:

SELECT *

é mais rápido de digitar.

Cinco segundos economizados na programação podem gerar trabalho desnecessário repetido milhões de vezes em produção.


20. Outro suspeito: SELECT dentro de LOOP

Agora Kojak encontra:

PERFORM 100000 TIMES

       SELECT ...

END-PERFORM

Acende a luz da sala de interrogatório.

Dependendo do problema, isso pode representar enorme quantidade de chamadas e processamento que talvez pudesse ser resolvida por uma estratégia SQL muito melhor.

O erro conceitual é tratar banco relacional como arquivo sequencial:

LEIA
LEIA
LEIA
LEIA
LEIA

SQL trabalha naturalmente com conjuntos.

Essa mudança de pensamento é enorme para quem vem de COBOL procedural.


21. Não coloque toda a investigação num único SQL monstruoso

Mas existe o extremo oposto.

Alguém aprende que SQL trabalha com conjuntos e produz:

SELECT
 JOIN
  JOIN
   JOIN
    CASE
     CASE
      SUBQUERY
       UNION
        CTE
         FUNCTION
          JOIN
           ...

O SQL parece o mapa genealógico de Game of Thrones.

SQL complexo não é automaticamente ruim.

Às vezes uma operação sofisticada no banco é exatamente a solução correta.

Mas complexidade precisa possuir justificativa.

Legibilidade importa.

Manutenção importa.

Performance importa.

Testabilidade importa.


22. EXPLAIN — reconstruindo a cena do crime

Se queremos investigar desempenho, precisamos saber mais sobre o access path.

É aí que conceitos relacionados ao EXPLAIN tornam-se fundamentais.

O objetivo é investigar como o Db2 pretende ou decidiu acessar os dados, conforme o cenário analisado.

Você começa a procurar pistas:

INDEX?
TABLESPACE SCAN?
JOIN METHOD?
JOIN ORDER?
ESTIMATIVAS?
SORT?

Kojak coloca fotografias na parede.

Agora temos uma investigação de verdade.

O programador deixa de dizer:

“Esse SELECT está lento.”

E começa a perguntar:

“Qual access path está sendo utilizado e por quê?”

Essa diferença separa palpite de diagnóstico.


23. O verdadeiro CPD aparece

Finalmente afastamos a câmera.

O programador pensava que estava trabalhando com:

COBOL + DB2

Mas agora enxerga:

                    z/OS
                      │
       ┌──────────────┼──────────────┐
       │              │              │
      JES2           CICS           Db2
       │              │              │
      JCL            COBOL          SQL
       │              │              │
    datasets           ├──────────────┤
                       │              │
                       MQ          PACKAGE
                       │              │
                      API         OPTIMIZER
                                      │
                                  ACCESS PATH
                                      │
                              ┌───────┴───────┐
                              │               │
                           INDEXES          TABLES

E ainda não terminamos.

Ao redor estão:

RACF
SMF
WLM
TCP/IP
LOGS
RECOVERY
BACKUP
MONITORAMENTO
PARALLEL SYSPLEX

Agora entendemos por que profissionais podem trabalhar décadas com mainframe e continuar aprendendo.


24. Kojak finalmente resolve o caso

Voltamos às 03:17.

O programa estava correto.

O SQL também.

O Db2 estava disponível.

O problema estava relacionado à concorrência.

Outra unidade de trabalho estava mantendo recursos necessários.

A transação esperou.

O limite foi atingido.

O SQL recebeu erro.

O programa não possuía tratamento suficientemente inteligente.

A mensagem apresentada ao operador foi:

ERRO NO BANCO

Ou seja:

o único inocente da investigação talvez fosse justamente “o banco”.

Kojak olha para o programador.

— Então você acusou Db2 sem verificar SQLCODE, reason code, locks, unidade de trabalho e logs?

— Sim.

Kojak coloca o pirulito na boca.

— Who loves ya, baby?


🍭 Easter egg — por que Kojak usa pirulito?

Esse detalhe é perfeito para nossa história.

O pirulito não nasceu simplesmente como um adereço aleatório inventado pelo departamento de marketing. Telly Savalas contou posteriormente que a ideia surgiu numa situação em que uma personagem queria que Kojak parasse de fumar e lhe entregava um pirulito; o detalhe pegou e tornou-se uma das marcas visuais do personagem. (Los Angeles Times)

Na própria série, o pirulito apareceu durante a primeira temporada e acabou associado à tentativa de reduzir o cigarro. (Wikipedia)

Ou seja:

pequena decisão
      │
      ▼
efeito inesperado
      │
      ▼
torna-se característica permanente

Qualquer semelhança com sistemas legados é absolutamente maravilhosa.

Um programador em 1984 cria:

05 WS-FLAG PIC X.

para resolver temporariamente um problema.

Quarenta anos depois:

“Não mexa no WS-FLAG. Ninguém sabe exatamente por quê, mas o fechamento mensal depende dele.”

😂


25. A lição que Kojak deixaria ao programador COBOL

O grande erro de quem começa no mainframe é imaginar que aprender COBOL significa aprender sintaxe:

MOVE
COMPUTE
IF
EVALUATE
PERFORM

Isso é apenas a porta de entrada.

Depois vem:

COBOL
  +
JCL
  +
Db2
  +
CICS
  +
VSAM
  +
MQ
  +
RACF
  +
JES2
  +
WLM
  +
SMF
  +
z/OS

E finalmente você percebe:

o sistema corporativo não é um programa. É um ecossistema de componentes cooperando.

O SELECT SALDO que parece possuir cinco linhas pode envolver host variables, processamento SQL, DBRM, package, optimizer, estatísticas, índices, buffer management, locking, logging, segurança, recuperação e infraestrutura antes de devolver alguns bytes para WS-SALDO.

Essa é uma das coisas mais bonitas do mainframe.

Na superfície:

EXEC SQL
   SELECT SALDO
   INTO :WS-SALDO
...
END-EXEC.

Debaixo:

               50 ANOS
                  DE
             ENGENHARIA
                  │
                  ▼
             WS-SALDO

O programador olha para a variável.

Depois olha para Kojak.

Finalmente compreendeu.

Não basta perguntar:

“O programa compilou?”

É preciso investigar:

Qual SQL executou? Qual SQLCODE retornou? Qual package? Qual access path? As estatísticas estão adequadas? Existe índice apropriado? Houve locking? Timeout? Deadlock? Onde começa e termina a unidade de trabalho? Houve COMMIT? O que os logs mostram?

Porque produção não aceita álibi.

Produção aceita evidência.

Kojak se levanta, pega o sobretudo e caminha para a porta do CPD.

O programador pergunta:

— Tenente, e se amanhã aparecer outro -911?

Kojak sorri.

— Agora você sabe interrogar os suspeitos, baby.

E sai.

Na mesa fica apenas um pirulito, um dump, três relatórios de performance e um post-it:

****************************************
* NÃO CULPE O DB2 ANTES DO EXPLAIN.    *
****************************************

Fim do JOB.

IEF404I KOJAK - ENDED
IEF142I KOJAK STEP01 - COND CODE 0000

E, pela primeira vez naquela madrugada, ninguém precisou dar ROLLBACK no café. ☕🍭

sábado, 31 de dezembro de 2022

COBOL, QSAM e Db2 sem Mistérios: a Jornada do Arquivo Sequencial até o INSERT na Tabela

 

Bellacosa Mainframe executando cobol com db2 e qsam

☕ Um Café no Bellacosa Mainframe

COBOL, QSAM e Db2 sem Mistérios: a Jornada do Arquivo Sequencial até o INSERT na Tabela

Imagine a cena: madrugada no datacenter, luzes azuis refletindo nos corredores, o IBM Z trabalhando silenciosamente e, diante da tela 3270, um programador COBOL padawan observa um pequeno JCL.

À primeira vista, são poucas linhas:

//EXECDB2 EXEC PGM=IKJEFT01,DYNAMNBR=20
//STEPLIB DD DSN=DSN910.SDSNLOAD,DISP=SHR
//LISTCOPAC DD DSN=INFEF00.COPIA.MUNDO,DISP=SHR
//SYSTSPRT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//SYSTSIN  DD *
  DSN SYSTEM(DB9G)
  RUN PROGRAM(COBDB501) PLAN(HERP0001) -
      LIB('ADCD.Z112.USERLOAD')
/*

Mas o verdadeiro mainframe nunca entrega todos os seus segredos de imediato.

Por trás dessas linhas existe uma cadeia completa de tecnologias:

JES2
  ↓
JCL
  ↓
IKJEFT01
  ↓
TSO Batch
  ↓
DSN Command Processor
  ↓
Db2 Attachment Facility
  ↓
PLAN
  ↓
PACKAGE
  ↓
Programa COBOL
  ↓
QSAM
  ↓
Arquivo sequencial
  ↓
INSERT no Db2
  ↓
COMMIT ou ROLLBACK

O JCL é pequeno, mas representa o último estágio de uma fábrica inteira de software. Antes de chegar a essa execução, alguém escreveu um programa COBOL, processou SQL pelo precompiler, compilou, linkeditou, gerou um load module, criou um DBRM, executou BIND PACKAGE, criou ou atualizou um PLAN e autorizou o usuário.

Vamos abrir cada porta desse templo tecnológico.


Bellacosa Mainframe executando um programa cobol db2 e qsam

1. Qual é a missão deste programa?

O próprio comentário do JCL entrega a missão:

//* PROGRAMA LE QSAM E INSERE TABELAS DB2

Em linguagem simples, o programa deverá:

  1. abrir um arquivo sequencial;

  2. ler cada registro;

  3. separar os campos;

  4. validar os dados;

  5. executar um INSERT em uma tabela Db2;

  6. tratar registros inválidos;

  7. realizar COMMIT;

  8. fechar o arquivo;

  9. retornar um código ao sistema operacional.

Um fluxo provável seria:

Abrir arquivo LISTCOPAC
        ↓
Ler primeiro registro
        ↓
Registro válido?
   ┌────┴────┐
   │         │
  Sim       Não
   │         │
INSERT      Registrar erro
   │         │
   └────┬────┘
        ↓
Atingiu intervalo de COMMIT?
        ↓
Executar COMMIT
        ↓
Ler próximo registro
        ↓
Fim do arquivo?
   ┌────┴────┐
   │         │
  Não       Sim
   │         │
Repetir     COMMIT final
             ↓
        Fechar arquivo
             ↓
           GOBACK

Esse tipo de programa é muito comum em sistemas corporativos.

Ele pode carregar:

  • clientes;

  • contas;

  • pagamentos;

  • movimentações;

  • produtos;

  • contratos;

  • dados de interfaces;

  • informações recebidas de outros sistemas;

  • arquivos produzidos por plataformas distribuídas.

É uma ponte entre o mundo dos arquivos batch e o mundo relacional do Db2.


2. O papel do JES

Antes que qualquer programa seja executado, o job precisa ser entregue ao JES.

JES significa Job Entry Subsystem.

Em muitos ambientes z/OS utiliza-se o JES2. Ele recebe o JCL, analisa as instruções, prepara os recursos, controla a execução e organiza as saídas no spool.

Quando o programador digita:

SUB

no ISPF Edit, não está executando o COBOL diretamente.

Na realidade, está entregando um pedido ao JES:

“JES, aceite este conjunto de instruções, valide o JCL, encontre os recursos e execute os steps na ordem indicada.”

O JES então:

  1. atribui um JOBID;

  2. lê o JCL;

  3. faz a conversão;

  4. verifica procedimentos;

  5. coloca o job na fila;

  6. seleciona uma initiator;

  7. executa os steps;

  8. recolhe as mensagens;

  9. grava os resultados no spool.

O nome mostrado na tela:

CATPGM1

é o nome do job.

O identificador:

JOB00056

é o JOBID atribuído pelo JES.

Esses dois nomes parecem semelhantes, mas representam coisas diferentes:

CATPGM1  = nome lógico fornecido no cartão JOB
JOB00056 = número atribuído pelo JES

3. A biblioteca JOBLIB

Na imagem existe:

//JOBLIB DD DSN=IBMUSER.CBL.LOADLIB,DISP=SHR

A JOBLIB define uma biblioteca de módulos executáveis para o job inteiro.

É como dizer:

“Ao procurar programas deste job, inclua esta biblioteca na busca.”

A biblioteca:

IBMUSER.CBL.LOADLIB

deve ser uma PDS ou PDSE contendo load modules ou program objects.

Um programa COBOL não é executado diretamente a partir do fonte:

IBMUSER.CBL.SOURCE(COBDB501)

O fonte precisa atravessar um processo:

Fonte COBOL
     ↓
Precompile Db2
     ↓
Compilação COBOL
     ↓
Object module
     ↓
Binder ou Link-edit
     ↓
Load module

O resultado final pode estar armazenado como:

IBMUSER.CBL.LOADLIB(COBDB501)

Um detalhe importante

No step da imagem também existe uma STEPLIB:

//STEPLIB DD DSN=DSN910.SDSNLOAD,DISP=SHR

Quando um step possui STEPLIB, ela normalmente substitui a JOBLIB para a busca de módulos naquele step.

Portanto, a existência de JOBLIB não significa que ela será usada pelo step EXECDB2.

Essa é uma daquelas curiosidades que derrubam muitos padawans.

O programador pensa:

“Meu programa está na JOBLIB, portanto será encontrado.”

Mas o sistema responde:

“Existe uma STEPLIB neste step. Minha busca seguirá outro caminho.”

No caso do JCL apresentado, o programa da aplicação é localizado por meio da cláusula:

LIB('ADCD.Z112.USERLOAD')

Isso evita que ele dependa da JOBLIB.


4. O step EXECDB2

//EXECDB2 EXEC PGM=IKJEFT01,DYNAMNBR=20

Essa linha cria um step chamado:

EXECDB2

O nome do step é escolhido pelo desenvolvedor.

Ele poderia ser:

//STEP01
//RUNCOB
//DB2RUN
//CARREGA

Um bom nome melhora a análise do spool.

Ao observar:

EXECDB2

já sabemos que aquele step provavelmente executará alguma coisa em um ambiente Db2.

A instrução:

EXEC PGM=IKJEFT01

determina o programa que o z/OS carregará inicialmente.

E aqui surge uma pergunta importante:

Por que o JCL não executa diretamente COBDB501?

Porque COBDB501 contém SQL estático e precisa executar conectado ao subsistema Db2. O IKJEFT01 cria o ambiente TSO batch, dentro do qual o command processor DSN estabelece essa conexão.

Assim, a sequência real é:

IKJEFT01
   ↓
Comando DSN
   ↓
DSN SYSTEM(DB9G)
   ↓
RUN PROGRAM(COBDB501)

5. O que é o IKJEFT01?

O IKJEFT01 é um programa do z/OS utilizado para executar comandos TSO em batch.

O TSO é normalmente associado ao trabalho interativo:

READY

O usuário digita comandos e recebe respostas.

Com IKJEFT01, não existe uma pessoa digitando os comandos. Eles são fornecidos por um dataset ou por dados instream no DD SYSTSIN.

Uma analogia Bellacosa:

  • TSO interativo é o Jedi no terminal;

  • IKJEFT01 é o droide que repete os comandos durante a madrugada;

  • SYSTSIN é o pergaminho com as ordens;

  • SYSTSPRT é o diário da missão.

O IKJEFT01 pode executar:

  • comandos TSO;

  • CLISTs;

  • execuções REXX;

  • comandos do Db2;

  • utilitários que dependem do ambiente TSO.


6. O parâmetro DYNAMNBR=20

DYNAMNBR=20

Esse parâmetro está relacionado ao número de alocações dinâmicas que o ambiente TSO pode utilizar.

Durante a execução, o IKJEFT01, o command processor DSN ou programas chamados podem precisar alocar datasets dinamicamente.

Exemplos:

  • bibliotecas;

  • arquivos temporários;

  • arquivos de controle;

  • mensagens;

  • datasets de trabalho.

O valor:

20

costuma ser suficiente para execuções simples.

Em ambientes maiores aparecem valores como:

DYNAMNBR=50

ou:

DYNAMNBR=100

Não significa que o sistema abrirá imediatamente 20 datasets. É uma capacidade reservada para o ambiente.

Um valor insuficiente pode provocar falhas de alocação em execuções mais complexas.


7. A STEPLIB do Db2

//STEPLIB DD DSN=DSN910.SDSNLOAD,DISP=SHR

A STEPLIB informa as bibliotecas usadas na procura dos programas daquele step.

A biblioteca:

DSN910.SDSNLOAD

contém módulos relacionados ao Db2.

Entre eles podem existir componentes necessários para:

  • iniciar o command processor DSN;

  • usar o TSO Attachment Facility;

  • conectar-se ao subsistema;

  • carregar rotinas internas;

  • interagir com os serviços Db2.

O nome DSN910 pode indicar uma instalação antiga, uma versão ou apenas uma convenção local.

Não devemos presumir que o nome da biblioteca representa exatamente a versão atual do Db2. Muitas instalações mantêm nomes históricos para evitar alterar centenas de JCLs.

Contudo, é essencial que essa biblioteca seja compatível com o subsistema usado.

O subsistema do exemplo é:

DB9G

Se a SDSNLOAD não for a correta, podem surgir:

  • mensagens de conexão;

  • módulo não encontrado;

  • falhas no attachment;

  • abends;

  • incompatibilidade de nível.


8. DISP=SHR

Tanto a JOBLIB quanto a STEPLIB e o arquivo de entrada utilizam:

DISP=SHR

O parâmetro DISP descreve o estado e o tratamento do dataset.

SHR significa que o dataset já existe e pode ser compartilhado.

Exemplo:

//STEPLIB DD DSN=DSN910.SDSNLOAD,DISP=SHR

Essa biblioteca poderá ser usada simultaneamente por vários jobs.

Isso é normal para load libraries, pois dezenas ou centenas de aplicações podem carregar módulos da mesma biblioteca.

No arquivo de entrada:

//LISTCOPAC DD DSN=INFEF00.COPIA.MUNDO,DISP=SHR

o SHR indica leitura compartilhada.

Se o programa estivesse atualizando diretamente um dataset, talvez fosse necessário:

DISP=OLD

Mas para leitura QSAM, SHR é a escolha mais comum.


9. O DD LISTCOPAC

//LISTCOPAC DD DSN=INFEF00.COPIA.MUNDO,DISP=SHR

Essa linha liga um nome lógico a um dataset físico.

O nome lógico é:

LISTCOPAC

O dataset físico é:

INFEF00.COPIA.MUNDO

No programa COBOL provavelmente existe:

SELECT ARQUIVO-COPAC
    ASSIGN TO LISTCOPAC
    ORGANIZATION IS SEQUENTIAL
    ACCESS MODE IS SEQUENTIAL
    FILE STATUS IS WS-FILE-STATUS.

O COBOL conhece o arquivo pelo nome lógico. O JCL informa qual dataset real será usado.

Essa separação é poderosa.

O mesmo programa pode processar arquivos diferentes sem precisar ser recompilado.

Hoje:

//LISTCOPAC DD DSN=INFEF00.COPIA.MUNDO,DISP=SHR

Amanhã:

//LISTCOPAC DD DSN=INFEF00.COPIA.MUNDO.NOVO,DISP=SHR

O programa continua igual.

É o JCL que conecta a aplicação ao dado certo.


10. O que é QSAM?

QSAM significa Queued Sequential Access Method.

É um método de acesso para datasets sequenciais.

O programa COBOL executa comandos simples:

OPEN INPUT
READ
CLOSE

Mas o QSAM trabalha nos bastidores com:

  • buffers;

  • blocos;

  • movimentação de dados;

  • controle de fim de arquivo;

  • tratamento de registros;

  • acesso ao dispositivo;

  • otimização de entrada e saída.

Imagine um arquivo com registros de 100 bytes:

LRECL=100

O sistema não precisa necessariamente ler um registro físico por operação de disco.

Ele pode ler um bloco contendo vários registros:

BLKSIZE=27900

Nesse caso, um bloco pode conter 279 registros de 100 bytes.

O programa continua pedindo um registro por vez, mas o QSAM já trouxe vários registros para a memória.

Essa é a magia silenciosa do buffering.


11. Exemplo de definição COBOL

Um arquivo poderia ter esta estrutura:

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.

    SELECT ARQ-COPAC
        ASSIGN TO LISTCOPAC
        ORGANIZATION IS SEQUENTIAL
        ACCESS MODE IS SEQUENTIAL
        FILE STATUS IS WS-FS-COPAC.

DATA DIVISION.
FILE SECTION.

FD  ARQ-COPAC
    RECORDING MODE IS F.

01  REG-COPAC.
    05 CP-CODIGO           PIC 9(05).
    05 CP-NOME             PIC X(40).
    05 CP-PAIS             PIC X(30).
    05 CP-POPULACAO        PIC 9(11).
    05 FILLER              PIC X(14).

O tamanho total seria:

5 + 40 + 30 + 11 + 14 = 100 bytes

Logo, o dataset deveria ter:

RECFM=FB
LRECL=100

Se o arquivo tiver LRECL=80, a definição estará incompatível.

O resultado pode ser:

  • erro de abertura;

  • registros truncados;

  • campos deslocados;

  • dados inválidos;

  • abend;

  • inserções incorretas no banco.


12. File Status: o sensor do arquivo

Todo programa COBOL profissional deveria usar FILE STATUS.

Exemplo:

01  WS-FS-COPAC         PIC XX.

Após o OPEN:

OPEN INPUT ARQ-COPAC

IF WS-FS-COPAC NOT = '00'
    DISPLAY 'ERRO NO OPEN DO ARQUIVO: ' WS-FS-COPAC
    MOVE 12 TO RETURN-CODE
    GOBACK
END-IF

Alguns estados comuns:

00 = operação concluída
10 = fim de arquivo
35 = arquivo não encontrado
39 = conflito de atributos
41 = arquivo já aberto
42 = arquivo não aberto
46 = tentativa inválida de READ

O status 39 merece atenção especial.

Ele pode ocorrer quando a definição física do arquivo não combina com o que o programa espera.

É o mainframe dizendo:

“Padawan, o arquivo existe, mas sua descrição não corresponde à realidade.”


13. O DD SYSTSPRT

//SYSTSPRT DD SYSOUT=*

O SYSTSPRT recebe mensagens do TSO e do command processor DSN.

É uma das saídas mais importantes para análise.

Ali podem aparecer:

  • início do DSN;

  • conexão com o subsistema;

  • processamento do comando RUN;

  • mensagens sobre PLAN;

  • falha na localização do programa;

  • retorno do ambiente Db2;

  • encerramento do command processor.

Quando o job falhar antes de entrar no programa COBOL, o SYSTSPRT deve ser uma das primeiras saídas examinadas.


14. O significado de SYSOUT=*

DD SYSOUT=*

Isso não significa “um arquivo chamado SYSOUT”.

SYSOUT=* envia a saída ao spool, usando normalmente a classe de saída definida pelo job.

Exemplo:

//SYSTSPRT DD SYSOUT=*

As mensagens poderão ser vistas no SDSF.

O asterisco significa, em termos práticos:

“Use a classe de saída padrão associada ao job.”

Também seria possível especificar uma classe:

//SYSTSPRT DD SYSOUT=X

A classe depende das regras da instalação.


15. O problema dos DDs duplicados

Na imagem aparecem duas linhas:

//SYSOUT DD SYSOUT=*
//SYSOUT DD SYSOUT=*

Esse é um provável erro.

Dentro do mesmo step, dois DD statements não devem possuir o mesmo DDNAME dessa maneira.

Se o programa precisa de duas saídas, use nomes diferentes:

//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*

Ou:

//RELATORI DD SYSOUT=*
//ERROS    DD SYSOUT=*

Os nomes devem corresponder ao que o programa espera.

Exemplo no COBOL:

SELECT ARQ-RELATORIO
    ASSIGN TO RELATORI.

SELECT ARQ-ERROS
    ASSIGN TO ERROS.

O JCL seria:

//RELATORI DD SYSOUT=*
//ERROS    DD SYSOUT=*

E se a intenção era concatenar?

A concatenação correta seria:

//ENTRADA  DD DSN=ARQUIVO.PARTE1,DISP=SHR
//         DD DSN=ARQUIVO.PARTE2,DISP=SHR

Observe que apenas a primeira linha possui DDNAME.

Portanto:

//SYSOUT DD SYSOUT=*
//SYSOUT DD SYSOUT=*

não é a maneira adequada de concatenar.


16. O DD SYSTSIN

//SYSTSIN DD *

O SYSTSIN fornece comandos ao ambiente TSO batch.

Tudo entre:

//SYSTSIN DD *

e:

/*

será entregue ao IKJEFT01.

No exemplo:

DSN SYSTEM(DB9G)
RUN PROGRAM(COBDB501) PLAN(HERP0001) -
    LIB('ADCD.Z112.USERLOAD')

Essas linhas não são JCL.

São comandos processados dentro do ambiente TSO/Db2.

Essa diferença é fundamental.

JCL:

//SYSTSIN DD *

Comando TSO:

DSN SYSTEM(DB9G)

Subcomando Db2:

RUN PROGRAM(COBDB501)

17. O comando DSN SYSTEM(DB9G)

DSN SYSTEM(DB9G)

O comando DSN inicia o command processor do Db2.

O parâmetro:

SYSTEM(DB9G)

identifica o subsistema desejado.

O nome de quatro caracteres:

DB9G

é o subsystem ID.

Em outros ambientes poderíamos encontrar:

DB2D
DB2T
DB2H
DB2P
D91A
DSN1

A convenção varia.

Por exemplo:

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

Mas essa nomenclatura não é uma regra do Db2. É apenas uma convenção possível.

Quando o comando é executado, o sistema tenta:

  1. localizar o subsistema;

  2. estabelecer o attachment;

  3. criar uma thread;

  4. validar o ambiente;

  5. preparar a execução do programa.

Se o subsistema estiver parado, o programa nem chegará a ser carregado.


18. O comando RUN PROGRAM

RUN PROGRAM(COBDB501)

O DSN recebe a ordem para executar o programa:

COBDB501

Esse nome deve corresponder ao load module ou program object gerado no link-edit.

O DSN não executa o fonte COBOL.

Ele procura algo como:

ADCD.Z112.USERLOAD(COBDB501)

O membro deve ser um executável válido.

Se o membro não existir, pode ocorrer uma mensagem de programa não encontrado ou até um abend S806, dependendo do ponto da falha.


19. A cláusula PLAN(HERP0001)

PLAN(HERP0001)

O PLAN representa o contexto de execução Db2 da aplicação.

Historicamente, o PLAN continha diretamente os DBRMs.

Nos ambientes modernos, é comum o PLAN apontar para PACKAGES:

PLAN
  ↓
PKLIST
  ↓
COLLECTION
  ↓
PACKAGE
  ↓
Seções SQL

O PLAN:

HERP0001

deve existir no subsistema DB9G.

Também precisa estar autorizado para o usuário que executa o job.

Caso contrário, podem surgir erros relacionados a:

  • autorização;

  • PLAN inexistente;

  • PACKAGE não localizado;

  • collection incorreta;

  • inconsistência entre programa e PACKAGE.


20. DBRM, PACKAGE e PLAN

Quando um programa COBOL contém SQL:

EXEC SQL
    INSERT INTO TB_COPAC
           (CODIGO, NOME, PAIS)
    VALUES (:CP-CODIGO, :CP-NOME, :CP-PAIS)
END-EXEC

o compilador COBOL não entende sozinho esse SQL.

Antes da compilação, ocorre o precompile Db2.

O precompiler produz dois resultados:

1. Fonte COBOL modificado
2. DBRM

O fonte modificado contém chamadas à interface Db2.

O DBRM contém as instruções SQL extraídas.

Fluxo completo:

COBOL + SQL
    ↓
PRECOMPILE
    ├── COBOL modificado
    └── DBRM
          ↓
      BIND PACKAGE
          ↓
       PACKAGE

Enquanto isso:

COBOL modificado
    ↓
COMPILER
    ↓
OBJECT MODULE
    ↓
LINK-EDIT
    ↓
LOAD MODULE

Na execução, o load module e o PACKAGE precisam pertencer à mesma geração lógica.


21. O clássico SQLCODE -818

O -818 ocorre quando o programa executável e o DBRM ou PACKAGE não possuem o mesmo consistency token.

Em linguagem Bellacosa:

O sabre de luz e o cristal kyber vieram de treinamentos diferentes.

Isso acontece quando:

  1. o programa é precompilado;

  2. é gerado um novo DBRM;

  3. o COBOL é compilado;

  4. o load module é atualizado;

  5. o PACKAGE antigo continua no Db2.

Ou o contrário:

  1. um novo PACKAGE é criado;

  2. o load module antigo continua na loadlib.

Resultado:

SQLCODE -818

A correção normalmente exige refazer o ciclo com os mesmos artefatos:

PRECOMPILE
COMPILE
LINK-EDIT
BIND PACKAGE

22. O SQLCODE -805

O -805 também é extremamente comum.

Ele indica que o Db2 não encontrou o PACKAGE necessário.

Possíveis causas:

  • PACKAGE não bindado;

  • collection errada;

  • PLAN não contém a collection;

  • nome do programa diferente;

  • ambiente errado;

  • PACKAGE removido;

  • load module promovido sem o BIND correspondente.

A mensagem geralmente fornece informações sobre:

  • localização;

  • collection;

  • package;

  • consistency token.

Esses dados devem ser analisados cuidadosamente.


23. A cláusula LIB

LIB('ADCD.Z112.USERLOAD')

A cláusula LIB informa a biblioteca onde o programa deve ser localizado.

Portanto:

RUN PROGRAM(COBDB501)
    PLAN(HERP0001)
    LIB('ADCD.Z112.USERLOAD')

significa:

Execute o programa COBDB501, utilizando o PLAN HERP0001, procurando o módulo na biblioteca ADCD.Z112.USERLOAD.

Essa instrução é importante porque a STEPLIB contém apenas a biblioteca Db2.

Sem a cláusula LIB, o programa da aplicação talvez não fosse encontrado.

Atenção à biblioteca antiga

A imagem também mostra:

//JOBLIB DD DSN=IBMUSER.CBL.LOADLIB,DISP=SHR

Temos então duas bibliotecas que podem conter o programa:

IBMUSER.CBL.LOADLIB
ADCD.Z112.USERLOAD

É importante confirmar onde está a versão correta.

Talvez exista:

IBMUSER.CBL.LOADLIB(COBDB501)

e também:

ADCD.Z112.USERLOAD(COBDB501)

Se a versão nova foi gravada na primeira biblioteca, mas o comando RUN aponta para a segunda, o job continuará executando o programa antigo.

Esse é um easter egg clássico do mainframe:

O código está correto, a compilação terminou com RC 0, mas o comportamento não mudou porque o job está carregando outra cópia do programa.

Para investigar, use ISPF 3.4 e compare:

  • data;

  • hora;

  • tamanho;

  • atributos;

  • usuário da última alteração.


24. O hífen de continuação

PLAN(HERP0001) -

O hífen informa que o comando continua na linha seguinte.

A continuação é:

LIB('ADCD.Z112.USERLOAD')

Sem o hífen, o DSN poderia tratar a primeira linha como um comando completo e a segunda como outro comando.

Uma versão bem formatada seria:

RUN PROGRAM(COBDB501) -
    PLAN(HERP0001)     -
    LIB('ADCD.Z112.USERLOAD')

O estilo depende do padrão da empresa, mas a legibilidade melhora bastante.


25. O comando END

O JCL da imagem não apresenta explicitamente:

END

É recomendável encerrar a sessão DSN:

//SYSTSIN DD *
  DSN SYSTEM(DB9G)
  RUN PROGRAM(COBDB501) PLAN(HERP0001) -
      LIB('ADCD.Z112.USERLOAD')
  END
/*

O fim do arquivo de comandos pode encerrar o command processor, mas o END deixa a intenção explícita.

É uma boa prática.


26. Exemplo completo de JCL corrigido

//CATPGM1 JOB (ACCT),'CARGA COBOL DB2',
//             CLASS=A,
//             MSGCLASS=X,
//             MSGLEVEL=(1,1),
//             NOTIFY=&SYSUID
//*
//*-------------------------------------------------------------------*
//* PROGRAMA COBOL LE ARQUIVO QSAM E INSERE DADOS NO DB2
//*-------------------------------------------------------------------*
//EXECDB2 EXEC PGM=IKJEFT01,DYNAMNBR=20
//*
//* MODULOS DO DB2
//*
//STEPLIB DD DSN=DSN910.SDSNLOAD,DISP=SHR
//*
//* ARQUIVO SEQUENCIAL DE ENTRADA
//*
//LISTCOPAC DD DSN=INFEF00.COPIA.MUNDO,DISP=SHR
//*
//* SAIDAS DO AMBIENTE E DO PROGRAMA
//*
//SYSTSPRT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//CEEDUMP  DD SYSOUT=*
//*
//* COMANDOS TSO E DB2
//*
//SYSTSIN DD *
  DSN SYSTEM(DB9G)
  RUN PROGRAM(COBDB501) PLAN(HERP0001) -
      LIB('ADCD.Z112.USERLOAD')
  END
/*
//

27. Explicação do cartão JOB

//CATPGM1 JOB (ACCT),'CARGA COBOL DB2',

CATPGM1 é o nome do job.

(ACCT)

representa informações contábeis da instalação.

'CARGA COBOL DB2'

é uma descrição.


CLASS=A

CLASS=A

Define a classe de execução.

A classe pode determinar:

  • prioridade;

  • initiator;

  • limites;

  • ambiente;

  • políticas de scheduling.

O significado de A varia conforme a instalação.


MSGCLASS=X

MSGCLASS=X

Define a classe das mensagens de saída.

Ela influencia onde e como o spool será tratado.


MSGLEVEL=(1,1)

MSGLEVEL=(1,1)

Controla o nível de detalhes registrado no spool.

O primeiro valor controla a impressão das instruções JCL.

O segundo controla mensagens de alocação e execução.


NOTIFY=&SYSUID

NOTIFY=&SYSUID

Solicita que o usuário que submeteu o job seja notificado quando ele terminar.

&SYSUID é substituído pelo ID do usuário.


28. Exemplo de programa COBOL

       IDENTIFICATION DIVISION.
       PROGRAM-ID. COBDB501.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.

           SELECT ARQ-COPAC
               ASSIGN TO LISTCOPAC
               ORGANIZATION IS SEQUENTIAL
               ACCESS MODE IS SEQUENTIAL
               FILE STATUS IS WS-FS-COPAC.

       DATA DIVISION.
       FILE SECTION.

       FD  ARQ-COPAC
           RECORDING MODE IS F.

       01  REG-COPAC.
           05 CP-CODIGO           PIC 9(05).
           05 CP-NOME             PIC X(40).
           05 CP-PAIS             PIC X(30).
           05 CP-POPULACAO        PIC 9(11).
           05 FILLER              PIC X(14).

       WORKING-STORAGE SECTION.

       01  WS-FS-COPAC            PIC XX.
       01  WS-FIM-ARQUIVO         PIC X VALUE 'N'.
           88 FIM-ARQUIVO               VALUE 'S'.

       01  WS-CONTADORES.
           05 WS-LIDOS            PIC 9(09) COMP-3 VALUE ZERO.
           05 WS-INSERIDOS        PIC 9(09) COMP-3 VALUE ZERO.
           05 WS-REJEITADOS       PIC 9(09) COMP-3 VALUE ZERO.
           05 WS-COMMIT           PIC 9(05) COMP-3 VALUE ZERO.

       01  WS-SQLCODE-AUX         PIC -9(09).

           EXEC SQL
               INCLUDE SQLCA
           END-EXEC.

       PROCEDURE DIVISION.

       0000-PRINCIPAL.

           PERFORM 1000-INICIALIZAR

           PERFORM 2000-PROCESSAR
               UNTIL FIM-ARQUIVO

           PERFORM 9000-FINALIZAR

           GOBACK.

29. Inicialização do programa

       1000-INICIALIZAR.

           DISPLAY 'INICIO DO PROGRAMA COBDB501'

           OPEN INPUT ARQ-COPAC

           IF WS-FS-COPAC NOT = '00'
               DISPLAY 'ERRO NO OPEN LISTCOPAC: ' WS-FS-COPAC
               MOVE 12 TO RETURN-CODE
               GOBACK
           END-IF

           PERFORM 2100-LER-ARQUIVO.

A primeira leitura é realizada na inicialização.

Esse padrão evita que o programa execute o processamento com um registro não carregado.


30. Leitura e processamento

       2000-PROCESSAR.

           ADD 1 TO WS-LIDOS

           PERFORM 3000-VALIDAR-REGISTRO

           IF CP-CODIGO IS NUMERIC
               PERFORM 4000-INSERIR-DB2
           ELSE
               ADD 1 TO WS-REJEITADOS
               DISPLAY 'CODIGO INVALIDO: ' CP-CODIGO
           END-IF

           PERFORM 2100-LER-ARQUIVO.

A leitura:

       2100-LER-ARQUIVO.

           READ ARQ-COPAC
               AT END
                   SET FIM-ARQUIVO TO TRUE
               NOT AT END
                   CONTINUE
           END-READ

           IF WS-FS-COPAC NOT = '00'
              AND WS-FS-COPAC NOT = '10'
               DISPLAY 'ERRO DE LEITURA: ' WS-FS-COPAC
               PERFORM 8000-ROLLBACK
               MOVE 12 TO RETURN-CODE
               GOBACK
           END-IF.

O status 10 representa fim de arquivo e não deve ser tratado como erro.


31. O INSERT Db2

       4000-INSERIR-DB2.

           EXEC SQL
               INSERT INTO TB_COPAC
               (
                   CODIGO,
                   NOME,
                   PAIS,
                   POPULACAO
               )
               VALUES
               (
                   :CP-CODIGO,
                   :CP-NOME,
                   :CP-PAIS,
                   :CP-POPULACAO
               )
           END-EXEC

           EVALUATE SQLCODE
               WHEN ZERO
                   ADD 1 TO WS-INSERIDOS
                   ADD 1 TO WS-COMMIT

               WHEN -803
                   ADD 1 TO WS-REJEITADOS
                   DISPLAY 'CHAVE DUPLICADA: ' CP-CODIGO

               WHEN OTHER
                   MOVE SQLCODE TO WS-SQLCODE-AUX
                   DISPLAY 'ERRO SQL: ' WS-SQLCODE-AUX
                   DISPLAY 'REGISTRO: ' CP-CODIGO
                   PERFORM 8000-ROLLBACK
                   MOVE 12 TO RETURN-CODE
                   GOBACK
           END-EVALUATE

           IF WS-COMMIT >= 1000
               PERFORM 7000-COMMIT
           END-IF.

32. Por que não fazer apenas um COMMIT no final?

Imagine uma carga de dez milhões de registros.

Se o programa executar um único COMMIT, poderá manter durante horas:

  • locks;

  • espaço de log;

  • páginas modificadas;

  • recursos;

  • unidade de trabalho gigantesca.

Se ocorrer erro no registro 9.999.999, o rollback poderá desfazer tudo.

Uma estratégia mais segura é:

COMMIT a cada 1.000 registros

Ou:

COMMIT a cada 5.000 registros

O valor ideal depende do ambiente.

Não existe um número mágico.

É preciso considerar:

  • volume;

  • concorrência;

  • log;

  • índices;

  • tempo de recuperação;

  • SLA;

  • restart;

  • regras de negócio.

Rotina:

       7000-COMMIT.

           EXEC SQL
               COMMIT
           END-EXEC

           IF SQLCODE NOT = ZERO
               DISPLAY 'ERRO NO COMMIT: ' SQLCODE
               MOVE 12 TO RETURN-CODE
               GOBACK
           END-IF

           MOVE ZERO TO WS-COMMIT.

33. ROLLBACK

       8000-ROLLBACK.

           EXEC SQL
               ROLLBACK
           END-EXEC

           DISPLAY 'ROLLBACK EXECUTADO'.

O rollback desfaz alterações realizadas desde o último commit.

Mas atenção: ele não desfaz tudo desde o início do programa se já ocorreram commits intermediários.

Exemplo:

1.000 registros → COMMIT
1.000 registros → COMMIT
500 registros → erro → ROLLBACK

Nesse caso:

  • os primeiros 2.000 permanecem;

  • os últimos 500 são desfeitos.


34. Finalização

       9000-FINALIZAR.

           IF WS-COMMIT > ZERO
               PERFORM 7000-COMMIT
           END-IF

           CLOSE ARQ-COPAC

           DISPLAY '--------------------------------'
           DISPLAY 'REGISTROS LIDOS     : ' WS-LIDOS
           DISPLAY 'REGISTROS INSERIDOS : ' WS-INSERIDOS
           DISPLAY 'REGISTROS REJEITADOS: ' WS-REJEITADOS
           DISPLAY 'FIM DO PROGRAMA COBDB501'
           DISPLAY '--------------------------------'.

Esses totais serão enviados ao SYSOUT ou à saída padrão do Language Environment, dependendo da configuração.

Eles são fundamentais para auditoria.


35. Códigos de retorno

O programa pode usar:

MOVE 0 TO RETURN-CODE

para sucesso.

Outros códigos comuns:

RC 0  = sucesso
RC 4  = sucesso com aviso
RC 8  = erro de aplicação
RC 12 = erro grave
RC 16 = falha crítica

Esses valores são convenções. A empresa pode definir outros padrões.

Um scheduler pode usar o retorno:

RC <= 4  → continuar
RC >= 8  → interromper fluxo

36. Possíveis falhas

JCL ERROR

Causa provável:

//SYSOUT DD SYSOUT=*
//SYSOUT DD SYSOUT=*

Correção: usar DDNAMEs distintos.


S806

O programa não foi encontrado.

Verificar:

ADCD.Z112.USERLOAD(COBDB501)

S013

Pode estar relacionado à incompatibilidade de atributos do dataset.

Verificar:

  • RECFM;

  • LRECL;

  • BLKSIZE;

  • modo de abertura;

  • definição FD.


SQLCODE -803

Chave duplicada.

O programa tentou inserir um valor único já existente.


SQLCODE -805

PACKAGE não encontrado.

Verificar:

  • collection;

  • BIND PACKAGE;

  • PLAN;

  • consistency token.


SQLCODE -818

Load module e PACKAGE incompatíveis.

Refazer compilação e BIND de forma sincronizada.


SQLCODE -904

Recurso indisponível.

Pode existir:

  • tablespace parado;

  • utility pendente;

  • objeto em estado restritivo;

  • problema de storage.


SQLCODE -911

Deadlock ou timeout com rollback.

A aplicação precisa registrar:

  • chave;

  • SQLCODE;

  • unidade de trabalho;

  • momento do erro.


SQLCODE -922

Problema de autorização ou conexão.

Verificar permissões para:

  • PLAN;

  • PACKAGE;

  • tabela;

  • operação INSERT;

  • subsistema.


37. Como investigar no SDSF

Depois de submeter o job, abra:

SDSF

Depois:

ST

Localize o job e abra com S.

Analise na seguinte ordem:

JESJCL

Mostra o JCL interpretado.

Útil para detectar:

  • erro de sintaxe;

  • DD duplicado;

  • PROC expandida;

  • símbolos substituídos.

JESYSMSG

Mostra mensagens do sistema.

Procure por prefixos:

IEF
IEC
IGD
ICH

SYSTSPRT

Mostra mensagens do TSO e DSN.

SYSOUT

Mostra os DISPLAY do COBOL.

CEEDUMP

Mostra informações de falhas do Language Environment.

SYSUDUMP

Pode conter detalhes de abend e registradores.


38. Easter egg: o programa antigo que nunca morre

Um dos problemas mais misteriosos do mainframe ocorre assim:

  1. o programador altera o fonte;

  2. compila com RC 0;

  3. submete o job;

  4. o comportamento antigo continua;

  5. compila novamente;

  6. nada muda;

  7. começa a desconfiar do compilador, do Db2 e talvez da própria realidade.

A causa:

O load module foi gravado em uma biblioteca,
mas o RUN está usando outra.

Exemplo:

Novo:
IBMUSER.CBL.LOADLIB(COBDB501)

Executado:
ADCD.Z112.USERLOAD(COBDB501)

O mainframe não está errado.

Ele apenas obedeceu exatamente ao que foi pedido.

Essa é uma das grandes lições do IBM Z:

O sistema raramente faz o que imaginamos. Ele faz o que realmente declaramos.


39. O grande mapa da missão

INFEF00.COPIA.MUNDO
          │
          │ LISTCOPAC
          ▼
     Programa COBOL
       COBDB501
          │
          │ EXEC SQL INSERT
          ▼
      PLAN HERP0001
          │
          ▼
        PACKAGE
          │
          ▼
       Db2 DB9G
          │
          ▼
       TB_COPAC

Ao redor dessa execução, estão:

JES2
IKJEFT01
SDSNLOAD
TSO Attachment
Language Environment
QSAM
RACF
SDSF
Logs do Db2

Nada acontece isoladamente.


Conclusão: poucas linhas, muitas engrenagens

O JCL apresentado é um excelente exemplo da filosofia mainframe: comandos pequenos podem coordenar estruturas gigantescas.

Uma linha como:

RUN PROGRAM(COBDB501) PLAN(HERP0001)

carrega décadas de evolução tecnológica.

Ela conecta:

  • um executável COBOL;

  • um ambiente TSO batch;

  • um subsistema Db2;

  • um PLAN;

  • PACKAGES;

  • SQL estático;

  • um arquivo sequencial;

  • QSAM;

  • segurança;

  • logging;

  • controle transacional.

Para o programador COBOL padawan, a principal lição é não observar o JCL como uma simples receita de execução.

Cada DD representa um contrato.

LISTCOPAC → contrato com o arquivo
STEPLIB   → contrato com as bibliotecas
SYSTSIN   → contrato com o TSO
SYSTSPRT  → contrato com as mensagens
PLAN      → contrato com o Db2
LIB       → contrato com o executável
COMMIT    → contrato com a integridade

Quando esses contratos estão alinhados, milhões de registros podem ser processados com precisão.

Quando um deles está errado, o sistema pode responder com um JCL ERROR, um S806, um -805, um -818 ou um silencioso arquivo lido com layout incorreto.

O verdadeiro domínio do mainframe não vem apenas de decorar comandos.

Ele nasce quando entendemos a jornada completa:

Fonte
  → Precompile
  → Compile
  → Link-edit
  → DBRM
  → BIND PACKAGE
  → BIND PLAN
  → JCL
  → IKJEFT01
  → DSN
  → COBOL
  → QSAM
  → Db2
  → COMMIT
  → SDSF

E assim, diante da tela verde, com uma caneca de café ao lado, o padawan percebe que aquele pequeno JCL não é apenas um arquivo de comandos.

É a porta de entrada para uma das arquiteturas de processamento corporativo mais robustas já construídas.

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