| Bellacosa Mainframe e as tabelas internas no COBOL occurs e arrays |
☕💥 Arrays em COBOL: O Poder Oculto do OCCURS, SSRANGE e a Guerra Contra a Invasão de Memória
Ou como evitar transformar seu Address Space em um filme de terror para Sysprogs
Introdução
Existe um momento na vida de todo desenvolvedor COBOL júnior em que ele descobre duas verdades universais:
A primeira é que OCCURS parece simples até deixar de ser simples.
A segunda é que existe uma entidade maligna chamada:
SSRANGE
capaz de transformar uma manhã tranquila em uma reunião emergencial envolvendo desenvolvimento, suporte, infraestrutura, DBA, operador e um sysprog segurando uma caneca de café já fria.
E tudo isso por causa de um pequeno detalhe:
MOVE WS-NOME(9999)
quando a tabela possui apenas:
OCCURS 100 TIMES.
Bem-vindo ao fascinante mundo das tabelas COBOL.
Capítulo 1 – O que é OCCURS?
OCCURS é o mecanismo utilizado pelo COBOL para criar estruturas repetitivas.
Em linguagens modernas chamaríamos isso de:
Array
Vetor
Lista fixa
Matriz
Exemplo:
01 CLIENTES.
05 CLIENTE OCCURS 10 TIMES.
10 NOME PIC X(30).
10 IDADE PIC 99.
Memória:
CLIENTE(1)
CLIENTE(2)
CLIENTE(3)
...
CLIENTE(10)
COBOL simplesmente reserva um bloco contínuo.
A origem histórica
Década de 60.
Memória era absurdamente cara.
IBM 1401
4 KB
IBM System/360
256 KB
370
1 MB
Não existia:
Java Collections
Python List
C++ Vector
Era necessário reservar memória antecipadamente.
Daí nasceu:
OCCURS
Curiosidade histórica
Os engenheiros da IBM chamavam essas estruturas de:
Table Handling
Muito antes da expressão Array Processing se popularizar.
Capítulo 2 — Como a memória é organizada
Exemplo:
01 TAB.
05 ITEM OCCURS 5 TIMES.
10 CODIGO PIC 9(5).
Cada item ocupa:
5 bytes
Total
25 bytes
Layout:
0000 ITEM(1)
0005 ITEM(2)
0010 ITEM(3)
0015 ITEM(4)
0020 ITEM(5)
Acesso:
MOVE ITEM(3) TO WS-X
COBOL faz:
Base + ((3-1)*5)
Capítulo 3 – O Terror do Out of Bounds
Tabela:
05 CLIENTE OCCURS 100 TIMES.
Código:
MOVE NOME(101)
Problema.
A posição não existe.
Antigamente
Compilador:
NOSSRANGE
Padrão.
Nenhuma verificação.
Resultado:
Leitura aleatória.
Sobrescrever memória.
Corrupção.
O verdadeiro vilão
Imagine:
01 TABELA.
05 DADOS OCCURS 100 TIMES.
05 FLAG-FINAL PIC X.
Erro:
MOVE "S" TO DADOS(101)
Na prática:
FLAG-FINAL = S
ou pior.
Modifica outra estrutura.
Isso é invasão de memória?
Sim.
Tecnicamente:
Buffer overflow
Memory overwrite
Storage corruption
Capítulo 4 — Address Space
No zOS cada Job possui.
Address Space.
Exemplo
JOB1234
Private Area
LSQA
SWA
Subpools
Heap
Stack
Seu programa COBOL vive ali.
Se escrever fora da tabela:
pode corromper:
Working Storage
Heap
LE Runtime
Control Blocks
Em casos extremos:
S0C4
S878
U4038
Capítulo 5 — SSRANGE
A melhor invenção desde o café expresso.
Compilação:
SSRANGE
ou
CBL SSRANGE
Exemplo
MOVE WS-NOME(101)
Resultado:
Abend imediato.
Mensagem:
IGZxxxx
Subscript out of range
Excelente para:
Homologação
Teste
QA
Produção?
Normalmente:
NOSSRANGE
Performance melhor.
Dica Bellacosa
Desenvolvimento
SSRANGE
Produção
NOSSRANGE
Capítulo 6 — Índices
Ruim:
77 WS-I PIC 999.
Melhor:
05 CLIENTE OCCURS 100 TIMES
INDEXED BY IDX.
SET
SET IDX TO 1
Próximo
SET IDX UP BY 1
Anterior
SET IDX DOWN BY 1
Por que índice é melhor?
Subscript:
CLIENTE(I)
Cálculo toda vez.
Index
Endereço pronto.
Ponteiro interno.
Mais rápido.
Capítulo 7 – Navegação
Crescente
SET IDX TO 1
PERFORM UNTIL IDX > MAX
PROCESSA
SET IDX UP BY 1
END-PERFORM
Decrescente
SET IDX TO MAX
PERFORM UNTIL IDX = 0
PROCESSA
SET IDX DOWN BY 1
END-PERFORM
Muito usado em:
Compressão
Ordenação
Rollback
Capítulo 8 — SEARCH
Busca sequencial.
SEARCH CLIENTE
AT END
DISPLAY "NAO ACHOU"
WHEN ID = WS-ID
DISPLAY NOME
END-SEARCH
Complexidade
O(n)
100 mil registros.
50 mil leituras médias.
SEARCH ALL
Arma secreta.
Busca binária.
Tabela obrigatoriamente ordenada.
SEARCH ALL CLIENTE
WHEN ID(IDX)=WS-ID
DISPLAY "ACHOU"
END-SEARCH
Complexidade
O(log n)
1000000 itens.
Comparações:
~20
Magia matemática.
Capítulo 9 — OCCURS DEPENDING ON
Tabela variável.
05 QTDE PIC 9(4).
05 CLIENTE OCCURS 1 TO 1000 TIMES
DEPENDING ON QTDE.
Muito usado em:
MQ
Copybooks
APIs
Arquivos
Capítulo 10 — Bidimensional
Exemplo.
Agência x Dia
05 MOVIMENTO.
10 AG OCCURS 100.
15 DIA OCCURS 31.
20 TOTAL PIC 9(10).
Uso:
TOTAL(10,15)
Agência 10.
Dia 15.
Tridimensional
ANO
MES
DIA
VENDAS(2026,6,23)
N dimensões
Teoricamente ilimitado.
Exemplo.
Banco.
País
Estado
Agência
Conta
Produto
Dia
Capítulo 11 — Ordenação
Tabela ordenada.
ASCENDING KEY
Muito útil para:
SEARCH ALL
Caches
Lookup
Capítulo 12 – Quando usar tabela
Excelente:
Parâmetros
Cache
Código UF
Tabela IR
CEP
Conversões
Ruim:
Milhões registros.
Melhor:
DB2
VSAM
IMS
Capítulo 13 – Performance
SEARCH
O(n)
SEARCH ALL
O(log n)
Index
Muito rápido
Subscript
Mais lento
SSRANGE
Seguro
NOSSRANGE
Rápido
Easter Egg COBOL
Existe uma lenda entre veteranos de mainframe.
Diz-se que em algum datacenter esquecido dos anos 80 existe um programa COBOL compilado com:
NOSSRANGE
OPT(2)
FASTSRT
ARITH(EXTEND)
executando desde 1987.
Ninguém sabe exatamente o que ele faz.
Ninguém possui o código-fonte.
Ninguém ousa recompilar.
Mas toda madrugada, às 02h17, ele produz um relatório financeiro perfeito, movimenta bilhões de dólares e desaparece novamente nas profundezas do JES2.
Os sysprogs apenas observam o spool, tomam um gole de café e repetem o antigo mantra do reino z/OS:
"Se está funcionando há 39 anos, não toque."
Conclusão
OCCURS é muito mais do que um simples array.
É uma das construções mais antigas, elegantes e eficientes já criadas para processamento em lote de grande volume.
Dominar:
OCCURS
INDEXED BY
SET
SEARCH
SEARCH ALL
SSRANGE
OCCURS DEPENDING ON
Tabelas multidimensionais
Navegação UP e DOWN
Layout de memória
Address Space do z/OS
é um dos marcos que separam o Padawan COBOL do Cavaleiro do Batch Jedi Council.
Porque no universo do Mainframe existe uma verdade absoluta:
"DB2 pode falhar, CICS pode reciclar, VSAM pode corromper, mas um OCCURS acessado fora dos limites sempre encontrará uma maneira criativa de arruinar o dia de alguém."
Sem comentários:
Enviar um comentário