embedded sql in rpg v2 - gomitec.com presentations/paul tuohy embedd… · sql pre-compile for...
TRANSCRIPT
Paul TuohyComCon System i Developer5, Oakton Court, BallybrackCo. DublinIreland
Phone: +353 1 282 6230e-Mail: [email protected]: www.systemideveloper.com www.ComConAdvisor.com
ComConProducers of the RPG & DB2 Summit
Embedded SQL in RPG
ComConPaul Tuohy
Paul Tuohy has worked in the development of IBM Midrange applications since the �70s. He has been IT manager for Kodak Ireland Ltd. and Technical Director of Precision Software Ltd. and is currently CEO of ComCon, a midrange consultancy company based in Dublin, Ireland. He has been teaching and lecturing since the mid-�80s.
Paul is the author of "Re-engineering RPG Legacy Applications�, �The Programmers Guide to iSeries Navigator� and the self teach course �iSeries Navigator for Programmers�. He writes regular articles for many publications and is one of the quoted industry experts in the IBM Redbook "Who knew you could do that with RPG IV?".
Paul is one of the co-founders of System i Developer and is also an award winning speaker who speaks regularly at US Common and other conferences throughout the world.
© ComCon and System i Developer, LLC 2006-2011 -1-
ComConDisclaimer
This presentation may contain small code examples that are furnished as simple examples to provide an illustration. These examples have not been thoroughly tested under all conditions. We therefore, cannot guarantee or imply reliability, serviceability, or function of these programs.
All code examples contained herein are provided to you "as is". THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED.
Have you visited SystemiDeveloper.com?
Check it out for the latest and greatest in System i RPG and database education
ComConAgenda
Syntax and rules for embedding SQL into programs
Using SQL cursors for processing individual rows in a set
Error detection and handling
Dynamic SQL introduction
Tips and Performance
© ComCon and System i Developer, LLC 2006-2011 -2-
ComConUsing SQL on i5OS (OS/400)
Interactive SQL - Use iSeries Navigator
Targeted primarily to programmers
Interactive SQL - Use STRSQL command
Targeted primarily to programmers
Embedded SQL - Put into High Level Language (HLL)
Such as RPG or COBOL
Query Manager - Report Formatter
Targeted primarily to end users
An alternative to Query
SQL Stored Procedures and SQL Triggers
Enforce business rules using SQL-based logic
ComConRun SQL Scripts
© ComCon and System i Developer, LLC 2006-2011 -3-
03/11/11 7
Run SQL Scripts (from the context menu on the machine id) is the equivalent of STRSQL - but you do not need the SQL development kit.
End each SQL statement with a semi colon.
More then one SQL statement may be run at a time.
Sample SQL statements are available in the drop down box.
The basic SQL statements may be prompted.
ComConTypes of SQL Statements
Data Manipulation Language (DML)
SELECT - retrieves data; one row or multiple
UPDATE - updates one row or multiple
DELETE - deletes one row or multiple
INSERT - adds one row or multiple
Data Definition Language (DDL)
CREATE - creates schemas, tables, views, etc.
DROP - deletes schemas, tables, views, etc.
ALTER - change the format or attributes of a table
Data Control Language (DCL)
GRANT & REVOKE - manages authorities to DB objects
Programming Statements
DESCRIBE, PREPARE - used for dynamic embedded SQL
Logic control statements for SQL procedures, triggers and functions
© ComCon and System i Developer, LLC 2006-2011 -4-
ComCon
Different names for what we already have
But the names we use are important
Guess which terminology the rest of the world uses?
Please, please, please start to use the SQL terminology
Native SQL
Library Schema or Collection
Physical File Table
Keyed Logical Index
Non-Keyed Logical View
Record Row
Field Column
Journal Log
SQL Terminology
ComConEmbedded SQL
Why embed SQL in programs?
Perform dynamic selection functions- ala OPNQRYF, except more flexible
Perform set-at-a-time functions under program control
Even to replace HLL I/O operations- e.g., READ, WRITE, UPDATE, CHAIN
What can be embedded?
Most common use is for SQL DML statements - SELECT, UPDATE, DELETE, INSERT
Even DDL statements- such as CREATE TABLE, etc.
Program control statements
e.g., DECLARE CURSOR, OPEN, CLOSE, FETCH, COMMIT, ROLLBACK
© ComCon and System i Developer, LLC 2006-2011 -5-
ComConSQL Pre-Compile for Embedded SQL
SQL is pre-compiled
Syntax check
Xref host variables
Converts SQL statements to RPG
Inserts required SQL declarations
Optionally call RPG compiler to include /COPY directives (more later)
Original SourceMember
Original SourceMember
*PGM*PGM
Modified SourceMember
ProcessedSQL
Statements
(temporary)
Modified SourceMember
ProcessedSQL
Statements
(temporary)
ProgramProgram
Access PlanAccess Plan
Pre-CompilePre-CompilePre-Compile CompileCompile
ComConRules: Embedding SQL in RPG Code (to V5R2)
All SQL statements must be coded on a C spec
SQL statements begin with /EXEC SQL in positions 7-15
with the slash in position 7
... and end with /END-EXEC in positions 7-15
You can enter SQL statements on the same line as /EXEC SQL
However, /END-EXEC must be on a separate line
All SQL statements must have C+ in positions 6-7
D getEmployee S 6a
D name S 15a
D deptno S 3a
C/EXEC SQL
C+ SELECT lastName, workDept
C+ INTO :name, :deptno
C+ FROM employee
C+ WHERE empno = :getEmployee
C/END-EXEC
D getEmployee S 6a
D name S 15a
D deptno S 3a
C/EXEC SQL
C+ SELECT lastName, workDept
C+ INTO :name, :deptno
C+ FROM employee
C+ WHERE empno = :getEmployee
C/END-EXEC
No F Spec RequiredNo F Spec Required
© ComCon and System i Developer, LLC 2006-2011 -6-
ComConSQL in Free Format (V5R3+)
SQL statements may now be coded directly in /Free format
Introduced in V5R4
PTFs SI23384, SI25532, and SI25763 required for V5R3
SQL statements begin with EXEC SQL
End the complete SQL statement with a semi colon
D getEmployee S 6a
D name S 15a
D deptno S 3a
/free
getEmployee = '00010';
exec SQL
select lastName, workDept
into :name, :deptno
from employee
where empno = :getEmployee ;
dsply Name;
D getEmployee S 6a
D name S 15a
D deptno S 3a
/free
getEmployee = '00010';
exec SQL
select lastName, workDept
into :name, :deptno
from employee
where empno = :getEmployee ;
dsply Name;
ComConSQL Host Variables
Host variables identify program fields used in static SQL statements
Host variable names are preceded by a colon
as in :host-variable-name
Host variables must be defined somewhere in the program
Typically in the D specs or in a display file
No F spec is used for database files accessed with SQL statements
D getEmployee S 6a
D name S 15a
D deptno S 3a
/free
getEmployee = '00010';
exec SQL
select lastName, workDept
into :name, :deptno
from employee
where empno = :getEmployee ;
dsply Name;
D getEmployee S 6a
D name S 15a
D deptno S 3a
/free
getEmployee = '00010';
exec SQL
select lastName, workDept
into :name, :deptno
from employee
where empno = :getEmployee ;
dsply Name;
© ComCon and System i Developer, LLC 2006-2011 -7-
ComConSELECT INTO
SELECT INTO SQL Statement is used to retrieve a single record from the database
If your statement returns more than 1 row, you must use another form of SELECT - which we will discuss later
D employeeNo S 6a
D lastName S 15a
D salary S 9p 2
exec SQL
select empNo, lastName, salary
into :employeeNo,:lastName,:salary
from employee
where empNo = '000010';
D employeeNo S 6a
D lastName S 15a
D salary S 9p 2
exec SQL
select empNo, lastName, salary
into :employeeNo,:lastName,:salary
from employee
where empNo = '000010';
ComConInserts, Updates and Deletes
SQL inserts, updates and deletes can be embedded as well
Extremely powerful
But - let the user beware!
exec SQL
delete from employee
where workDept = 'E21';
exec SQL
delete from employee
where workDept = 'E21';
exec SQL
update employee
set salary = salary + (salary * .10)
where workDept = 'E21';
exec SQL
update employee
set salary = salary + (salary * .10)
where workDept = 'E21';
exec SQL
insert into employee (empno, fName, lastName, workDept)
values(:employeeNo, :first, :last, 'E21');
exec SQL
insert into employee (empno, fName, lastName, workDept)
values(:employeeNo, :first, :last, 'E21');
© ComCon and System i Developer, LLC 2006-2011 -8-
ComConUsing Structures in SQL
Host structures are groups of variables
Data structures in RPG
Structures can be used in SQL statements
Replaces list of variables
DS subfields must contain the correct number, type and sequence for SELECT columns
D employeeInfo DS
D employeeNo 6a
D lastName 15a
D salary 9p 2
D getEmployee S 6a
/free
exec SQL
select empNo, lastName, salary
into :employeeInfo
from employee
where empNo = :getEmployee;
D employeeInfo DS
D employeeNo 6a
D lastName 15a
D salary 9p 2
D getEmployee S 6a
/free
exec SQL
select empNo, lastName, salary
into :employeeInfo
from employee
where empNo = :getEmployee;
ComConExternal Data Structures
Only if all columns are required
Use a SELECT * request
Declare an externally described Data Structure
Subfields will be brought in to match all the fields in the record format
No level checking- Up to you to re-compile if format changes
Watch out for date/time fields- May require compile or SET options
D employeeData E DS extName(employee)
D getEmployee S 6a
exec SQL
select *
into :employeeData
from employee
where empNo = :getEmployee;
D employeeData E DS extName(employee)
D getEmployee S 6a
exec SQL
select *
into :employeeData
from employee
where empNo = :getEmployee;
© ComCon and System i Developer, LLC 2006-2011 -9-
ComConResult Set
A Result Set is:-
A group of rows that are derived as a result of an SQL query
The answer to your SQL question
Made up of rows and columns
select deptno, deptname from department where admrdept = 'D01';select deptno, deptname from department where admrdept = 'D01';
ComConSelecting & Processing Multiple Rows
Steps to access multiple rows:
Declare cursor
Open cursor
Fetch a row (record)
Process row (UPDATE, INSERT, etc)
IF NOT last row: loop to Fetch
Close cursor
Just like any sequential read!
© ComCon and System i Developer, LLC 2006-2011 -10-
ComConDECLARE CURSOR statement
Similar in function to HLL file declarations (F-specs)
No processing actually takes place - just definition
Host variables may be included in the statement
Created using an embedded SELECT command
most SELECT clauses may be used - ORDER BY, GROUP BY, etc
A cursor must be declared before being referenced
exec SQL
declare empCursor cursor for
select empNo, lastName, salary
from eEmployee
where workDept = :dept;
exec SQL
declare empCursor cursor for
select empNo, lastName, salary
from eEmployee
where workDept = :dept;
ComConDECLARE CURSOR - more clauses
By default, all columns may be updated or deleted
FOR READ ONLY - specifies no updating/deleting allowed- Improves performance- Rows not locked for update
FOR UPDATE OF - lists the columns that are to be updated- columns listed in an ORDER BY clause may NOT be listed in FOR UPDATE OF clause
Considerations:
FOR READ ONLY - may improve performance; better documentation
FOR UPDATE OF - security; may improve performance
exec SQL
declare empCursor cursor for
select empNo, lastName, salary
from eEmployee
where workDept = :dept
for read only ;
exec SQL
declare empCursor cursor for
select empNo, lastName, salary
from eEmployee
where workDept = :dept
for read only ;
© ComCon and System i Developer, LLC 2006-2011 -11-
ComConOPEN statement
Actually executes the SQL Select statement
Builds the access path if necessary
Successful Open places the file cursor before the first row of the result set
Cursor must be closed before it can be opened
Syntax: OPEN cursor-name
exec SQL
open empCursor ;
exec SQL
open empCursor ;
ComConFETCH statement
Bring rows into the program
One at a time for processing
Fields placed into host variables
one for one with fields in SELECT
exec SQL
fetch next from empCursor
into :employeeNo,:lastName,:salary ;
exec SQL
fetch next from empCursor
into :employeeNo,:lastName,:salary ;
© ComCon and System i Developer, LLC 2006-2011 -12-
ComConProcess FETCHed Row
To Update or Delete the fetched row
Use Where Current of Clause on Update/Delete statement
Can only be done after a successful Fetch
exec SQL
update employee
set salary = salary + :raise
where current of empCursor;
exec SQL
update employee
set salary = salary + :raise
where current of empCursor;
ComConAlternatives with FETCH
Alternatives to Next processing:
must define the cursor as a scrollable cursor in the declare statement
exec SQL
declare empCursor scroll cursor for
select empNo, lastName, salary
from employee
where workDept = :dept
order by empNo ;
exec SQL
fetch prior from empCursor
into :employeeNo,:lastName,:salary;
exec SQL
declare empCursor scroll cursor for
select empNo, lastName, salary
from employee
where workDept = :dept
order by empNo ;
exec SQL
fetch prior from empCursor
into :employeeNo,:lastName,:salary;
© ComCon and System i Developer, LLC 2006-2011 -13-
ComConFetch Options
Alternatives to Next processing
Fetch keyword
Keyword Positions Cursor
next On the next row after the current row
prior On the row before the current row
first On the first row
last On the last row
before Before the first row - must not use INTO
after After the last row - must not use INTO
current On the current row (no change in position)
relative n n < -1 Positions to nth row before current n = -1 Same as Prior keywordn = 0 Same as Current keyword n = 1 Same as Next keywordn > 1 Positions to nth row after current
ComConClose Statement
Close the cursor
Cursor must be opened in order to be closed
Cursor will be closed if
job end
activation group ends
program ends
modules ends
commit or rollback without a 'with hold' clause
error handling...
exec SQL
close empCursor ;
exec SQL
close empCursor ;
© ComCon and System i Developer, LLC 2006-2011 -14-
ComConPutting it all together�
Sequential read of a file
exec SQL
declare empCursor cursor for
select empNo, lastName, salary
from eEmployee
where workDept = :dept
for read only ;
exec SQL
open empCursor ;
exec SQL
fetch next from empCursor
into :employeeNo,:lastName,:salary ;
doW (SQLCode >= 0 and SQLCode <> 100); // More in a moment
// Do Your stuff here
exec SQL
fetch next from empCursor
into :employeeNo,:lastName,:salary ;
endDo;
exec SQL
close empCursor ;
exec SQL
declare empCursor cursor for
select empNo, lastName, salary
from eEmployee
where workDept = :dept
for read only ;
exec SQL
open empCursor ;
exec SQL
fetch next from empCursor
into :employeeNo,:lastName,:salary ;
doW (SQLCode >= 0 and SQLCode <> 100); // More in a moment
// Do Your stuff here
exec SQL
fetch next from empCursor
into :employeeNo,:lastName,:salary ;
endDo;
exec SQL
close empCursor ;
ComConError Detection and Handling (1 of 3)
Status always returned in the code
both successful and unsuccessful statements
Programmer must check return codes within program
SQL Communications Area (SQLCA)
contains feedback information
must be included in all SQL programs
RPG includes SQLCA automatically
other languages must have specific INCLUDE
© ComCon and System i Developer, LLC 2006-2011 -15-
ComConError Detection and Handling (2 of 3)
SQL Communications Area (SQLCA)
SQLCAID Char(8) Structure identifying literal: "SQLCA"
SQLCABC Integer Length of SQLCA
SQLCode Integer Return code
SQLErrML SmallInt Length of SQLErrMC
SQLErrMC Char(70) Message Replacement text
SQLErrP Char(8) Product ID literal: "QSQ" for DB2 UDB
SQLErrD Array of Integers
SQLErrD(1) - last 4 characters of CPF or other escape message SQLErrD(2) - last 4 characters of CPF or other diagnostic message SQLErrD(3) - for Fetch, Insert, Update or Delete, number of rows retrieved or updated SQLErrD(4) - for Prepare, relative number indicating resources required for execution SQLErrD(5) - for multiple-row Fetch, contains 100 if last available row is fetched; for Delete, number of rows affected by referential constraints; for Connect or Set Connection, contains -1 if unconnected, 0 if local and 1 if connection is remote SQLErrD(6) - when SQLCode is 0, contains SQL completion message id
ComConError Detection and Handling (3 of 3)
SQL Communications Area (SQLCA) - continued
SQLWarn Char(11) Set of 11 warning indicators; each is blank, W, or N
SQLWarn0 Char(1) Blank if all other SQLWARNx warning indicators are blank W if any warning indicator contains W or N
SQLWarn1 Char(1) W if a string column was truncated when assigned to host variable
SQLWarn2 Char(1) W if null values were eliminated from a function
SQLWarn3 Char(1) W if number of columns is larger than number of host variables
SQLWarn4 Char(1) W if prepared Update or Delete statement has no a Where clause
SQLWarn5 Char(1) Reserved
SQLWarn6 Char(1) W if date arithmetic results in end-of-month adjustment
SQLWarn7 Char(1) Reserved
SQLWarn8 Char(1) W if result of character conversion contains the substitution character
SQLWarn9 Char(1) Reserved
SQLWarnA Char(1) Reserved
SQLState Char(5) Return code; "00000" if no error or warning
© ComCon and System i Developer, LLC 2006-2011 -16-
ComConSQLCA Data Structure (1 of 2)
D SQLCA DS
D SQLCAID 8A INZ(X'000000000000000
D SQLAID 8A OVERLAY(SQLCAID)
D SQLCABC 10I 0
D SQLABC 9B 0 OVERLAY(SQLCABC)
D SQLCODE 10I 0
D SQLCOD 9B 0 OVERLAY(SQLCODE)
D SQLERRML 5I 0
D SQLERL 4B 0 OVERLAY(SQLERRML)
D SQLERRMC 70A
D SQLERM 70A OVERLAY(SQLERRMC)
D SQLERRP 8A
D SQLERP 8A OVERLAY(SQLERRP)
D SQLERR 24A
D SQLER1 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER2 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER3 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER4 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER5 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER6 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLERRD 10I 0 DIM(6) OVERLAY(SQLERR)
D SQLCA DS
D SQLCAID 8A INZ(X'000000000000000
D SQLAID 8A OVERLAY(SQLCAID)
D SQLCABC 10I 0
D SQLABC 9B 0 OVERLAY(SQLCABC)
D SQLCODE 10I 0
D SQLCOD 9B 0 OVERLAY(SQLCODE)
D SQLERRML 5I 0
D SQLERL 4B 0 OVERLAY(SQLERRML)
D SQLERRMC 70A
D SQLERM 70A OVERLAY(SQLERRMC)
D SQLERRP 8A
D SQLERP 8A OVERLAY(SQLERRP)
D SQLERR 24A
D SQLER1 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER2 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER3 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER4 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER5 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLER6 9B 0 OVERLAY(SQLERR:*NEXT)
D SQLERRD 10I 0 DIM(6) OVERLAY(SQLERR)
SQLCA is automatically inserted by pre-compiler
ComConSQLCA Data Structure (2 of 2)
D SQLWRN 11A
D SQLWN0 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN1 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN2 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN3 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN4 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN5 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN6 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN7 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN8 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN9 1A OVERLAY(SQLWRN:*NEXT)
D SQLWNA 1A OVERLAY(SQLWRN:*NEXT)
D SQLWARN 1A DIM(11) OVERLAY(SQLWRN)
D SQLSTATE 5A
D SQLSTT 5A OVERLAY(SQLSTATE)
D SQLWRN 11A
D SQLWN0 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN1 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN2 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN3 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN4 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN5 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN6 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN7 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN8 1A OVERLAY(SQLWRN:*NEXT)
D SQLWN9 1A OVERLAY(SQLWRN:*NEXT)
D SQLWNA 1A OVERLAY(SQLWRN:*NEXT)
D SQLWARN 1A DIM(11) OVERLAY(SQLWRN)
D SQLSTATE 5A
D SQLSTT 5A OVERLAY(SQLSTATE)
Note double definition of names
Allows for programs converted from RPG III- e.g. SQLCODE and SQLCOD
SQLCA is not the only set of definitions inserted by the pre-compiler
Other definitions are dependent on the actual SQL statements
All inserted names start with the characters SQL
Try to refrain from naming any variables starting with SQL
© ComCon and System i Developer, LLC 2006-2011 -17-
ComConSQLCODE Error Handling
SQLCODE contains return code
= 0 Successful statement execution
> 0 Successful, with warning condition
< 0 Unsuccessful - statement failed
SQLCODE value indicates exact error or condition
e.g.. 100 = Row not found (or end of file)
e.g.. -552 = Not authorized to object
SQLCODE values have corresponding messages
e.g.. SQL0100 = Row not found
e.g.. SQL0552 = Not authorized to &1
Many SQL programmers also check SQLWN0
A few warning conditions do not return > 0 SQLCODE value- e.g., If SQLCOD > 0 or SQLWN0 <> *Blank
ComConSQLCODE and Messages
Most SQLCODE values map to message IDs in QSQLMSG message file
MSGID is SQxxxxx where xxxxx is derived with the following rules:- Calculate the absolute value of the SQLCODE value- Zero-fill the result with leading zeros to construct a 5-digit number
- If the first digit in this number is 0, replace it with the letter 'L'
For example, SQLCODE value of -151 = message ID SQL0151
SQLCODE value of -30090 = message ID SQ30090
Use DSPMSGD RANGE(messageId) MSGF(QSQLMSG) to quickly find meanings of SQLCODE values
© ComCon and System i Developer, LLC 2006-2011 -18-
ComConSQLCODE vs. SQLSTATE (1 of 2)
SQLCODE values vary by platform
By contrast, SQLSTATE values are standard across platforms
However, SQLCODE is most widely used, especially for individual statements
SQLCODE is a deprecated function in current SQL standard
"Deprecated" means function replaced with a newer method- i.e SQLSTATE
Use of deprecated functions is typically discouraged
DB2 UDB for i plans to continue to support SQLCODE for the foreseeable future
Condition SQLCODE SQLSTATE Class(1st 2 positions)
Successful 0 00'
Warning >0 01'
End of Data Row not found
100 02'
Error <0 >='03'
ComConSQLCODE vs. SQLSTATE (2 of 2)
exec SQL
select lastName into :name
from employee
where empNo = :number;
select;
when SQLCode < 0;
// Bad Error
when SQLCode = 100;
// No More Rows
when ( SQLCode > 0
Or SQLWarn0 <> *Blank );
// Warning Error
other;
// Process Row
endSL;
exec SQL
select lastName into :name
from employee
where empNo = :number;
select;
when SQLCode < 0;
// Bad Error
when SQLCode = 100;
// No More Rows
when ( SQLCode > 0
Or SQLWarn0 <> *Blank );
// Warning Error
other;
// Process Row
endSL;
exec SQL
select lastName into :name
from employee
where empNo = :number;
select;
when %subSt(SQLStt:1:2) >= '03';
// Bad Error
when %subSt(SQLStt:1:2) = '02';
// No More Rows
when %subSt(SQLStt:1:2) = '01';
// Warning Error
other;
// Process Row
endSL;
exec SQL
select lastName into :name
from employee
where empNo = :number;
select;
when %subSt(SQLStt:1:2) >= '03';
// Bad Error
when %subSt(SQLStt:1:2) = '02';
// No More Rows
when %subSt(SQLStt:1:2) = '01';
// Warning Error
other;
// Process Row
endSL;
© ComCon and System i Developer, LLC 2006-2011 -19-
ComConFetch Multiple Rows
D listGroups DS dim(1000)
D group 5a
D description 50a
D numberOfRows S 10i 0 inz(%elem(listGroups))
exec SQL
declare C1 scroll cursor for
select a.group, descript
from groups a inner join sessions b
on a.group = b.group
order by 1
for read only;
exec SQL
open C1;
exec SQL
fetch first from C1 for :numberOfRows rows into :listGroups ;
rowsReturned = SQLErrd(3);
D listGroups DS dim(1000)
D group 5a
D description 50a
D numberOfRows S 10i 0 inz(%elem(listGroups))
exec SQL
declare C1 scroll cursor for
select a.group, descript
from groups a inner join sessions b
on a.group = b.group
order by 1
for read only;
exec SQL
open C1;
exec SQL
fetch first from C1 for :numberOfRows rows into :listGroups ;
rowsReturned = SQLErrd(3);
Fetch multiple rows with a single Fetch
Use a data structure array- Older methods use a more cumbersome multiple occurrence data structure
Number of rows returned in SQLERRD(3)
ComConBlocked INSERT
Multiple elements from a host structure are inserted into a table
Program variable may be used to set the number of records to be inserted
Executes as if n INSERT statements had been issued - but with improved performance
D listGroups DS dim(1000)
D group 5a
D description 50a
D numberOfRows S 10i 0
exec SQL
insert into Employee
:numberOfRows rows
values (listGroups) ;
D listGroups DS dim(1000)
D group 5a
D description 50a
D numberOfRows S 10i 0
exec SQL
insert into Employee
:numberOfRows rows
values (listGroups) ;
© ComCon and System i Developer, LLC 2006-2011 -20-
ComConCRTSQLRPGI
Use CRTSQLRPGI to create programs and modules
OBJTYPE � Compile type (*PGM, *SRVPGM, *MODULE)- Can be used to create single module service program
Not two separate commands
/COPY directives not included automatically
Must specify RPGPPOPT(*LVL1) or RPGPPOPT(*LVL2) on compile
Watch out for some of the other compile parameters
COMMIT � Commitment Control (More later)
OPTION � Pre-compiler options (*SYS, *SQL)
INCLUDE � Include file
CLOSQLCSR � Close SQL Cursor
DATFMT � Date Format
But there is an alternative for some of the compile parameters�
03/11/11 42
The CRTSQLRPGI command may be used to create *MODULE, *PGM or *SRVPGM objects based on the value specified for the OBJTYPE parameter.
RPGPPOPT(*LVL1) means that /COPY directives and conditional compilation directives are processed - RPGPPOPT(*LVL1) is the same as *LVL1 with the addition of /INCLUDE directives being processed.
Other compiler directives to watch out for are:� COMMIT � We will discuss later.
� OPTION � Specify whether system (*SYS, the default) or *SQL (SQL) notation/naming convention is used in embedded SQL statements. This si more then simply using a dot or a slash notation on qualified names - *SYS means that the jobs library list is taken into account whereas *SQL assumes all tables are in a single schema (library) and, unless changed, it is assumed that the name of the default schema is the same as user profile for the calling job. OPTION is also used to set other compile options.
� INCLUDE � specifies the source physical file to be used for SQL Include directives (not to be confused with RPG directives)
� CLOSSQLCSR � specifies when an open cursor should be implicitly closed � end of module or end of activation group.
� DATFMT � specifies the date format to be used with date fields in SQL statements. Any date fields used as host variables must correspond to this format.
© ComCon and System i Developer, LLC 2006-2011 -21-
ComConSET OPTION
Some compile options can be set using a SET statement
Much like compile options in the H spec
SET OPTION keyword = value- COMMIT � Commitment control
- NAMING � SQL naming convention
- DATFMT/DATSEP � Date format and separator- TIMFMT/TIMSEP � Time format and separator
- DBGVIEW � Debugging View
Consider a standard SET OPTION statement in an include (copy) member
DBGVIEW may only specify a value of *NONE or *SOURCE
But *SOURCE actually results in three source views being available- SQL Root Source view
- SQL Output view (output from SQL pre-compiler)
- Listing view
exec SQL
set option commit = *NONE
datFmt = *ISO
datSep = '-'
naming = *SQL;
exec SQL
set option commit = *NONE
datFmt = *ISO
datSep = '-'
naming = *SQL;
ComConSQL and Commitment Control
The default on compiles is Commit *CHG
This means:
If files are not journaled, programs will abnormally terminate whenever you attempt to use any SQL on those files
If your files are journaled, you will have uncommitted transactions unless you remember to explicitly commit them
If your shop does not normally use commitment control, consider using Commit *NONE on your compile commands
Or use SET OPTION COMMIT = *NONE
© ComCon and System i Developer, LLC 2006-2011 -22-
ComConStatic and Dynamic SQL
Static SQL
SQL Statements known at compile time
Better Performance
Dynamic SQL
SQL Statements build during program execution
Greater Flexibility
Dynamic SQL provides a different way to use SQL
SQL statements are not predefined in program- Dynamically created on the fly as part of program logic
SQL Precompiler cannot fully process dynamically created SQL statements- PREPARE statement is used in program logic to compile dynamically created SQL
statements at run time
Simple dynamic SQL statement process:- Build SQL statement in a character variable
- PREPARE the SQL statement- EXECUTE the SQL statement
ComConWhere to use Dynamic SQL
Report programs with user run time selection for
Files
Fields
Record selection criteria
Sorting
SQL built in functions
Whenever the exact syntax of an SQL statement cannot be determined beforehand
Dynamic SQL can be resource intensive
A dynamic SQL statement has to be parsed (interpreted) and executed at run time
Negative performance impact
Use dynamic SQL only when necessary
© ComCon and System i Developer, LLC 2006-2011 -23-
ComConDynamic SQL � Example 1
Delete all employees in a department or delete a single employee row
Construct statement as string
PREPARE the statement- Apply a name to the prepared statement
- Check of SQLCODE to ensure statement is correct
EXECUTE the name defined on the PREPARE
if deleteDepartment;
condition = 'workDept = ''' + inputValue + '''' ;
else ;
condition = 'empNo = ''' + inputValue + '''' ;;
endIf;
mySQLStatement = 'delete from employee where ' + condition;
exec SQL
prepare dynamicSQL
from :mySQLStatement;
if (SQLCode = 0);
exec SQL
execute dynamicSQL
endIf;
if deleteDepartment;
condition = 'workDept = ''' + inputValue + '''' ;
else ;
condition = 'empNo = ''' + inputValue + '''' ;;
endIf;
mySQLStatement = 'delete from employee where ' + condition;
exec SQL
prepare dynamicSQL
from :mySQLStatement;
if (SQLCode = 0);
exec SQL
execute dynamicSQL
endIf;
ComConParameter Markers in Dynamic SQL
Dynamic SQL statements cannot contain host variables
e.g. :employeeNo
Parameter markers are placed in embedded SQL statements
Indicated by ?
Used to dynamically insert host variable data for predicate values and/or column assignments
Multiple markers and values can be assigned
Values are assigned to markers when the statement is executed- Example on next chart
mySQLStatement = 'delete from employee where empNo = ?' mySQLStatement = 'delete from employee where empNo = ?'
© ComCon and System i Developer, LLC 2006-2011 -24-
ComConDynamic SQL � Example Again
Delete all employees in a department or delete a single employee row
Construct statement as string- Place ? for any replacement value
PREPARE the statement- Apply a name to the prepared statement
- Check of SQLCODE to ensure statement is correct
EXECUTE the name defined on the PREPARE- Provide replacement values here
if deleteDepartment;
condition = 'workDept = ?' ;
else ;
condition = 'empNo = ?';
endIf;
mySQLStatement = 'delete from employee where ' + condition;
exec SQL
prepare dynamicSQL
from :mySQLStatement;
if (SQLCode = 0);
exec SQL
execute dynamicSQL using :inputValue;
endIf;
if deleteDepartment;
condition = 'workDept = ?' ;
else ;
condition = 'empNo = ?';
endIf;
mySQLStatement = 'delete from employee where ' + condition;
exec SQL
prepare dynamicSQL
from :mySQLStatement;
if (SQLCode = 0);
exec SQL
execute dynamicSQL using :inputValue;
endIf;
ComConDynamic SQL Using a Cursor
Delete all employees in a department or delete a single employee row
Construct the string and PREPARE the statement
DECLARE the cursor using the name defined on the PREPARE- Assign a cursor name
OPEN the cursor- Using the cursor name defined on the DECLARE
- Provide replacement values here
if deleteDepartment;
condition = 'workDept = ?' ;
else ;
condition = 'empNo = ?';
endIf;
mySQLStatement = 'select * from employee where ' + condition;
exec SQL
PREPARE dynamicSQL from :mySQLStatement;
if (SQLCode = 0);
exec SQL
declare empCursor cursor for dynamicSQL;
exec SQL
open empCursor using :inputValue;
endIf;
if deleteDepartment;
condition = 'workDept = ?' ;
else ;
condition = 'empNo = ?';
endIf;
mySQLStatement = 'select * from employee where ' + condition;
exec SQL
PREPARE dynamicSQL from :mySQLStatement;
if (SQLCode = 0);
exec SQL
declare empCursor cursor for dynamicSQL;
exec SQL
open empCursor using :inputValue;
endIf;
© ComCon and System i Developer, LLC 2006-2011 -25-
ComCon�True� Embedded SQL
exec SQL
declare C1 cursor For
With T1 as (select day, sequence, room, session, id as forId
from schedule left outer join speakers
on speaker = id ),
T2 as (select day, sequence, room, a.session, shorttitle,
coalesce(forId, speakerOwn) as speaker
from T1 a inner join sessions b
on a.session = b.session)
select daynum, Dayname, showseq, a.type, fromtotime, title,
room, c.session, c.shorttitle, name, fromtime, fullDay,
allowrpt
from agendav1 a inner join daynums b
on a.day = b.day
left outer join T2 c
on a.day = c.day and
a.sequence = c.sequence
left outer join speakers d
on c.Speaker = d.Id
left outer join sessions e
on c.session = e.session
where dayNum > 1 and
(a.type <> 'E' or (a.type = 'E' and IncAttSel = 'Y'))
order by 1, 3 for read only;
exec SQL
declare C1 cursor For
With T1 as (select day, sequence, room, session, id as forId
from schedule left outer join speakers
on speaker = id ),
T2 as (select day, sequence, room, a.session, shorttitle,
coalesce(forId, speakerOwn) as speaker
from T1 a inner join sessions b
on a.session = b.session)
select daynum, Dayname, showseq, a.type, fromtotime, title,
room, c.session, c.shorttitle, name, fromtime, fullDay,
allowrpt
from agendav1 a inner join daynums b
on a.day = b.day
left outer join T2 c
on a.day = c.day and
a.sequence = c.sequence
left outer join speakers d
on c.Speaker = d.Id
left outer join sessions e
on c.session = e.session
where dayNum > 1 and
(a.type <> 'E' or (a.type = 'E' and IncAttSel = 'Y'))
order by 1, 3 for read only;
ComConEmbedded SQL Tips
/COPY and /INCLUDE directives not included automatically
Must specify RPGPPOPT(*LVL1) or RPGPPOPT(*LVL2) on compile
SQL precompile step happens before RPG compile
If SQL syntax or semantic error occurs, no "typical" compile source listing available
Can be very difficult to work through problems at this stage
Try removing "SQL" from member type and compile "normally"
Compile will fail, but you can see results of externally described structures, COPYs, etc.
When using ILE source view debugger
ILE SQL program compiles automatically generate 3 different views with DBGVIEW(*SOURCE)
To help diagnose run-time problems
Look in your job log after running the SQL program
Messages there often help diagnose problems
Put your job in debug mode before running SQL program, then look in your job log- Additional messages are put in job log when in debug mode which can be helpful in
diagnosing SQL performance problems
To really hunt down performance problems, use Visual Explain in Run SQL Scripts
© ComCon and System i Developer, LLC 2006-2011 -26-
ComConPerformance Tips
Test statements in Run SQL Scripts before embedding them
Copy/Paste into RSE
SQL uses two basic ways to retrieve data
Dataspace scan or arrival sequence - Generally used when MORE than 20% of records will be selected
Index based or keyed access - Generally used when LESS than 20% of records will be selected
Performance can improve significantly if SQL can use an index
Create indexes for - columns frequently referenced in WHERE, GROUP BY and ORDER BY clauses- Fields that are frequently used to join tables
Where possible, make use of
Multiple Row FETCH
Blocked Insert
ComConPerformance Analysis Tools
PRTSQLINF
Prints information about the embedded SQL statements in a program, SQL package or service program
- SQL statements, Access plans, List of command parameters used by pre-compiler
STRDBMON
Or Database Monitor in Navigator
Predictive Query Governor
CHGQRYA command
TRCJOB
Visual Explain
Option in Run SQL Scripts in Navigator
© ComCon and System i Developer, LLC 2006-2011 -27-
ComConSummary
Practical, effective solution for applications requiring complex data retrieval
Very flexible, functional application development tool
embedded in a HLL program
or entered interactively
Portability to other relational databases
Easy report writing with programmable flexibility
Similarity across many relational databases
ComConBy the Speaker
�Re-Engineering RPG Legacy Applications�
ISBN 1-58347-006-9
�The Programmers Guide to iSeries Navigator�
ISBN 1-58347-047-6
www.mcpressonline.com
www.midrange.com
www.amazon.com
etc.
iSeries Navigator for Programmers
A self teach course
www.lab400.com
Article links at
www.comconadvisor.com
© ComCon and System i Developer, LLC 2006-2011 -28-