1. DBD completo — todas as macros

O DBD é escrito em assembler usando macros IBM e compilado pelo utilitário DBDGEN. O resultado é um módulo em IMS.DBDLIB que o IMS carrega quando o banco é aberto.

DBD completo — banco de clientes e contas (HDAM)
         PRINT NOGEN
*
* DBD do banco de clientes - organização HDAM
*
         DBD    NAME=BANCOCLI,             NOME DO BANCO (8 chars)   X
                ACCESS=HDAM               TIPO DE ORGANIZACAO
*
* Dataset group: define o arquivo VSAM que armazena o banco
*
         DATASET DD1=BANCOCLID,           DDNAME no JCL             X
                DEVICE=3390,             TIPO DE DISPOSITIVO        X
                SIZE=4096                TAMANHO DO BLOCO FISICO
*
* RANDOMIZER: funcao de hash para HDAM
*
         RMNAME NAME=DFSHDC40,           MODULO RANDOMIZADOR IBM    X
                NUMENTRIES=50000,        NUMERO RAIZ ESTIMADO       X
                NUMBLOCKS=10,            BLOCOS POR RAIZ            X
                BYTESLEFT=5             BYTES LIVRES NO ROOT ANCHOR
*
* SEGMENTO RAIZ: CLIENTE
*
         SEGM   NAME=CLIENTE,            NOME (8 chars)             X
                BYTES=80,               TAMANHO EM BYTES            X
                PARENT=0,               0 = SEGMENTO RAIZ           X
                PTR=T                   TWIN FORWARD POINTER
         FIELD  NAME=(CLICPF,SEQ,U),    SEQUENCE FIELD UNICO       X
                BYTES=11,              COMPRIMENTO                  X
                START=1,               POSICAO NO SEGMENTO (1-base) X
                TYPE=P                 TIPO: P=PACKED DECIMAL
         FIELD  NAME=CLINOME,            CAMPO NOME                 X
                BYTES=40,START=12,TYPE=C
         FIELD  NAME=CLINASC,            DATA NASCIMENTO            X
                BYTES=8,START=52,TYPE=P
         FIELD  NAME=CLITIPO,            F=FISICO / J=JURIDICO      X
                BYTES=1,START=60,TYPE=C
*
* SEGMENTO FILHO: CONTA
*
         SEGM   NAME=CONTA,                                         X
                BYTES=60,                                           X
                PARENT=((CLIENTE,SNGL))  PAI = CLIENTE, PTR=SNGL
         FIELD  NAME=(CTANUM,SEQ,U),    NUMERO DA CONTA (CHAVE)    X
                BYTES=10,START=1,TYPE=C
         FIELD  NAME=CTATIPO,BYTES=2,START=11,TYPE=C
         FIELD  NAME=CTASLDO,BYTES=8,START=13,TYPE=P
         FIELD  NAME=CTASTTS,BYTES=1,START=29,TYPE=C
*
* SEGMENTO NETO: MOVIMENT
*
         SEGM   NAME=MOVIMENT,                                      X
                BYTES=30,                                           X
                PARENT=((CONTA,SNGL))   PAI = CONTA
         FIELD  NAME=(MOVDATA,SEQ),     DATA (NAO UNICA - twins)   X
                BYTES=8,START=1,TYPE=P
         FIELD  NAME=MOVVALOR,BYTES=8,START=9,TYPE=P
         FIELD  NAME=MOVTIPO,BYTES=1,START=17,TYPE=C
*
         DBDGEN                          GERA O DBD
         FINISH
         END

2. SEGM — definindo segmentos

A macro SEGM define cada tipo de segmento da hierarquia. Seus parâmetros controlam tamanho, relacionamento com o pai e tipo de ponteiro usado internamente.

Parâmetro SEGMValoresSignificado
NAME 1–8 chars Nome do tipo de segmento — usado nos SSAs do programa
BYTES 1–32767 Comprimento máximo em bytes. Para segmentos de tamanho variável, use BYTES=(min,max)
PARENT 0 ou nome 0 = segmento raiz. Nome = pai direto na hierarquia
PTR T, TB, TF, TFB, SNGL, SNGLB, DBLE, DBLEB Tipo de ponteiro físico. T = twin forward. SNGL = forward only. DBLE = forward + backward
RULES R, LAST, HERE Regra de inserção de novos twins. R = pela chave (default). LAST = sempre no fim. HERE = na posição atual
FREQ Número Estimativa de número médio de ocorrências por pai — ajuda o IMS a alocar buffers
🟣 PTR e performance
SNGL (ponteiro só para o próximo twin) é mais eficiente em espaço e funciona bem para varredura sequencial. DBLE (ponteiro para próximo e anterior) permite GHN + DLET sem precisar reposicionar do pai, mas usa 8 bytes extras de ponteiro por segmento. T (twin) é o mais comum em HDAM — armazena ponteiro forward no próprio segmento.

3. FIELD — definindo campos e sequence field

A macro FIELD define cada campo dentro de um segmento. O campo de sequência (SEQ) é especial — determina a ordem dos twins e é o campo usado nos SSAs qualificados.

Parâmetro FIELDValoresSignificado
NAME (nome,SEQ,U) ou (nome,SEQ,M) ou nome Nome do campo (8 chars). SEQ = campo de sequência. U = único. M = múltiplo (twins com mesmo valor permitidos)
BYTES 1–255 Comprimento em bytes
START 1–n Posição inicial dentro do segmento (começa em 1)
TYPE C, P, Z, X, F, H C=character, P=packed decimal, Z=zoned decimal, X=hexadecimal, F=fullword binary, H=halfword binary
Exemplos de FIELD com diferentes tipos
      *    Campo de chave único (SEQ,U) - CHARACTER
         FIELD  NAME=(CTANUM,SEQ,U),BYTES=10,START=1,TYPE=C

      *    Campo de chave não-único (SEQ,M) - PACKED DECIMAL
      *    Permite twins com mesma data (vários movimentos no mesmo dia)
         FIELD  NAME=(MOVDATA,SEQ,M),BYTES=8,START=1,TYPE=P

      *    Campo normal sem SEQ - ZONED DECIMAL (display numérico)
         FIELD  NAME=CLIIDADE,BYTES=3,START=61,TYPE=Z

      *    Campo binário FULLWORD (4 bytes)
         FIELD  NAME=CLIFLAGS,BYTES=4,START=64,TYPE=F

      *    Campo sem definição explícita de TYPE - padrão é C
         FIELD  NAME=CLIEMAIL,BYTES=50,START=30
✅ Campos não precisam cobrir o segmento inteiro
Você não precisa definir FIELD para cada byte do segmento — apenas para os campos que serão usados em SSAs qualificados ou que o DBA quer documentar. Os bytes não cobertos por um FIELD são acessíveis ao programa COBOL através da área de dados do segmento, mas o IMS não os conhece pelo nome.

4. LCHILD e XDFLD — índice secundário no DBD

O IMS suporta índice secundário — acesso a um segmento por um campo que não é o sequence field. A definição envolve dois DBDs: o DBD do banco original (com LCHILD e XDFLD) e um DBD especial do índice.

DBD do banco com definição de índice secundário
      *    No banco BANCOCLI, queremos acessar CLIENTE por CLINOME
      *    além do acesso primário por CLICPF

         SEGM   NAME=CLIENTE,BYTES=80,PARENT=0
         FIELD  NAME=(CLICPF,SEQ,U),BYTES=11,START=1,TYPE=P
         FIELD  NAME=CLINOME,BYTES=40,START=12,TYPE=C
*
* LCHILD: aponta para o DBD do índice secundário
*
         LCHILD NAME=(CLINOMIDX,BANCOCLII),   SEGM,DBD DO INDICE   X
                POINTER=INDX,                TIPO INDIRETO          X
                RULES=LAST
*
* XDFLD: define o campo indexado e a chave no índice
*
         XDFLD  NAME=CLINOMX,                  NOME LOGICO          X
                SRCH=CLINOME,                 CAMPO DE BUSCA        X
                SEGMENT=CLIENTE,              SEGMENTO ONDE ESTA    X
                SUBSEQ=CLICPF                DESEMPATE = CHAVE PRIM
DBD do índice secundário (BANCOCLII)
         DBD    NAME=BANCOCLII,ACCESS=INDEX
         DATASET DD1=BANCLIID,DEVICE=3390,SIZE=4096
         SEGM   NAME=CLINOMIDX,BYTES=51,PARENT=0
         FIELD  NAME=(CLINOMX,SEQ,M),BYTES=40,START=1,TYPE=C
         FIELD  NAME=CLICPFX,BYTES=11,START=41,TYPE=P
         DBDGEN
         FINISH
         END

5. ACCESS — tipos de organização física

ACCESSNomeDataset VSAMAcesso rootQuando usar
HDAM Hierarchical Direct ESDS (data) + ESDS (overflow) Hash direto Acesso aleatório dominante — o mais comum em produção
HIDAM Hierarchical Indexed Direct KSDS (index) + ESDS (data) Índice B+ Acesso sequencial por chave importa; grandes bancos
HISAM Hierarchical Indexed Sequential KSDS (primário) + ESDS (overflow) KSDS Bancos pequenos; acesso misto mas predominantemente sequencial
HSAM Hierarchical Sequential QSAM (sequencial) Sequencial Tape ou datasets de arquivo; raramente novo hoje
SHDAM Simple HDAM ESDS Hash direto Variante do HDAM sem overflow separado; bancos menores
INDEX Secondary Index KSDS Índice B+ Exclusivo para DBDs de índice secundário

6. PSB completo — todas as macros

O PSB (Program Specification Block) define a visão do programa sobre um ou mais bancos. Um PSB contém um ou mais PCBs — cada PCB aponta para um DBD e define quais segmentos o programa pode acessar e com quais permissões.

PSB completo com múltiplos PCBs
         PRINT NOGEN
*
* PCB 1: acesso ao banco de clientes (leitura e atualização)
*
         PCB    TYPE=DB,                  TIPO BANCO               X
                DBDNAME=BANCOCLI,         NOME DO DBD              X
                KEYLEN=21,               KEYLEN (ver secao 10)     X
                PROCOPT=A                A = TODAS AS OPERACOES
         SENSEG NAME=CLIENTE,            SEGMENTO SENSIVELX
                PROCOPT=A
         SENSEG NAME=CONTA,              FILHO CONTA               X
                PROCOPT=A
         SENSEG NAME=MOVIMENT,           NETO MOVIMENT             X
                PROCOPT=GD              APENAS LEITURA E DELETE
*
* PCB 2: acesso pelo indice secundario de nome
*
         PCB    TYPE=DB,                                           X
                DBDNAME=BANCOCLII,        DBD DO INDICE            X
                KEYLEN=51,               KEYLEN DO INDICE          X
                PROCOPT=G                SO LEITURA VIA INDICE
         SENSEG NAME=CLINOMIDX,PROCOPT=G
*
* Gera o PSB para COBOL
*
         PSBGEN LANG=COBOL,PSBNAME=PGMBANKI
         END
🦕 PSB é como um contrato de acesso
O PSB é o que o programa "assina" quando é carregado pelo IMS. Ele diz exatamente: "este programa pode ler CLIENTE, ler/inserir/atualizar/deletar CONTA, só ler e deletar MOVIMENT". O IMS verifica o PSB em cada DL/I call — qualquer tentativa de operação não autorizada retorna status AM (access method error).

7. PROCOPT — tabela completa de opções

PROCOPT (Processing Option) aparece em dois lugares: no PCB (opção geral do banco) e no SENSEG (opção por segmento individual). O SENSEG refina o que o PCB permite.

PROCOPTCalls DL/I permitidasDescrição
GGU, GN, GNPGet only — somente leitura. Mais restritivo.
GUGU somenteApenas Get Unique — sem GN ou GNP
IISRTInsert only — apenas inserção, sem leitura prévia
DGHU, GHN, GHNP, DLETDelete — inclui Get Hold para posicionamento
RGHU, GHN, GHNP, REPLReplace — inclui Get Hold para posicionamento
ATodasAll — G + I + D + R. Acesso completo.
GOGU, GN, GNP (sem lock)Get Optional — leitura sem lock (não bloqueia escritores)
GRGU, GN, GNP, REPLGet + Replace
GDGU, GN, GNP, DLET (+ hold)Get + Delete
LSGU, GN, GNPLoad Sequential — para carga inicial de banco
PSB com PROCOPT refinado por segmento
      *    PCB com PROCOPT=A mas restringindo segmentos individuais
         PCB    TYPE=DB,DBDNAME=BANCOCLI,KEYLEN=21,PROCOPT=A
*
      *    CLIENTE: só leitura (programa não altera dados cadastrais)
         SENSEG NAME=CLIENTE,PROCOPT=G
*
      *    CONTA: leitura e atualização (atualiza saldo)
         SENSEG NAME=CONTA,PROCOPT=GR
*
      *    MOVIMENT: leitura e inserção (nunca deleta movimentos)
         SENSEG NAME=MOVIMENT,PROCOPT=GI
⚠️ PROCOPT no PCB vs no SENSEG
O PROCOPT no PCB é o limite superior de permissão. O SENSEG só pode restringir, nunca ampliar. Se o PCB tem PROCOPT=G (somente leitura) e um SENSEG tem PROCOPT=A, o IMS honra apenas G — o SENSEG não pode dar mais permissão que o PCB. Na prática: defina PROCOPT=A no PCB e use SENSEG para restringir segmentos específicos.

8. Múltiplos PCBs num mesmo PSB

Um PSB pode conter vários PCBs — um para cada banco que o programa acessa. No COBOL, cada PCB corresponde a um item na LINKAGE SECTION, e todos aparecem no ENTRY 'DLITCBL' USING.

COBOL — múltiplos PCBs na LINKAGE SECTION
       LINKAGE SECTION.
*
      *    PCB 1 — banco principal de clientes
       01  PCB-BANCOCLI.
           05 PCB-DBD-NAME   PIC X(08).
           05 PCB-SEG-LEVEL  PIC XX.
           05 PCB-STATUS     PIC XX.
           05 PCB-PROC-OPT   PIC X(04).
           05 FILLER         PIC X(04).
           05 PCB-SEG-NAME   PIC X(08).
           05 PCB-KEY-LEN    PIC S9(05) COMP.
           05 PCB-NUMB-SENS  PIC S9(05) COMP.
           05 PCB-KEY-FDBK   PIC X(21).

      *    PCB 2 — índice secundário de nome
       01  PCB-INDICE.
           05 PCB-I-DBD-NAME  PIC X(08).
           05 PCB-I-SEG-LEVEL PIC XX.
           05 PCB-I-STATUS    PIC XX.
           05 PCB-I-PROC-OPT  PIC X(04).
           05 FILLER          PIC X(04).
           05 PCB-I-SEG-NAME  PIC X(08).
           05 PCB-I-KEY-LEN   PIC S9(05) COMP.
           05 PCB-I-NUMB-SENS PIC S9(05) COMP.
           05 PCB-I-KEY-FDBK  PIC X(51).

       PROCEDURE DIVISION.
      *    Todos os PCBs listados na ordem do PSB
           ENTRY 'DLITCBL' USING PCB-BANCOCLI
                                 PCB-INDICE.

       0000-PRINCIPAL.
      *    Busca por nome via PCB-INDICE
           CALL 'CBLTDLI' USING
               WS-SSA-1 WS-FUNC-GU PCB-INDICE
               WS-SEG-IDXNOME WS-SSA-IDX-NOME

      *    Agora usa a chave primária recuperada para buscar no banco real
           MOVE IDX-CPF TO SSA-CLI-CPF
           CALL 'CBLTDLI' USING
               WS-SSA-1 WS-FUNC-GU PCB-BANCOCLI
               WS-SEG-CLIENTE WS-SSA-CLI-QUAL.

9. PCB mask — todos os campos

A PCB mask é a estrutura que o IMS atualiza após cada DL/I call. Conhecer todos os seus campos permite extrair informações detalhadas sobre cada operação.

CampoPICConteúdo após a call
DBD-NAME PIC X(08) Nome do DBD que o PCB está acessando
SEG-LEVEL PIC XX Nível hierárquico do segmento retornado (01, 02, 03...)
STATUS PIC XX Código de status da call (espaços = sucesso, GE, GB, etc.)
PROC-OPT PIC X(04) PROCOPT definido no PSB para este PCB
FILLER PIC X(04) Reservado — não usar
SEG-NAME PIC X(08) Nome do tipo de segmento acessado na última call
KEY-LENGTH PIC S9(05) COMP Comprimento da concatenated key no campo KEY-FEEDBACK
NUMB-SENS-SEGS PIC S9(05) COMP Número de segmentos sensitivos definidos no PCB
KEY-FEEDBACK PIC X(n) — n = KEYLEN Concatenated key: chaves de todos os segmentos no caminho desde o root até o segmento atual

Usando KEY-FEEDBACK para diagnóstico

O KEY-FEEDBACK contém as chaves concatenadas de todos os segmentos no caminho hierárquico até o segmento atual. É a "trilha de pão" do IMS — mostra exatamente onde você está na hierarquia.

COBOL — lendo o KEY-FEEDBACK após GU
      *    Após GU bem-sucedido em MOVIMENT (3 níveis):
      *    KEY-FDBK contém:
      *    [CPF do cliente (11 bytes)] [NUM conta (10 bytes)] [DATA mov (8 bytes)]

       01  PCB-BANCO.
           05 PCB-DBD-NAME   PIC X(08).
           05 PCB-SEG-LEVEL  PIC XX.
           05 PCB-STATUS     PIC XX.
           05 PCB-PROC-OPT   PIC X(04).
           05 FILLER         PIC X(04).
           05 PCB-SEG-NAME   PIC X(08).
           05 PCB-KEY-LEN    PIC S9(05) COMP.
           05 PCB-NUMB-SENS  PIC S9(05) COMP.
           05 PCB-KEY-FDBK.
               10 KF-CLI-CPF  PIC 9(11).      -- chave do CLIENTE
               10 KF-CTA-NUM  PIC X(10).      -- chave da CONTA
               10 KF-MOV-DATA PIC 9(08).      -- chave do MOVIMENT

       PROCEDURE DIVISION.
       1000-LER-MOVIMENT.
           CALL 'CBLTDLI' USING
               WS-SSA-3 WS-FUNC-GU PCB-BANCO
               WS-SEG-MOVIMENT
               WS-SSA-CLI-QUAL
               WS-SSA-CTA-QUAL
               WS-SSA-MOV-QUAL
           IF PCB-STATUS = SPACES
               DISPLAY 'CLIENTE CPF : ' KF-CLI-CPF
               DISPLAY 'CONTA NUM   : ' KF-CTA-NUM
               DISPLAY 'MOVIMENTO   : ' KF-MOV-DATA
               DISPLAY 'SEGMENTO    : ' PCB-SEG-NAME
               DISPLAY 'NIVEL       : ' PCB-SEG-LEVEL
           END-IF.

10. KEYLEN — calculando o valor correto

KEYLEN no PCB especifica o tamanho máximo da concatenated key — a soma dos sequence fields de todos os segmentos no caminho mais longo do root até o segmento mais profundo acessado pelo PCB. O IMS usa isso para alocar o buffer do KEY-FEEDBACK.

Cálculo de KEYLEN para BANCOCLI
Hierarquia:
  CLIENTE   — sequence field CLICPF  = 11 bytes  (packed, 6 bytes físicos)
    CONTA   — sequence field CTANUM  = 10 bytes  (character)
      MOVIMENT — sequence field MOVDATA = 8 bytes  (packed, 5 bytes físicos)

KEYLEN = BYTES de cada sequence field (tamanho lógico, não físico)
       = 11 + 10 + 8 = 29 bytes... mas o IMS usa regras de arredondamento:

Regra: KEYLEN = soma dos comprimentos definidos em BYTES= no FIELD SEQ
     = 11 (CLICPF) + 10 (CTANUM) + 8 (MOVDATA) = 29

Convenção segura: arredondar para cima ao próximo múltiplo ímpar
ou simplesmente usar 21 (se KEY-FEEDBACK for CHARACTER concatenado)

Na prática: consulte o DBA ou use KEYLEN gerado automaticamente.
✅ KEYLEN conservador
Um KEYLEN maior que o necessário não causa erro — apenas aloca um pouco mais de memória. Um KEYLEN menor que o necessário faz o IMS truncar o KEY-FEEDBACK. A prática mais segura é somar os BYTES de todos os sequence fields no caminho mais longo e adicionar 1 como margem.

11. DBDGEN, PSBGEN e ACBGEN

DBD e PSB são escritos em assembler mas nunca rodados diretamente — eles passam por utilitários que os compilam em módulos binários usados pelo IMS em runtime.

JCL — DBDGEN (compilar um DBD)
//DBDGEN   JOB (ACCT),'DBDGEN',CLASS=A,MSGCLASS=X
//STEP1    EXEC PGM=ASMA90,
//             PARM='DECK,NOOBJECT'
//SYSLIB   DD DSN=IMS.SDFSMAC,DISP=SHR    -- macros IMS
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD UNIT=SYSDA,SPACE=(CYL,(2,1))
//SYSUT2   DD UNIT=SYSDA,SPACE=(CYL,(2,1))
//SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(2,1))
//SYSPUNCH DD DSN=&&OBJDBD,DISP=(NEW,PASS),
//            SPACE=(CYL,(1,1))
//SYSIN    DD DSN=PROD.IMS.SOURCE(BANCOCLI),DISP=SHR
//*
//STEP2    EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=&&OBJDBD,DISP=(OLD,DELETE)
//SYSUT2   DD DSN=IMS.DBDLIB(BANCOCLI),DISP=SHR
//SYSIN    DD DUMMY
JCL — PSBGEN (compilar um PSB)
//PSBGEN   JOB (ACCT),'PSBGEN',CLASS=A,MSGCLASS=X
//STEP1    EXEC PGM=ASMA90,
//             PARM='DECK,NOOBJECT'
//SYSLIB   DD DSN=IMS.SDFSMAC,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD UNIT=SYSDA,SPACE=(CYL,(2,1))
//SYSUT2   DD UNIT=SYSDA,SPACE=(CYL,(2,1))
//SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(2,1))
//SYSPUNCH DD DSN=&&OBJPSB,DISP=(NEW,PASS),
//            SPACE=(CYL,(1,1))
//SYSIN    DD DSN=PROD.IMS.SOURCE(PGMBANKI),DISP=SHR
//*
//STEP2    EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=&&OBJPSB,DISP=(OLD,DELETE)
//SYSUT2   DD DSN=IMS.PSBLIB(PGMBANKI),DISP=SHR
//SYSIN    DD DUMMY
JCL — ACBGEN (gerar Application Control Block)
//ACBGEN   JOB (ACCT),'ACBGEN',CLASS=A,MSGCLASS=X
//STEP1    EXEC PGM=DFSRRC00,
//             PARM='UPB,ACBGEN'
//STEPLIB  DD DSN=IMS.RESLIB,DISP=SHR
//IMS      DD DSN=IMS.PSBLIB,DISP=SHR
//         DD DSN=IMS.DBDLIB,DISP=SHR
//IMSACB   DD DSN=IMS.ACBLIB,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  BUILD PSB(PGMBANKI)
/*
🦕 DBD → DBDGEN → ACBGEN → runtime
Pense no DBD como código-fonte (assembler), o DBDGEN como compilador (gera módulo em DBDLIB), e o ACBGEN como o linker (combina DBD + PSB num ACB em ACBLIB que o IMS carrega em milissegundos na abertura do banco). Qualquer mudança no DBD ou PSB exige reexecutar DBDGEN/PSBGEN e depois ACBGEN antes que o programa veja a mudança.

12. Índice secundário — acesso por campo não-chave

O índice secundário do IMS permite que um programa acesse segmentos por um campo que não é o sequence field primário. O fluxo é: buscar no banco de índice pelo campo secundário → obter a chave primária → buscar no banco principal pela chave primária.

COBOL — busca por nome usando índice secundário
      *    Área do segmento índice
       01  WS-SEG-IDX.
           05 IDX-NOME  PIC X(40).
           05 IDX-CPF   PIC 9(11).

      *    SSA para busca no índice por nome
       01  WS-SSA-IDX-NOME.
           05 FILLER    PIC X(08) VALUE 'CLINOMIDX'.
           05 FILLER    PIC X(01) VALUE '('.
           05 FILLER    PIC X(08) VALUE 'CLINOMX '.
           05 FILLER    PIC X(02) VALUE '= '.
           05 SSA-NOME  PIC X(40).
           05 FILLER    PIC X(01) VALUE ')'.

       2000-BUSCA-POR-NOME.
           MOVE 'MARIA SILVA                             '
               TO SSA-NOME

      *    Passo 1: busca no banco índice (PCB-INDICE)
           CALL 'CBLTDLI' USING
               WS-SSA-1 WS-FUNC-GU PCB-INDICE
               WS-SEG-IDX WS-SSA-IDX-NOME
           EVALUATE PCB-I-STATUS
               WHEN SPACES
                   CONTINUE
               WHEN 'GE'
                   DISPLAY 'NOME NAO ENCONTRADO'
                   GOBACK
               WHEN OTHER
                   PERFORM 9999-ERRO-IMS
           END-EVALUATE

      *    Passo 2: usa CPF retornado pelo índice para buscar no banco real
           MOVE IDX-CPF TO SSA-CLI-CPF
           CALL 'CBLTDLI' USING
               WS-SSA-1 WS-FUNC-GU PCB-BANCOCLI
               WS-SEG-CLIENTE WS-SSA-CLI-QUAL
           IF PCB-STATUS = SPACES
               DISPLAY 'CLIENTE ENCONTRADO: ' CLI-NOME
                       ' CPF: ' CLI-CPF
           END-IF.
🟣 Índice secundário vs acesso direto no banco
O índice secundário do IMS não é transparente — o programa precisa explicitamente acessar o banco de índice (PCB-INDICE) para obter a chave primária e depois acessar o banco real (PCB-BANCOCLI). Isso é diferente do DB2, onde um índice secundário é transparente ao SQL. A vantagem do IMS é controle explícito e previsibilidade de performance; a desvantagem é código mais verboso.

Resumo do fluxo completo: DBD a runtime

Pipeline completo de metadados IMS
DBA escreve:
  BANCOCLI.asm (DBD source)  →  DBDGEN  →  IMS.DBDLIB(BANCOCLI)
  PGMBANKI.asm (PSB source)  →  PSBGEN  →  IMS.PSBLIB(PGMBANKI)
                                    ↓
                                ACBGEN
                                    ↓
                          IMS.ACBLIB(PGMBANKI)
                                    ↓
Programador compila:
  PGMCRUD.cbl  →  compilador COBOL  →  IMS.LOADLIB(PGMCRUD)
                                    ↓
IMS em runtime:
  JCL executa DFSRRC00 com PARM='DLI,PGMCRUD,PGMBANKI,...'
    1. Carrega PGMBANKI de ACBLIB (PSB + DBDs pré-ligados)
    2. Carrega PGMCRUD de LOADLIB
    3. Chama ENTRY 'DLITCBL' passando PCBs na LINKAGE
    4. Processa cada CALL 'CBLTDLI' contra BANCOCLI