☕ 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

sábado, 29 de agosto de 2026

CRUD Walker — Quando Chuck Norris Auditou um Cadastro COBOL, Encontrou Cinquenta Clientes na WORKING-STORAGE e Descobriu que o UPDATE Fugiu Antes da Compilação

 

Bellacosa Mainframe 

☕ Um Café no Bellacosa Mainframe

CRUD Walker — Quando Chuck Norris Auditou um Cadastro COBOL, Encontrou Cinquenta Clientes na WORKING-STORAGE e Descobriu que o UPDATE Fugiu Antes da Compilação

Ou: o jovem padawan chamou o programa de CRUD, Chuck Norris contou apenas três letras, Igor tentou esconder os clientes dentro de um OCCURS e o mainframe perguntou onde estavam o arquivo, o FILE STATUS e o COMMIT



Prólogo — O cadastro que entrou no saloon com uma letra faltando

O programa compilava.

O menu aparecia.

Clientes podiam ser incluídos, consultados, listados e excluídos. Havia confirmação antes da exclusão, tratamento de opções inválidas e até reorganização da tabela depois que um registro era removido.

Igor olhou para a tela verde, ajeitou o chapéu e anunciou:

— Está pronto! Um CRUD completo de clientes em COBOL!

No fundo da sala, Chuck Norris levantou os olhos do relatório de compilação.

Não disse nada.

Apenas escreveu quatro letras no quadro:

C — CREATE
R — READ
U — UPDATE
D — DELETE

Depois examinou o menu:

1 - INCLUIR CLIENTE
2 - CONSULTAR CLIENTE
3 - LISTAR CLIENTES
4 - EXCLUIR CLIENTE
0 - SAIR

Chuck contou novamente.

Havia CREATE, READ e DELETE. O UPDATE não estava ali.

Igor tentou explicar que “listar” talvez pudesse ser considerado o U, mas o compilador pediu demissão antes de participar daquela discussão.

O projeto não era ruim. Pelo contrário: era um laboratório muito interessante para quem está aprendendo COBOL. Ele reunia estruturas de dados, controle de fluxo, validação, pesquisa, interação pelo terminal e manipulação de registros em memória.

Mas ainda era um CRD, não um CRUD completo.

A boa notícia é que acrescentar o UPDATE não exige demolir o programa. Exige amadurecer sua construção.

E é exatamente nessa evolução que aparecem algumas das lições mais valiosas do desenvolvimento corporativo.



1. Antes do código: o que significa CRUD?

CRUD é um acrônimo criado para representar as quatro operações fundamentais executadas sobre dados persistentes:

LetraPalavraOperação
CCreateCriar um registro
RReadLer ou consultar
UUpdateAlterar um registro existente
DDeleteExcluir um registro

Em um cadastro de clientes:

CREATE → cadastrar Paulo
READ   → consultar Paulo
UPDATE → mudar o telefone de Paulo
DELETE → remover ou inativar Paulo

Embora a sigla tenha ficado muito associada aos bancos de dados, essas operações podem ser simuladas em qualquer estrutura:

  • tabela OCCURS;

  • arquivo sequencial;

  • VSAM KSDS;

  • tabela Db2;

  • fila;

  • memória;

  • aplicação CICS;

  • serviço exposto por API.

O mecanismo muda, mas a intenção permanece.

No protótipo original, os clientes vivem dentro de uma tabela em memória. Isso permite estudar o comportamento do CRUD sem introduzir imediatamente JCL, arquivos, catálogos, VSAM, SQL, locks e unidades de trabalho.

É como aprender a estacionar em um pátio vazio antes de tentar fazê-lo na Avenida Paulista às seis da tarde.

Chuck Norris, naturalmente, estaciona o mainframe em uma vaga de motocicleta. Mas o jovem padawan deve começar com cinquenta registros.




2. Onde os clientes estão guardados?

A estrutura central do protótipo pode ser representada assim:

       01  WS-TABELA-CLIENTES.
           05 WS-CLIENTE OCCURS 50 TIMES.
              10 WS-CODIGO      PIC 9(05).
              10 WS-NOME        PIC X(40).
              10 WS-CPF         PIC X(11).
              10 WS-TELEFONE    PIC X(15).

O OCCURS 50 TIMES cria uma tabela com cinquenta posições.

Mas atenção: ele não cadastra cinquenta clientes.

Ele apenas reserva espaço para até cinquenta ocorrências da estrutura WS-CLIENTE.

Por isso, normalmente existe um contador:

       01  WS-CONTROLE.
           05 WS-TOTAL-CLIENTES     PIC 9(02) VALUE ZERO.
           05 WS-POSICAO            PIC 9(02) VALUE ZERO.
           05 WS-POSICAO-ENCONTRADA PIC 9(02) VALUE ZERO.

A tabela pode possuir cinquenta posições físicas, mas apenas as primeiras posições correspondentes a WS-TOTAL-CLIENTES são consideradas ocupadas.

Por exemplo:

PosiçãoCódigoNomeEstado
100001Ana MariaOcupada
200002Paulo HenriqueOcupada
300003Carla SouzaOcupada
4–50zeros/espaçosLivres

Nesse momento:

WS-TOTAL-CLIENTES = 03

O contador representa a fronteira entre o território ocupado e o deserto.

Se ele estiver incorreto, o programa poderá:

  • ignorar clientes válidos;

  • listar posições vazias;

  • sobrescrever registros;

  • pesquisar além da área útil;

  • tentar acessar uma ocorrência fora do limite.

Uma regra fundamental é:

0WS-TOTAL-CLIENTES500 \leq WS\text{-}TOTAL\text{-}CLIENTES \leq 50

Chuck Norris não ultrapassa o limite de uma tabela. A tabela aumenta o OCCURS quando percebe que ele chegou.



3. PIC: não é decoração, é contrato de dados

Um iniciante pode olhar para:

05 WS-CODIGO PIC 9(05).
05 WS-NOME   PIC X(40).

e pensar que PIC serve apenas para determinar o tamanho do campo.

Mas PICTURE descreve a natureza lógica do dado.

PIC 9(05)

significa um campo numérico com cinco posições.

PIC X(40)

significa um campo alfanumérico de quarenta posições.

Essa escolha deve refletir o significado do dado.

Código do cliente

Se o código sempre tiver cinco algarismos:

05 WS-CODIGO PIC 9(05).

Se puder aceitar letras:

05 WS-CODIGO PIC X(05).

CPF

O CPF contém números, mas não representa uma quantidade.

Não fazemos:

CPF + CPF
CPF / 2
média de CPF
juros sobre CPF

O CPF é um identificador. Por isso, uma representação alfanumérica costuma ser adequada:

05 WS-CPF PIC X(11).

Isso também preserva zeros à esquerda.

Telefone

Telefone também não é quantidade:

05 WS-TELEFONE PIC X(15).

Com PIC X, podemos admitir:

  • zeros à esquerda;

  • código internacional;

  • sinal +;

  • DDD;

  • diferentes tamanhos.

Uma curiosidade importante: dizer que um campo possui apenas dígitos não significa que ele deva ser numericamente armazenado. CEP, número de documento, código de barras e telefone são exemplos clássicos.

O dado pode parecer número sem ser matematicamente numérico.



4. O menu: onde EVALUATE controla o saloon

Uma aplicação textual normalmente apresenta as opções e recebe a escolha do usuário:

       1000-EXIBIR-MENU.
           DISPLAY "=============================="
           DISPLAY "       CADASTRO DE CLIENTES"
           DISPLAY "=============================="
           DISPLAY "1 - INCLUIR CLIENTE"
           DISPLAY "2 - CONSULTAR CLIENTE"
           DISPLAY "3 - LISTAR CLIENTES"
           DISPLAY "4 - ALTERAR CLIENTE"
           DISPLAY "5 - EXCLUIR CLIENTE"
           DISPLAY "0 - SAIR"
           DISPLAY "OPCAO: "
           ACCEPT WS-OPCAO.

Em seguida:

       1100-PROCESSAR-OPCAO.
           EVALUATE WS-OPCAO
               WHEN 1
                   PERFORM 2000-INCLUIR-CLIENTE
               WHEN 2
                   PERFORM 3000-CONSULTAR-CLIENTE
               WHEN 3
                   PERFORM 4000-LISTAR-CLIENTES
               WHEN 4
                   PERFORM 5000-ALTERAR-CLIENTE
               WHEN 5
                   PERFORM 6000-EXCLUIR-CLIENTE
               WHEN 0
                   MOVE "S" TO WS-FIM
               WHEN OTHER
                   DISPLAY "OPCAO INVALIDA"
           END-EVALUATE.

EVALUATE é apropriado porque o usuário escolhe uma alternativa entre várias possibilidades.

Seria possível usar vários IF, mas isso tornaria o fluxo menos legível:

IF WS-OPCAO = 1
   ...
ELSE
   IF WS-OPCAO = 2
      ...
   ELSE
      IF WS-OPCAO = 3

Depois de alguns níveis, Igor precisaria de um mapa, uma lanterna e uma autorização do RACF para encontrar o END-IF correto.



5. Nível 88: quando o número ganha significado

O COBOL permite associar nomes semânticos aos valores:

       01  WS-OPCAO                 PIC 9.
           88 OP-INCLUIR            VALUE 1.
           88 OP-CONSULTAR          VALUE 2.
           88 OP-LISTAR             VALUE 3.
           88 OP-ALTERAR            VALUE 4.
           88 OP-EXCLUIR            VALUE 5.
           88 OP-SAIR               VALUE 0.
           88 OPCAO-VALIDA          VALUE 0 THRU 5.

Agora é possível escrever:

       IF NOT OPCAO-VALIDA
           DISPLAY "OPCAO INVALIDA"
       END-IF

Em vez de perguntar “o valor está entre zero e cinco?”, o programa pergunta “a opção é válida?”.

Esse é um dos poderes discretos do COBOL: aproximar o código da linguagem do negócio.

Outro exemplo:

       01  WS-ENCONTRADO            PIC X VALUE "N".
           88 CLIENTE-ENCONTRADO    VALUE "S".
           88 CLIENTE-NAO-ENCONTRADO VALUE "N".

Então:

       IF CLIENTE-ENCONTRADO
           DISPLAY "CLIENTE LOCALIZADO"
       ELSE
           DISPLAY "CLIENTE NAO LOCALIZADO"
       END-IF

Chuck Norris não compara flags com "S". A flag pergunta a ele qual valor deve assumir.



6. Inclusão: criar não significa jogar dados na primeira vaga

Na inclusão, o programa precisa proteger alguns estados.

Antes de tudo:

       IF WS-TOTAL-CLIENTES >= 50
           DISPLAY "LIMITE DE CLIENTES ATINGIDO"
       END-IF

Depois, deve receber os dados em uma área temporária:

       01  WS-CLIENTE-ENTRADA.
           05 WS-ENT-CODIGO         PIC 9(05).
           05 WS-ENT-NOME           PIC X(40).
           05 WS-ENT-CPF            PIC X(11).
           05 WS-ENT-TELEFONE       PIC X(15).

Por que não gravar diretamente na tabela?

Porque o usuário pode:

  • informar código duplicado;

  • deixar o nome vazio;

  • digitar CPF inválido;

  • cancelar a operação;

  • interromper a entrada no meio.

Se o programa escrever diretamente na tabela, poderá criar um registro parcialmente válido.

O fluxo correto é:

Receber → Validar → Verificar duplicidade → Gravar → Incrementar

Exemplo:

       2000-INCLUIR-CLIENTE.
           IF WS-TOTAL-CLIENTES >= 50
               DISPLAY "TABELA CHEIA"
           ELSE
               INITIALIZE WS-CLIENTE-ENTRADA
               PERFORM 2100-RECEBER-DADOS
               PERFORM 2200-VALIDAR-DADOS

               IF DADOS-VALIDOS
                   MOVE WS-ENT-CODIGO
                     TO WS-CODIGO-PESQUISA

                   PERFORM 7000-LOCALIZAR-CLIENTE

                   IF CLIENTE-ENCONTRADO
                       DISPLAY "CODIGO JA CADASTRADO"
                   ELSE
                       ADD 1 TO WS-TOTAL-CLIENTES

                       MOVE WS-CLIENTE-ENTRADA
                         TO WS-CLIENTE(WS-TOTAL-CLIENTES)

                       DISPLAY "CLIENTE INCLUIDO"
                   END-IF
               END-IF
           END-IF.

O contador deve ser incrementado somente quando o registro estiver aprovado para entrar na tabela.



7. A busca é o coração compartilhado

Consulta, alteração e exclusão começam da mesma forma:

Localize o cliente pelo código.

Em vez de escrever três pesquisas diferentes, o programa deve possuir uma rotina reutilizável:

       7000-LOCALIZAR-CLIENTE.
           SET CLIENTE-NAO-ENCONTRADO TO TRUE
           MOVE ZERO TO WS-POSICAO-ENCONTRADA

           PERFORM VARYING WS-POSICAO FROM 1 BY 1
               UNTIL WS-POSICAO > WS-TOTAL-CLIENTES
                  OR CLIENTE-ENCONTRADO

               IF WS-CODIGO(WS-POSICAO)
                    = WS-CODIGO-PESQUISA
                   SET CLIENTE-ENCONTRADO TO TRUE
                   MOVE WS-POSICAO
                     TO WS-POSICAO-ENCONTRADA
               END-IF
           END-PERFORM.

Essa é uma busca linear.

No pior caso, ela examina todos os registros:

O(n)O(n)

Para cinquenta clientes, isso é mais do que suficiente.

Um iniciante pode ficar tentado a implementar imediatamente uma pesquisa binária com SEARCH ALL. Mas ela exige que a tabela esteja ordenada pela chave.

Sem ordenação garantida, a pesquisa binária pode procurar o cliente com velocidade impressionante no lugar errado.

Dica de Chuck Norris:

Primeiro faça a busca correta. Depois meça. Só então otimize.



8. Consulta e listagem não são a mesma coisa

Ambas pertencem ao READ, mas possuem objetivos diferentes.

Consulta

Procura um cliente específico:

       3000-CONSULTAR-CLIENTE.
           DISPLAY "CODIGO: "
           ACCEPT WS-CODIGO-PESQUISA

           PERFORM 7000-LOCALIZAR-CLIENTE

           IF CLIENTE-ENCONTRADO
               PERFORM 7100-MOSTRAR-CLIENTE
           ELSE
               DISPLAY "CLIENTE NAO ENCONTRADO"
           END-IF.

Listagem

Percorre todos os registros ativos:

       4000-LISTAR-CLIENTES.
           IF WS-TOTAL-CLIENTES = ZERO
               DISPLAY "NENHUM CLIENTE CADASTRADO"
           ELSE
               PERFORM VARYING WS-POSICAO FROM 1 BY 1
                   UNTIL WS-POSICAO > WS-TOTAL-CLIENTES

                   DISPLAY "CODIGO: "
                       WS-CODIGO(WS-POSICAO)
                   DISPLAY "NOME: "
                       WS-NOME(WS-POSICAO)
               END-PERFORM
           END-IF.

A consulta é acesso seletivo. A listagem é varredura.

Essa diferença aparecerá novamente no Db2:

SELECT ... WHERE CODIGO = ?

para consulta individual, e um cursor para múltiplos registros.



9. O UPDATE entra pela porta principal

Agora chegamos à letra desaparecida.

O UPDATE não cria uma nova posição e não remove a existente. Ele altera determinados atributos do cliente na mesma ocorrência.

Antes:

CampoValor
Código00025
NomePaulo Henrique
CPF12345678909
Telefone11999990000

Depois:

CampoValor
Código00025
NomePaulo Henrique Silva
CPF12345678909
Telefone11988887777

Observe:

  • o cliente continua na mesma posição;

  • o código permanece igual;

  • o contador não muda;

  • não há deslocamento de registros;

  • apenas determinados campos são substituídos.

Portanto:

CREATE → WS-TOTAL-CLIENTES aumenta
UPDATE → WS-TOTAL-CLIENTES não muda
DELETE → WS-TOTAL-CLIENTES diminui

Se uma alteração incrementar o total, o programa terá criado uma duplicata em vez de atualizar o registro.



10. A chave não deve ser tratada como um telefone

O código identifica o cliente:

05 WS-CODIGO PIC 9(05).

Nome, CPF e telefone são atributos.

Em geral, o UPDATE deve preservar a chave.

Permitir que o operador altere livremente o código pode causar:

  • duplicidade;

  • perda de referências;

  • quebra da ordenação;

  • inconsistência com outros arquivos;

  • dificuldade de auditoria;

  • relações órfãs em bancos de dados.

No protótipo, ainda não existem contas, contratos ou endereços vinculados. Mesmo assim, proteger a chave ensina a mentalidade correta.

Se realmente fosse necessário trocar o código, essa deveria ser uma operação especial, com verificação de duplicidade e atualização das referências relacionadas.

Curiosidade: em VSAM KSDS, a chave primária não é tratada como um campo comum regravável. Muitas vezes, mudar a chave exige excluir o registro antigo e gravar outro com a nova chave.

Ou seja: até o VSAM olha desconfiado quando Igor diz “vou apenas dar um MOVE na chave”.



11. Antes e depois: o mini-COMMIT do laboratório

A melhor construção para o UPDATE utiliza duas imagens:

       01  WS-CLIENTE-ANTES.
           05 WS-ANTES-CODIGO       PIC 9(05).
           05 WS-ANTES-NOME         PIC X(40).
           05 WS-ANTES-CPF          PIC X(11).
           05 WS-ANTES-TELEFONE     PIC X(15).

       01  WS-CLIENTE-DEPOIS.
           05 WS-DEPOIS-CODIGO      PIC 9(05).
           05 WS-DEPOIS-NOME        PIC X(40).
           05 WS-DEPOIS-CPF         PIC X(11).
           05 WS-DEPOIS-TELEFONE    PIC X(15).

Depois de localizar o cliente:

       MOVE WS-CLIENTE(WS-POSICAO-ENCONTRADA)
         TO WS-CLIENTE-ANTES

       MOVE WS-CLIENTE(WS-POSICAO-ENCONTRADA)
         TO WS-CLIENTE-DEPOIS

Os novos dados são aplicados apenas na imagem DEPOIS.

O registro oficial continua intacto até:

  • os campos serem validados;

  • as duplicidades serem verificadas;

  • o usuário confirmar;

  • o programa decidir efetivar a operação.

Depois da confirmação:

       MOVE WS-CLIENTE-DEPOIS
         TO WS-CLIENTE(WS-POSICAO-ENCONTRADA)

Esse MOVE funciona como uma espécie de commit lógico didático.

Não é um COMMIT real de banco de dados, mas a analogia é útil:

Protótipo em memóriaSistema transacional
Imagem ANTESEstado confirmado
Imagem DEPOISAlteração preparada
ValidaçãoRegras e constraints
ConfirmaçãoAprovação
MOVE finalCommit lógico
Descartar DEPOISRollback lógico

Chuck Norris faz COMMIT olhando para o banco. O Db2 confirma por respeito.



12. Pressionar Enter significa o quê?

Suponha:

NOME ATUAL: PAULO HENRIQUE
NOVO NOME [ENTER=MANTER]:

O usuário apenas pressiona Enter.

Existem duas interpretações:

  1. apagar o nome;

  2. manter o nome atual.

O programa deve definir explicitamente a regra.

Em um cadastro, uma boa escolha é:

Campo vazio mantém o valor anterior.

Exemplo:

       DISPLAY "NOVO NOME [ENTER=MANTER]: "
       ACCEPT WS-NOVO-NOME

       IF WS-NOVO-NOME NOT = SPACES
           MOVE WS-NOVO-NOME
             TO WS-DEPOIS-NOME
       END-IF

O mesmo vale para CPF e telefone.

Mas surge outra pergunta: como o usuário apaga intencionalmente um campo opcional?

Uma solução seria aceitar um comando especial:

ENTER = manter
*     = limpar
valor = substituir

Exemplo:

       EVALUATE TRUE
           WHEN WS-NOVO-TELEFONE = SPACES
               CONTINUE
           WHEN WS-NOVO-TELEFONE = "*"
               MOVE SPACES TO WS-DEPOIS-TELEFONE
           WHEN OTHER
               MOVE WS-NOVO-TELEFONE
                 TO WS-DEPOIS-TELEFONE
       END-EVALUATE.

Esse pequeno detalhe mostra que interface não é apenas ACCEPT e DISPLAY. Ela também é um contrato de significado.



13. O CPF novo pode pertencer a outro cliente

Se o CPF puder ser alterado, o programa precisa verificar duplicidade.

Mas há uma armadilha.

Ao procurar o novo CPF, o sistema encontrará o CPF do próprio cliente. Por isso, a validação deve ignorar a posição que está sendo atualizada:

       MOVE "N" TO WS-CPF-DUPLICADO

       PERFORM VARYING WS-POSICAO FROM 1 BY 1
           UNTIL WS-POSICAO > WS-TOTAL-CLIENTES
              OR WS-CPF-DUPLICADO = "S"

           IF WS-POSICAO NOT = WS-POSICAO-ENCONTRADA
              AND WS-CPF(WS-POSICAO) = WS-DEPOIS-CPF
               MOVE "S" TO WS-CPF-DUPLICADO
           END-IF
       END-PERFORM.

A expressão:

WS-POSICAO NOT = WS-POSICAO-ENCONTRADA

é essencial.

Sem ela, o sistema rejeitaria o CPF atual como duplicado de si mesmo.

É o equivalente cadastral de Chuck Norris ser barrado na porta porque sua fotografia se parece demais com ele.



14. O fluxo completo da alteração

Uma estrutura modular poderia ser:

       5000-ALTERAR-CLIENTE.
           DISPLAY "=== ALTERAR CLIENTE ==="
           DISPLAY "CODIGO: "
           ACCEPT WS-CODIGO-PESQUISA

           PERFORM 7000-LOCALIZAR-CLIENTE

           IF CLIENTE-NAO-ENCONTRADO
               DISPLAY "CLIENTE NAO ENCONTRADO"
           ELSE
               PERFORM 5100-PREPARAR-IMAGENS
               PERFORM 5200-MOSTRAR-DADOS-ATUAIS
               PERFORM 5300-RECEBER-NOVOS-DADOS
               PERFORM 5400-VALIDAR-ALTERACAO

               IF DADOS-VALIDOS
                   PERFORM 5500-MOSTRAR-COMPARACAO
                   PERFORM 5600-CONFIRMAR-ALTERACAO

                   IF ALTERACAO-CONFIRMADA
                       PERFORM 5700-EFETIVAR-ALTERACAO
                   ELSE
                       DISPLAY "ALTERACAO CANCELADA"
                   END-IF
               END-IF
           END-IF.

Essa divisão deixa cada parágrafo com uma responsabilidade.

Preparação

       5100-PREPARAR-IMAGENS.
           MOVE WS-CLIENTE(WS-POSICAO-ENCONTRADA)
             TO WS-CLIENTE-ANTES

           MOVE WS-CLIENTE(WS-POSICAO-ENCONTRADA)
             TO WS-CLIENTE-DEPOIS.

Entrada

       5300-RECEBER-NOVOS-DADOS.
           INITIALIZE WS-NOVO-NOME
                      WS-NOVO-CPF
                      WS-NOVO-TELEFONE

           DISPLAY "NOVO NOME [ENTER=MANTER]: "
           ACCEPT WS-NOVO-NOME

           DISPLAY "NOVO CPF [ENTER=MANTER]: "
           ACCEPT WS-NOVO-CPF

           DISPLAY "NOVO TELEFONE [ENTER=MANTER]: "
           ACCEPT WS-NOVO-TELEFONE.

Efetivação

       5700-EFETIVAR-ALTERACAO.
           MOVE WS-CLIENTE-DEPOIS
             TO WS-CLIENTE(WS-POSICAO-ENCONTRADA)

           DISPLAY "CLIENTE ALTERADO COM SUCESSO".


15. E se nada tiver mudado?

O usuário pode entrar na alteração e manter todos os campos.

Nesse caso:

       IF WS-CLIENTE-ANTES = WS-CLIENTE-DEPOIS
           DISPLAY "NENHUMA ALTERACAO INFORMADA"
           SET DADOS-INVALIDOS TO TRUE
       END-IF.

Isso evita apresentar:

CLIENTE ALTERADO COM SUCESSO

quando nada foi alterado.

Em sistemas corporativos, atualizações vazias também podem gerar efeitos desnecessários:

  • logs;

  • auditoria;

  • locks;

  • escrita em disco;

  • replicação;

  • triggers;

  • mensagens;

  • alteração de timestamp;

  • eventos para outros sistemas.

Uma operação tecnicamente válida pode ainda ser operacionalmente inútil.


16. Exclusão: fechar o buraco deixado na mesa

Considere:

PosiçãoCliente
1Ana
2Bruno
3Carla
4Diego

Ao excluir Bruno, a posição 2 ficaria vazia.

Para manter a tabela compacta, os registros posteriores são deslocados:

       PERFORM VARYING WS-POSICAO
           FROM WS-POSICAO-ENCONTRADA BY 1
           UNTIL WS-POSICAO >= WS-TOTAL-CLIENTES

           MOVE WS-CLIENTE(WS-POSICAO + 1)
             TO WS-CLIENTE(WS-POSICAO)
       END-PERFORM

       INITIALIZE WS-CLIENTE(WS-TOTAL-CLIENTES)
       SUBTRACT 1 FROM WS-TOTAL-CLIENTES

Depois:

PosiçãoCliente
1Ana
2Carla
3Diego
4vazia

O INITIALIZE da última posição é importante. Sem ele, uma cópia residual de Diego poderia permanecer na área livre.

A aplicação talvez não a listasse porque o contador agora seria 3, mas o dado antigo continuaria fisicamente na memória.

Essa é uma curiosidade importante:

Um registro pode deixar de existir logicamente e continuar presente fisicamente.

O mesmo princípio aparece em discos, bancos, caches, filas e arquivos temporários. “Excluir” nem sempre significa destruir imediatamente todos os bytes.



17. Exclusão física ou lógica?

Em sistemas corporativos, o cliente raramente é simplesmente apagado.

Pode haver:

  • contratos;

  • contas;

  • movimentações;

  • obrigações regulatórias;

  • auditorias;

  • investigações;

  • histórico de atendimento.

Por isso, o sistema pode usar um status:

       05 WS-STATUS PIC X.
          88 CLIENTE-ATIVO    VALUE "A".
          88 CLIENTE-INATIVO  VALUE "I".
          88 CLIENTE-BLOQUEADO VALUE "B".

Então o DELETE de negócio seria:

       SET CLIENTE-INATIVO TO TRUE

O registro continua armazenado, mas deixa de participar das operações normais.

A isso damos frequentemente o nome de exclusão lógica.

O problema é que a aplicação precisa lembrar-se de filtrar os inativos. Caso contrário, Igor “exclui” o cliente no menu, mas ele aparece novamente na listagem cinco minutos depois como um fantasma do Db2.



18. ACCEPT e DISPLAY não são CICS por encantamento

O protótipo usa:

ACCEPT
DISPLAY

Isso oferece uma interface textual, mas não comprova que o sistema seja uma transação CICS nem uma verdadeira tela 3270.

Dependendo do ambiente:

  • ACCEPT pode ler da entrada padrão;

  • DISPLAY pode escrever na saída padrão;

  • em GnuCOBOL, pode ser um terminal Windows ou Linux;

  • em batch z/OS, a entrada pode vir de SYSIN;

  • a saída pode aparecer em SYSOUT;

  • em CICS, a interação normalmente envolve EXEC CICS e mapas BMS.

Uma execução batch poderia receber:

//SYSIN DD *
1
00001
PAULO HENRIQUE
12345678909
11999990000
0
/*

Isso não representa um operador navegando por uma tela 3270. É um job consumindo dados previamente fornecidos.

Em CICS, a construção seria diferente. A aplicação normalmente envia a tela, encerra a task e volta quando o usuário responde. Esse é o modelo pseudoconversacional.

A lição é simples:

COBOL é a linguagem. z/OS é o sistema operacional. CICS é o monitor transacional. 3270 é o modelo de terminal. Eles convivem, mas não são sinônimos.



19. Memória não é persistência

Todos os clientes do protótipo vivem na WORKING-STORAGE.

Quando o programa termina, os dados desaparecem.

Isso significa que o cadastro atual oferece:

  • manipulação de registros;

  • estado durante a execução;

  • regras de validação;

  • experiência didática.

Mas ainda não oferece:

  • persistência;

  • recuperação;

  • acesso simultâneo;

  • auditoria;

  • compartilhamento;

  • backup;

  • restart;

  • histórico.

A memória é como a prancheta do atendente.

VSAM ou Db2 são o arquivo oficial da empresa.

Chuck Norris memoriza todos os clientes. O restante da equipe precisa de persistência.



20. Primeiro degrau: arquivo sequencial

Uma próxima versão poderia utilizar um arquivo:

       SELECT CLIENTES-FILE
           ASSIGN TO CLIENTES
           ORGANIZATION IS SEQUENTIAL
           FILE STATUS IS WS-FILE-STATUS.

E:

       FD CLIENTES-FILE.
       01 CLIENTES-RECORD.
          05 CLIENTE-CODIGO    PIC 9(05).
          05 CLIENTE-NOME      PIC X(40).
          05 CLIENTE-CPF       PIC X(11).
          05 CLIENTE-TELEFONE  PIC X(15).

Agora aparecem:

OPEN
READ
WRITE
CLOSE

E também:

FILE STATUS

O arquivo sequencial traz persistência, mas a atualização fica mais trabalhosa.

Para alterar um cliente:

  1. abrir o arquivo original;

  2. abrir um arquivo temporário;

  3. ler cada registro;

  4. gravar todos no temporário;

  5. quando encontrar o cliente, gravar a versão alterada;

  6. fechar os arquivos;

  7. substituir o original de maneira controlada.

É trabalhoso, mas ensina processamento batch real.



21. Segundo degrau: VSAM KSDS

Para acesso direto por código:

       SELECT CLIENTES-FILE
           ASSIGN TO CLIENTES
           ORGANIZATION IS INDEXED
           ACCESS MODE IS DYNAMIC
           RECORD KEY IS CLIENTE-CODIGO
           FILE STATUS IS WS-FILE-STATUS.

O CRUD passa a corresponder a:

OperaçãoVSAM
CriarWRITE
ConsultarREAD
AlterarREWRITE
ExcluirDELETE

Exemplo do UPDATE:

       READ CLIENTES-FILE
           KEY IS CLIENTE-CODIGO
       END-READ

       IF WS-FILE-STATUS = "00"
           MOVE WS-NOVO-NOME
             TO CLIENTE-NOME

           REWRITE CLIENTES-RECORD
           END-REWRITE

           IF WS-FILE-STATUS = "00"
               DISPLAY "CLIENTE ALTERADO"
           ELSE
               DISPLAY "ERRO NO REWRITE: "
                   WS-FILE-STATUS
           END-IF
       ELSE
           DISPLAY "CLIENTE NAO ENCONTRADO"
       END-IF.

Aqui, o FILE STATUS deixa de ser um detalhe e se torna parte da lógica.

Não basta executar REWRITE. É preciso perguntar ao sistema se ele conseguiu.



22. Terceiro degrau: Db2

No Db2:

UPDATE CLIENTE
   SET NOME     = :HV-NOME,
       CPF      = :HV-CPF,
       TELEFONE = :HV-TELEFONE
 WHERE CODIGO   = :HV-CODIGO

No COBOL:

       EXEC SQL
           UPDATE CLIENTE
              SET NOME     = :HV-NOME,
                  CPF      = :HV-CPF,
                  TELEFONE = :HV-TELEFONE
            WHERE CODIGO   = :HV-CODIGO
       END-EXEC.

Depois, o programa verifica SQLCODE:

       EVALUATE TRUE
           WHEN SQLCODE = ZERO
               EXEC SQL
                   COMMIT
               END-EXEC
               DISPLAY "CLIENTE ALTERADO"

           WHEN SQLCODE = 100
               DISPLAY "CLIENTE NAO ENCONTRADO"

           WHEN OTHER
               EXEC SQL
                   ROLLBACK
               END-EXEC
               DISPLAY "ERRO SQL: " SQLCODE
       END-EVALUATE.

Aqui aparece uma observação importante: dependendo do comando e da forma usada, “nenhuma linha atualizada” deve ser confirmado por diagnóstico apropriado, incluindo a quantidade de linhas afetadas. Não se deve imaginar que todo sucesso técnico corresponde a uma alteração de negócio.

O Db2 também introduz:

  • locks;

  • isolamento;

  • deadlock;

  • timeout;

  • integridade referencial;

  • constraints;

  • concorrência;

  • unidade de recuperação.

O protótipo pergunta:

Posso mudar este telefone?

O sistema corporativo pergunta:

Posso mudar este telefone, neste instante, sem violar regras, perder a atualização de outro usuário ou deixar metade da transação confirmada?



23. O problema dos dois operadores

Imagine dois usuários consultando o mesmo cliente:

Telefone atual: 11999990000

Operador A muda para:

11911112222

Operador B, que ainda vê a versão antiga, muda para:

11933334444

Se B gravar por último, a alteração de A poderá desaparecer.

Isso é chamado de lost update, ou atualização perdida.

A tabela em memória com um único usuário não mostra esse problema. Em um ambiente corporativo, ele precisa ser tratado por:

  • locks;

  • isolamento;

  • versionamento;

  • timestamp;

  • comparação da imagem anterior;

  • controle otimista de concorrência.

Uma estratégia seria atualizar somente se o registro ainda estiver na versão consultada:

UPDATE CLIENTE
   SET TELEFONE = :NOVO-TELEFONE,
       VERSAO   = VERSAO + 1
 WHERE CODIGO   = :CODIGO
   AND VERSAO   = :VERSAO-LIDA

Se nenhuma linha for atualizada, alguém modificou o registro antes.

Chuck Norris não sofre lost update. Quando ele altera uma linha, os outros usuários recebem um aviso antes mesmo de abrir a tela.



24. Passo a passo para construir o protótipo completo

Para um iniciante, eu seguiria esta ordem:

Passo 1 — Defina o registro

CODIGO
NOME
CPF
TELEFONE

Decida tamanhos e tipos conscientemente.

Passo 2 — Crie a tabela

OCCURS 50 TIMES

Mantenha um contador de registros ativos.

Passo 3 — Crie o menu

Use DISPLAY, ACCEPT e EVALUATE.

Passo 4 — Implemente a inclusão

Receba em área temporária, valide e somente depois grave.

Passo 5 — Centralize a pesquisa

Crie LOCALIZAR-CLIENTE e armazene a posição encontrada.

Passo 6 — Implemente consulta e listagem

Uma consulta por código e uma varredura completa.

Passo 7 — Implemente o UPDATE

Use imagens ANTES e DEPOIS, proteja a chave e peça confirmação.

Passo 8 — Implemente a exclusão

Localize, confirme, desloque os registros e diminua o contador.

Passo 9 — Trate limites e entradas inválidas

Teste tabela cheia, tabela vazia, código duplicado e cliente inexistente.

Passo 10 — Crie casos de teste

Não teste apenas o caminho feliz.



25. Roteiro de testes sob o olhar desconfiado de Chuck Norris

TesteResultado esperado
Incluir primeiro clienteTotal passa de 0 para 1
Incluir código repetidoInclusão recusada
Incluir 51º clienteLimite informado
Consultar cliente existenteDados exibidos
Consultar inexistenteMensagem controlada
Listar tabela vaziaNenhum cliente cadastrado
Alterar nomeMesma posição e mesmo código
Alterar CPF para CPF já usadoOperação recusada
Entrar no Update e não mudar nadaNenhuma alteração
Cancelar UpdateRegistro original preservado
Excluir primeiro clienteRegistros deslocados
Excluir cliente intermediárioTabela permanece compacta
Excluir último clienteÚltima posição inicializada
Cancelar exclusãoTotal e tabela permanecem iguais
Digitar opção inválidaMenu reapresentado
Encerrar e reabrirDados desaparecem na versão em memória

O último teste não é um defeito inesperado. É uma limitação conhecida da arquitetura.

Documentar limitações é uma forma de qualidade.





26. Easter eggs escondidos na WORKING-STORAGE

Easter egg 1 — O CRUD estava incompleto

O primeiro segredo estava no próprio acrônimo: faltava o U.

Easter egg 2 — Listar não cria outra letra

Consulta e listagem são duas formas de leitura. Portanto, ambas pertencem ao R.

Easter egg 3 — OCCURS 50 não significa cinquenta clientes

Significa espaço para cinquenta ocorrências. O contador informa quantas estão logicamente ocupadas.

Easter egg 4 — Excluir não apaga necessariamente os bytes

A exclusão lógica e os resíduos de memória mostram que existência física e existência de negócio são conceitos diferentes.

Easter egg 5 — O MOVE final imita um commit

As áreas ANTES e DEPOIS introduzem, em miniatura, o conceito de preparar, validar, confirmar ou abandonar uma mudança.

Easter egg 6 — O terminal pode não ser 3270

Uma tela verde não transforma automaticamente ACCEPT e DISPLAY em uma aplicação CICS.

Easter egg 7 — COBOL não significa necessariamente mainframe

COBOL pode rodar em outras plataformas. Para afirmar que é uma aplicação z/OS, é preciso demonstrar o ambiente, a compilação e a execução.

Easter egg 8 — O código mais importante pode ser o que não altera nada

A validação que impede uma operação indevida pode ser mais valiosa do que o MOVE que grava os dados.





Epílogo — O dia em que o UPDATE voltou ao menu

Ao final da revisão, o menu apareceu novamente:

1 - INCLUIR CLIENTE
2 - CONSULTAR CLIENTE
3 - LISTAR CLIENTES
4 - ALTERAR CLIENTE
5 - EXCLUIR CLIENTE
0 - SAIR

Chuck Norris examinou a WORKING-STORAGE.

Conferiu o limite de cinquenta posições.

Testou código duplicado.

Tentou atualizar um CPF já utilizado.

Pressionou Enter sem mudar nenhum campo.

Cancelou a alteração.

Excluiu o primeiro registro.

Depois encerrou o programa e confirmou que todos os clientes desapareceram, porque ainda estavam apenas na memória.

Igor respirou aliviado:

— Agora é um CRUD completo?

Chuck Norris respondeu:

— Agora ele possui as quatro operações. Completo é outra conversa.

E essa talvez seja a maior lição do projeto.

Um CRUD em memória pode ser excelente para aprender:

  • estruturação de dados;

  • lógica procedural;

  • modularização;

  • pesquisa;

  • validação;

  • estados;

  • inclusão;

  • consulta;

  • alteração;

  • exclusão.

Mas um sistema corporativo também exige:

  • persistência;

  • controle de concorrência;

  • segurança;

  • auditoria;

  • recuperação;

  • integridade;

  • testes;

  • tratamento de erros;

  • observabilidade;

  • operações transacionais.

O protótipo não precisa fingir que já é tudo isso.

Seu valor está justamente em mostrar uma evolução compreensível:

OCCURS em memória
        ↓
arquivo sequencial
        ↓
VSAM KSDS
        ↓
Db2
        ↓
CICS
        ↓
segurança, auditoria e produção

O jovem padawan que entende essa sequência deixa de ser alguém que apenas conhece comandos COBOL.

Ele começa a compreender como dados nascem, mudam, sobrevivem, desaparecem e precisam ser protegidos dentro de sistemas que não podem improvisar.

E, sob o olhar desconfiado de Chuck Norris, a regra final ficou registrada:

Um UPDATE não é apenas sobrescrever caracteres. É localizar a entidade correta, preservar sua identidade, preparar uma nova versão, validar as regras, impedir conflitos e somente então alterar o estado oficial.

Igor tentou acrescentar essa frase ao programa usando um DISPLAY.

Chuck Norris pediu que ele criasse primeiro o FILE STATUS.



sexta-feira, 28 de agosto de 2026

Westworld no CICS — Quando o Cowboy de Chapéu Preto Atravessou a Região, Igor Tentou Dar RETURN e Descobriu que o ABEND Ainda Tinha Balas

 

Bellacosa Mainframe e o westworld no CICS 

☕ Um Café no Bellacosa Mainframe

Westworld no CICS — Quando o Cowboy de Chapéu Preto Atravessou a Região, Igor Tentou Dar RETURN e Descobriu que o ABEND Ainda Tinha Balas

Ou: um jovem padawan COBOL entrou no parque de diversões do CICS, confundiu condição excepcional com fim do mundo, encontrou ASRA no saloon, AICA galopando em círculos e aprendeu que capturar o Pistoleiro não significa recuperar a transação


Prólogo — “Temos as férias perfeitas para você”

Em 1973, muito antes de alguém discutir inteligência artificial generativa no café da firma, Michael Crichton escreveu e dirigiu Westworld. O filme mostrava Delos, um parque de diversões para adultos formado por três mundos: o Velho Oeste, a Roma Antiga e a Europa medieval. Os visitantes pagavam para viver fantasias cercados por androides tão convincentes que pareciam humanos.

Tudo funcionava até deixar de funcionar.

Pequenas anomalias surgiam aqui e ali. Um robô recusava uma ordem. Uma cascavel mecânica atacava quando não deveria. Um cavaleiro ultrapassava os limites de segurança. Os técnicos percebiam que alguma coisa estava errada, mas ainda acreditavam que o problema cabia dentro dos painéis da sala de controle.

Então aparece o Pistoleiro, interpretado por Yul Brynner: roupa preta, passos metódicos, olhos artificiais e uma persistência que faria qualquer operador pedir um CEMT INQUIRE TASK. Aquilo que fora criado para perder duelos e divertir visitantes passa a perseguir Peter Martin como se tivesse recebido uma instrução impossível de cancelar.

O filme é uma metáfora quase perfeita para uma região CICS.

Delos é a região. Cada visitante é uma task. Os edifícios são recursos. Os anfitriões são programas. A sala subterrânea representa as equipes de operação. As regras do parque são as definições e controles do CICS. E o Cowboy de Chapéu Preto é o ABEND: ele pode surgir num programa profundo, atravessar níveis lógicos e continuar subindo até encontrar alguém preparado para recebê-lo.

Mas há uma diferença importante: no CICS, não basta atirar no mensageiro, apagar a mensagem da tela e dizer que o parque voltou ao normal. É preciso descobrir o que aconteceu com a unidade de trabalho, o que foi atualizado, o que precisa ser desfeito e se a transação ainda é confiável.

Bem-vindo a Westworld. Favor manter mãos, pés e COMMAREA dentro da transação.




1. Antes do tiroteio: transação, task e programa não são a mesma coisa

Para o programador COBOL iniciante, esses três conceitos às vezes parecem sinônimos. Não são.

A transação é identificada normalmente por um código de quatro caracteres, como TR01. Sua definição informa ao CICS qual programa inicial deve ser executado e contém atributos operacionais importantes.

A task é a instância daquela transação em execução. Se cinquenta usuários executarem TR01, teremos uma mesma definição de transação, mas várias tasks, cada qual com seu número, seu contexto e seus dados.

O programa é o código que executa dentro da task. Uma task pode passar por muitos programas:

TR01
  └── PROGA
        └── LINK PROGB
              └── LINK PROGC

Pense em Delos. “Westworld” é a atração anunciada no catálogo. A visita de Peter Martin é uma execução concreta. O saloon, a cadeia e o hotel são partes diferentes da experiência. Do mesmo modo, a transação é a entrada comercial; a task é a visita em andamento; e os programas são os ambientes atravessados.

Quando ocorre um ABEND, é a task que termina anormalmente. O programa que estava ativo pode ter provocado a falha, recebido a falha ou simplesmente estar no caminho dela.

Essa distinção muda o diagnóstico. Dizer “o programa caiu” é confortável, mas incompleto. O suporte precisa saber:

  • qual região CICS;

  • qual transação;

  • qual número da task;

  • qual programa estava executando;

  • qual nível lógico;

  • qual comando ou instrução falhou;

  • qual unidade de trabalho estava aberta;

  • quais recursos haviam sido alterados.

O código do ABEND é a placa pendurada no saloon. A cena do crime continua lá dentro.



2. Afinal, o que é um ABEND?

ABEND significa abnormal end, ou término anormal. Ele ocorre quando a task não pode — ou não deve — continuar seu processamento normal.

As causas incluem:

  • program check;

  • erro de lógica;

  • dado incompatível;

  • endereço de memória inválido;

  • condição excepcional CICS não tratada;

  • loop ou consumo excessivo de CPU;

  • arquivo fechado ou indisponível;

  • programa inexistente ou desabilitado;

  • falha de autorização;

  • timeout ou purge;

  • erro em comunicação;

  • EXEC CICS ABEND emitido deliberadamente pela aplicação;

  • problema de integridade em uma unidade de trabalho.

O iniciante costuma imaginar que todo ABEND é equivalente a uma explosão. Alguns são explosões. Outros são portas que a aplicação tentou abrir sem possuir a chave. Outros ainda são o próprio programa puxando o alarme porque percebeu que continuar seria perigoso.

Por isso, “eliminar todos os ABENDs” não é uma meta madura. Uma aplicação financeira pode preferir terminar anormalmente e executar backout a continuar depois de uma atualização incompleta.

O objetivo correto é:

evitar falhas previsíveis, tratar condições esperadas, preservar evidências nas falhas inesperadas e proteger a integridade dos dados.

No parque de Crichton, o problema não foi um único robô quebrar. O problema foi o sistema continuar vendendo normalidade enquanto os sinais mostravam que as garantias haviam desaparecido.



3. Condição excepcional não é automaticamente ABEND

Esta é a primeira grande curva da trilha.

Considere:

EXEC CICS READ
     FILE('CLIENTES')
     INTO(WS-CLIENTE)
     RIDFLD(WS-CHAVE)
END-EXEC.

Se a chave não existir, o CICS poderá retornar NOTFND. Isso é uma condição excepcional do comando READ, mas pode ser uma situação normal para o negócio: o usuário procurou um cliente que não está cadastrado.

O que acontecerá depende de como o programa foi preparado:

EstratégiaO que acontece
RESP e RESP2O programa recebe os códigos e decide
HANDLE CONDITIONO controle é desviado para uma rotina
IGNORE CONDITIONA ação padrão é suprimida para a condição
NOHANDLE no comandoO tratamento automático é suprimido naquele comando
Nenhuma proteçãoO CICS aplica a ação padrão, frequentemente um ABEND

Essa é a diferença entre um hóspede não encontrado no hotel e o Cowboy atravessando a recepção a tiros. Os dois são eventos fora do caminho feliz, mas não pertencem à mesma categoria.



4. RESP e RESP2: pergunte ao comando o que aconteceu

Para código COBOL estruturado, RESP e RESP2 geralmente tornam o fluxo mais claro:

01  WS-RESP   PIC S9(8) COMP VALUE ZERO.
01  WS-RESP2  PIC S9(8) COMP VALUE ZERO.

EXEC CICS READ
     FILE('CLIENTES')
     INTO(WS-CLIENTE)
     RIDFLD(WS-CHAVE)
     RESP(WS-RESP)
     RESP2(WS-RESP2)
END-EXEC

EVALUATE WS-RESP
    WHEN DFHRESP(NORMAL)
         PERFORM PROCESSAR-CLIENTE

    WHEN DFHRESP(NOTFND)
         PERFORM INFORMAR-CLIENTE-INEXISTENTE

    WHEN DFHRESP(NOTOPEN)
         PERFORM REGISTRAR-ERRO-TECNICO
         PERFORM ABORTAR-OPERACAO

    WHEN OTHER
         PERFORM REGISTRAR-RESPOSTA-INESPERADA
         PERFORM ABORTAR-OPERACAO
END-EVALUATE.

RESP fornece a condição principal. RESP2 oferece detalhe adicional cujo significado depende do comando e da resposta. Portanto, não existe um dicionário universal de RESP2: é preciso consultar a documentação do comando específico.

Também é preferível comparar com DFHRESP(NORMAL), DFHRESP(NOTFND) e outras constantes simbólicas, em vez de espalhar números mágicos pelo fonte. Daqui a dois anos, ninguém deveria precisar perguntar por que Igor escreveu IF WS-RESP = 13.

Dica de produção

Inicialize as variáveis, teste a resposta imediatamente depois do comando e preserve o contexto antes de executar outras operações CICS. O último comando pode alterar campos do EIB e deixar a equipe investigando o mensageiro em vez do atirador.



5. HANDLE CONDITION: coloque um xerife na esquina

HANDLE CONDITION associa condições CICS a rótulos:

EXEC CICS HANDLE CONDITION
     NOTFND(SEM-CLIENTE)
     NOTOPEN(ARQUIVO-FECHADO)
     IOERR(ERRO-DE-IO)
END-EXEC.

Quando uma dessas condições surgir em comando sujeito ao mecanismo, o controle poderá saltar para a rotina indicada.

É útil, especialmente em programas antigos ou em fluxos bem delimitados, mas exige cuidado. O tratamento fica ativo no nível lógico e pode capturar uma condição gerada longe do ponto onde foi declarado. Em um fonte grande, isso cria um roteiro de faroeste no qual o espectador precisa rever quarenta minutos para descobrir por que alguém entrou pela janela.

Para iniciantes, uma regra prática:

  • use RESP quando a decisão pertence à operação específica;

  • use HANDLE CONDITION quando um desvio controlado realmente melhora o desenho;

  • não misture estilos sem entender precedência e escopo;

  • nunca continue usando uma área de dados quando o comando que deveria preenchê-la falhou.



6. NOHANDLE: retirar o alarme não apaga a fumaça

NOHANDLE impede que os mecanismos automáticos de tratamento sejam aplicados àquele comando:

EXEC CICS READ
     FILE('CLIENTES')
     INTO(WS-CLIENTE)
     RIDFLD(WS-CHAVE)
     NOHANDLE
END-EXEC.

Isso não significa “ignore o erro e considere sucesso”.

Se a leitura falhar e o programa prosseguir:

PERFORM CALCULAR-LIMITE.

WS-CLIENTE pode conter zeros, dados antigos ou conteúdo inconsistente. O erro original era um NOTFND; o erro seguinte pode virar ASRA, cálculo incorreto ou, pior, uma decisão financeira válida sobre o cliente errado.

NOHANDLE sem verificação é Igor cobrindo os olhos do androide e anunciando que o Pistoleiro não consegue mais enxergá-lo.



7. HANDLE ABEND: a última barreira do parque

HANDLE ABEND instala uma saída de ABEND no nível lógico do programa:

EXEC CICS HANDLE ABEND
     PROGRAM('ERRPGM')
END-EXEC.

Em contextos compatíveis, também pode apontar para um rótulo:

EXEC CICS HANDLE ABEND
     LABEL(ROT-ABEND)
END-EXEC.

Ele não deve substituir o tratamento de condições previsíveis. Seu papel é receber falhas anormais, preservar informações e conduzir uma terminação ou recuperação controlada.

Imagine:

PROGA — saída A ativa
  └── LINK PROGB — saída B ativa
        └── LINK PROGC — nenhum handler
              └── ASRA

O CICS procura uma saída no nível atual. Não encontrando, sobe pelos níveis lógicos até localizar uma saída ativa. Se não houver nenhuma, a task termina anormalmente.

Existe apenas uma saída ativa por nível lógico. Declarar outra nesse mesmo nível desativa a anterior. Quando a saída recebe controle, o CICS a desativa antes de executar seu código, evitando reentrada infinita caso o próprio handler falhe.

É o Cowboy de Chapéu Preto atravessando Westworld, Medievalworld e Romanworld. Ele só para quando encontra alguém preparado — ou quando não resta mais parque.



8. CANCEL versus CANCEL: duas placas iguais em portas diferentes

O material que iniciou nossa conversa colocava “CANCEL versus HANDLE ABEND”, mas essa comparação pode induzir o iniciante ao erro.

EXEC CICS HANDLE ABEND
     CANCEL
END-EXEC.

Esse comando desativa a saída de ABEND do nível lógico atual. Ele não ordena, por si só, o encerramento imediato da task.

Já:

EXEC CICS ABEND
     CANCEL
END-EXEC.

é outra operação: cancela as saídas de ABEND em todos os níveis e força o término anormal.

ComandoSignificado
HANDLE ABEND PROGRAM(...)Ativa programa de tratamento
HANDLE ABEND LABEL(...)Ativa rotina local
HANDLE ABEND CANCELDesativa a saída do nível atual
HANDLE ABEND RESETReativa a saída após ela ter recebido controle
ABEND ABCODE('E001')Provoca ABEND definido pela aplicação
ABEND CANCELIgnora todas as saídas e termina a task

No CICS, contexto é munição. A mesma palavra, colocada em outro comando, produz outro resultado.



9. O erro mais perigoso: capturar o ABEND e dar RETURN

Chegamos à cena central.

Suponha uma transferência:

1. Debitar conta A
2. Creditar conta B
3. Gravar histórico
4. Enviar confirmação

O débito é realizado. Antes do crédito, o programa sofre ASRA. O handler registra “erro tratado” e executa:

EXEC CICS RETURN
END-EXEC.

Parece elegante. Não é.

Quando uma saída de ABEND termina com RETURN, o CICS pode devolver controle ao nível lógico superior como se o programa inferior tivesse retornado normalmente. Se a transação atualizou recursos recuperáveis e dependia do ABEND para provocar backout, o backout não ocorre; as alterações podem ser confirmadas.

Assim, uma rotina criada para proteger a aplicação pode transformar:

falha detectável + backout

em:

falha escondida + commit parcial

A própria IBM adverte que, quando é necessário preservar a integridade de recursos recuperáveis, a saída deve terminar com ABEND, não simplesmente retornar. Consulte How it works: Abend exit code.

Um desenho prudente:

ERRPGM-MAIN.

    PERFORM CAPTURAR-CONTEXTO
    PERFORM GRAVAR-LOG-SANITIZADO
    PERFORM NOTIFICAR-OPERACAO

    EXEC CICS ABEND
         ABCODE('E001')
    END-EXEC.

O handler pode registrar e notificar. Mas, se a unidade de trabalho precisa ser desfeita, deve permitir ou provocar o término anormal adequado.

Matar o alarme não mata o Cowboy.



10. Backout, commit e unidade de trabalho

Uma Unit of Work agrupa alterações que devem ser tratadas como uma unidade coerente.

UPDATE VSAM
   +
UPDATE Db2
   +
mensagem persistente
   =
trabalho ainda não confirmado

Quando ocorre um syncpoint bem-sucedido, as alterações recuperáveis são confirmadas. Quando uma task termina anormalmente em condições apropriadas, o CICS pode executar dynamic transaction backout.

Mas nem tudo é automaticamente recuperável:

  • um arquivo precisa estar definido e operado como recurso recuperável;

  • integrações externas podem não participar do mesmo escopo transacional;

  • uma chamada HTTP pode ter sido processada embora a resposta tenha se perdido;

  • uma mensagem pode pertencer a outra unidade de trabalho;

  • efeitos fora do CICS podem exigir compensação;

  • uma UOW distribuída pode ficar in-doubt.

Por isso, “deu ABEND, então tudo voltou” é uma crença perigosa.

Antes de repetir a transação, confirme:

  1. Houve backout?

  2. Algum syncpoint ocorreu antes da falha?

  3. O Db2 confirmou alterações?

  4. A mensagem MQ foi publicada?

  5. O sistema remoto recebeu a solicitação?

  6. Existe chave de idempotência?

  7. A primeira tentativa pode ter terminado com sucesso apesar da resposta perdida?

Retry sem conhecer o estado anterior é o equivalente operacional de colocar dois Pistoleiros no parque para resolver o problema do primeiro.



11. ASRA — o anfitrião perdeu o controle do próprio corpo

ASRA indica que a task terminou por causa de um program check.

Possíveis causas:

  • dado não numérico em operação decimal;

  • subscrito fora dos limites;

  • referência inválida à memória;

  • endereço corrompido;

  • storage já liberado;

  • incompatibilidade de parâmetros entre chamador e chamado;

  • copybooks divergentes;

  • comprimento incorreto;

  • corrupção de storage ocorrida antes;

  • erro em COBOL, PL/I, assembler ou componente chamado.

ASRA não é a causa-raiz; é a categoria. A investigação precisa localizar:

  • programa;

  • offset;

  • statement correspondente no compile listing;

  • PSW;

  • registradores;

  • traceback do Language Environment;

  • áreas de dados envolvidas;

  • versão exata do módulo carregado;

  • cadeia de LINK, XCTL ou chamadas.

Se o load module em execução não corresponde ao listing usado na investigação, o offset pode levar a uma linha inocente. É como analisar o mapa de Westworld da semana passada depois que alguém mudou o saloon de lugar.

A definição oficial pode ser consultada em IBM — ASRA.



12. AICA — o Cowboy que galopa em círculos

AICA indica uma possível runaway task: a task consumiu tempo de execução além do limite considerado aceitável.

Exemplo:

PERFORM UNTIL WS-FIM = 'S'
    ADD 1 TO WS-CONTADOR
END-PERFORM.

Se WS-FIM nunca mudar, temos um loop clássico.

Mas AICA não prova automaticamente “loop infinito”. Também pode sinalizar:

  • processamento legítimo grande demais para uma transação online;

  • algoritmo ineficiente;

  • ausência de pontos de suspensão;

  • volume anormal;

  • configuração inadequada do intervalo de runaway;

  • rotina batch colocada dentro do CICS;

  • instrumentação alterando o tempo;

  • laço que deveria avançar um cursor, mas não avança.

O CICS consegue detectar determinados loops comparando a execução com o intervalo configurado. Algumas chamadas que suspendem a task podem alterar esse comportamento. A investigação oficial está em IBM — AICA.

O conserto não é simplesmente aumentar o timeout. Primeiro determine se o trabalho pertence ao ambiente online, se pode ser paginado, dividido, agendado ou redesenhado.

Dar mais tempo a um loop infinito apenas permite que o Cowboy cavalgue mais longe.



13. AEI9 — a pista errada do infográfico

Aqui existe uma correção objetiva e importante.

O infográfico original apresentou AEI9 como algo relacionado a comando ou parâmetro inválido. AEI9 corresponde a MAPFAIL.

MAPFAIL costuma aparecer no BMS quando:

  • nenhum dado utilizável foi transmitido;

  • o usuário acionou uma tecla sem modificar campos;

  • a entrada chegou sem o formato esperado;

  • o programa esperava dados mapeados, mas recebeu entrada não formatada.

INVREQ, condição associada a requisição inválida, aparece como AEIP nessa família. AEIS corresponde a NOTOPEN.

CódigoCondição
AEI9MAPFAIL
AEIPINVREQ
AEISNOTOPEN
AEIMNOTFND
AEI0PGMIDERR

Essa diferença não é preciosismo. Se o operador procura parâmetro inválido diante de AEI9, perderá tempo examinando o comando errado quando deveria investigar entrada de terminal e BMS. Veja IBM — MAPFAIL.



14. EIB: o bolso do casaco do visitante

O EXEC Interface Block contém informações sobre o contexto da task:

  • EIBTRNID: identificador da transação;

  • EIBTASKN: número da task;

  • EIBTRMID: terminal;

  • EIBDATE e EIBTIME: data e hora;

  • EIBFN: função do último comando;

  • EIBRESP: resposta principal;

  • EIBRESP2: resposta secundária;

  • EIBCALEN: tamanho da COMMAREA recebida;

  • EIBAID: tecla de atenção recebida.

O detalhe crítico é “último comando”. Se o programa de erro executar vários comandos antes de preservar o EIB, poderá sobrescrever a evidência original.

MOVE EIBTRNID TO LOG-TRANSACAO
MOVE EIBTASKN TO LOG-TASK
MOVE EIBTRMID TO LOG-TERMINAL
MOVE EIBFN    TO LOG-FUNCAO
MOVE EIBRESP  TO LOG-RESP
MOVE EIBRESP2 TO LOG-RESP2.

Faça a captura cedo. Depois sanitize e registre.

Também não grave indiscriminadamente senhas, tokens, PINs, CVV, chaves, documentos completos ou COMMAREAs inteiras. Um log excelente para diagnóstico pode ser excelente também para um invasor.



15. Passo a passo do suporte de produção

Passo 1 — Identifique a visita

Colete região, transação, task, usuário, terminal ou canal, horário e correlation ID.

Passo 2 — Leia as mensagens associadas

O código de ABEND sozinho não conta a história. Procure mensagens DFH, logs da região, JES, Language Environment, Db2, MQ e demais componentes relacionados.

Passo 3 — Preserve dump e trace

Não suprima dumps por reflexo. Dump é caro quando existe em excesso, mas ausência de evidência também custa. A política deve equilibrar diagnóstico, volume, privacidade e recorrência.

Passo 4 — Classifique

É program check, runaway, condição EXEC não tratada, autorização, indisponibilidade, purge, timeout, falha distribuída ou ABEND criado pela aplicação?

Passo 5 — Localize o ponto

Para condição CICS, identifique comando, RESP, RESP2, parâmetros e recurso.

Para ASRA, use dump, offset, listing, PSW, registradores e traceback.

Passo 6 — Descubra o que mudou

  • deploy recente;

  • copybook alterado;

  • módulo sem NEWCOPY ou PHASEIN adequado;

  • definição de arquivo;

  • mudança RACF;

  • mapa BMS regenerado;

  • aumento de volume;

  • alteração no programa chamador;

  • erro restrito a uma região ou registro.

Passo 7 — Verifique integridade

Determine commit, backout, syncpoints, mensagens enviadas e efeitos externos.

Passo 8 — Só então decida

Corrigir, recuperar, compensar, reiniciar, repetir de modo idempotente ou escalar.



16. CEDF: visitar o parque com as luzes acesas

CEDF ajuda a observar interativamente o fluxo de comandos CICS. Ele pode mostrar entrada e saída de comandos, condições, opções e sequência de execução.

Mas não é máquina do tempo.

CEDF:

  • ajuda a reproduzir;

  • revela o fluxo;

  • permite examinar comandos;

  • não substitui dump;

  • pode alterar timing;

  • pode esconder problemas concorrentes;

  • exige extremo cuidado em produção.

A combinação forte é:

CEDF para compreender
+ dump para congelar a falha
+ trace para reconstruir a sequência
+ logs para correlacionar componentes
+ listing para localizar a instrução

Observar o Pistoleiro em câmera lenta ajuda. Ainda precisamos saber quem liberou a arma, qual trava falhou e se a sala de controle perdeu energia.



17. Curiosidades escondidas no parque

Easter egg 1 — o Pistoleiro já havia cavalgado antes

O visual de Yul Brynner em Westworld foi construído para lembrar Chris Adams, personagem interpretado por ele em The Magnificent SevenSete Homens e um Destino. Roupa escura, postura e presença criam uma referência cinematográfica deliberada. O robô parece uma cópia de outro cowboy, quase como um módulo recompilado a partir de um fonte antigo.

Easter egg 2 — visão digital antes de CGI virar rotina

O filme foi pioneiro no uso de processamento digital de imagem em longa-metragem para simular a visão pixelada do Pistoleiro. Décadas antes de dashboards coloridos e observabilidade distribuída, Crichton já nos colocava dentro do “sensor” da máquina.

Easter egg 3 — três mundos, três ambientes

Romanworld, Medievalworld e Westworld parecem ambientes separados, mas os defeitos atravessam fronteiras. É uma boa lembrança de que regiões, serviços e plataformas isolados no organograma podem compartilhar dependências invisíveis.

Easter egg 4 — Crichton repetiria a pergunta

Anos depois, Jurassic Park retomaria a ideia de uma atração tecnológica complexa, vendida como controlável, cuja segurança dependia de camadas frágeis e excesso de confiança corporativa.

Easter egg 5 — a frase de marketing

O slogan de Delos prometia férias extraordinárias. Depois do desastre, a promessa volta com ironia. Em TI, o equivalente é o slide que anuncia “zero incidentes” antes de a primeira evidência chegar ao console.

Informações históricas do filme podem ser consultadas na página oficial de Michael Crichton e no relato técnico da American Society of Cinematographers.



18. O mapa de decisão do jovem padawan

Quando um comando CICS não retorna NORMAL, pergunte:

  1. A condição é esperada pelo negócio?

  2. Ela pertence ao comando atual?

  3. Posso tratá-la localmente com RESP?

  4. Alguma área de dados deixou de ser preenchida?

  5. É seguro continuar?

  6. Houve atualização recuperável?

  7. Preciso provocar backout?

  8. Existe efeito fora da unidade de trabalho?

  9. Preciso de dump?

  10. Tenho evidência suficiente antes de emitir outro comando?

Quando ocorre ABEND:

  1. Preserve o código original.

  2. Capture o contexto.

  3. Não mascare falha de integridade.

  4. Não execute RETURN por hábito.

  5. Não repita a transação cegamente.

  6. Não confunda o código com a causa-raiz.

  7. Confirme o estado da UOW.

  8. Diferencie recuperação técnica de recuperação do negócio.



Epílogo — O Cowboy fecha o chamado?

No início de Westworld, os visitantes acreditam que o parque é seguro porque os androides foram programados para obedecer. A confiança nasce da regra escrita, não da evidência operacional.

No CICS, acontece algo parecido. O programa foi testado. O arquivo é recuperável. O handler existe. O log foi criado. A mensagem “erro tratado” apareceu. Tudo isso ajuda, mas nada disso prova que a transação terminou de forma íntegra.

HANDLE ABEND não é um colete à prova de balas. É uma saída program-level que oferece à aplicação uma última oportunidade de decidir o que fazer diante do término anormal.

Às vezes, a decisão será limpar recursos e continuar em um nível superior.

Às vezes, será converter uma falha técnica em resposta controlada.

Às vezes, será registrar o contexto e emitir outro ABEND para garantir o backout.

E muitas vezes, o ato mais profissional será admitir que o estado não é confiável e impedir que a task confirme uma meia verdade.

O programador iniciante aprende sintaxe:

EXEC CICS HANDLE ABEND
     PROGRAM('ERRPGM')
END-EXEC.

O profissional aprende responsabilidade:

Capturar uma falha não significa recuperar o negócio; remover o alarme não restaura a integridade; e nenhum RETURN deve atravessar a porta antes que alguém confira o que aconteceu com o commit e o backout.

Na última cena, o parque permanece silencioso. A sala de controle já não controla nada. Peter Martin sobrevive, mas olha ao redor sem saber exatamente onde terminou a fantasia e começou a falha.

No console do CICS, o Cowboy de Chapéu Preto deixa sua última mensagem:

ABEND CODE IS NOT ROOT CAUSE

Igor olha para o dump, tira lentamente o dedo do CANCEL e finalmente chama o programador que guardou o compile listing correto.

O boteco pode reabrir.

Mas somente depois do backout.



Referências essenciais



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