01 - Programmazione01a - RPG

RPG – FAQ & Howtos (IT Part.3)

Terza puntata della serie RPG – FAQ & Howtos, le puntate precedenti le trovate qui;

RPG-FAQ-021: PTF SI73189 (7.3 TR8 e 7.4 TR2) – Timestamp ed errore MCH4437

La compilazione di programmi RPG che utilizzano Timestamp su una partizione IBM i aggiornata con la PTF SI73189 potrebbe generare errori (MCH4437) nel caso che l’oggetto della compilazione venga spostato su una partizione senza installata quella PTF.

Naturalmente la soluzione migliore sarebbe quella di aggiornare entrambe le partizioni con le stesse PTF … ma se non fosse possibile una alternativa è quella di interventire su una Variabile di Ambiente (grazie a Barbara Morris per il suggerimento) nella partizione di compilazione (quella aggiornata con la PTF indicata)

ADDENVVAR QIBM_RPG_DISABLE_TIMESTAMP_MICROSEC VALUE('Y')
volendo è possibile settarlo anche a livello di sistema
ADDENVVAR QIBM_RPG_DISABLE_TIMESTAMP_MICROSEC VALUE('Y') LEVEL(*SYS)
ricordandosi di fare un signoff-signon pe "caricare" questa variabile di ambiente

RPG-FAQ-022: Service Program e *DEFER

I vantaggi dei service program nello sviluppo di applicazioni ILE probabilmente lo conosciamo tutti, ma forse non tutti sanno che i services program, proprio per garantire le migliori prestazioni, vengono “caricati” tutti alla creazione / apertura del activation group: questo significa che se il numero dei service program diventa “importante” potremmo avere dei problemi di prestazioni proprio al primo caricamento del programma (o creazione dell’Activation Group).

Oltre al problema di prestazioni un altro problema potrebbe essere quello della lista delle librerie che deve essere “impostata” proprio al caricamento iniziale del programma.

Utilizzare la keyword *DEFER in fase di compilazione del programma nella definizione dei service program… in questo caso il service program verrà caricato solo al momento del suo primo utilizzo … demandando il caricamento in memoria in quel momento e quindi “alleggerendo” l’apertura iniziale e permettendo di “settare” la lista delle librerie solo all’effettivo utilizzo:

CRTPGM PGM(YOURLIB/YOURPGM)                           
       MODULE(*PGM)                                   
       BNDSRVPGM((*LIBL/YOURSRVPGM *DEFER))

oppure ... quando si aggiunge il service program alla Bind Directory

ADDBNDDIRE BNDDIR(FAQ400/MYBINDDIR) OBJ((FAQ400/MYSRVPGM *SRVPGM *DEFER))

Il problema della libreria è naturalmente risolvibile anche indicandola esplicitamente in compilazione o all’aggiunta della Binddire:

CRTPGM PGM(YOURLIB/YOURPGM)                           
       MODULE(*PGM)                                   
       BNDSRVPGM((YOURLIB/YOURSRVPGM))

RPG-FAQ-023: Come evitare l’errore MCH3402 quando si sostituisce un oggetto programma

Se ne è parlato su Midrange.com in questi giorni: come evitare l’errore MCH3402 quando si sostituisce un oggetto programma con una nuova versione. Sappiamo che se compiliamo con REPLACE(*YES) la vecchia versione dell’oggetto viene spostata nella QRPLOBJ e l’errore non si presenta … ma, alle volte, magari proprio per delle Fix veloci, risulta più comodo e meno rischioso, recuperare oggetti programma magari da un backup utilizzando MOVOBJ … creando, spesso, l’errore MCH3402 nei Job che tentato di accedere alla vecchia versione dell’oggetto.

Anche la tecnica di utilizzare una libreria “NEWOBJ” da mettere davanti nella *LIBL non risolve del tutto il problema …

Una soluzione interessante è quella di utilizzare la API QLIRNMO … magari tramite una interfaccia come quella di CARSTEN FLENSBURG in questo vecchio, ma pur sempre valido, post: “APIS BY EXAMPLE: MOVE AND RENAME OBJECT API, AND IBM CL COMMAND REUSE”.

RPG-FAQ-024: Quali programmi usano il mio service program?

Se voglio sapere quali sono i programmi che usano il mio service program posso utilizzare gli IBM i services … e, in particolar modo, il QSYS2.BOUND_SRVPGM_INFO … con una istruzione SQL tipo questa:

SELECT *
  FROM QSYS2.BOUND_SRVPGM_INFO
  WHERE BOUND_SERVICE_PROGRAM = 'MYSRVPGM';

Un’altra alternativa … per versioni di OS un po’ più vecchie possiamo arrivarci tramite DSPPGMREF:

DSPPGMREF PGM(MYLIBPGM/*ALL) OUTPUT(*OUTFILE) OBJTYPE(*PGM) OUTFILE(MYLIB/MYPGMREF)

select * from MYLIB.MYPGMREF where whfnam='MYSRVPGM' and whotyp='*SRVPGM';                                                                       

RPG-FAQ-025: Quali procedure esportano i miei service program?

Un modo semplice da linea comando è DSPSRVPGM SRVPGM(MYSRVPGM), oppure passando dai moduli DSPMOD MODULE(MYSRVPGM) DETAIL(*EXPORT)

… oppure usando SQL e gli IBM i Service SQL:

 SELECT *
  FROM QSYS2.BOUND_SRVPGM_INFO
  WHERE BOUND_SERVICE_PROGRAM = 'MYSRVPGM';

RPG-FAQ-026: Ricercare righe modificate in diversi sorgenti in un certo periodo

Se con FNDSTRPDM possiamo cercare una particolare stringa in un file sorgente, con Rational Rdi e le sue ricerche possiamo lavorare anche su più file sorgenti. Meglio ancora con le funzioni di ricerca di Isphere, l’ottimo plugin di Rational Rdi.

Non abbiamo però la possibilità di cercare tutte le righe modificate ieri, o in un intervallo di date particolare, su diversi membri e file sorgenti.

Se ne è parlato su una mailing list di Midrange.com, dove Sam Lennon ha proposto una ottima Stored Procedure SQL per fare questo tipo di ricerca:

-- First, create a table for the search summary
create table faq400.srcfnd 
(plib char(10) not null default '',
pfile char(10) not null default '',
pmember char(10) not null default '',
vsrcseq char(10) not null default '',
vsrcdat char(10) not null default '',
vsrcdta char(100) not null default '');

-- Then create a Stored Procedure
CREATE OR REPLACE FUNCTION faq400.src_line_date(
   plib varchar(10),
   pfile varchar(10),
   pmember varchar(10),
   pymdfrom numeric(6),
   pymdto numeric(6)
)
RETURNS INTEGER
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
   declare SQLCODE Integer Default 0;
   declare insert_count integer default 0;
   declare vsrcseq numeric(6,0);
   declare vsrcdat numeric(6,0);
   declare Vsrcdta varchar(256);
   declare alias_name varchar(40);
   declare skip_recd integer;
   declare bad_data condition for SQLSTATE '22023'; --Invalid data
   declare src_mbr CURSOR FOR
     select * from qtemp.zz_src where srcdat between pymdfrom and pymdto;
   declare continue handler for bad_data
     set skip_recd = 1;
   set alias_name = plib concat '."' concat pfile
     concAT '"("' concat pmember concat '")';
   execute immediate 'create alias qtemp.zz_src FOR ' concat alias_name;
   OPEN src_mbr;
   LblLoop:
     loop
       set skip_recd = 0;
       fetch next from src_mbr into vsrcseq, vsrcdat, vsrcdta;
       if SQLCODE=100 then leave LblLoop;
       end if;
       if skip_recd = 1 then goto LblLoop;
       end if;
       insert into faq400.srcfnd
           values(plib,pfile,pmember,vsrcseq,vsrcdat, vsrcdta);
       set insert_count = insert_count + 1;
     end Loop;
   close src_mbr;
   execute immediate 'drop alias qtemp.zz_src';
   return insert_count;
end;


--- And now try to searh all memberes with some row modified yesterday (August 15 2020)
WITH MBRS AS
   (SELECT SYSTEM_TABLE_SCHEMA AS LIB,
           SYSTEM_TABLE_NAME AS FILE,
              SYSTEM_TABLE_MEMBER AS MEMBER
    FROM   QSYS2.SYSPARTITIONSTAT
    WHERE  TABLE_SCHEMA = 'FAQ400' AND SOURCE_TYPE IS NOT NULL
           AND SOURCE_TYPE NOT IN ('PF', 'LF')
           --EVFTEMPF is IBM file and contains bad SRCDAT data
           AND SYSTEM_TABLE_NAME not like('EVFTEMPF%')
           -- fetch first 5 rows only
   )
SELECT   lib, file, member,
          faq400.src_line_date(
             lib, file, member, 200815, 200815) Found_Lines
FROM     MBRS
ORDER BY Found_Lines desc, lib, file, member;

-- And list all rows modified
select * from faq400.srcfnd where vsrcdat=200815
order by plib, pfile, pmember, vsrcseq;

RPG-FAQ-027: Precisione nei risultati intermedi nelle operazioni RPG (Precision of intermediate results and Precision Rules for Numeric Operations)

Quando facciamo una somma, sottrazione, moltiplicazione e divisioni tra variabili numeriche nei calcoli in RPG otteniamo dei risultati con un numero di cifre e decimali dipendenti, naturalmente, dalle dimensioni delle variabili in gioco secondo le regole riportate in questa pagina del manuale IBM:

https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzasd/prectdf.htm#prectdf

Questo significa che la precisione dei risultati intermedi potrebbe influire sul risultato finale delle operazioni stesse, sulla loro dimensione di lunghezza e Nr di decimali.

Proviamo con un semplice programma RPG a fare delle operazioni su delle variabili numeriche e a mostrarne il risultato proprio secondo quelle regole riportate nella guida IBM di cui sopra: nell’esempio riportato provo ad effettuare operazioni su due variabili V1/V2 packed(7:0) … e poi su due variabili V3/V4 con dei valori decimali … vediamo come cambiano le lunghezze (e il numero di decimali) del risultato (intermedio), una variabile temporanea creata dal compilatore RPG.

      ************************************************************
      *  ESE106 Precision rules of numeric operations
      *
      ************************************************************
       ctl-opt option(*srcstmt:*nodebugio);

       dcl-s  v1       packed(7:0);
       dcl-s  v2       packed(7:0);

       dcl-s  v3       packed(5:2);
       dcl-s  v4       packed(3:1);

       dcl-s  string      char(20);
       dcl-s  inp         int(5);


       // without decimals
       v1=100;
       v2=50;

       string='------123456789012345';
       dsply string;
       string='V1   ='+%editc(v1:'4');
       dsply string;
       string='V2   ='+%editc(v2:'4');
       dsply string;
       string='V1+V2='+%editc(v1+v2:'4');
       dsply string;
       string='V1-V2='+%editc(v1-v2:'4');
       dsply string;
       string='V1*V2='+%editc(v1*v2:'4');
       dsply string;
       string='V1/V2='+%editc(v1/v2:'4');
       dsply string;



       // with decimals
       v3=123.45;
       v4=6.7;

       string='v3   ='+%editc(v3:'4');
       dsply string;
       string='v4   ='+%editc(v4:'4');
       dsply string;
       string='v3+v4='+%editc(v3+v4:'4');
       dsply string;
       string='v3-v4='+%editc(v3-v4:'4');
       dsply string;
       string='v3*v4='+%editc(v3*v4:'4');
       dsply string;
       string='v3/v4='+%editc(v3/v4:'4');
       dsply string;

       string='';
       dsply string '*EXT' inp;

       exsr fine;


       //---------------------------
       // fine
       //---------------------------
       begsr fine;
         *inlr = *on;
         return;
       endsr;                   

E vediamone il suo risultato:


Come si può vedere nell’esempio con le variabili V3 (packed(5:2)) e V4 (packed(3:1)) … i risultato cambia in lunghezza e numero decimali in modo importante, soprattutto in caso di moltiplicazione e divisione!

--- Roberto De Pedrini Faq400.com
About author

Founder di Faq400 Srl, IBM Champion, ideatore del sito Faq400.com e del Blog blog.faq400.com. Sviluppatore RPG da quando avevo i pantaloni corti, forte sostenitore della piattaforma IBM i (ex AS400), ho sempre cercato di convididere le mie conoscenze con gli altri tramite forum, eventi e corsi. Oggi, tramite Faq400 Srl, cerchiamo di aiutare le aziende a sfruttare al meglio questa fantastica piattaforma IBM i.

Rispondi

%d blogger hanno fatto clic su Mi Piace per questo: