RPGLE in i5/OS V5R4

IDEs:

wiki context:

MISC

LIB

Definition Specification

------------------------------------------------------------------------------
     C                |                RPG
----------------------+-------------------------------------------------------
int x                 |   D   x           10I 0   VALUE
long x                |   D   x           10I 0   VALUE
long long x           |   D   x           20I 0   VALUE
unsigned int x        |   D   x           10U 0   VALUE
unsigned long x       |   D   x           10U 0   VALUE
unsigned long long x  |   D   x           20U 0   VALUE
double x              |   D   x            8F     VALUE
                      |
short *x              |   D   x            5I 0
int *x                |   D   x           10I 0
long *x               |   D   x           10I 0
long long *x          |   D   x           20I 0
unsigned short *x     |   D   x            5U 0
unsigned int *x       |   D   x           10U 0
unsigned long *x      |   D   x           10U 0
unsigned long long *x |   D   x           20U 0
float *x              |   D   x            4F
double *x             |   D   x            8F
------------------------------------------------------------------------------
      C               |                RPG
----------------------+-------------------------------------------------------
struct SSS s          |   D   s                   VALUE LIKE(SSS)
struct SSS *s         |   D   s                   LIKE(SSS)
TTT t                 |   D   t                   VALUE LIKE(TTT)
TTT *t                |   D   t                   LIKE(TTT)
char *s               |   D   s             *     VALUE OPTIONS(*STRING)
                      |OR D   s            nA
void *p               |   D   p             *     VALUE
                      |OR D   s                   LIKE(SSS)
wchar_t a             |   D   a            1C     VALUE
wchar_t a             |OR D   a            1G     VALUE
wchar_t *a            |   D   a            nC
wchar_t *a            |OR D   a            nG
------------------------------------------------------------------------------
Java Data Type    | ILE RPG Data Type           |  RPG Definitions
------------------+-----------------------------+-----------------------------
boolean           | indicator                   |  N
byte 1            | integer                     |  3I 0
                  | character                   |  1A
byte[]            | character length > 1        |  nA
                  | array of character length=1 |  1A DIM(x)
                  | date                        |  D
                  | time                        |  T
                  | timestamp                   |  Z
short             | 2-byte integer              |  5I 0
char              | UCS-2 length=1              |  1C
char[]            | UCS-2 length>1              |  nC
                  | array of UCS-2 length=1     |  1C DIM(x)
int               | 4-byte integer              | 10I 0
long              | 8-byte integer              | 20I 0
float             | 4-byte float                |  4F
double            | 8-byte float                |  8F
any java object   | object                      |   O CLASS(x)
any array         | array of equivalent type    |   DIM(x)
------------------------------------------------------------------------------

input Parameters

CALL MYLIB/MYPGM (HELLO)
      *--------------------------------------------------------------------------
     D action          S             10a
     D testname        s             10a
     C     *ENTRY        PLIST
     C                   PARM                    testname
      /free
        // if you dont pass a parameter, the program cant run
        monitor;
          action = %trim(''+testname);
        on-error;
          action = '';
        endmon;
 
        select;
            when action = 'SC';
                exsr search_for_cod_art;
            OTHER;
                dsply 'no valid action specified(SC,...)';
        endsl;
      /end-free

RPGLE basics

uppercase

     D U_case          C                   CONST('ABCDEFGHIJKLMNOPQRST-
     D                                     UVWXYZAEEIOU')
     D L_Case          C                   CONST('abcdefghijklmnopqrst-
     D                                     uvwxyzàèéìòù')
     $$_des = %xlate(l_case:u_case:$$_des);

strpos

     D $oo             S              5i 0
    $oo=%scan(%trim(priceV):$$_des:1);
    if $oo >= 1;
    endif;
// itera un'array a per settare un valore all'indice i
numrec = %elem(a);
for i=1 to numrec;
    a(i) = val;
endfor;

iterare una DS

     D CustomerInfo     DS                         QUALIFIED BASED(@)
     D    Name                               20A
     D    Address                            50A
 
     D ProductInfo      DS                         QUALIFIED BASED(@)
     D    Number                              5A
     D    Description                        20A
     D    Cost                                9P 2
 
     D SalesTransaction...
     D                  DS                         QUALIFIED
     D    Buyer                                    LIKEDS(CustomerInfo)
     D    Seller                                   LIKEDS(CustomerInfo)
     D    NumProducts                        10I 0
     D    Products                                 LIKEDS(ProductInfo)
     D                                             DIM(10)
 
      /free
          TotalCost = 0;
          for i = 1 to SalesTransation.Numproducts;
              TotalCost = TotalCost + SalesTransaction.Products (i).Cost;
              dsply SalesTransaction.Products (i).Cost;
          endfor;
          dsply ('Total cost is ' + %char(TotalCost));
      /end-free

select/switch

      /free
       Select;
         When sqlstt='00000';
           // row was received, normal
           ReturnVar=*on;
         When sqlstt='02000';
           // same as %eof, sooner or later this is normal
           ReturnVar=*off;
         Other;
           // alert the troops!
           ReturnVar=*off;
       EndSl;
       return ReturnVar;
      /end-free

error handling

/free
    MONITOR;
        OPEN FILE;
        DOW getNextRecord();
            X = X + 1;
            nameList(X) = name;
        ENDDO;
        CLOSE FILE;
        ON-ERROR 1216;
            DSPMSG ('Error opening file FILE':%status);
        RETURN;
        ON-ERROR 121;
            DSPMSG ('Array NAME is too small':%status);
        RETURN;
        ON-ERROR *ALL;
            DSPMSG ('Unexpected error':%status);
        RETURN;
    ENDMON;
 
       // parola chiave *PSSR;
       // error handling routine
       begsr *PSSR;
           o_errmsg='PSSR status:'+%char(%status());
           errore=*on;
           *inlr=*on;
           return;
       endsr;
 
      *-------------------------------------------------------------------------
      * PROTOTIPI
      *-------------------------------------------------------------------------
      * TODO: gestione degli errori standard
     d  o_err                        80a   dim(30)
     d  o_errn                        3s 0
     D set_error       PR
     D    msg                        80a   VALUE
 
 
/end-free

%status() BIF ritorna un errore numerico, la lista degli errori di sistema si ottien con:

DSPMSGD RANGE(*FIRST *LASTMSGF(QRNXMSGDETAIL(*BASIC)

es.
907 Si verificato un errore di dati decimali

exec platform commands

     D $cmd            s           1000a
     D exec            pr                  extpgm('QCMDEXC')
     D   cmd                      32702a   const
     D   cmdlen                      15p 5 const
       $cmd = 'CHGLIBL LIBL(MY_DAT)';
       exec($cmd:%len(%trim($cmd)));

prototypes

definizione di funzione

     D calc_int        PR            10I 0
     D    parm1                       5I 0 VALUE
      * must match the corresponding prototype
      * (PI is optional if the SubR does not return and does not have any parameters)
      * Other def of variables, constants and prototypes, are LOCAL definitions
      * Calc may refer to both local and global definitions
      * SubR must contain a RETURN operation
     P calc_int        B
     D calc_int        PI            10I 0
     D    parm1                       5I 0 VALUE
     D Result          S             10I 0
      /free
         Result = parm1 +1;
         return Result;
      /end-free
     P                 E
 
 
     D quote           PR            99a   VARYING
     D    sql                        99a   VALUE
      * ritorna una stringapreparata per SQL
     P quote           B
     D quote           PI            99a   VARYING
     D    sql                        99a   VALUE
     D $ap             C                   const('''')
      /free
         return $ap+%trim(sql)+$ap;
      /end-free
     P                 E

Chain

     * tabela base: controlla il file specification per sapere il tracciato record
     Fintct30L  uf a e           k disk    rename(intct0:intct_30)
     F                                     prefix(t_)
     D OrdRecKeys      ds                  likerec(intct_30:*key)
      /free
           // vantaggi %KDS: sempre aggiornata, tutti i campi disponibili, dimensioni corrette
           // la DS *key è automaticamente qualified
           OrdRecKeys.t_tcoage   = i_coage;
           OrdRecKeys.t_tanord   = i_anord;
           OrdRecKeys.t_tnuord   = i_nuord;
 
            chain(e) %kds(OrdRecKeys) intct_30;
            if %error;
              // TODO: report key not found
            endif;
            if %found();
                if t_tdaord;
                  // ... elabora il record come in fixed
                endif;
            endif;
      /end-free

SQL

basic setup

/free
exec SQL SET OPTION COMMIT=*NONE, CloSQLCsr =*ENDMOD, DatFmt =*ISO, TimFmt =*ISO, SqlPath=*LIBL
/end-free
  • CURRENT SCHEMA: used to find files/tables, views and indexes => DATA
  • SQL PATH: used to find Stored Procedures => PROGRAMS
/free
exec SQL SET PATH = system path, php_obj;
// PATH is only used to find "programs" but not "data", CURRENT SCHEMA is used for data
exec SQL SET CURRENT PATH = *LIBL
exec SQL SET PATH = *LIBL
 
 
// uses the *LIBL for unqualified access
exec sql SET OPTION NAMING = *SYS;
// you can get only unqualfied access for files within current library
exec sql SET OPTION NAMING = *SQL;
 
 
/end-free

The CURRENT SCHEMA is either the library/schema with the same name as the user profile or is set by executing the SQL Command SET CURRENT SCHEMA.

/free
exec sql SET CURRENT SCHEMA = X;
/end-free

to access tables outside *LIBL, you need to qualify SQL tables used

SQL operation result:

// The SQLCODE is also set by the database manager after each SQL
// statement is executed as follows:
//   - If SQLCODE = 0 and SQLWARN0 is blank, execution was successful.
//   - If SQLCODE = 100, no data was found. For example, a FETCH
//       statement returned no data, because the cursor was positioned
//       after the last row of the result table.
//   - If SQLCODE > 0 and not = 100, execution was successful with a warning
//   - If SQLCODE = 0 and SQLWARN0 = 'W', execution was successful with a warning
//   - If SQLCODE < 0, execution was not successful
Psql_found        B
D                 PI              N
 /free
  return (SQLCOD >= 0) and (SQLCOD<>100);
 /end-free
Psql_found        E

select values:

/FREE
exec SQL  SELECT FName, LName, email INTO :fstname,:lstname,:email
  FROM  contacts
    WHERE cstnbr = :client
    FETCH FIRST ROW ONLY;
 
    if (SQLSTATE >= '02000'); // Record not found?
        // NOT FOUND processing here.
    else;  We got it!
        // FOUND processing here.
    endif
/end-free
/FREE
  exec sql insert into contacts
           values(DEFAULT, 'Bob', 'Cozzi', DEFAULT, :email);
  // IDENTITY_VAL_LOCAL() returns the most recently generated IDENTITY value
  exec sql VALUES IDENTITY_VAL_LOCAL() INTO :client_id;
  // modifica seguente
  exec sql update contacts set FName = 'Bob', LName = 'Cozzi', email = :email
           where cstnbr = :client_id;
/end-free

SQL paginazione con cursore

// ritorna da $pos, $nrows righe
exec sql FETCH RELATIVE :$pos FROM C1 FOR :$nrows ROWS INTO :$rs_ec;

SQL lanciare una query e leggere il risultato embed SQL tutorial

      * prototipo
     D calcTotOrdine   PR             8s 2
     D    inuord                      5I 0 VALUE
     D    icocli                      6a   VALUE
      * definire all afine della C spec, dopo *PSSR
     P calcTotOrdine   B
     D calcTotOrdine   PI             8s 2
     D    inuord                      5I 0 VALUE
     D    icocli                      6a   VALUE
     D* Result          S             10I 0
     D $rs_row         ds                  OCCURS(1000) INZ QUALIFIED
     D  ipreva                        8S 2
     D  iquaor                        5I 0
     D $sqlSelectRow   S          32000a   varying
     D $nrSelect       S              5I 0
     D $nRecRead       S              5I 0
     D $i              S              5I 0
     D $result         S              8s 2 inz(0)
      /free
       $sqlSelectRow = ' select xxx, yyyy '
           +' from xsxs00f '
           +' where         '
           +'  icocli= '+FQ+TCOCLI+FQ
           +'  and inuord='+%char(TNUORD)
           +'  and itipre<>' +FQ + 'A' +FQ ;
       // TODO: rinomina S4 e C2
       exec sql prepare S4 FROM :$sqlSelectRow;
       if SQLCOD<>0;
           errore = *on;
           o_errmsg  = 'sql error SQLCOD: '+%char(SQLCOD) ;
       endif;
       exec sql DECLARE C2 INSENSITIVE SCROLL CURSOR FOR S4;
       exec sql OPEN C2;
 
       exec sql get diagnostics :$nrSelect  = DB2_NUMBER_ROWS;
       if $nrSelect  = 0;
           exec sql close C2;
           return 0;
       endif;
 
       exec sql FETCH RELATIVE 1 FROM C2
       FOR :$nrSelect  ROWS INTO :$rs_row;
       if SQLCOD<>0;
           errore = *on;
           o_errmsg  = 'fetch error SQLCOD: '+%char(SQLCOD);
       endif;
 
       exec sql get diagnostics :$nRecRead = ROW_COUNT;
       //     if $n_rec_read <= 0;
       //      o_errmsg = '0 rec found';
       //      leavesr;
       //     endif;
 
       for $i=1 to $nRecRead;
           %OCCUR($rs_row) = $i;
           $result += ($rs_row.ipreva * $rs_row.iquaor);
       endfor;
 
       exec sql close C2;
       return $result;
      /end-free
     P                 E
     * per estrarre tutti i campi
     D $zntcl        E DS                  QUALIFIED OCCURS( 50 ) INZ
     D                                     EXTNAME( zntcl00f )

SELECT INTO DS**

     D $matM2          ds                  QUALIFIED
     D  des1                         70a
     D  des2                         70a
     exec sql select padem1, padem2 into :$MATM2 from MATM200f
         where key = :var
         FETCH FIRST ROW ONLY;
     if SQLCOD<>0;
        errore = '1';
        o_errstr  = 'SQL error SQLCOD: '+%char(SQLCOD) ;
        o_errn = SQLCOD;
     endif;

per debuggare SQL, controlla risultati della singola operazione

EV SQLCODE // return code
EV SQLSTT  // stato
EV SQLERM  // err message
 
// better error message
DSPMSGD RANGE(SQL0326) MSGF(QSQLMSG)

call stored procedure:

/free
    exec SQL SET PATH *LIBL;
    exec SQL Call SP_MYPROC(:param);
/end-free

include require

/copy espande inserisce sorgente nel listato(si vede da joblog) temporaneo da compilare

      ** copy di prototipi
      /copy *libl/srccpy,cpy_protxx
 
      ** copy di una DS
      /copy *libl/srccpy,cpy_pssr01
 
      ** copy di una C spec
      /copy *LIBL/srccpy,cpy_errsql

per proteggere da include multipli dovuti a dipendenze multiple

/IF NOT DEFINED __HTTPAPI_H__
/DEFINE __HTTPAPI_H__
    // code goes here
/ENDIF
 
/if defined(__HTTPAPI_H__)
/eof
/endif

la direttiva /include è uguale a /copy ma non funziona con i file .sqlrpgle

Trubleshooting

"Errore di livello nel file" : ricompilare il programma che accede a un file con una signature vecchia

Causa . . . . . :   La procedura RPG MYPGM001 nel programma MYOBJ/MYPGM001
  ha ricevuto il messaggio CPF4131 durante l'esecuzione di un'operazione OPEN
  implicita sul file AABBC30L. Il file effettivo è AABBC30L.
Correzione . . . :Controllare la registrazione lavori per una descrizione

It's a record format level check. This means that the record format in the file you are opening does not have the same format level ID that was found when the program was compiled.

You should enter the command DSPFD against the file, near the bottom you'll find the format name and the format identification level and fields count, then enter the command DSPPGMREF against the program that fail, find the format id required, than look at runtime *LIBL of the program and which file it will use, the error says it has a different signature. compile with correct signature or change runtime *LIBL

// verificare errori di compilazione
// e vedi quali files con percorso assoluto sono utilizzati
WRKSPLF SELECT(*CURRENT *ALL *ALL *ALL *ALL OR*)
 
// job in esebuzione bloccati?
// con quale *LIBL gira il programma?
WRKUSRJOB USER(PHPWEB)
WRKACTJOB job(PHPJOB)
 
// quali files vengono utilizzati dal programma
DSPPGMREF PHP_OBJ/MYPROGRAM004
 
// id formato file, numero campi, lunghezza record dei files coinvolti
DSPFD MILIB/MYFILE00L