Quem desenvolve em Java ou Python está acostumado a listas que aumentam ou diminuem durante a execução. Ao chegar ao COBOL, é natural surgir a pergunta:
Como retornar uma quantidade desconhecida de registros do DB2 para uma aplicação Java ou Python, utilizando COBOL e CICS, sem criar uma tabela gigantesca?
A resposta curta é: não tente reproduzir no COBOL a mesma estratégia usada por uma lista dinâmica de Java ou Python. Em aplicações transacionais, quase sempre é melhor limitar o resultado, recuperar os dados com cursor e entregar páginas controladas ao consumidor.
Isso não significa que o COBOL seja incapaz de trabalhar com quantidades variáveis. Ele oferece tabelas com OCCURS, tamanho lógico variável com OCCURS DEPENDING ON e, em implementações modernas, armazenamento dinâmico com ALLOCATE e FREE. A questão é escolher a solução certa para cada cenário.
O que chamamos de array em COBOL?
Em COBOL, a estrutura equivalente a um array é normalmente chamada de tabela. Ela é declarada com a cláusula OCCURS:
01 WS-TABELA-CLIENTES.
05 WS-CLIENTE OCCURS 10 TIMES
INDEXED BY IDX-CLIENTE.
10 WS-CLIENTE-ID PIC 9(05).
10 WS-CLIENTE-NOME PIC X(30).
10 WS-CLIENTE-SALDO PIC S9(07)V99 COMP-3.
Nesse exemplo, há espaço para exatamente dez clientes. Essa capacidade é conhecida durante a compilação.
O acesso pode ser feito por subscrito:
MOVE 12345 TO WS-CLIENTE-ID(1)
MOVE 'JOSE ROBERTO' TO WS-CLIENTE-NOME(1)
Ou pelo índice definido em INDEXED BY:
SET IDX-CLIENTE TO 1
MOVE 12345 TO WS-CLIENTE-ID(IDX-CLIENTE)
SET IDX-CLIENTE UP BY 1
O subscrito representa uma ocorrência. O índice é um item especial administrado pelo compilador para localizar a ocorrência na tabela. Em ambos os casos, é obrigação do programa impedir acessos fora dos limites.
OCCURS DEPENDING ON: variável, mas dentro de um limite
OCCURS DEPENDING ON, também conhecido como ODO, define uma tabela cuja quantidade lógica de ocorrências varia durante a execução:
01 WS-RESPOSTA.
05 WS-QTD-CLIENTES PIC 9(03) COMP-3.
05 WS-CLIENTE OCCURS 0 TO 100 TIMES
DEPENDING ON WS-QTD-CLIENTES.
10 WS-CLIENTE-ID PIC 9(05).
10 WS-CLIENTE-NOME PIC X(30).
A tabela pode representar de zero a cem clientes. Se WS-QTD-CLIENTES contiver 12, somente doze ocorrências são consideradas parte lógica da estrutura.
O ponto central é este:
OCCURS DEPENDING ONnão significa capacidade ilimitada.
Existe um limite máximo declarado — cem ocorrências no exemplo. Dependendo do contexto, do compilador e da forma como a estrutura é usada, o comprimento lógico pode variar, mas isso não transforma automaticamente a tabela em uma coleção como ArrayList ou list.
Alguns cuidados importantes:
- mantenha o campo controlador dentro do intervalo mínimo e máximo;
- valide o limite antes de preencher a tabela;
- não use um máximo exagerado apenas para “garantir que caiba”;
- confirme as regras do compilador para itens que aparecem depois de uma tabela ODO;
- em interfaces, mantenha uma copybook versionada e compartilhada entre chamador e chamado.
Então existe array dinâmico em COBOL?
A resposta tecnicamente correta é: depende do que você chama de dinâmico.
| Recurso | O que varia | Limite |
|---|---|---|
OCCURS n TIMES |
Nada; capacidade e tamanho lógico são fixos | Definido no fonte |
OCCURS m TO n DEPENDING ON |
Quantidade lógica utilizada | Máximo n definido no fonte |
ALLOCATE e FREE |
Bloco de armazenamento obtido em execução | Memória disponível e regras da implementação |
Tabela UNBOUNDED |
Capacidade associada ao armazenamento obtido | Recurso dependente da versão/compilador |
O IBM Enterprise COBOL atual possui ALLOCATE e FREE e documenta seu uso inclusive com tabelas UNBOUNDED. Isso permite obter e liberar armazenamento durante a execução. Entretanto, exige ponteiros, controle explícito e conhecimento das regras do compilador.
Um exemplo mínimo, deliberadamente genérico, é:
WORKING-STORAGE SECTION.
01 WS-PTR USAGE POINTER VALUE NULL.
01 WS-TAMANHO PIC 9(09) COMP-5 VALUE 4096.
PROCEDURE DIVISION.
ALLOCATE WS-TAMANHO CHARACTERS
INITIALIZED
RETURNING WS-PTR
END-ALLOCATE
IF WS-PTR = NULL
DISPLAY 'NAO FOI POSSIVEL OBTER ARMAZENAMENTO'
GOBACK
END-IF
*> Associar WS-PTR a uma estrutura BASED e processar os dados.
FREE WS-PTR
GOBACK.
Esse trecho mostra a ideia, não uma solução completa de tabela dinâmica. A declaração da estrutura BASED, o cálculo do tamanho e as opções aceitas devem seguir a documentação da versão utilizada. A sintaxe e o suporte não devem ser presumidos iguais entre Enterprise COBOL e GnuCOBOL.
Para uma consulta online no CICS, alocar espaço para todos os registros raramente é a melhor escolha. Memória dinâmica resolve alocação; não resolve volume, tempo de resposta, transporte nem concorrência.
Quantidade desconhecida no DB2: use cursor
Quando um SELECT pode retornar várias linhas, o caminho tradicional é um cursor:
- declarar o cursor;
- abri-lo;
- executar
FETCHenquanto houver dados; - tratar o fim do resultado;
- fechar o cursor.
EXEC SQL
DECLARE C-CLIENTES CURSOR FOR
SELECT ID_CLIENTE,
NOME_CLIENTE
FROM TB_CLIENTE
WHERE SITUACAO = 'A'
ORDER BY ID_CLIENTE
END-EXEC
EXEC SQL
OPEN C-CLIENTES
END-EXEC
IF SQLCODE NOT = 0
PERFORM 9000-TRATA-ERRO-DB2
END-IF
PERFORM UNTIL SQLCODE = 100
EXEC SQL
FETCH C-CLIENTES
INTO :WS-ID-CLIENTE,
:WS-NOME-CLIENTE
END-EXEC
EVALUATE SQLCODE
WHEN 0
PERFORM 3000-PROCESSA-CLIENTE
WHEN 100
CONTINUE
WHEN OTHER
PERFORM 9000-TRATA-ERRO-DB2
END-EVALUATE
END-PERFORM
EXEC SQL
CLOSE C-CLIENTES
END-EXEC
No Db2 for z/OS, SQLCODE +100 representa a condição de dados não encontrados ou fim do resultado. Não é um erro de infraestrutura. Códigos negativos devem seguir o padrão de tratamento do ambiente, normalmente com dados adicionais da SQLCA ou GET DIAGNOSTICS.
O exemplo é didático. Em produção, controle se o cursor foi aberto antes de fechá-lo e organize a saída por um parágrafo único de finalização, garantindo o CLOSE também nos caminhos de erro.
Multi-row FETCH: várias linhas por chamada
Para volumes maiores, o Db2 for z/OS suporta rowset cursor e host-variable arrays. Em vez de uma chamada ao Db2 por linha, o programa recupera um conjunto de linhas por FETCH.
Uma declaração típica usa WITH ROWSET POSITIONING:
EXEC SQL
DECLARE C-PRODUTOS CURSOR
WITH ROWSET POSITIONING FOR
SELECT ID_PRODUTO,
NOME_PRODUTO
FROM TB_PRODUTO
WHERE SITUACAO = 'A'
ORDER BY ID_PRODUTO
END-EXEC
As host-variable arrays são declaradas por coluna:
01 WS-ROWSET.
05 WS-ID-PRODUTO
OCCURS 100 TIMES PIC 9(05).
05 WS-NOME-PRODUTO
OCCURS 100 TIMES PIC X(30).
01 WS-QTD-ROWSET PIC S9(09) COMP-5.
E o lote pode ser recuperado desta forma conceitual:
MOVE 100 TO WS-QTD-ROWSET
EXEC SQL
FETCH NEXT ROWSET FROM C-PRODUTOS
FOR :WS-QTD-ROWSET ROWS
INTO :WS-ID-PRODUTO,
:WS-NOME-PRODUTO
END-EXEC
A quantidade efetivamente recuperada deve ser obtida conforme a interface recomendada pela versão do Db2 — por exemplo, por informações de diagnóstico — e somente essas ocorrências devem ser processadas. Colunas anuláveis também exigem arrays de indicadores compatíveis.
O ganho vem da redução de interações com o Db2. O custo é uma área de trabalho maior e uma lógica de controle mais cuidadosa. O tamanho ideal do rowset precisa ser medido no ambiente; “quanto maior, melhor” não é uma regra.
O gargalo pode estar no transporte, não no array
Recuperar os dados é apenas metade do problema. Depois, eles precisam sair do programa COBOL e chegar ao Java ou Python.
COMMAREA
A COMMAREA é o mecanismo clássico para passagem de dados entre programas e transações CICS. Nos comandos em que se aplica o limite tradicional, seu comprimento máximo é 32.763 bytes. EIBCALEN informa o comprimento recebido pelo programa.
IF EIBCALEN < LENGTH OF DFHCOMMAREA
MOVE 12 TO LK-CODIGO-RETORNO
MOVE 'COMMAREA COM TAMANHO INVALIDO'
TO LK-MENSAGEM
GOBACK
END-IF
Não basta verificar se “cabe no PIC”. Chamador e chamado precisam concordar sobre layout, comprimento, tipos binários, versão da copybook e codificação.
Channels and Containers
Channels and Containers removem a restrição clássica da COMMAREA e permitem separar os dados em blocos nomeados. Uma solução pode usar, por exemplo:
- um contêiner para os parâmetros de entrada;
- um contêiner para status e paginação;
- um contêiner para os registros.
Ainda assim, não são ilimitados: utilizam armazenamento e possuem custo de cópia e transporte. Um contêiner enorme apenas desloca o problema.
Outras alternativas
| Mecanismo | Uso mais adequado |
| COMMAREA | Chamadas síncronas e mensagens pequenas |
| Channels and Containers | Chamadas CICS com estruturas maiores ou separadas |
| IBM MQ | Integração assíncrona, desacoplamento e entrega confiável |
| API REST | Consumo síncrono por aplicações web, Java ou Python |
| Arquivo | Extrações e cargas de grande volume em processamento batch |
| TSQ/TDQ | Necessidades específicas de armazenamento ou enfileiramento no CICS |
Para milhares ou milhões de registros, uma transação online raramente deve devolver tudo. Nesse caso, considere paginação, processamento assíncrono ou arquivo batch.
A solução recomendada: paginação por chave
Uma API não precisa manter o cursor Db2 aberto entre duas chamadas HTTP. Manter uma unidade de trabalho ou tarefa CICS esperando o usuário pedir a próxima página consome recursos e cria acoplamento desnecessário.
Uma alternativa melhor é a keyset pagination, ou paginação pela última chave processada.
Primeira chamada:
GET /clientes?limite=50
Próxima chamada:
GET /clientes?limite=50&ultimaChave=00001235
A consulta correspondente é semelhante a:
SELECT ID_CLIENTE,
NOME_CLIENTE
FROM TB_CLIENTE
WHERE SITUACAO = 'A'
AND ID_CLIENTE > :WS-ULTIMA-CHAVE
ORDER BY ID_CLIENTE
FETCH FIRST 51 ROWS ONLY
Se o limite solicitado é 50, o programa busca até 51 linhas. A linha adicional serve somente para detectar a existência da página seguinte.
Regras:
- retorne no máximo 50 registros;
- se houver o registro 51, informe que existe próxima página;
- use como token a chave do 50º registro retornado, e não a chave do registro excedente;
- na próxima consulta, use
ID_CLIENTE > :ULTIMA-CHAVE; - imponha um limite máximo aceito pela API.
Quando a coluna usada na ordenação não for única, use uma chave composta. Por exemplo:
ORDER BY DATA_CADASTRO, ID_CLIENTE
O token precisa carregar os dois valores, e a condição de continuação deve respeitar a mesma ordem. Sem uma ordenação única e determinística, podem ocorrer duplicidades ou perdas entre páginas.
Por que não usar apenas OFFSET?
OFFSET é simples e permite saltar diretamente para uma página, mas páginas profundas podem exigir que o banco processe muitas linhas anteriores. Além disso, inclusões e exclusões entre chamadas podem deslocar os resultados.
A paginação por chave normalmente é mais adequada para grandes tabelas e APIs stateless porque aproveita índices e continua a partir de um valor conhecido. Ela não oferece acesso direto à “página 900”, mas esse requisito costuma ser dispensável em integrações de alto volume.
Copybook de uma resposta paginada
01 LK-RESPOSTA.
05 LK-CODIGO-RETORNO PIC S9(04) COMP-5.
05 LK-MENSAGEM PIC X(100).
05 LK-QTD-SOLICITADA PIC 9(03) COMP-3.
05 LK-QTD-RETORNADA PIC 9(03) COMP-3.
05 LK-IND-PROXIMA-PAGINA PIC X(01).
88 LK-TEM-PROXIMA VALUE 'S'.
88 LK-NAO-TEM-PROXIMA VALUE 'N'.
05 LK-PROXIMA-CHAVE PIC 9(08).
05 LK-CLIENTE OCCURS 0 TO 50 TIMES
DEPENDING ON LK-QTD-RETORNADA.
10 LK-CLIENTE-ID PIC 9(08).
10 LK-CLIENTE-NOME PIC X(30).
Em interfaces externas, campos de exibição em formato textual costumam simplificar a interoperabilidade. Campos COMP, COMP-3 e ponteiros não devem atravessar a fronteira para JSON sem uma etapa explícita de transformação.
Também vale separar o token recebido da próxima chave devolvida. A nomenclatura precisa deixar claro que o valor representa o último item entregue ao consumidor.
Resposta JSON
Uma camada de integração pode transformar a copybook em uma resposta como esta:
{
"codigo": 0,
"mensagem": "Consulta realizada com sucesso",
"quantidade": 2,
"possuiProximaPagina": true,
"proximaChave": "00001235",
"registros": [
{
"id": "00001234",
"nome": "CLIENTE EXEMPLO"
},
{
"id": "00001235",
"nome": "OUTRO CLIENTE"
}
]
}
O Python normalmente consumirá uma API ou fila, em vez de chamar uma transação CICS diretamente. Java dispõe de opções como APIs HTTP, IBM MQ e CICS Transaction Gateway, conforme a arquitetura adotada.
Exemplo de consumo em Python
import requests
URL = "https://api.exemplo.com/clientes"
LIMITE = 50
ultima_chave = None
while True:
parametros = {"limite": LIMITE}
if ultima_chave:
parametros["ultimaChave"] = ultima_chave
resposta = requests.get(URL, params=parametros, timeout=15)
resposta.raise_for_status()
dados = resposta.json()
if dados.get("codigo") != 0:
raise RuntimeError(dados.get("mensagem", "Erro na consulta"))
for cliente in dados.get("registros", []):
print(cliente["id"], cliente["nome"])
if not dados.get("possuiProximaPagina", False):
break
nova_chave = dados.get("proximaChave")
if not nova_chave or nova_chave == ultima_chave:
raise RuntimeError("Token de paginação inválido ou repetido")
ultima_chave = nova_chave
O timeout, o tratamento HTTP e a proteção contra token repetido evitam que o cliente fique preso em um ciclo infinito.
Exemplo de consumo em Java
O exemplo usa HttpClient, disponível desde o Java 11. A transformação do JSON pode ser feita com Jackson, JSON-B ou a biblioteca padronizada no projeto.
HttpClient cliente = HttpClient.newBuilder().build();
String ultimaChave = null;
boolean continuar = true;
while (continuar) {
String url = "https://api.exemplo.com/clientes?limite=50";
if (ultimaChave != null) {
url += "&ultimaChave=" +
URLEncoder.encode(ultimaChave, StandardCharsets.UTF_8);
}
HttpRequest requisicao = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(15))
.GET()
.build();
HttpResponse<String> resposta = cliente.send(
requisicao, HttpResponse.BodyHandlers.ofString());
if (resposta.statusCode() != 200) {
throw new IllegalStateException(
"Erro HTTP: " + resposta.statusCode());
}
// Desserializar, processar registros e atualizar:
// continuar = retorno.possuiProximaPagina();
// ultimaChave = retorno.proximaChave();
}
Em produção, use objetos tipados para a resposta, não concatene parâmetros arbitrários e aplique autenticação, rastreabilidade e política de repetição conforme o contrato da API.
Arquitetura de referência
flowchart TD
A["Aplicação Java ou Python"] --> B["API Gateway"]
B --> C["CICS Transaction Server"]
C --> D["Programa COBOL"]
D --> E["Db2 for z/OS"]
E --> D
D --> C
C --> B
B --> A
Cada camada tem uma responsabilidade:
- Db2: armazenamento, filtragem, ordenação e acesso indexado;
- COBOL: validações, regras de negócio e montagem da resposta;
- CICS: execução transacional e integração;
- API Gateway: autenticação, autorização, limites e observabilidade;
- Java ou Python: consumo das páginas e apresentação ou processamento.
COBOL continua no centro das regras de negócio. A modernização acontece ao redor dele, por contratos bem definidos, sem a necessidade de reescrever um núcleo estável apenas para adotar uma tecnologia mais nova.
Comparativo das soluções
| Solução | Vantagem | Limitação | Melhor uso |
OCCURS |
Simples e previsível | Tamanho fixo | Quantidade conhecida |
OCCURS DEPENDING ON |
Tamanho lógico variável | Mantém um máximo declarado | Mensagens e lotes controlados |
ALLOCATE/FREE |
Armazenamento obtido em execução | Mais complexidade e controle manual | Estruturas realmente dinâmicas e casos específicos |
| Cursor linha a linha | Pouca memória e lógica simples | Mais chamadas ao Db2 | Poucas linhas ou tratamento individual |
| Rowset/multi-row FETCH | Reduz chamadas ao Db2 | Controle de arrays e diagnósticos | Processamento em lotes |
| COMMAREA | Ampla compatibilidade | Limite tradicional de 32.763 bytes | Mensagens pequenas |
| Channels/Containers | Mais flexibilidade e volume | Consome armazenamento; não é ilimitado | Integração CICS com estruturas maiores |
| API paginada | Stateless e fácil de consumir | Exige contrato e token corretos | Java, Python, web e mobile |
| IBM MQ | Resiliência e desacoplamento | Modelo assíncrono e operação adicional | Eventos e integrações confiáveis |
| Arquivo batch | Excelente para volume massivo | Não é resposta online imediata | Cargas e extrações |
Boas práticas de desempenho e segurança
- imponha limite máximo por página, mesmo que o cliente solicite um valor maior;
- use
WHEREseletivo e escolha apenas as colunas necessárias; - crie ou valide índices coerentes com filtro e ordenação;
- não use
SELECT *em contratos de integração; - não mantenha cursor e tarefa CICS abertos entre chamadas HTTP;
- valide comprimento e versão das áreas de comunicação;
- proteja a API com autenticação, autorização e criptografia em trânsito;
- não exponha
SQLCODE, nomes de tabelas ou dados sensíveis ao consumidor; - trate conversões entre EBCDIC e UTF-8 de maneira explícita;
- monitore CPU, tempo Db2, número de chamadas, armazenamento e tamanho da resposta;
- defina timeouts e uma política cuidadosa de retentativas;
- teste concorrência, atualização de dados entre páginas e tokens inválidos.
Erros comuns
- Tratar ODO como memória infinita. Existe uma capacidade máxima declarada.
- Criar uma tabela enorme “por segurança”. Isso transfere o risco para armazenamento e desempenho.
- Devolver milhares de linhas numa COMMAREA. O limite do mecanismo deve fazer parte do desenho.
- Ignorar
SQLCODE +100. Ele indica ausência ou fim dos dados no contexto doFETCH. - Não fechar o cursor nos caminhos de erro. Centralize a finalização.
- Usar o registro excedente como próxima chave. O token deve representar o último registro entregue.
- Paginar sem
ORDER BYúnico. A navegação pode duplicar ou perder linhas. - Confiar no limite enviado pelo cliente. O servidor deve impor seu próprio máximo.
- Manter estado transacional entre páginas. APIs devem preferir tokens stateless.
- Confundir solução de memória com solução de integração. Ainda existem limites de transporte, tempo e concorrência.
Curiosidades técnicas
- O armazenamento contíguo das tabelas ajuda a explicar por que o COBOL oferece acesso previsível e eficiente às ocorrências.
OCCURS DEPENDING ONé especialmente útil em registros e mensagens cujo comprimento lógico acompanha a quantidade de itens válidos.- Channels and Containers surgiram como uma alternativa mais flexível à COMMAREA, mas não eliminaram a necessidade de controlar volume.
- Multi-row
FETCHpreserva uma ideia antiga e eficiente do mainframe: fazer mais trabalho útil por interação com o subsistema. - A paginação por chave aproxima o desenho mainframe das APIs modernas sem retirar do COBOL a responsabilidade pelas regras de negócio.
Conclusão
Existe array dinâmico em COBOL? O COBOL tradicional trabalha principalmente com tabelas de capacidade definida. OCCURS DEPENDING ON fornece tamanho lógico variável, enquanto versões modernas oferecem recursos como ALLOCATE, FREE e tabelas UNBOUNDED para armazenamento dinâmico.
Mas, quando o problema é retornar uma quantidade desconhecida de registros do Db2 para Java ou Python, a melhor resposta geralmente não é “criar um array que caiba tudo”. A solução mais segura é:
- filtrar e ordenar no Db2;
- recuperar os dados com cursor ou rowset;
- limitar a quantidade por requisição;
- usar paginação baseada em chave;
- transportar apenas os campos necessários;
- escolher COMMAREA, containers, API, MQ ou arquivo conforme o volume e a necessidade de sincronismo.
É uma arquitetura simples de entender, previsível para operar e alinhada ao que o mainframe sempre fez bem: processar regras críticas com controle rigoroso de dados e recursos.
Perguntas frequentes
OCCURS DEPENDING ONaloca memória conforme a quantidade usada?- Ele altera a quantidade lógica de ocorrências dentro de um intervalo declarado. O comportamento de armazenamento e comprimento deve ser conferido no contexto e compilador utilizados; não o trate como uma lista ilimitada.
- Posso usar
ALLOCATEeFREEno COBOL?- Sim, em implementações que suportam essas instruções, como versões atuais do IBM Enterprise COBOL. A sintaxe e os recursos associados devem ser validados na documentação da versão.
- Qual é o limite da COMMAREA?
- Nos comandos CICS tradicionais aplicáveis, o comprimento máximo é 32.763 bytes. Confirme o comando, a topologia da chamada e a versão do ambiente.
- Channels and Containers são ilimitados?
- Não. Eles permitem volumes maiores e estruturas mais flexíveis, mas continuam consumindo armazenamento e recursos do CICS.
- O que significa
SQLCODE +100?- Significa que nenhuma linha foi encontrada ou que o cursor chegou ao fim do resultado, conforme a operação executada.
- Quando usar multi-row FETCH?
- Quando a redução do número de chamadas ao Db2 trouxer benefício para o processamento de lotes. O tamanho do rowset deve ser testado.
- OFFSET ou paginação por chave?
- OFFSET é simples e permite saltar páginas. Para grandes volumes e navegação sequencial, a paginação por chave costuma ser mais eficiente e estável.
- Python chama uma transação CICS diretamente?
- Normalmente, não. O padrão é consumir uma API, uma fila MQ ou outro componente de integração que acione o programa no CICS.
- É possível manter o cursor aberto entre páginas?
- É tecnicamente possível em desenhos stateful, mas não é a abordagem recomendada para APIs REST. Ela prolonga o uso de recursos e acopla as requisições.
- Como saber se existe outra página?
- Busque uma linha além do limite. Se o limite for 50 e vierem 51, retorne os primeiros 50 e use a chave do 50º como token de continuação.
Fontes oficiais e leitura recomendada
- IBM Enterprise COBOL — ALLOCATE statement
- IBM Enterprise COBOL — exemplo com ALLOCATE, FREE e tabela UNBOUNDED
- IBM Db2 for z/OS — recuperação de múltiplas linhas em host-variable arrays
- IBM Db2 for z/OS — FETCH statement
- IBM Db2 for z/OS — row retrieval with a cursor
- IBM Enterprise COBOL — tabelas, arrays e ponteiros
- GnuCOBOL Programmer’s Guide
Atenção: sintaxe, limites e recursos podem variar conforme as versões do Enterprise COBOL, GnuCOBOL, Db2 for z/OS e CICS Transaction Server. Valide os exemplos no compilador e no ambiente usados pela sua organização antes de levá-los à produção.

