Translate

Mostrar mensagens com a etiqueta b-tree. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta b-tree. Mostrar todas as mensagens

quarta-feira, 25 de outubro de 2023

COBOL Recursivo sem Mistérios

 

Bellacosa Mainframe dicas e pratica em cobol mainframe recursivo

☕ Um Café no Bellacosa Mainframe

COBOL Recursivo sem Mistérios

Como Programar Funções Recursivas e Percorrer Árvores B como um Oficial da Frota Estelar

"A maioria dos programadores COBOL passa décadas escrevendo programas sem nunca utilizar recursividade. Não porque ela não exista. Mas porque o universo do processamento batch sempre favoreceu algoritmos iterativos. Entretanto, quando você entra no mundo de compiladores, parsers, XML, JSON, árvores de decisão, estruturas hierárquicas e inteligência artificial, descobrirá que existe uma arma secreta escondida dentro do Enterprise COBOL."

Prepare seu café.

Hoje o Capitão Kirk autorizou acesso aos bancos de dados mais profundos da USS Enterprise.

Vamos explorar uma tecnologia que muitos acreditam que COBOL "não possui".

Possui.

E muito bem.


O mito

Existe uma frase repetida há décadas:

"COBOL não suporta recursividade."

Isso era verdade...

...há muitos anos.

Desde o Enterprise COBOL moderno, programas podem chamar a si próprios.

Basta utilizar as opções corretas do compilador.

E entender o que realmente acontece na memória.


O que é recursividade?

Recursividade é quando um programa chama...

...ele mesmo.

Exemplo extremamente simples.

Imagine contar regressivamente.

5
4
3
2
1
Fim

Ao invés de fazer:

PERFORM VARYING

fazemos

CONTAR(5)

↓

CONTAR(4)

↓

CONTAR(3)

↓

CONTAR(2)

↓

CONTAR(1)

Cada chamada cria uma nova execução independente.


Pensando como Spock

Spock não resolveria um problema inteiro.

Ele dividiria.

Sempre.

Existe solução?

↓

Resolva um pedaço

↓

O restante é igual

↓

Chame novamente

Isso é exatamente recursividade.


Como o COBOL consegue fazer isso?

Cada chamada cria uma nova área de trabalho.

Ela contém:

  • variáveis locais

  • parâmetros

  • ponteiros

  • retorno

Tudo fica armazenado na pilha (Stack).

Visualmente.

MAIN

↓

PROGRAMA

↓

PROGRAMA

↓

PROGRAMA

↓

PROGRAMA

Cada nível ocupa memória.


Por isso existe um risco

Se esquecer a condição de parada...

Programa

↓

Programa

↓

Programa

↓

Programa

↓

Programa

↓

Programa

↓

Programa

Nunca termina.

Resultado:

Stack Overflow

Ou

S878

S80A

Storage Exhausted

Dependendo do ambiente.


A regra número 1

Toda função recursiva precisa possuir uma condição de parada.

Sempre.

Exemplo.

IF N = ZERO
    EXIT
END-IF

Sem isso...

adeus memória.


Ativando recursividade

No Enterprise COBOL normalmente utiliza-se

RECURSIVE

na identificação do programa.

IDENTIFICATION DIVISION.

PROGRAM-ID. TREESEARCH
    RECURSIVE.

ou opção equivalente do compilador dependendo da versão.

Outra prática comum é utilizar:

RENT

para permitir reentrância.


Reentrante x Recursivo

São conceitos diferentes.

Reentrante

→ vários usuários usam ao mesmo tempo.

Recursivo

→ o programa chama ele próprio.

Pode existir:

✔ Reentrante

sem ser

✔ Recursivo.


Quando utilizar?

Quando o problema possui natureza hierárquica.

Por exemplo.

Árvore.

XML.

JSON.

AST de compilador.

Pastas.

Menus.

Dependências.

Organogramas.

Genealogia.

Árvore de chamadas.


Imagine uma árvore B

Uma árvore B organiza registros.

             40

      20            60

   10   30      50     70

Encontrar um valor nela é extremamente elegante usando recursividade.


Estrutura lógica

Cada nó possui

Valor

Filho esquerdo

Filho direito

No COBOL real normalmente usamos tabelas e índices.

Exemplo didático.

NODE-ID

LEFT-CHILD

RIGHT-CHILD

Nossa missão

Encontrar

50

Algoritmo

Primeiro olhamos

40

50 é maior.

Então ignoramos todo lado esquerdo.

Seguimos para direita.

60

Agora

50 é menor.

Voltamos para esquerda.

Encontramos

50

Fim.


Em pseudocódigo

SEARCH(NODE)

IF NODE = NULL
    NÃO EXISTE

IF NODE = CHAVE
    ENCONTROU

SE CHAVE < NODE
    SEARCH(LEFT)

SENÃO
    SEARCH(RIGHT)

Perceba.

O algoritmo inteiro possui poucas linhas.

Porque ele reutiliza a própria lógica.


Exemplo COBOL simplificado

IDENTIFICATION DIVISION.
PROGRAM-ID. TREESEARCH RECURSIVE.

WORKING-STORAGE SECTION.

01 WS-KEY          PIC 9(4).

LINKAGE SECTION.

01 LK-NODE.
   05 LK-VALUE     PIC 9(4).
   05 LK-LEFT      POINTER.
   05 LK-RIGHT     POINTER.

PROCEDURE DIVISION USING LK-NODE.

    IF LK-NODE = NULL
        GOBACK
    END-IF

    IF WS-KEY = LK-VALUE
        DISPLAY "ENCONTRADO"
        GOBACK
    END-IF

    IF WS-KEY < LK-VALUE
        CALL "TREESEARCH"
             USING LK-LEFT
    ELSE
        CALL "TREESEARCH"
             USING LK-RIGHT
    END-IF.

    GOBACK.

Este exemplo é conceitual. Em aplicações reais, árvores costumam ser representadas por tabelas indexadas, estruturas dinâmicas com ALLOCATE/FREE (quando suportado) ou áreas obtidas por serviços do sistema.


Observe a mágica

O programa nunca pergunta

Estou no nível 2?

Estou no nível 5?

Estou no nível 30?

Ele simplesmente chama ele mesmo.


Visualizando a pilha

SEARCH(40)

↓

SEARCH(60)

↓

SEARCH(50)

↓

Encontrado

Depois começa retornar.

SEARCH(50)

↓

SEARCH(60)

↓

SEARCH(40)

↓

MAIN

É literalmente uma subida e descida.


O retorno automático

Cada chamada lembra onde parou.

Imagine.

A chama B

↓

B chama C

↓

C chama D

Quando D termina.

Volta para C.

Depois B.

Depois A.

Sem que você precise controlar isso.


Onde COBOL utiliza isso na prática?

Mais do que muitos imaginam.

Ferramentas IBM fazem uso intenso.

Compiladores COBOL.

Parser SQL.

Parser XML.

JSON Parser.

XPath.

XSD.

Analisadores sintáticos.

Motores de regras.


Árvore B em bancos

Db2 utiliza árvores B (B-Trees).

Quando fazemos

SELECT

WHERE CPF

O banco NÃO lê milhões de registros.

Ele navega pela árvore.

Raiz

↓

Nó

↓

Folha

Pouquíssimos acessos.


Curiosidade

Quando você cria

CREATE INDEX

Na prática.

Está construindo uma enorme árvore balanceada.


Então...

Todo programador COBOL usa árvore B.

Mesmo sem perceber.


Mas...

Devemos escrever árvore recursiva sempre?

Não.

Existe um preço.


CPU

Cada chamada possui custo.

Salvar registradores

↓

Criar stack frame

↓

Passar parâmetros

↓

Retornar

Tudo isso consome CPU.


Memória

Cada chamada cria.

Variáveis

Endereço retorno

Parâmetros

Estado

Imagine 100.000 níveis.

Pode explodir.


Comparando

Iterativo

WHILE

Consome

CPU menor

Memória fixa

Recursivo

CPU maior

Stack crescente

Então por que usar?

Porque alguns problemas ficam absurdamente mais simples.

Exemplo.

Árvore.

Iterativo

300 linhas

Recursivo

40 linhas

Mais fácil.

Mais elegante.

Menos bugs.


Quando evitar?

Processamento sequencial.

Leitura VSAM.

Arquivo QSAM.

Loops simples.

Relatórios.

Batch tradicional.

Nestes casos.

PERFORM VARYING

vence.


Tail Recursion

Existe uma otimização famosa.

Tail Recursion.

Função termina chamando ela mesma.

Alguns compiladores eliminam o crescimento da pilha.

Infelizmente.

Nem todo compilador COBOL faz isso.

Portanto.

Nunca conte com essa otimização.


Cuidado com milhões de chamadas

Imagine uma árvore degenerada.

10

 \

 20

   \

   30

     \

     40

Ela parece uma lista.

A recursividade fará milhares de chamadas.

Ruim.

Árvores balanceadas evitam isso.


B-Tree resolve exatamente este problema

Ela mantém altura pequena.

Mesmo com milhões de registros.

É justamente por isso que bancos usam B-Tree.

Não Binary Tree simples.


Dica de ouro

Nunca escreva recursividade sem antes responder:

Qual é minha condição de parada?

Se não conseguir responder.

Ainda não terminou o algoritmo.


Outra dica

Desenhe.

Sempre.

Árvores ficam muito mais fáceis no papel.


Debug

Durante testes faça:

DISPLAY

Mostrando o nível.

DISPLAY "LEVEL=" WS-NIVEL

Assim você visualiza a profundidade.


Performance em Mainframe

No IBM Z.

CPU é dinheiro.

Cada microssegundo importa.

Por isso.

Recursividade costuma aparecer mais em:

  • middleware

  • compiladores

  • parsers

  • XML

  • JSON

  • IA

  • engines

Do que em batch financeiro.


Curiosidade histórica

Nos anos 70.

Poucos compiladores COBOL aceitavam recursividade.

A memória era extremamente cara.

Muitas máquinas tinham poucos megabytes.

Era impensável desperdiçar stack.

Hoje.

Servidores IBM Z possuem centenas de gigabytes.

O cenário mudou.


Boas práticas

✔ Sempre tenha condição de parada clara.

✔ Documente a lógica antes de codificar.

✔ Prefira árvores balanceadas.

✔ Limite profundidade quando possível.

✔ Evite variáveis globais compartilhadas.

✔ Teste casos extremos.

✔ Monitore consumo de CPU e memória.

✔ Utilize recursividade apenas quando ela realmente simplifica o problema.

✔ Faça revisão de código focando em chamadas recursivas.

✔ Meça desempenho antes de concluir que a solução é "rápida".


Armadilhas comuns

❌ Esquecer a condição de parada.

❌ Modificar dados globais inesperadamente.

❌ Assumir que toda árvore é balanceada.

❌ Ignorar consumo de stack.

❌ Trocar elegância por complexidade desnecessária.

❌ Usar recursividade onde um PERFORM VARYING resolveria de forma mais simples.


Recursividade e Enterprise COBOL

As versões modernas do IBM Enterprise COBOL oferecem suporte a programas recursivos, mas é importante observar alguns detalhes:

  • Declare o programa como RECURSIVE quando necessário.

  • Utilize opções de compilação adequadas ao ambiente, frequentemente combinadas com RENT em aplicações compartilhadas.

  • Consulte sempre o padrão adotado pela sua empresa e a documentação da versão do compilador em uso, pois políticas de compilação variam entre instalações.

Em ambientes CICS, IMS ou aplicações de alta concorrência, também é essencial compreender os conceitos de reentrância, armazenamento automático e áreas de trabalho para evitar efeitos colaterais entre execuções simultâneas.


Missão para o Padawan COBOL

Depois de dominar este artigo, experimente implementar os seguintes desafios:

  1. Fatorial usando recursividade.

  2. Sequência de Fibonacci (comparando desempenho com versão iterativa).

  3. Percorrer uma árvore binária em ordem (in-order).

  4. Percorrer uma árvore em pré-ordem (pre-order).

  5. Percorrer uma árvore em pós-ordem (post-order).

  6. Simular um índice de clientes usando uma árvore binária simples.

  7. Comparar o tempo de busca entre uma tabela sequencial e uma árvore.

  8. Criar um visualizador com DISPLAY mostrando o nível de cada chamada recursiva.

Cada exercício ajudará você a entender não apenas como a recursividade funciona, mas quando ela é realmente a melhor ferramenta.

Conclusão — O Holodeck da Recursividade

Existe uma lição que diferencia um programador comum de um verdadeiro oficial da Frota Estelar.

O iniciante procura resolver problemas escrevendo mais código.

O engenheiro experiente procura resolver problemas encontrando a estrutura correta.

A recursividade é exatamente isso: uma mudança de perspectiva. Em vez de atacar um problema gigantesco de uma única vez, você o divide em pequenas partes idênticas, permitindo que o próprio algoritmo repita a solução até alcançar a condição de parada.

No universo do COBOL, ela não substitui os tradicionais PERFORM VARYING, nem foi criada para processar milhões de registros sequenciais de um batch financeiro. Seu verdadeiro poder aparece quando trabalhamos com estruturas hierárquicas: árvores B, XML, JSON, compiladores, interpretadores, mecanismos de regras, grafos e diversos algoritmos modernos que fazem parte da computação atual.

Como diria o Sr. Spock:

"A solução mais elegante normalmente é aquela que respeita a estrutura natural do problema."

Quando você compreender essa filosofia, deixará de enxergar a recursividade como um truque de linguagem e passará a vê-la como uma ferramenta de modelagem.

E esse é um dos momentos em que um Padawan COBOL começa a trilhar o caminho para se tornar um verdadeiro Mestre do Mainframe.


quarta-feira, 11 de março de 2020

🔥☕ DB2 z/OS MAINFRAME — A ANATOMIA DO “CÉREBRO DOS DADOS” ☕🔥

 

Bellacosa Mainframe entenda o funcionamento do DB2

🔥☕ DB2 z/OS MAINFRAME — A ANATOMIA DO “CÉREBRO DOS DADOS” ☕🔥

Salve jovem padawan neste laboratorio pratico veremos alguns dos componentes mais profundos e importantes do DB2 z/OS:
Storage Groups, Bufferpools, Logs, Optimizer, EDM Pool, índices B-Tree, Data Sharing, BSDS e arquitetura interna do banco.

Isso já entra no território de:

  • DBA de produção,
  • suporte avançado,
  • performance tuning,
  • recovery,
  • troubleshooting crítico,
  • arquitetura interna do DB2.

O DB2 no z/OS não é apenas um “banco de dados”.

Ele é:

  • sistema transacional,
  • gerenciador de memória,
  • engine de recovery,
  • scheduler interno,
  • coordenador de locking,
  • otimizador SQL,
  • e controlador de integridade transacional.

🔥 1) STORAGE GROUP — O “MAPEAMENTO DO TERRITÓRIO”

🧠 O que é

Storage Group é o agrupamento lógico de volumes DASD usados pelo DB2.


🔍 Função

O DBA não precisa dizer:

  • “grave exatamente no disco XYZ”

O DB2 usa o Storage Group para decidir:

  • onde alocar datasets,
  • como distribuir dados,
  • onde criar VSAM LDS.

🧨 Exemplo

CREATE STOGROUP STGPRD
VOLUMES(PRD001,PRD002)
VCAT(DB2CAT);

🔥 O que ele controla

  • datasets DB2
  • VSAM LDS
  • tablespaces
  • indexspaces
  • crescimento físico

🚨 Problema clássico

Storage Group sem espaço.

Resultado:

  • inserts falham,
  • extents explodem,
  • utilities quebram.

🔥 LAB 01 — STORAGE GROUP LOTADO

🚨 Problema

Aplicação falhando:

SQLCODE -904
RESOURCE UNAVAILABLE

🔍 Investigação

Verificar volumes:

-DIS DB(*) SPACENAM(*)

💣 Diagnóstico

DASD cheio.


✅ Solução

Adicionar volume:

ALTER STOGROUP STGPRD
ADD VOLUMES(PRD003);

🧠 Explicação

O DB2 não conseguia expandir datasets.


🔥 2) TABELAS — O “CORPO FÍSICO” DOS DADOS

🧠 Estrutura lógica

Tabela:

  • colunas
  • linhas
  • constraints
  • índices

Mas internamente:

  • pages
  • RID
  • slots
  • overflow pages

🧨 Exemplo

CREATE TABLE ALUNOS
(
ID INTEGER,
NOME CHAR(40),
CURSO CHAR(20)
);

🔥 Tipos de tabelas

TipoUso
Segmentedtradicional
Partitionedgrandes volumes
Universalmoderno
Temporarytemporárias
Clonedeploy online

🚨 Problema clássico

Tabela enorme sem particionamento.

Resultado:

  • REORG gigantesco,
  • recovery lento,
  • scans monstruosos.

🔥 LAB 02 — TABELA GIGANTE

🚨 Problema

Tabela com 4 bilhões de linhas.

REORG demora 18 horas.


✅ Solução

Migrar para partitioned tablespace.


🧠 Explicação

Particionamento divide carga física.


🔥 3) ÍNDICES — O GPS DO DB2

🧠 O que fazem

Índices evitam full scan.


🔥 Estrutura B-Tree

Seu material menciona:

B-Tree : Índice – Arvore Binaria


🧠 Como funciona

A árvore possui:

  • root page
  • branch pages
  • leaf pages

🔍 O DB2 percorre:

ROOT → BRANCH → LEAF → ROW

🚨 Sem índice

O DB2 lê:

  • milhões de páginas.

🧨 Exemplo

CREATE INDEX IXALUNO
ON ALUNOS(ID);

🔥 LAB 03 — SQL MATANDO CPU

🚨 Problema

SELECT demorando minutos.


🔍 Investigação

EXPLAIN mostra:

TABLESPACE SCAN

✅ Solução

Criar índice:

CREATE INDEX IXCPF
ON CLIENTE(CPF);

🧠 Explicação

DB2 deixou de varrer tabela inteira.


🔥 4) CATALOGO DB2 — O “DNA” DO BANCO

Seu material aborda:

Catalogo
Metadados


🧠 O que é

O catálogo guarda:

  • definição tabelas
  • índices
  • colunas
  • privileges
  • packages
  • plans

🔍 Tabelas famosas

TabelaFunção
SYSIBM.SYSTABLEStabelas
SYSIBM.SYSCOLUMNScolunas
SYSIBM.SYSINDEXESíndices
SYSIBM.SYSPACKAGEpackages

🧨 Exemplo

SELECT NAME
FROM SYSIBM.SYSTABLES
WHERE CREATOR='ESCOLA';

🔥 LAB 04 — DESCOBRIR ÍNDICES

🚨 Problema

Ninguém sabe quais índices existem.


✅ Solução

SELECT NAME
FROM SYSIBM.SYSINDEXES
WHERE TBNAME='CLIENTE';

🧠 Explicação

Catálogo é o “Google interno” do DB2.


🔥 5) LOG — A “CAIXA PRETA” DO DB2

Seu material aborda:

Active LOG
Archive LOG
BSDS


🧠 O que é o LOG

Tudo que muda no DB2 vai para log.


🔥 Serve para

  • rollback
  • recovery
  • restart
  • integridade
  • auditoria

🔥 ACTIVE LOG

Logs atuais em uso.


🔥 ARCHIVE LOG

Logs antigos arquivados.


🔥 BSDS

Bootstrap Dataset.

Contém:

  • inventário logs
  • checkpoints
  • bootstrap recovery

🚨 Se BSDS corrompe…

O DB2 entra em crise séria.


🔥 LAB 05 — LOG FULL

🚨 Problema

Sistema travado.


🔍 Investigação

-DIS LOG

💣 Resultado

Logs esgotados.


✅ Solução

  • aumentar logs
  • reduzir transações longas
  • acelerar archive

🧠 Explicação

Sem log livre o DB2 para updates.


🔥 6) BUFFERPOOL — O “PULMÃO” DO DB2

Seu material aborda:

Bufferpool
Frame Bufferpool


🧠 O que é

Cache de páginas em memória.


🔍 Fluxo

DASD → BUFFERPOOL → CPU

🚨 Bufferpool ruim = muito I/O


🧨 Exemplo

-DIS BUFFERPOOL(BP0)

🔥 LAB 06 — HIT RATIO HORRÍVEL

🚨 Problema

I/O gigantesco.


🔍 Resultado

HIT RATIO 58%

✅ Solução

Aumentar:

ALTER BUFFERPOOL(BP0) VPSIZE(50000)

🧠 Explicação

Mais páginas em cache.


🔥 7) DB2 DATA SHARING — O “CLUSTER” DO MAINFRAME

Seu material mostra:

DB2 DATA SHARING com Group Bufferpools


🧠 O que é

Vários DB2s compartilhando dados simultaneamente.


🔥 Permite

  • alta disponibilidade
  • escalabilidade
  • failover
  • paralelismo

🔍 Componentes

ComponenteFunção
Coupling Facilitysincronização
GBPcache compartilhado
IRLMlocking

🚨 Problema clássico

Contention no GBP.


🔥 LAB 07 — CONTENTION EM DATA SHARING

🚨 Problema

Locks excessivos.


🔍 Investigação

-DIS GROUP

💣 Resultado

GBP saturation.


✅ Solução

Aumentar Group Bufferpool.


🧠 Explicação

Muitos membros acessando mesmas páginas.


🔥 8) OPTIMIZER — O “CÉREBRO” DO SQL

Seu material aborda:

DB2 Optimizer


🧠 O que faz

Decide:

  • índice
  • join
  • scan
  • sort
  • access path

🔥 Sem optimizer

SQL seria inviável.


🔍 Ele analisa:

  • cardinalidade
  • seletividade
  • RUNSTATS
  • índices
  • distribuição dados

🔥 LAB 08 — OPTIMIZER ESCOLHEU MAL

🚨 Problema

SQL piorou após deploy.


🔍 Investigação

Novo access path.


✅ Solução

Executar:

RUNSTATS TABLESPACE FINANCE.CLIENTE

Rebind package.


🧠 Explicação

Stats antigas enganaram optimizer.


🔥 9) EDM POOL — O “CACHE CEREBRAL”

Seu material aborda:

  • EDM POOL
  • Dynamic Cache
  • PT/CT
  • Skeleton Pool
  • DBD


🧠 O que é

Cache interno de:

  • packages
  • plans
  • SQL dinâmico
  • estruturas DBD

🔥 Problema clássico

EDM pequeno.


🚨 Resultado

  • compilação excessiva
  • CPU alta
  • cache thrashing

🔥 LAB 09 — EDM SATURADO

🚨 Problema

CPU do DB2 explodindo.


🔍 Investigação

-DIS DDF

e monitor EDM.


💣 Resultado

Dynamic statement cache lotado.


✅ Solução

Aumentar EDM pool.


🧠 Explicação

SQL dinâmico recompilando continuamente.


🔥 10) BIND E PACKAGE

Seu material cita:

BindProgram


🧠 O que é BIND

Transforma SQL em package executável.


🔥 PACKAGE

Código SQL otimizado armazenado.


🔥 LAB 10 — PACKAGE INVALIDADO

🚨 Problema

Programa falha após alteração tabela.


💣 Resultado

Package inválido.


✅ Solução

REBIND PACKAGE

🧠 Explicação

DDL alterou estrutura dependente.


🔥 LAB EXTRA — INCIDENTE COMPLETO

🚨 Cenário

Sistema financeiro lento.


🔍 Investigação

Descoberto:

  • RUNSTATS vencido
  • bufferpool saturado
  • índice inválido
  • logs pressionados

✅ Solução

Fluxo:

  1. REBUILD INDEX
  2. REORG
  3. RUNSTATS
  4. Ajuste BUFFERPOOL
  5. Revisão commits

🧠 Resultado

CPU caiu:

  • de 92%
  • para 34%

☕ VISÃO “BELLACOSA MAINFRAME”

O DB2 z/OS parece um banco…

Mas internamente ele é:

  • sistema operacional de dados,
  • motor transacional,
  • mecanismo de recuperação,
  • orquestrador de memória,
  • e inteligência analítica.

Quem aprende:

  • logs,
  • bufferpool,
  • optimizer,
  • EDM,
  • utilities,
  • data sharing,

não aprende apenas SQL…

aprende a anatomia do coração digital das grandes corporações. ☕💣

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