1. O que é uma Procedure
Uma Procedure JCL é um bloco nomeado de statements JCL (um ou mais steps) que pode ser chamado e reutilizado por vários jobs. Em vez de repetir os mesmos 30 linhas de JCL em cada job, você define a procedure uma vez e a chama com EXEC PROC=nome.
🦕 Analogia — procedure é como uma receita de bolo
Uma receita de bolo de chocolate está escrita no caderno da vovó. Qualquer pessoa da família pode fazer o bolo seguindo a receita — e pode customizar substituindo o chocolate amargo por ao leite (override de parâmetro). A receita não muda, só o ingrediente passado muda. É exatamente isso: a procedure é a receita, e você passa os ingredientes via parâmetros simbólicos.
2. Instream Procedure
Definida dentro do próprio job, antes do primeiro //nome JOB... espera, na verdade instream procedures ficam depois do JOB card e antes dos steps que a chamam, delimitadas por PROC e PEND.
//MEUJOB JOB ACCT,'LADY COBOL',CLASS=A,MSGCLASS=X //*--------------------------------------------------------* //* Definição da instream procedure COPIAPROC * //*--------------------------------------------------------* //COPIAPROC PROC DSN1=PADRAO.ENTRADA, * param com default // DSN2=PADRAO.SAIDA //COPYSTEP EXEC PGM=IEBGENER //SYSUT1 DD DSN=&DSN1,DISP=SHR * usa o parametro //SYSUT2 DD DSN=&DSN2, // DISP=(NEW,CATLG,DELETE), // UNIT=SYSDA,SPACE=(TRK,(5,2)), // LIKE=&DSN1 //SYSIN DD DUMMY //SYSPRINT DD SYSOUT=* // PEND * fim da definição da procedure //*--------------------------------------------------------* //* Chamadas à procedure com parâmetros diferentes * //*--------------------------------------------------------* //EXEC01 EXEC COPIAPROC, // DSN1=PROD.FUNC.JAN, // DSN2=BKUP.FUNC.JAN //EXEC02 EXEC COPIAPROC, // DSN1=PROD.FUNC.FEV, // DSN2=BKUP.FUNC.FEV
✅ Quando usar instream procedure
Use quando a procedure é específica para aquele job e não precisa ser compartilhada com outros jobs. São boas para testes ou para encapsular lógica de steps repetidos dentro de um mesmo job longo.
3. Cataloged Procedure
Armazenada permanentemente em um PROCLIB (biblioteca de procedures) — geralmente SYS1.PROCLIB ou uma biblioteca do site. Qualquer job pode chamar sem precisar definir a procedure localmente.
//MEUJOB JOB ACCT,'LADY COBOL',CLASS=A,MSGCLASS=X //* Chama a proc COBUCL (compilacao COBOL catalogada) //COMPILE EXEC COBUCL, // MEMBER=CALCFOL, * nome do fonte // SRCLIB=LC001.COBOL.SRC * biblioteca do fonte //
💗 Como descobrir quais procedures existem no site
No ISPF, use o comando ISRDDN ou pesquise nos datasets da JCLLIB/PROCLIB. Muitos sites também têm documentação interna listando as procedures disponíveis e seus parâmetros. Outra forma: se você tiver o nome, use EDIT 'SYS1.PROCLIB(NOMEPROC)' para ler o fonte da procedure.
4. Parâmetros simbólicos
Parâmetros simbólicos são variáveis dentro da procedure, indicadas com &. Você define os defaults no PROC e sobrescreve na chamada.
| Onde | Sintaxe | Exemplo |
|---|---|---|
| Definição (padrão) | //nome PROC SYM=valor-default | //MINHA PROC ENV=PROD,MES=202412 |
| Uso dentro da proc | &SIMBOLO ou &&SIMBOLO | DSN=&ENV..FUNC.&MES |
| Na chamada | EXEC NOMPROC,SYM=valor | EXEC MINHA,ENV=TEST,MES=202411 |
⚠️ &SIM vs. &SIM.. — os dois pontos importam
Quando o símbolo é seguido imediatamente por letras ou números (sem separador), você precisa de dois pontos para delimitar o nome: &ENV..DADOS significa o valor de ENV seguido de ".DADOS". Sem os pontos duplos, o sistema tentaria interpretar "ENVDADOS" como um único símbolo. Isso é um dos erros mais comuns ao escrever procedures.
//* Definição da procedure no PROCLIB //PROCFOL PROC ENV=PROD, * ambiente: PROD ou TEST // MES=202412, * mes de referencia // REGIAO=128M * regiao de memoria //CALCSTEP EXEC PGM=CALCFOL,PARM='&MES', // REGION=®IAO //STEPLIB DD DSN=&ENV..LOAD.LIB,DISP=SHR * ^-- ENV + ".LOAD.LIB" = PROD.LOAD.LIB ou TEST.LOAD.LIB //ENTRADA DD DSN=&ENV..FUNC.&MES,DISP=SHR * ^-- PROD.FUNC.202412 ou TEST.FUNC.202411 //SYSOUT DD SYSOUT=* // PEND //*-- Chamada em producao (usa defaults) //RODAR EXEC PROCFOL //*-- Chamada em teste com outro mes //TESTAR EXEC PROCFOL, // ENV=TEST, // MES=202411
5. Override de DDs e parâmetros
Mesmo após chamar uma procedure, você pode sobrescrever DDs específicos adicionando um DD com o mesmo nome após o EXEC. A sintaxe usa stepname.ddname:
//MEUJOB JOB ACCT,'LADY COBOL',CLASS=A,MSGCLASS=X //EXECPROC EXEC PROCFOL,ENV=TEST //* Override: substitui o DD ENTRADA definido na proc //* Formato: //stepname.ddname DD ... //CALCSTEP.ENTRADA DD DSN=TEST.FUNC.ESPECIAL,DISP=SHR //* Override: redireciona SYSOUT para arquivo em vez de spool //CALCSTEP.SYSOUT DD DSN=TEST.SAIDA.LOG, // DISP=(NEW,CATLG,DELETE), // UNIT=SYSDA,SPACE=(TRK,(2,1)) //
6. Procedures aninhadas
É possível chamar uma procedure a partir de outra (nesting), mas com uma limitação importante: no máximo 2 níveis de aninhamento (uma procedure chamando outra, mas não uma terceira dentro da segunda).
⚠️ Instream procedures não podem ser aninhadas
Apenas Cataloged Procedures podem ser aninhadas. Tentar aninhar uma instream procedure causa erro de JCL. Em ambientes complexos, a abordagem mais limpa é ter procedures catalogadas bem projetadas com parâmetros simbólicos em vez de aninhar profundamente.
7. Exemplo real: proc de compilação COBOL
Veja uma procedure completa de compilação COBOL, semelhante ao que você encontraria em ambientes reais:
//*============================================================* //* PROC : COBCOMP * //* DESCR: Compila um programa COBOL e gera o objeto * //* PARAM: SRCLIB = biblioteca de fontes COBOL * //* MEMBER = nome do membro a compilar * //* LOADLIB = biblioteca de destino do objeto * //*============================================================* //COBCOMP PROC // SRCLIB=PROD.COBOL.SOURCE, // MEMBER=PROGRAMA, // LOADLIB=PROD.LOAD.LIB, // REGION=0M //* Step 1: Compilacao //COMPILE EXEC PGM=IGYCRCTL,REGION=®ION //STEPLIB DD DSN=IGY.V6R4M0.SIGYCOMP,DISP=SHR //SYSIN DD DSN=&SRCLIB(&MEMBER),DISP=SHR //SYSLIN DD DSN=&&OBJETO,DISP=(NEW,PASS), // UNIT=SYSDA,SPACE=(TRK,(10,5)) //SYSPRINT DD SYSOUT=* //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(3,1)) //SYSUT2 DD UNIT=SYSDA,SPACE=(CYL,(3,1)) //SYSUT3 DD UNIT=SYSDA,SPACE=(CYL,(3,1)) //SYSUT4 DD UNIT=SYSDA,SPACE=(CYL,(3,1)) //* Step 2: Link-Edit (so roda se compilacao ok) // IF (COMPILE.RC <= 4) THEN //LKED EXEC PGM=IEWL,REGION=0M //SYSLIN DD DSN=&&OBJETO,DISP=(OLD,DELETE) // DD DSN=CEE.SCEELKED,DISP=SHR * runtime LE //SYSLMOD DD DSN=&LOADLIB(&MEMBER),DISP=SHR //SYSPRINT DD SYSOUT=* // ENDIF // PEND * fim da procedure COBCOMP
Chamando a procedure no job
//COMPJOB JOB ACCT,'LADY COBOL',CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID //* Compila CALCFOL da library de desenvolvimento //STEP01 EXEC COBCOMP, // SRCLIB=LC001.COBOL.SOURCE, // MEMBER=CALCFOL, // LOADLIB=LC001.LOAD.LIB //* Compila RELAT-MES com defaults da proc //STEP02 EXEC COBCOMP, // MEMBER=RELATMES * so sobrescreve o MEMBER //
🟣 JCLLIB — onde o JES procura as procedures
Por padrão, o JES procura procedures no SYS1.PROCLIB e outras bibliotecas configuradas no sistema. Você pode adicionar suas próprias bibliotecas usando o statement JCLLIB ORDER= antes do primeiro EXEC:
//MYLIBS JCLLIB ORDER=(MINHA.PROCLIB,SYS1.PROCLIB)
Isso é útil para trabalhar com procedures em desenvolvimento antes de movê-las para a biblioteca oficial de produção.