
Last Updated on 20 Agosto 2020 by Roberto De Pedrini
Terza puntata della serie RPG – FAQ & Howtos, le puntate precedenti le trovate qui;
Index
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