Embedding SQL in RPG

Post on 23-Apr-2017

232 views 3 download

transcript

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

System Name Related SQL TermLibrary SchemaPhysical File TableRecord 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 Functiond dsd empnbr 1 5 0d empnam 6 30d empdpt 31 33 0

c/exec sqlc+ DECLARE emp_cursor CURSOR for SELECT nbr, nam, dpt INTO :empnbr,c+ :empnam, :empdpt FROM empmas WHERE mar_stat = ‘M’ ORDER BYc+ dpt, namc/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 Functionc/exec sqlc+ OPEN emp_cursorc/end-exec

The FETCH Functionc/exec sqlc+ FETCH NEXT FROM emp_cursorc/end-exec

As mentioned earlier, the INTO clause can also be used here

c/exec sqlc+ FETCH NEXT FROM emp_cursor INTO :empnbr, :empnam, :empdptc/end-exec

• Make sure your fields on the SELECT match your fields on the INTO

Additional FETCH OptionsAlternatives 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 PRIORIf n = 0 Same as CURRENTIf n = 1 Same as NEXT If n > 1 Retrieves the nth row after the current row

DECLARE for FETCH PRIORc/exec sqlc+ DECLARE emp_cursor SCROLL CURSOR for SELECT nbr, nam, dpt INTO

:empnbr,c+ :empnam, :empdpt FROM empmas WHERE mar_stat = ‘M’ ORDER BYc+ dpt, namc/end-exec

SCROLL makes it possible for you to read forward or backward.

Example of RELATIVEc/exec sqlc+ FETCH RELATIVE 5000 FROM emp_cursorc/end-exec

Same as…

c do 5000c/exec sqlc+ FETCH NEXT FROM emp_cursorc/end-execc enddo

FETCH and data structuresD emp_ds dsD 1 5 0 nbrD 6 30 nameD 31 31 job

c/exec sqlC+ declare emp_cursor cursor for select emp_nbr, emp_name, emp_jobC+ from empc/end-exec c/exec sqlC+ FETCH NEXT FROM emp_cursor INTO :empdsc/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 sqlc+ update empc+ set sal = sal + :raisec+ where current of empcsrc/end-exec

Will update the currently read record, by adding a program field called raise to the file field called sal

The CLOSE Functionc/exec sqlc+ CLOSE emp_cursorc/end-exec

Error Detection & HandlingThe 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 sqlc+ FETCH NEXT FROM emp_cursor INTO :empds where emp_nbr = 500c/end-exec

C if sqlcode <> 0C exsr sr_errC endif

Dynamic SQLWhat 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 artmep900 d where’)10001100 * Declare SQL Cursor1200 c/exec sql1300 c+ declare artmap cursor scroll cursor for sl1400 c/eod-exec15001600 c eval SQL stmt %trimr(SQLstmt) + ‘ ‘ +1700 c ‘ASFL = ‘‘‘ + scfleg +1800 c eval curr group = 119002000 c select2100 c when scselt = ‘P2200 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 endsl28002900 c if scquel <> *blenks3000 c eval SQL stmt = %trimr(SQLstmt) + ‘ and ‘ +3100 c ‘ASMCD = ‘ ‘ ‘ + scqual + ‘ ‘3200 c endif33003400 c if scwid c> 03600 c eval SQL stmt = %trimr(SQLstmt) + ‘ and ‘ +3600 c ‘ASBNI = ‘ + scwidalph3700 c endif38003900 c if eden <> 04000 c eval SQL stmt = %trimr(SQLstmt) ÷ ‘ and ‘ +4100 c ‘ASLAEI ‘ + sclenalph4200 c endif43004400 c if sclicn c> 04500 c eval SQL stmt = %trimr(SQLstmt) + ‘ and ‘ +4600 c ‘ASLIZD = ‘ + sclicnalph4700 c endif48004900 c if scstyl c>6000 c eval SQL stmt = %trimr(SQLstmt) ÷ ‘ and ‘ +5100 c ‘ASSNR = ‘ ‘ ‘ + scstyl ÷ ‘ ‘ ‘5200 c endif

7700 *Prepare variable SQL statement7800 c/exec sql7900 c+ prepare s1 from :SQL_stmt8000 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.