TS vs TD — quando usar cada um

Característica Temporary Storage (TS) Transient Data (TD)
AcessoAleatório — por número de itemSequencial — FIFO, um sentido
Leitura destrutiva?Não — o item permanece após READQSim — READQ remove o registro da fila
EscritaWRITEQ TS (novo item ou reescreve)WRITEQ TD (sempre adiciona ao final)
ExclusãoDELETEQ TS apaga a fila inteiraNão há DELETEQ TD; esvazia lendo
Definição prévia?Não — criada dinamicamente pelo programaSim — TDQUEUE deve ser definida no CSD
Trigger automáticoNãoSim — dispara transação ao atingir nível
Uso típicoPaginação, cache temporário entre telasImpressão, log, fila de processamento
🦕 Analogia: TS é como um bloco de notas numerado — você escreve na página 1, página 2, depois volta e relê a página 3 quantas vezes quiser. TD é como uma caixa de correio — você deposita cartas (WRITEQ TD), elas ficam em fila, e quem lê (READQ TD) pega e descarta uma por uma.

Temporary Storage — MAIN vs AUXILIARY

Ao gravar em uma fila TS, você pode especificar onde o CICS deve armazená-la:

OpçãoArmazenamentoVelocidadePersistênciaQuando usar
MAINMemória principal (RAM)Muito rápidaPerdida se CICS cairDados temporários pequenos, alta frequência de acesso
AUXILIARYDataset em disco (DFHTEMP)Mais lentaSobrevive a restart do CICS (se recovery ativo)Volumes maiores, listas longas, dados que precisam de proteção
Regra prática: use MAIN para filas pequenas de uma única sessão de usuário (até 10–20 registros) e AUXILIARY para listagens longas ou quando há risco de o CICS ser reiniciado durante o processamento.

Nomeando a fila TS

O nome da fila TS tem até 8 caracteres e é criado dinamicamente pelo programa. Para garantir unicidade por usuário, a convenção mais usada é concatenar o TERMID (identificador do terminal, 4 chars) com um sufixo fixo:

       WORKING-STORAGE SECTION.
       01  WS-QUEUE-NAME.
           05  WS-TERMID        PIC X(4).
           05  WS-QUEUE-SUFIXO  PIC X(4) VALUE 'CTLG'.

       PROCEDURE DIVISION.
           MOVE EIBTRMID TO WS-TERMID
           * WS-QUEUE-NAME = 'T001CTLG' para o terminal T001
⚠️ Filas TS são compartilhadas no CICS. Dois usuários no mesmo terminal produzem o mesmo nome de fila e sobrescrevem dados um do outro. Sempre inclua o TERMID (EIBTRMID) no nome da fila para garantir isolamento por sessão.

WRITEQ TS — gravando na fila

WRITEQ TS adiciona um novo item à fila ou reescreve um item existente. Cada item recebe um número sequencial (1, 2, 3...) retornado no parâmetro ITEM.

* gravar novo item no final da fila
           EXEC CICS WRITEQ TS
                          QUEUE(WS-QUEUE-NAME)
                          FROM(WS-REGISTRO-CONTA)
                          LENGTH(LENGTH OF WS-REGISTRO-CONTA)
                          ITEM(WS-NUMERO-ITEM)     * CICS retorna o número do item gravado
                          MAIN                     * ou AUXILIARY
                          RESP(WS-RESP)
           END-EXEC

* reescrever um item já existente (REWRITE)
           EXEC CICS WRITEQ TS
                          QUEUE(WS-QUEUE-NAME)
                          FROM(WS-REGISTRO-CONTA)
                          LENGTH(LENGTH OF WS-REGISTRO-CONTA)
                          ITEM(WS-NUMERO-ITEM)
                          REWRITE                  * sobrescreve o item de número WS-NUMERO-ITEM
                          RESP(WS-RESP)
           END-EXEC
ParâmetroObrigatórioSignificado
QUEUE(nome)SimNome da fila TS (até 8 chars)
FROM(área)SimÁrea de Working-Storage com os dados a gravar
LENGTH(n)SimComprimento do item em bytes
ITEM(var)NãoCICS retorna o número do item gravado; obrigatório para REWRITE
MAIN / AUXILIARYNãoOnde armazenar. Padrão depende da instalação (geralmente MAIN)
REWRITENãoSobrescreve o item identificado por ITEM
NOSUSPENDNãoNão suspende a tarefa se a fila estiver cheia — retorna NOSPACE

READQ TS — lendo da fila

READQ TS lê um item da fila sem removê-lo. Você pode ler pelo número do item ou sequencialmente com NEXT.

* ler item específico pelo número
           EXEC CICS READQ TS
                          QUEUE(WS-QUEUE-NAME)
                          INTO(WS-REGISTRO-CONTA)
                          LENGTH(WS-LENGTH)
                          ITEM(WS-NUMERO-ITEM)     * item a ler
                          RESP(WS-RESP)
           END-EXEC

* ler próximo item sequencialmente
           EXEC CICS READQ TS
                          QUEUE(WS-QUEUE-NAME)
                          INTO(WS-REGISTRO-CONTA)
                          LENGTH(WS-LENGTH)
                          NEXT                     * avança ponteiro interno da fila
                          RESP(WS-RESP)
           END-EXEC

* verificar conteúdo sem consumir (NUMITEMS = total de itens)
           EXEC CICS READQ TS
                          QUEUE(WS-QUEUE-NAME)
                          INTO(WS-REGISTRO-CONTA)
                          LENGTH(WS-LENGTH)
                          ITEM(WS-NUMERO-ITEM)
                          NUMITEMS(WS-TOTAL-ITENS) * CICS retorna total de itens na fila
                          RESP(WS-RESP)
           END-EXEC
RESP retornadoSignificado
DFHRESP(NORMAL)Item lido com sucesso
DFHRESP(QIDERR)Fila não existe (ainda não foi criada ou já foi deletada)
DFHRESP(ITEMERR)Número de item inválido ou fora do intervalo
DFHRESP(ENDDATA)NEXT: não há mais itens após o ponteiro atual
DFHRESP(LENGERR)LENGTH menor que o item armazenado — dados truncados

DELETEQ TS — limpando a fila

DELETEQ TS apaga a fila inteira de uma vez — todos os itens, sem possibilidade de desfazer. Sempre execute ao final do uso para liberar memória ou espaço em disco.

           EXEC CICS DELETEQ TS
                          QUEUE(WS-QUEUE-NAME)
                          RESP(WS-RESP)
           END-EXEC

           IF WS-RESP = DFHRESP(QIDERR)
               CONTINUE     * fila não existia — não é erro crítico
           END-IF
⚠️ Limpeza obrigatória. Filas TS não são removidas automaticamente quando a transação termina. Se o programa não fizer DELETEQ TS, a fila persiste no CICS (MAIN) ou no dataset DFHTEMP (AUXILIARY) consumindo recursos indefinidamente. Em ambiente de produção com centenas de usuários isso leva a esgotamento de memória.

Padrão de paginação multi-tela com TS

O uso mais comum de TS é implementar listagens paginadas: o programa carrega todos os registros na fila na primeira execução, depois navega por elas com PF7 (página anterior) e PF8 (próxima página).

Estrutura da COMMAREA para paginação

       01  WS-COMMAREA.
           05  WS-FASE          PIC X.
               88  PRIMEIRA-VEZ     VALUE 'I'.
               88  PAGINANDO        VALUE 'P'.
           05  WS-PAG-ATUAL     PIC S9(4) COMP VALUE 1.
           05  WS-TOT-PAGINAS   PIC S9(4) COMP.
           05  WS-REGS-POR-PAG  PIC S9(4) COMP VALUE 15.
           05  WS-QUEUE-NAME    PIC X(8).

Fluxo completo de paginação

       PROCEDURE DIVISION.

       INICIO.
           IF EIBCALEN = 0
               MOVE 'I' TO WS-FASE
           ELSE
               MOVE DFHCOMMAREA TO WS-COMMAREA
           END-IF

           EVALUATE TRUE
               WHEN PRIMEIRA-VEZ
                   PERFORM CARREGAR-FILA-TS
                   PERFORM EXIBIR-PAGINA
               WHEN PAGINANDO AND EIBAID = DFHPF8   * próxima página
                   IF WS-PAG-ATUAL < WS-TOT-PAGINAS
                       ADD 1 TO WS-PAG-ATUAL
                   END-IF
                   PERFORM EXIBIR-PAGINA
               WHEN PAGINANDO AND EIBAID = DFHPF7   * página anterior
                   IF WS-PAG-ATUAL > 1
                       SUBTRACT 1 FROM WS-PAG-ATUAL
                   END-IF
                   PERFORM EXIBIR-PAGINA
               WHEN EIBAID = DFHPF3                   * sair — limpar fila
                   EXEC CICS DELETEQ TS
                                  QUEUE(WS-QUEUE-NAME)
                                  RESP(WS-RESP)
                   END-EXEC
                   EXEC CICS XCTL PROGRAM('PGMMENU') END-EXEC
           END-EVALUATE

           EXEC CICS RETURN
                          TRANSID(EIBTRNID)
                          COMMAREA(WS-COMMAREA)
                          LENGTH(LENGTH OF WS-COMMAREA)
           END-EXEC.

       CARREGAR-FILA-TS.
           * montar nome único de fila
           MOVE EIBTRMID TO WS-TERMID
           MOVE 'LIST'    TO WS-QUEUE-SUFIXO

           * garantir que fila anterior foi limpa
           EXEC CICS DELETEQ TS
                          QUEUE(WS-QUEUE-NAME)
                          RESP(WS-RESP)
           END-EXEC

           * ler todos os registros do VSAM/DB2 e gravar na fila
           EXEC CICS STARTBR FILE('CNTFILE')
                          RIDFLD(WS-CHAVE-INICIO)
                          RESP(WS-RESP)
           END-EXEC

           MOVE 0 TO WS-TOTAL-REGISTROS
           PERFORM UNTIL WS-RESP NOT = DFHRESP(NORMAL)
               EXEC CICS READNEXT FILE('CNTFILE')
                              INTO(WS-REG-CONTA)
                              RIDFLD(WS-CHAVE)
                              RESP(WS-RESP)
               END-EXEC
               IF WS-RESP = DFHRESP(NORMAL)
                   EXEC CICS WRITEQ TS
                                  QUEUE(WS-QUEUE-NAME)
                                  FROM(WS-REG-CONTA)
                                  LENGTH(LENGTH OF WS-REG-CONTA)
                                  AUXILIARY
                                  RESP(WS-RESP2)
                   END-EXEC
                   ADD 1 TO WS-TOTAL-REGISTROS
               END-IF
           END-PERFORM

           EXEC CICS ENDBR FILE('CNTFILE') END-EXEC

           * calcular total de páginas
           COMPUTE WS-TOT-PAGINAS =
               (WS-TOTAL-REGISTROS + WS-REGS-POR-PAG - 1)
               / WS-REGS-POR-PAG

           MOVE 1     TO WS-PAG-ATUAL
           MOVE 'P'   TO WS-FASE.

       EXIBIR-PAGINA.
           * calcular primeiro e último item desta página
           COMPUTE WS-ITEM-INICIO =
               (WS-PAG-ATUAL - 1) * WS-REGS-POR-PAG + 1
           COMPUTE WS-ITEM-FIM =
               WS-PAG-ATUAL * WS-REGS-POR-PAG

           MOVE LOW-VALUES TO MAPLISTO

           PERFORM VARYING WS-ITEM FROM WS-ITEM-INICIO BY 1
                   UNTIL WS-ITEM > WS-ITEM-FIM
               EXEC CICS READQ TS
                              QUEUE(WS-QUEUE-NAME)
                              INTO(WS-REG-CONTA)
                              LENGTH(WS-LENGTH)
                              ITEM(WS-ITEM)
                              RESP(WS-RESP)
               END-EXEC
               IF WS-RESP = DFHRESP(NORMAL)
                   PERFORM MOVER-PARA-LINHA-TELA
               END-IF
           END-PERFORM

           EXEC CICS SEND MAP('MAPLISTA')
                          MAPSET('BANCMAP2')
                          FROM(MAPLISTO)
                          ERASE
           END-EXEC.

Transient Data — intrapartição e extrapartição

As filas TD são definidas previamente no CSD (Control Section Dataset) e têm dois tipos:

TipoOnde gravaQuem lêUso típico
Intrapartição Dataset interno do CICS (DFHINTRA) Outra transação CICS (via READQ TD ou trigger) Comunicação entre transações CICS, filas de impressão interna, log de eventos
Extrapartição Dataset externo (qualquer QSAM ou JES SPOOL) Jobs batch fora do CICS, impressoras, arquivos de saída Gerar relatórios, enviar dados para processamento batch, saída em SYSOUT
💗 Extrapartição na prática: Imagine uma transação CICS que gera um comprovante de transferência. Em vez de imprimir diretamente, ela grava o registro em uma fila TD extrapartição apontando para o SPOOL do JES. O JES captura e imprime automaticamente — sem que o CICS precise gerenciar a impressora.

Definição de fila TD no CSD

Antes de usar uma fila TD, ela precisa ser definida com CEDA:

* definição de fila intrapartição (via CEDA ou DFHCSDUP)
DEFINE TDQUEUE(PRNT)
       GROUP(BANCGRP)
       TYPE(INTRA)
       TRIGGERLEVEL(1)           * dispara transação após 1 item na fila
       TRANSID(PRNTRANS)         * transação disparada automaticamente

* definição de fila extrapartição
DEFINE TDQUEUE(RELAT)
       GROUP(BANCGRP)
       TYPE(EXTRA)
       DDNAME(RELDDIN)           * DD do JCL do CICS que aponta para o dataset
       OPENTIME(INITIAL)         * abre o arquivo quando o CICS inicia
       DISPOSITION(MOD)          * modo de abertura do dataset

WRITEQ TD — gravando na fila TD

WRITEQ TD sempre adiciona um registro ao final da fila. Não há número de item — é puramente sequencial.

       WORKING-STORAGE SECTION.
       01  WS-LOG-RECORD.
           05  WS-LOG-DATA      PIC X(10).
           05  WS-LOG-HORA      PIC X(8).
           05  WS-LOG-USERID    PIC X(8).
           05  WS-LOG-TRANSID   PIC X(4).
           05  WS-LOG-MENSAGEM  PIC X(50).

       PROCEDURE DIVISION.

       GRAVAR-LOG.
           MOVE CURRENT-DATE(1:10) TO WS-LOG-DATA
           MOVE CURRENT-DATE(12:8) TO WS-LOG-HORA
           EXEC CICS ASSIGN USERID(WS-LOG-USERID) END-EXEC
           MOVE EIBTRNID TO WS-LOG-TRANSID
           MOVE 'TRANSFERENCIA EFETUADA' TO WS-LOG-MENSAGEM

           EXEC CICS WRITEQ TD
                          QUEUE('ALOG')            * nome de 4 chars para TD
                          FROM(WS-LOG-RECORD)
                          LENGTH(LENGTH OF WS-LOG-RECORD)
                          RESP(WS-RESP)
           END-EXEC

           IF WS-RESP NOT = DFHRESP(NORMAL)
               DISPLAY 'ERRO AO GRAVAR LOG TD: ' WS-RESP
           END-IF.
Nomes de filas TD têm apenas 4 caracteres (diferente de TS que tem 8). O CICS reserva alguns nomes especiais: CSML (log de mensagens do sistema), CSSL (log de estatísticas), CSDL (log de deadlocks). Evite esses prefixos em filas de aplicação.

READQ TD — lendo da fila TD

READQ TD lê e remove o primeiro registro da fila (FIFO). Não é possível reler um registro já lido — ele desaparece após a leitura.

       PROCEDURE DIVISION.

       LER-FILA-IMPRESSAO.
           PERFORM UNTIL WS-RESP NOT = DFHRESP(NORMAL)
               EXEC CICS READQ TD
                              QUEUE('PRNT')
                              INTO(WS-LINHA-IMPRESSAO)
                              LENGTH(WS-LENGTH)
                              RESP(WS-RESP)
               END-EXEC

               EVALUATE WS-RESP
                   WHEN DFHRESP(NORMAL)
                       PERFORM IMPRIMIR-LINHA
                   WHEN DFHRESP(QZERO)
                       CONTINUE   * fila vazia — fim do PERFORM
                   WHEN OTHER
                       DISPLAY 'ERRO READQ TD: ' WS-RESP
               END-EVALUATE
           END-PERFORM.
RESP retornadoSignificado
DFHRESP(NORMAL)Registro lido e removido da fila
DFHRESP(QZERO)Fila vazia — não há mais registros
DFHRESP(QIDERR)Fila não existe (nome inválido ou não definida no CSD)
DFHRESP(LENGERR)Registro maior que a área INTO — dados truncados

TDQUEUE com trigger — disparando transações

Filas TD intrapartição podem ter um TRIGGERLEVEL — quando o número de registros na fila atinge esse valor, o CICS automaticamente dispara a transação definida em TRANSID. Isso permite construir pipelines de processamento assíncrono dentro do CICS.

🦕 Analogia: É como uma campainha na porta de um restaurante: quando 5 pedidos se acumulam no balcão (TRIGGERLEVEL=5), o sistema toca a campainha e avisa o cozinheiro (TRANSID=COOK) para vir buscar. O garçom não precisa ir pessoalmente avisar — o mecanismo é automático.
* definição da fila com trigger
DEFINE TDQUEUE(PEND)
       GROUP(BANCGRP)
       TYPE(INTRA)
       TRIGGERLEVEL(10)          * dispara quando acumular 10 registros
       TRANSID(BTCH)             * transação BTCH é iniciada automaticamente
       USERID(BTCHUSER)          * usuário sob o qual a transação roda

A transação disparada pelo trigger lê a fila com READQ TD e processa os registros. Ela termina quando a fila fica vazia (QZERO). Se mais registros chegarem enquanto ela está rodando, o trigger não é acionado novamente até que a transação termine e o nível seja atingido de novo.

* transação BTCH — disparada pelo trigger da fila PEND
       PROCEDURE DIVISION.
       INICIO.
           PERFORM UNTIL WS-FILA-VAZIA
               EXEC CICS READQ TD
                              QUEUE('PEND')
                              INTO(WS-PEDIDO)
                              LENGTH(WS-LENGTH)
                              RESP(WS-RESP)
               END-EXEC

               IF WS-RESP = DFHRESP(QZERO)
                   SET WS-FILA-VAZIA TO TRUE
               ELSE IF WS-RESP = DFHRESP(NORMAL)
                   PERFORM PROCESSAR-PEDIDO
               END-IF
           END-PERFORM

           EXEC CICS RETURN END-EXEC.

Boas práticas e armadilhas comuns

Temporary Storage

PráticaPor quê
Sempre inclua EIBTRMID no nome da filaEvita colisão de nomes entre usuários diferentes
Faça DELETEQ TS ao sair da transação (PF3, CLEAR, timeout)Evita acúmulo de filas órfãs consumindo memória
Use AUXILIARY para listas longas (> 50 registros)MAIN consome memória do region CICS; AUXILIARY vai para disco
Verifique QIDERR antes de READQ TS na primeira telaFila pode não existir se a transação foi iniciada sem dados
Grave o tamanho do item na COMMAREAREADQ TS pode truncar se LENGTH for menor que o gravado

Transient Data

PráticaPor quê
Nomes de fila TD têm exatamente 4 charsNomes menores causam QIDERR; maiores são truncados
Trate QZERO como condição normal, não como erroFila vazia é o sinal de fim de leitura sequencial
Não use TD para dados críticos sem recovery configuradoRegistros em DFHINTRA podem ser perdidos se CICS cair sem journal
Para extrapartição, defina OPENTIME=INITIAL no CSDAbre o dataset quando o CICS sobe — evita falha no primeiro WRITEQ

Armadilha clássica: fila TS não deletada

* ERRADO: programa termina sem limpar a fila
       SAIR.
           EXEC CICS XCTL PROGRAM('PGMMENU') END-EXEC.
* a fila WS-QUEUE-NAME persiste no CICS consumindo recursos!

* CORRETO: limpar antes de sair
       SAIR.
           EXEC CICS DELETEQ TS
                          QUEUE(WS-QUEUE-NAME)
                          RESP(WS-RESP)
           END-EXEC
           EXEC CICS XCTL PROGRAM('PGMMENU') END-EXEC.

Armadilha clássica: LENGTH errado no READQ TS

* item gravado com 200 bytes
           EXEC CICS WRITEQ TS
                          QUEUE(WS-QUEUE-NAME)
                          FROM(WS-REGISTRO)
                          LENGTH(200)
                          RESP(WS-RESP)
           END-EXEC

* ERRADO: lendo com 100 bytes — dados truncados, RESP = LENGERR
           EXEC CICS READQ TS
                          QUEUE(WS-QUEUE-NAME)
                          INTO(WS-REGISTRO)
                          LENGTH(100)            * menor que o gravado!
                          ITEM(1)
                          RESP(WS-RESP)
           END-EXEC

* CORRETO: usar o mesmo tamanho do item gravado
           EXEC CICS READQ TS
                          QUEUE(WS-QUEUE-NAME)
                          INTO(WS-REGISTRO)
                          LENGTH(200)
                          ITEM(1)
                          RESP(WS-RESP)
           END-EXEC
🟣 Avançado — TS Shared Queues: Em ambientes CICS com múltiplos sistemas (CICSplex), a fila TS de um sistema não é visível nos outros por padrão. Para compartilhar filas entre sistemas CICS use Shared Temporary Storage, que persiste em um coupling facility do z/OS. Isso permite que uma transação no CICS A grave e uma transação no CICS B leia a mesma fila — essencial em arquiteturas de alta disponibilidade.