1. Return Codes — o que são
Quando um step termina, ele retorna um Return Code (RC) — um número inteiro de 0 a 4095 que indica o resultado da execução. Os valores mais comuns por convenção:
| RC | Significado convencional |
|---|---|
| 0 | Sucesso total — tudo certo |
| 4 | Sucesso com avisos — processou, mas com alguma advertência |
| 8 | Erro — processou com erros, resultado pode ser inválido |
| 12 | Erro grave — processamento abortado internamente |
| 16 | Erro fatal — não processou |
🦕 Analogia — RC é como a nota de uma prova
O RC é a "nota" que o programa dá para si mesmo ao terminar. RC=0 é 10 (perfeito), RC=4 é 7 (passou, mas com ressalvas), RC=8 é 4 (reprovado). O JCL pode olhar essa nota e decidir: "se o step anterior tirou menos que 5, não deixo o próximo step rodar".
✅ Utilitários IBM têm convenção própria
DFSORT retorna RC=0 (ok) ou RC=16 (erro grave). IDCAMS retorna RC=0, 4, 8 ou 12. O compilador COBOL (IGYCRCTL) retorna RC=0 (sem erros), RC=4 (warnings), RC=8 (erros de compilação), RC=12 (erros severos). Sempre verifique a documentação do utilitário que você está usando.
2. Setando RC no programa COBOL
Seu programa COBOL pode definir o Return Code que o job vai receber através do campo especial RETURN-CODE na WORKING-STORAGE:
WORKING-STORAGE SECTION. 01 WS-STATUS-PROC PIC X(01). 88 PROC-OK VALUE 'S'. 88 PROC-ERRO VALUE 'E'. PROCEDURE DIVISION. 0000-INICIO. PERFORM 2000-PROCESSAR IF PROC-OK MOVE 0 TO RETURN-CODE * RC=0: tudo ok ELSE MOVE 8 TO RETURN-CODE * RC=8: houve erros END-IF STOP RUN.
3. IF/THEN/ELSE/ENDIF no JCL
Introduzido no z/OS moderno, é a forma recomendada para controle de fluxo. Muito mais legível que o COND antigo.
// IF (condição) THEN //stepname EXEC PGM=programa * executado se condição TRUE // ELSE //stepname EXEC PGM=outro * executado se condição FALSE // ENDIF
💗 O IF do JCL não executa código — ele executa STEPs
Cuidado com a analogia com o IF do COBOL. No JCL, o IF não executa uma instrução — ele decide se um step inteiro (EXEC) vai rodar ou não. O bloco IF..ENDIF pode conter vários steps, todos condicionados ao mesmo teste.
4. Operadores de comparação
A condição do IF testa o RC do step indicado:
| Expressão | Alternativa simbólica | Significado |
|---|---|---|
RC = 0 | RC EQ 0 | RC igual a 0 |
RC > 0 | RC GT 0 | RC maior que 0 |
RC >= 4 | RC GE 4 | RC maior ou igual a 4 |
RC < 8 | RC LT 8 | RC menor que 8 |
RC <= 4 | RC LE 4 | RC menor ou igual a 4 |
RC ¬= 0 | RC NE 0 | RC diferente de 0 |
ABEND | — | Step terminou com abend |
RUN | — | Step foi executado |
//MEUJOB JOB ACCT,'LADY COBOL',CLASS=A,MSGCLASS=X //* Step 1: compila o programa //COMPILE EXEC PGM=IGYCRCTL //SYSPRINT DD SYSOUT=* //SYSIN DD DSN=LC001.COBOL.SOURCE(CALCFOL),DISP=SHR //* ... outros DDs da compilacao //* Se a compilacao ok (RC <= 4): faz o link e executa // IF (COMPILE.RC <= 4) THEN //LKED EXEC PGM=IEWL //* ... DDs do linkedit //EXEC EXEC PGM=CALCFOL //* ... DDs do programa // ELSE //* Se compilacao falhou: gera aviso //ERRO EXEC PGM=IEFBR14 //SYSOUT DD SYSOUT=* // ENDIF
Testando múltiplos steps e usando AND/OR
//* Executa STEP03 somente se STEP01 e STEP02 deram RC=0 // IF (STEP01.RC = 0 AND STEP02.RC = 0) THEN //STEP03 EXEC PGM=MEUPGM // ENDIF //* Executa limpeza se qualquer step teve abend // IF (STEP01.ABEND OR STEP02.ABEND) THEN //LIMPEZA EXEC PGM=IEFBR14 // ENDIF
5. Parâmetro COND (legado)
O COND é o mecanismo antigo, ainda muito presente em código legado. A lógica é invertida e confunde muita gente: a condição do COND é o que faz o step ser pulado — não o que faz ele rodar.
⚠️ A lógica invertida do COND
COND=(0,NE) parece dizer "execute se RC diferente de 0", mas na verdade diz:
"PULE este step se o RC de qualquer step anterior for diferente de 0"
Ou seja: execute APENAS se todos os steps anteriores tiverem RC=0. É exatamente o oposto do que a expressão sugere. Por isso o IF/THEN/ELSE foi criado — é muito mais legível. Prefira sempre o IF.
* COND=(valor, operador) — pula o step SE a condição for TRUE //STEP02 EXEC PGM=PROG2,COND=(0,NE) * "Pule STEP02 se qualquer RC anterior for NE (diferente) de 0" * = execute STEP02 apenas se todos anteriores tiveram RC=0 * Testar RC de um step especifico //STEP03 EXEC PGM=PROG3,COND=(4,LT,STEP01) * "Pule STEP03 se RC do STEP01 for LT (menor) que 4" * = execute STEP03 apenas se STEP01 tiver RC >= 4
6. COND=EVEN e COND=ONLY
Dois valores especiais do COND que controlam steps de limpeza e tratamento de erro:
| Valor | Comportamento | Uso típico |
|---|---|---|
COND=EVEN | Executa este step mesmo se steps anteriores sofreram abend | Steps de limpeza que devem rodar sempre |
COND=ONLY | Executa este step SOMENTE se um step anterior sofreu abend | Steps de tratamento de erro |
//STEP01 EXEC PGM=MEUPROG //* ... DDs //* Roda SEMPRE, mesmo se STEP01 abendou — faz limpeza //LIMPEZA EXEC PGM=IEFBR14,COND=EVEN //DSWORK DD DSN=PROD.WORK.TEMP,DISP=(OLD,DELETE) //* Roda SOMENTE se houve abend — envia alerta //ALERT EXEC PGM=SENDMAIL,COND=ONLY //SYSOUT DD SYSOUT=*
7. Cenários práticos completos
Cenário 1 — Pipeline de compilação, link e execução
//CLGJOB JOB ACCT,'LADY COBOL',CLASS=A,MSGCLASS=X //* STEP1: Compilacao //COMPILE EXEC PGM=IGYCRCTL,REGION=0M //STEPLIB DD DSN=IGY.V6R4M0.SIGYCOMP,DISP=SHR //SYSIN DD DSN=LC001.COBOL.SRC(CALCFOL),DISP=SHR //SYSLIN DD DSN=&&OBJETO,DISP=(NEW,PASS), // UNIT=SYSDA,SPACE=(TRK,(5,2)) //SYSPRINT DD SYSOUT=* //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(1,1)) //* Se compilacao ok, faz link-edit e executa // IF (COMPILE.RC <= 4) THEN //* STEP2: Link-Edit //LKED EXEC PGM=IEWL,REGION=0M //SYSLIN DD DSN=&&OBJETO,DISP=(OLD,DELETE) //SYSLMOD DD DSN=LC001.LOAD.LIB(CALCFOL),DISP=SHR //SYSPRINT DD SYSOUT=* //* STEP3: Execucao //EXEC EXEC PGM=CALCFOL //STEPLIB DD DSN=LC001.LOAD.LIB,DISP=SHR //ENTRADA DD DSN=PROD.FUNC.DADOS,DISP=SHR //SYSOUT DD SYSOUT=* // ENDIF //
🟣 IF aninhado — cuidado com a indentação
O JCL permite IFs aninhados (IF dentro de IF), mas a indentação não é obrigatória — o sistema não se importa com espaços extras. Em jobs complexos, é tentador encadear muitos IFs, mas isso torna o JCL difícil de manter. Uma alternativa melhor é usar Procedures com parâmetros simbólicos para encapsular a lógica de steps e manter o JCL principal limpo.