240 likes | 380 Views
Embedding SQL in RPG. Why SQL?. SQL is the IBM standard for relational database access SQL is the industry standard for relational database access SQL is the defacto standard for Client/Server data retrieval Don’t ask me what that means – it was in an IBM-supplied slide. SQL Terms.
E N D
Why SQL? • SQL is the IBM standard for relational database access • SQL is the industry standard for relational database access • SQL is the defacto standard for Client/Server data retrieval • Don’t ask me what that means – it was in an IBM-supplied slide
SQL Terms System Name Related SQL Term Library Schema Physical File Table Record Row Field Column
SQL Commands • SELECT • Retrieves data from a file (or table in SQL terms) • UPDATE • Updates a record (row) in a file (table) • DELETE • Deletes a record (row) from a file (table) • INSERT • Adds a record (row) to a file (table) Full disclosure: I have not used the UPDATE, DELETE, or INSERT commands in an RPG program yet. (Perhaps Tony has and can share some info with us.)
Additional SQL Functions • DECLARE (CURSOR) • Sets the “rules” for what data will be included in the temporary result table and how to sequence it • Similar to the FILE, QRYSLT and KEYFLD keywords on an OPNQRYF in a CL program • OPEN and CLOSE (CURSOR) • Opens and closes the temporary result table • Similar to the OVRDBF, OPNQRYF, and CLOF statements in a CL program • FETCH • Retrieves data from the temporary result table • Similar to the READ or READP Op-Codes in RPG • COMMIT/ROLLBACK (journaling functions) and GRANT/REVOKE (security functions) will not be addressed in this session (primarily because I have not used them to this point).
RPG Source Types • SQLRPGLE • SQLRPG • This option (embedded SQL) is not automatically included in the iSeries OS • It is a billable add-on • If your system does not allow it, you can create the source, but you can’t compile them. You can run the compiled objects if they are compiled on a system that does allow it. • These source types go through a “pre-compiler” that parses (interprets) the SQL statements before compiling the RPG code.
Compiler Directives • SQL Commands are embedded between 2 compiler directives • C/EXEC SQL • C+ Place your • C+ SQL command • C+ here • C/END-EXEC
The DECLARE Function d ds d empnbr 1 5 0 d empnam 6 30 d empdpt 31 33 0 c/exec sql c+ DECLARE emp_cursor CURSOR for SELECT nbr, nam, dpt INTO :empnbr, c+ :empnam, :empdpt FROM empmas WHERE mar_stat = ‘M’ ORDER BY c+ dpt, nam c/end-exec • Program variables must be preceded by a colon • The INTO clause identifies where the data from the retrieved fields (columns) will be stored • Can be specified here or on the FETCH statement • The WHERE clause identifies records to be retrieved (QRYSLT) • The ORDER BY clause identifies sorting criteria (KEYFLD). • ORDER BY dpt DESCEND
Additional DECLARE Options • FOR UPDATE OF (Field Name) • Default is ALL columns (fields) can be updated and ALL rows (records) can be deleted • FOR UPDATE OF lists the columns that are to be updated • Columns listed in the ORDER BY clause may not be listed in the FOR UPDATE OF clause • FOR READ ONLY • Specifies no updating/deleting allowed • May improve performance • WITH HOLD • Default: Cursors close when Commit/Rollback commands execute • WITH HOLD keeps the cursor open
The OPEN Function c/exec sql c+ OPEN emp_cursor c/end-exec
The FETCH Function c/exec sql c+ FETCH NEXT FROM emp_cursor c/end-exec As mentioned earlier, the INTO clause can also be used here c/exec sql c+ FETCH NEXT FROM emp_cursor INTO :empnbr, :empnam, :empdpt c/end-exec • Make sure your fields on the SELECT match your fields on the INTO
Additional FETCH Options Alternatives to NEXT • PRIOR Retrieves the row before the current row • FIRST Retrieves the first row • LAST Retrieves the last row • BEFORE Positions the cursor before the first row (do NOT use INTO) • AFTER Positions the cursor after the last row (do NOT use INTO) • CURRENT Retrieves the current row (no change in cursor position) • RELATIVE n If n < -1 Retrieves the nth row before the current row If n = -1 Same as PRIOR If n = 0 Same as CURRENT If n = 1 Same as NEXT If n > 1 Retrieves the nth row after the current row
DECLARE for FETCH PRIOR c/exec sql c+ DECLARE emp_cursor SCROLL CURSOR for SELECT nbr, nam, dpt INTO :empnbr, c+ :empnam, :empdpt FROM empmas WHERE mar_stat = ‘M’ ORDER BY c+ dpt, nam c/end-exec SCROLL makes it possible for you to read forward or backward.
Example of RELATIVE c/exec sql c+ FETCH RELATIVE 5000 FROM emp_cursor c/end-exec Same as… c do 5000 c/exec sql c+ FETCH NEXT FROM emp_cursor c/end-exec c enddo
FETCH and data structures D emp_ds ds D 1 5 0 nbr D 6 30 name D 31 31 job c/exec sql C+ declare emp_cursor cursor for select emp_nbr, emp_name, emp_job C+ from emp c/end-exec c/exec sql C+ FETCH NEXT FROM emp_cursor INTO :empds c/end-exec Full disclosure: I haven’t tried this either. IBM’s slide says it should work.
UPDATE • As I said earlier, I haven’t used this command in an RPG program myself yet, but I found an example: c/exec sql c+ update emp c+ set sal = sal + :raise c+ where current of empcsr c/end-exec Will update the currently read record, by adding a program field called raise to the file field called sal
The CLOSE Function c/exec sql c+ CLOSE emp_cursor c/end-exec
Error Detection & Handling The field SQLCODE stores a return code after every SQL command is executed: • = 0 Successful statement execution • > 0 Successful statement execution, with warning condition • < 0 Unsuccessful statement execution The value indicates the exact condition: • 100 = Row not found • -522 = Not authorized to object
Error Detection (Cont’d) WHENEVER statement checks the SQLCA (SQL Communications Area) and can branch to a location based on a condition. There are 3 conditions: • SQLWARNING (SQLCODE > 0 but not = 100) • SQLERROR (SQLCODE < 0) • NOT FOUND (SQLCODE = 100) And 2 possible actions: • CONTINUE • GO TO • c/exec sql • c+ FETCH NEXT FROM emp_cursor INTO :empds where emp_nbr = 500 • c+ WHENEVER NOT FOUND GO TO not_found_tag • c/end-exec
Error Detection (Cont’d) Check for an error after every command: c/exec sql c+ FETCH NEXT FROM emp_cursor INTO :empds where emp_nbr = 500 c/end-exec C if sqlcode <> 0 C exsr sr_err C endif
Dynamic SQL What is Dynamic SQL? • SQL statements are not predefined in program • Dynamically created on the fly as part of program logic • PREPARE statement can be used in program logic to compile dynamically created SQL statements • Used when run time variables are involved in the selection process or the exact syntax of an SQL statement cannot be pre-determined for any other reason • Since dynamic SQL statements did not go through the precompiler, they need to be interpreted and executed within the program – this can make them resource intensive.
400 d SQL_ok c coost)0) 500 d SQL_more s n inz(*on) 600 d SQL stmt s 500 inz)’select esbnr, eeleb, aspack, 700 d esupc, essc, asmcd, esbri, aslaei, 800 d asbez, es esdnr from artmep 900 d where’) 1000 1100 * Declare SQL Cursor 1200 c/exec sql 1300 c+ declare artmap cursor scroll cursor for sl 1400 c/eod-exec 1500 1600 c eval SQL stmt %trimr(SQLstmt) + ‘ ‘ + 1700 c ‘ASFL = ‘‘‘ + scfleg + 1800 c eval curr group = 1 1900 2000 c select 2100 c when scselt = ‘P 2200 c evel SQL stmt = %trimr(SQLstmt) + ‘ end ‘ + 2300 c ‘ASEG between 700 and 799’ 2400 c when scselt = ‘B’ 2500 c eval SQL stmt %trimr(SQLstmt) + end ‘ + 2600 c ‘ASEG not between 700 and 799’ 2700 c endsl 2800 2900 c if scquel <> *blenks 3000 c eval SQL stmt = %trimr(SQLstmt) + ‘ and ‘ + 3100 c ‘ASMCD = ‘ ‘ ‘ + scqual + ‘ ‘ 3200 c endif 3300 3400 c if scwid c> 0 3600 c eval SQL stmt = %trimr(SQLstmt) + ‘ and ‘ + 3600 c ‘ASBNI = ‘ + scwidalph 3700 c endif 3800 3900 c if eden <> 0 4000 c eval SQL stmt = %trimr(SQLstmt) ÷ ‘ and ‘ + 4100 c ‘ASLAEI ‘ + sclenalph 4200 c endif 4300 4400 c if sclicn c> 0 4500 c eval SQL stmt = %trimr(SQLstmt) + ‘ and ‘ + 4600 c ‘ASLIZD = ‘ + sclicnalph 4700 c endif 4800 4900 c if scstyl c> 6000 c eval SQL stmt = %trimr(SQLstmt) ÷ ‘ and ‘ + 5100 c ‘ASSNR = ‘ ‘ ‘ + scstyl ÷ ‘ ‘ ‘ 5200 c endif
7700 *Prepare variable SQL statement 7800 c/exec sql 7900 c+ prepare s1 from :SQL_stmt 8000 c/end-exec The DECLARE statement declared a cursor called ARTMAP, so you would perform your FETCH from ARTMAP just as if this had been a pre-defined select statement instead of a prepared one.