AS/400 Capítulo 7: Módulos e Procedimentos

A utilização de módulos revela-se extremamente útil, principalmente em grandes aplicações, pois permite a reutilização de código de forma relativamente simples.

Um módulo é um componente de um programa executável. Quando compilamos um módulo não obtemos um programa executável, mas antes uma unidade que, quando interligada com outras, resulta no programa executável.

Um módulo pode ser constituído por um ou mais procedimentos. Um procedimento é uma espécie de função. É possível passar variáveis por parâmetro e retornar valores de um procedimento.

Uma das vantagens dos módulos é permitir a reutilização do código, visto que o mesmo módulo pode ser utilizado por mais que um programa.

Criação de um programa a partir de módulos

Os módulos são interligados com o comando:

CRTPGM(PGM_NAME) MODULE(MAIN_MOD MOD1 MOD2...)

Assume-se sempre que o primeiro módulo da lista é o principal. Neste caso, MAIN_MOD é o módulo principal do programa.

Para chamar o programa só tem que escrever no prompt: CALL PGM_NAME

Criação dos módulos

Vamos criar dois módulos que depois vamos interligar. O que os nossos módulos vão fazer é o seguinte: o módulo principal envia uma data de aniversário para um procedimento noutro módulo; este por sua vez retorna o número de anos passados desde essa data (a idade). Vamos fazer isto para todos os elementos da tabela clientes.

Vamos começar pelo módulo principal. Comece por criar um ficheiro SQLplain com o nome MAIN_MOD.

Defina uma variável do tipo data que vai guardar o valor da data de aniversário - chame-lhe birth. Define também uma variável numérica para guardar a idade retornada - chame-lhe age.

Vamos construir um cursor para correr a tabela de clientes. Para isso temos que ter 4 sub-rotinas para as seguintes funções:

Declarar o cursor (declareCursor)

DECLARE CURSOR1 CURSOR FOR SELECT BIRTH_CLI
FROM DEMO/CLIENTS

Abrir o cursor (openCursor)

OPEN CURSOR1

Ir buscar dados ao cursor (fetchCursor)

FETCH CURSOR1 INTO :birth

Fechar o cursor (closeCursor)

CLOSE CURSOR1

Agora na parte principal do programa vamos ter que chamar a subrotina para declarar e depois para abrir o cursor, dentro de um ciclo fazer o fetch do cursor e depois fechar o cursor. Pode fazer o ciclo da seguinte maneira:

    exSr fetchCursor;
    dow sqlcod <> 100;
        ...
        exSr fetchCursor;
    enddo;

Ou:

dow sqlstt = '00000';
    exSr fetchCursor;
    ...
enddo;

As variáveis sqlcod e sqlstt guardam o estado que resulta da última instrução de SQL. O sqlstt = '00000' representa sucesso, enquanto que o sqlcod = 100 indica que a instrução não retornou nenhuns dados.

Mais informações sobre estes códigos.

Vamos deixar este módulo assim e passar agora ao módulo com o procedimento que calcula a idade e no final fazemos a ligação entre os dois.

Feche e guarde as alterações ao ficheiro MAIN_MOD. Crie outro ficheiro CALC_AGE do tipo plain.

Na primeira linha deste ficheiro deve constar HNOMAIN,a partir da 1º coluna do SEU,o que significa que este módulo não vai ser um módulo principal.

Procedimentos

Vamos ver agora como funciona a declaração de procedimentos e a passagem de parâmetros.

Um procedimento é delimitado pelas linhas:

Pnome_proc B EXPORT
Dnome_proc PI 3i 0
Dparametro1 D

...declarações de código

P E

Linha 1

Definição do início do procedimento que começa com o carácter P (procedimento), o B (begin) define o início do procedimento, assim como o E (end) da linha 4 indica o fim. A palavra EXPORT permite que outros módulos usem este procedimento, ou seja, o procedimento é público a todos os módulos. Se a palavra EXPORT não estivesse definida, o procedimento só seria visível pelo módulo onde está definido.

Linha 2

Repete-se o nome do procedimento, só que desta vez temos uma especificação D. Esta linha está a declarar o tipo de retorno '3i 0', ou seja, um inteiro com comprimento de 3 e 0 casas decimais. Caso não seja retornado nenhum valor deve-se declarar esta linha sem definir o tipo de variável, neste caso não se definiria o '3i 0'.

Linha 3

Define o parâmetro recebido. Um procedimento pode receber mais que um parâmetro e cada um deles deve estar definido numa linha diferente. Por defeito um parâmetro é passado por referência, mas se usarmos a palavra chave VALUE no campo das functions o parâmetro é passado por valor. Com a palavra chave CONST o parâmetro é passado por referência, mas só são permitidas operações de leitura sobre ele.

Linha 7

Fim do procedimento. Defina agora o início e o fim do procedimento CALC_AGE (tem o mesmo nome que o ficheiro, mas poderia ter outro qualquer), que vai receber por parâmetro uma data e retornar um inteiro. Defina também uma variável auxiliar que vai guardar o valor da idade. Quando terminar de fazer isto, verifique se o seu código ficou como o que está em baixo e coloque no seu código a linha 6.

Dage S 3P 0
PCALC_AGE B EXPORT
dCALC_AGE PI 3i 0
Db_date D
/free
age = %diff (%date() : b_date : *years);
return age;
/end-free
P E 

Linha 6

A função %date() retorna a data actual do sistema. A função diff faz a diferença entre as duas datas (%date() e b_date) em anos (*years). Repare que existem dois pontos (:) a separar cada valor - este é o separador de parâmetros utilizado em RPG, como temos por exemplo a vírgula em C++, Java, etc. Se quiser saber mais informações sobre manipulação de datas em RPG consulte este site.

Linha 7

Para retornar um valor usamos a função return. Falta ainda um pormenor na declaração de procedimentos. Sempre que criamos um procedimento ou quando o vamos invocar, devemos ter no cabeçalho do ficheiro a declaração do protótipo da função. Que seria algo deste género:

DCALC_AGE         PR             3i 0
Db_date                           D

Portanto, no ficheiro CALC_AGE vamos ter que definir estas linhas (podem estar antes ou depois da variável age). Repare que no protótipo está a definir o tipo de retorno e o parâmetro recebido. Estes valores têm de coincidir com os que indicamos no início do procedimento.

Ficamos assim com o resultado final:

     *
     HNOMAIN
     *
     Dage S 3P 0
  
     DCALC_AGE PR 3i 0
     Db_date D
     *
     PCALC_AGE B EXPORT
     dCALC_AGE PI 3i 0
     Db_date D
      /free
          age = %diff (%date() : b_date : *years);
          return age;
      /end-free
     P                 E

Voltando ao MAIN_MOD, só nos falta agora declarar o protótipo deste procedimento e invocá-lo. Voltemos então a este ficheiro. Deve estar com algo deste género:

     Dbirth s d
     Dage s 3i 0
      /free
           exsr declareCursor;
           exsr openCursor;
           exsr fetchCursor;
  
           dow sqlcod <> 100;
               exsr fetchCursor;
           enddo;
           exsr closeCursor;
  
           *inlr = *on;
           return;
      /end-free
  
     *
     * sub-routines declaration
     *

Defina agora o protótipo do procedimento, exactamente igual ao que colocou no outro ficheiro. Dentro do ciclo é necessário chamar o procedimento:

age = CALC_AGE(birth);

O ciclo ficaria então assim:

dow sqlcod <> 100;
    age = CALC_AGE(birth);
    dsply age;
    exsr fetchCursor;
enddo;

Compilação de módulos

Compile os dois módulos, mas tenha no entanto atenção pois um módulo não é compilado da mesma forma que outro ficheiro qualquer. Um módulo é compilado com a opção 15 do PDM 'Create Module'. Depois da compilação bem sucedida faça a ligação entre os módulos e teste o programa. Vamos ver a seguir como interligar os módulos.

Criação de um programa a partir de módulos

Os módulos são interligados com o comando:

CRTPGM(PGM_NAME) MODULE(MAIN_MOD MOD1 MOD2...)

Assume-se sempre que o primeiro módulo da lista é o principal. Neste caso, MAIN_MOD é o módulo principal do programa.

Para chamar o programa só tem que escrever no prompt: CALL PGM_NAME

Artigos relacionados