Extract From Embee SQL in RPG Beyon the Basics Paul Tuohy System i Develoer 5, Oakton Court, Ballybrack Co. Dublin Irelan Phone: +353 1 282 6230 e-mail: aul@systemieveloer.com Web: www.systemieveloer.com www.avisor.com Paul Tuohy Paul Tuohy, author of "Re-engineering RPG Legacy Alications" an "The Programmer's Guie to iseries Navigator", is one of the most rominent consultants an trainer/eucators for alication moernization an eveloment technologies on the IBM Mirange. He currently hols ositions as CEO of, a consultancy firm base in Dublin, Irelan, an founing artner of System i Develoer, the consortium of to eucators who rouce the acclaime RPG & DB2 Summit conference. Previously, he worke as IT Manager for Koak Irelan Lt. an Technical Director of Precision Software Lt. In aition to hosting an seaking at the RPG & DB2 Summit, Paul is an awar-winning seaker at COMMON, COMMON Euroe Congress an other conferences throughout the worl. His articles frequently aear in System i NEWS, iseries Exerts Journal, The Four Hunre Guru, RPG Develoer an other leaing ublications. This resentation may contain small coe examles that are furnishe as simle examles to rovie an illustration. These examles have not been thoroughly teste uner all conitions. We therefore, cannot guarantee or imly reliability, serviceability, or function of these rograms. All coe examles containe herein are rovie to you "as is". THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED.
Reminer Using a Cursor Sequential rea of a file Fetch row at a time H otion(*srcstmt : *nodebugio)) ata Ds qualifie etno etname 36a varying /inclue STANDARD eclare C1 cursor for select etno, etname from eartment orer by etno for rea only; oen C1; fetch next from C1 into :ata ; ow (SQLCODE >= 0 an SQLCODE <> 100); sly ('Fetch Loo ' + ata.etno + ' ' + ata.etname); fetch next from C1 into :ata ; endo; close C1; *inlr = *on; Multi Row Fetch A Multi Row Fetch is a much more efficient way of retrieving rows H otion(*srcstmt : *nodebugio) MAX_ROWS C 10 i s 10i 0 getrows s 10i 0 inz(max_rows) ata Ds im(max_rows) qualifie etno etname 36a varying /inclue STANDARD eclare C1 scroll cursor for select etno, etname from eartment orer by etno for rea only; oen C1; fetch first from C1 for :getrows rows into :ata ; for i = 1 to SQLERRD(3); sly ('Normal ' + ata(i).etno + ' ' + ata(i).etname); enfor; close C1;
Multi Row Fetch Consierations Much faster than a FETCH Loo That alone is reason enough to use it An easy way of generating a result set When using embee SQL for store roceures DS Array can be asse as a arameter Provies an easy means of using result sets in RPG alications Data Structure Array or Multile Occurrence Data Structure (MODS) MODS is the oler (an more cumbersome) technique DS Arrays are much easier Only a finite number of rows may be retrieve Pre-V6R1 64K of ata Post V6R1 16M of ata What if the result set excees the size of the DS array? Does subfile aging ring a bell? Fetch Otions Alternatives to Next rocessing Fetch keywor Keywor next rior first last before after current relative n Positions Cursor On the next row after the current row On the row before the current row On the first row On the last row Before the first row - must not use INTO After the last row - must not use INTO On the current row (no change in osition) n < -1 Positions to nth row before current n = -1 Same as Prior keywor n = 0 Same as Current keywor n = 1 Same as Next keywor n > 1 Positions to nth row after current
Sequential Multi Row Fetch Sequential rea of a age at a time H otion(*srcstmt : *nodebugio) MAX_ROWS C 3 i s 10i 0 getrows s 10i 0 inz(max_rows) ata Ds im(max_rows) qualifie etno etname 36a varying /inclue STANDARD eclare C1 scroll cursor for select etno, etname from eartment orer by etno for rea only; oen C1; Naughty!!! ou SQLCODE <> 0; fetch relative 1 from C1 for :getrows rows into :ata ; for i = 1 to SQLERRD(3); sly ('Sequential ' + ata(i).etno + ' ' + ata(i).etname); enfor; endo; close C1; *inlr = *on; FETCH RELATIVE FETCH RELATIVE is relative to the current cursor osition in the result set 0 is the current osition of the cursor 1 is the next row - i.e. Fetch relative 1 is the same as Fetch Next -1 is the revious row - i.e. Fetch relative -1 is the same as Fetch Prior As rows are fetche, cursor is lace on last row rea
Paging Multi Row Fetch A Samle Program To age forwar/back through a result set Using a multi row fetch A simle examle - eclareanoen() contains the same Declare Cursor an Oen Cursor as revious - closecursor() contains the same Close Cursor as revious examle - Comlete listing in notes H otion(*srcstmt : *nodebugio) MAX_ROWS C 11 agesize s 10i 0 inz(max_rows) /inclue STANDARD sly 'Number of rows er age: ' ' ' agesize; if (agesize > (MAX_ROWS-1)); agesize = (MAX_ROWS-1); eclareanoen(); getrows(agesize); closecursor(); *inlr = *on; Paging Consierations Paging consierations:- SQLCODE not set if rows rea < age size - Use GET DIAGNOSTICS to etermine if EOF reache - Or use SQLERRD(5) EOF not set if last row of age is last row of result set - i.e. EOF not set if 10 rows in result set, 10 rows in age Rea one more row than age size - To etect EOF Factors The size of a age The number of rows just rea EOF Controlling the relative osition For first age, set relative osition to 1 If Page Back requeste, set relative osition to (1 - (rows on this age + age size)) - i.e. Next Page starts with the first row of the revious age Rea age size + 1 If not EOF set relative osition to 0 - i.e. Next Page starts with the last row rea If EOF set relative osition to (1 rows just rea) - i.e. Next Page starts with the first row of this age
Paging Multi Row Fetch getrows() (1 of 3) These are the D Secs for the getrows() subroceure irection - F = Forwar, B = Back, E = En getpagesize - set to agesize + 1 relativerow Initialize to 1 for the first age rea getrows... agesize b PI 10i 0 const the requeste Page Size ata Ds im(max_rows) qualifie etno etname 36a varying i s 10i 0 irection s 1a inz('f') getpagesize s 10i 0 relativerow s 10i 0 inz(1) backrows s 10i 0 lastrow s 10i 0 DS array for the fetch aging irection rows to retrieve on the fetch relative offset for next rea number of rows fetche status for EOF Paging Multi Row Fetch getrows() (2 of 3) The basic logic is (continue on next slie) Set the no. of rows to retrieve on the fetch If age back requeste set relative offset to start of revious age Fetch the age Store the no of rows retrieve Check for EOF Assume next relative offset is from last row just rea If EOF - set relative offset to start of this age ou (irection = 'E'); getpagesize = agesize + 1; if (irection = 'B'); relativerow = (1 - (agesize + backrows)); fetch relative :relativerow from C1 for :getpagesize rows into :ata; backrows = SQLERRD(3); get iagnostics :lastrow = DB2_LAST_ROW; relativerow = 0; if (lastrow = 100); sly ('Reache EOF'); relativerow = (1 - backrows); no. of rows to retrieve Page back? offset to start of revious age Fetch age Store rows retrieve Check for EOF Assume next relative offset EOF? offset to start of this age
Paging Multi Row Fetch getrows() (3 of 3) The basic logic is (continue from revious slie) If no rows retrieve, loa first age - Usually cause by aging beyon start of result set Dislay age - This examle islay all rows retrieve - Usually islay backrows or agesize Whichever is less Promt for next aging otion if (backrows = 0); fetch first from C1 for :getpagesize rows into :ata; backrows = SQLERRD(3); for i = 1 to backrows; sly ('Paging ' + ata(i).etno + ' ' + ata(i).etname); enfor; sly 'Direction (F/B/E) ' ' ' irection ; endo; e H otion(*srcstmt : *nodebugio) MAX_ROWS C 11 agesize s 10i 0 inz(max_rows) /inclue STANDARD sly 'Number of rows er age: ' ' ' agesize; if (agesize > (MAX_ROWS-1)); agesize = (MAX_ROWS-1); eclareanoen(); getrows(agesize); closecursor(); *inlr = *on; eclareanoen... b PI eclare C1 scroll cursor for select etno, etname from eartment orer by etno for rea only; oen C1; e
getrows... agesize b PI 10i 0 const ata Ds im(max_rows) qualifie etno etname 36a varying i s 10i 0 irection s 1a inz('f') getpagesize s 10i 0 relativerow s 10i 0 inz(1) backrows s 10i 0 lastrow s 10i 0 ou (irection = 'E'); getpagesize = agesize + 1; if (irection = 'B'); relativerow = (1 - (agesize + backrows)) ; fetch relative :relativerow from C1 for :getpagesize rows into :ata; backrows = SQLERRD(3); get iagnostics :lastrow = DB2_LAST_ROW; relativerow = 0; if (lastrow = 100); sly ('Reache EOF'); relativerow = (1 - backrows); if (backrows = 0); fetch first from C1 for :getpagesize rows into :ata; backrows = SQLERRD(3); for i = 1 to backrows; sly ('Paging ' + ata(i).etno + ' ' + ata(i).etname); enfor; sly 'Direction (F/B/E) ' ' ' irection ; endo; e closecursor... b PI close C1; e
A Multi Row Insert Insert multile rows using a DS Array Secify the number of rows on the INSERT statement Shoul really be using commitment control MAX_ROWS C 100 numorerdetails... s 10i 0 orerheaer e s extname(ordhead) qualifie orerdetail e s extname(orddetl) qualifie im(max_rows) set otion naming = *SYS, atfmt = *ISO, atse = '-'; insert into ORDHEAD values( :orerheaer); if (SQLCODE = 0); insert into ORDDETL :numorerdetails rows values (:orerdetail); if (SQLCODE = 0); commit; else; rollback; By the Seaker Re-Engineering RPG Legacy Alications ISBN 1-58347-006-9 The Programmers Guie to iseries Navigator ISBN 1-58347-047-6 www.mcressonline.com www.mirange.com www.amazon.com etc. iseries Navigator for Programmers A self teach course www.lab400.com Article links at www.comconavisor.com