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 ON nã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:

  1. declarar o cursor;
  2. abri-lo;
  3. executar FETCH enquanto houver dados;
  4. tratar o fim do resultado;
  5. 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:

  1. retorne no máximo 50 registros;
  2. se houver o registro 51, informe que existe próxima página;
  3. use como token a chave do 50º registro retornado, e não a chave do registro excedente;
  4. na próxima consulta, use ID_CLIENTE > :ULTIMA-CHAVE;
  5. 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 WHERE seletivo 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

  1. Tratar ODO como memória infinita. Existe uma capacidade máxima declarada.
  2. Criar uma tabela enorme “por segurança”. Isso transfere o risco para armazenamento e desempenho.
  3. Devolver milhares de linhas numa COMMAREA. O limite do mecanismo deve fazer parte do desenho.
  4. Ignorar SQLCODE +100. Ele indica ausência ou fim dos dados no contexto do FETCH.
  5. Não fechar o cursor nos caminhos de erro. Centralize a finalização.
  6. Usar o registro excedente como próxima chave. O token deve representar o último registro entregue.
  7. Paginar sem ORDER BY único. A navegação pode duplicar ou perder linhas.
  8. Confiar no limite enviado pelo cliente. O servidor deve impor seu próprio máximo.
  9. Manter estado transacional entre páginas. APIs devem preferir tokens stateless.
  10. 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 FETCH preserva 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 é:

  1. filtrar e ordenar no Db2;
  2. recuperar os dados com cursor ou rowset;
  3. limitar a quantidade por requisição;
  4. usar paginação baseada em chave;
  5. transportar apenas os campos necessários;
  6. 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

  1. OCCURS DEPENDING ON aloca 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.
  2. Posso usar ALLOCATE e FREE no 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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.
  9. É 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.
  10. 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.