Você está na página 1de 22

Embedding SQL

in RPG Programs

Susan Gantner
susan.gantner@partner400.com
www.Partner400.com
www.SystemiDeveloper.com Your partner in System i Education

Many RPG programmers have used interactive SQL as a tool to quickly browse data or to create
test data scenarios, but have stopped short of embedding it into their RPG programs. Come to this
session to learn why, when and how you may want to use SQL in conjunction with RPG. We will
cover the basics of embedding SQL into RPG, including using SQL cursors.

The authors, Susan Gantner and Jon Paris, are co-founders of Partner400, a firm specializing in
customized education and mentoring services for AS/400 and iSeries developers. After many years
with IBM, including several years at the Rochester and Toronto laboratories, Jon and Susan are
now devoted to educating developers on techniques and technologies to extend and modernize
their applications and development environments. This is done via on-site custom classes for
individual companies as well as conferences and user group events.

Together with her partner, Jon Paris, Susan authors regular technical articles for the IBM
publication, IBM Systems Magazine, i5 edition (formerly iSeries Magazine and eServer Magazine,
iSeries edition), and the companion electronic newsletter, i5 EXTRA (formerly iSeries Extra). You
may view articles in current and past issues and/or subscribe to the free newsletter or the magazine
at: http://www.ibmsystemsmag.com.

Susan and Jon are also partners in SystemiDeveloper, a company that hosts the RPG Summit and
DB2 Summit conferences. See SystemiDeveloper.com for more details.

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.

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 1-2 .


Agenda
Quick review: What is SQL?
Syntax and rules for embedding SQL into programs
Using SQL cursors for processing individual rows in a set
Error detection and handling
Tips
Dynamic SQL (appendix only)

Types 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
(SPL)

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 3-4 .


Using SQL on System i
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/400

iSeries Navigator
SQL wizards, productivity and testing tools
Graphical alternative to Interactive SQL

SQL Stored Procedures and SQL Triggers


Enforce business rules using SQL-based logic

Quick Review of SQL SELECT Syntax

Enter SQL Statements

Type SQL statement, press Enter.

> SELECT * FROM users WHERE clue > 0________


_0 rows returned._________________________
__________________________________________
__________________________________________
__________________________________________
__________________________________________
__________________________________________
__________________________________________
Bottom
F14=Delete line F15=Split line F16=Select library
F17=Select files F18=Select fields F24=More keys

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 5-6 .


RPG Interface - Source
Retrieve column/field values into program variables
One-to-one correspondence between SELECT and INTO lists
SELECT....INTO expects only a SINGLE row/record
Multiple rows require the use of cursor operations

Note: /Free form allows embedded SQL only V5R4 and later
* No F spec needed !
D EmpNbr S 5 0
D Name S 25
D Job S 1
C/EXEC SQL
C+ SELECT NAME, POS
C+ INTO :Name, :Job
C+ FROM EMPL
C+ WHERE NBR = :EmpNbr
C/END-EXEC
/Free
EXEC SQL SELECT NAME, POS
INTO :Name, :Job FROM EMPL
WHERE NBR = :EmpNbr;

Rules: Embedding SQL in RPG Code


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 (except in /Free form V5R4+)

... and end with /END-EXEC in positions 7-15 (except in /Free)


SQL statements may appear on the same line as /EXEC SQL
/END-EXEC must be on a separate line

Between beginning and ending delimiters, all SQL


statements must have + in position 7 (except in /Free form
V5R4+)
Note: SQL statements CANNOT be coded in the /FREE parts
of your C specs until V5R4
The SQL statement itself is free-form within the limitations listed here

Comments may be included at end of line preceded with --

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 7-8 .


More Rules: Embedding SQL in RPG
Program variables referenced in the SQL statement are
preceded with a colon (e.g., :EmpNbr)
Must not have names beginning with SQ, SQL, RDI, or DSN
Names must not be > 64 characters long
If local variables have same names as other locals or globals, all
definitions of that name must be identical
In V5R4, they need only be of the same type (e.g., numeric, character,
date) but will still issue Severity 11 warning
Set GENLVL parameter to be 11 or higher to have them accepted

SQL statements cannot be included via a /COPY statement


However, you can use the SQL INCLUDE statement instead

C/Exec SQL
C+ Include SrcMbrName
C/End-Exec

SELECT 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 we will discuss later

D CustID S 7P 0
D CustName S 30A
D CustSales S 7P 0
C/EXEC SQL
C+ SELECT CUSTID,CUSTNAM, CUSTSALES
C+ INTO :CUSTID,:CUSTNAME,:CUSTSALES
C+ FROM CUSTOMER
C+ WHERE CUSTID = :InputCust
C/END-EXEC

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 9-10 .


Updates and Deletes
SQL updates and deletes can be embedded as well
Set-at-a-time updates do not require cursor operations
This statement will update ALL records that meet the Where criteria

C/EXEC SQL
C+ UPDATE empl
C+ SET sal = sal + (sal * .10)
C+ WHERE pos = 5
C/END-EXEC

Using 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 CustInfo DS
D CustID 7P 0
D CustName 30A
D CustSales 7P 0
D InputCust S 7P 0
C/EXEC SQL
C+ SELECT CUSTID, CUSTNAM, CUSTSALES
C+ INTO :CustInfo
C+ FROM CUSTOMER
C+ WHERE CUSTID = :InputCust
C/END-EXEC

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 11-12 .


External Data Structures
The simple way to define a complete record format to match
a SELECT * request
Declare an externally described Data Structure
Subfields will be brought in to match all the fields in the record format

D CustRec E DS ExtName(Customer)
D InputCust S 7P 0
C/EXEC SQL
C+ SELECT *
C+ INTO :CustRec
C+ FROM CUSTOMER
C+ WHERE CUSTID = :InputCust
C/END-EXEC

SQL Result Sets


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 nbr, name


SQL Statement
FROM empl Produces
WHERE pos = 5

Nbr
10
Name
AMY
Pos
2
Sex
F
Sal
1200
Result Set
35 JOE 5 M 1000 Nbr Name

30 JON 7 M 1500 35 JOE

20 DON 5 M 1150 20 DON

25 ANN 8 F 1550

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 13-14 .


Selecting & Processing Multiple Rows

Steps to access multiple rows:


1. Declare cursor
2. Open cursor
3. Fetch a row (record)
4. Process row (UPDATE, INSERT, etc)
5. IF last row: go to Step 6,
ELSE go to Step 3
6. Close cursor

DECLARE CURSOR statement


Similar in function to HLL file declarations (F-specs or FD's)
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

Must be declared before being referenced


"Before" meaning physically present in the source member earlier

If updating fields/columns, specify "For Update Of ..." clause


List the column(s) that may be updated using this cursor
C/EXEC SQL
C+ DECLARE empcsr CURSOR FOR
C+ SELECT nbr, nam, sal
C+ FROM emp
C+ WHERE dpt = :dept
C+ FOR UPDATE OF sal
C/END-EXEC

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 15-16 .


OPEN 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 re-opened

C/EXEC SQL
C+ OPEN empcsr
C/END-EXEC

FETCH statement:
Bring rows into the program
One at a time for processing
Fields placed into host variables
one for one with fields in SELECT

Fetch Next is the default behavior


If a cursor is declared as "scrollable", Fetch has other options
e.g., Prior, First, Last

C/EXEC SQL
C+ FETCH NEXT FROM empcsr
C+ INTO :number, :name, :salary
C/END-EXEC

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 17-18 .


Positioned Update and Delete Stmts
Update or delete the current row of an updatable cursor
Can only be done after successful Fetch operation
Add a "Where Current of" clause to the Update and Delete statements
C/EXEC SQL
C+ DECLARE empcsr CURSOR FOR
C+ SELECT nbr, nam, sal
C+ FROM emp ORDER BY nbr
C+ FOR UPDATE OF sal
C/END-EXEC
C/EXEC SQL OPEN empcsr
C/END-EXEC
C/EXEC SQL
C+ FETCH NEXT FROM empcsr
C+ INTO :number, :name, :salary
C/END-EXEC
C/EXEC SQL
C+ UPDATE emp
C+ SET sal = sal + :raise
C+ WHERE CURRENT OF empcsr
C/END-EXEC

Close Statement
Close the cursor
Cursor must be opened in order to be closed

DB2/400 may close cursors for other reasons also:


job end
activation group ends
program ends
modules ends
commit or rollback without a 'with hold' clause
error handling......

C/EXEC SQL
C+ CLOSE empcsr
C/END-EXEC

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 19-20 .


SQL Precompiler for Embedded SQL

User Modified
Source Precompile Source Compile Program
Member Member

Processed Access
SQL Stmts Plans

(temporary)

Warning for Leading Edge RPGers


The SQL precompiler does not fully understand or support all
the latest RPG language features
V5R4 allows embedded SQL in /Free calcs and relaxed local variable
naming rules
Examples of things not supported as of V5R3 (not a complete list)
SQL embedded in /Free RPG calcs
> 1 level of qualification for DS subfields
Proper recognition of local variables in subprocedures
Examples of things not supported UNTIL V5R3 (not a complete list)
DS arrays for blocked fetches or inserts
One level of simple DS subfield qualification (not for DS array)
LIKEDS and LIKEREC support (2nd parameter still not supported)

See the iSeries Information Center for details on limitations


of RPG IV support
Topic is "Embedded SQL Programming" under
"Database/Programming" topic

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 21-22 .


Creating Programs with SQL Stmts
Create RPG/400 SQL applications using CRTSQLRPG
Creates a *PGM object

Create RPG IV SQL applications using CRTSQLRPGI


Creates either a *PGM, *MODULE, or *SRVPGM object

Compiling RPG/400 SQL Programs

Create SQL RPG Program (CRTSQLRPG)

Program . . . . . . . ________ Name


Library . . . . . . *CURLIB Name, *CURLIB
Source file . . . . . QRPGSRC Name, QRPGSRC
Library . . . . . . *LIBL Name, *LIBL, *CURLIB
Source member . . . . *PGM Name, *PGM
Commitment control . . *CHG *CHG, *ALL, *CS, *NONE...
Relational database . *LOCAL
Text 'description' . . *SRCMBRTXT
Precompiler options . *NOSRC__ *SRC, *SOURCE, *NOSRC...
+ for more values _______
Target release . . . *CURRENT *CURRENT, *PRV, V4R4M0, ...
INCLUDE file . . . . *SRCFILE Name, *SRCFILE
Library . . . . . *LIBL Name, *LIBL, *CURLIB
. . . .
To source file . . . . QSQLTEMP Name
Library . . . . . . QTEMP Name, *LIBL, *CURLIB

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 23-24 .


Compiling RPG IV SQL Programs
Create SQL ILE RPG Object (CRTSQLRPGI)
Object . . . . . . . _________ Name
Library . . . . . *CURLIB Name, *CURLIB
Source file . . . . QRPGLESRC Name, QRPGLESRC
Library . . . . . *LIBL Name, *LIBL, *CURLIB
Source member . . . *OBJ Name, *OBJ
Commitment control . *CHG *CHG, *ALL, *CS, *NONE...
Relational database *LOCAL
Compile type . . . . *PGM *PGM, *SRVPGM, *MODULE
Listing output . . . *NONE *NONE, *PRINT
Text 'description' . *SRCMBRTXT
Precompiler options. *XREF *XREF, *NOXREF, *GEN...
+ for more values ________
Target release . . . *CURRENT *CURRENT, *PRV, V4R4M0, ...
INCLUDE file . . . . *SRCFILE Name, *SRCFILE
Library . . . . . *LIBL Name, *LIBL, *CURLIB
. . . . .
Close SQL cursor . . *ENDACTGRP *ENDMOD, *ENDACTGRP
. . . . .
Debugging view . . . *NONE *SOURCE, *NONE
To source file . . . QSQLTEMP Name
Library . . . . . QTEMP Name, *LIBL, *CURLIB

SQL and Commitment Control


Note that default on compiles is Commit *CHG
This means:
If files aren’t journaled, programs will abnormally terminate whenever
you attempt to use 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

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 25-26 .


Debugging Embedded SQL
When using ILE source view debugger
ILE SQL program compiles automatically generate 3 different views
with DBGVIEW(*SOURCE):

Use F15 to switch between:


SQL Root Source view
SQL Output view (output from SQL precompiler)
Listing view

V5R3+ Compile Enhancement


What about compile options that are valid on CRTRPGPGM
or CRTBNDRPG or CRTRPGMOD that are NOT present on the
corresponding SQL compile statements?
With SQLRPGLE members, the best way to handle this is by
embedding the compile options on the H spec
e.g., H DFTACTGRP(*No) ACTGRP(MYAG) BNDDIR('MYBNDDIR')
This option has been available for many releases

New parameter added in V5R3:


Works for other source types (e.g., SQLRPG, SQLCBL)
Also works for SQLRPGLE types if recommended H spec option is not used
Compiler Options (COMPILEOPT)
A 5,000 character parameter field allowing parameters to be passed on to
the language compiler after the SQL precompile step
Parameters that are included on the SQL compile already cannot be
specified here because it will result in duplicate parameters being specified
Use compile keywords with the values

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 27-28 .


Error Detection and Handling
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
COBOL programs must have specific include, as shown below:

/EXEC SQL

INCLUDE SQLCA

/END-EXEC

Error Detection and Handling


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/400
SQLErrD Array of Integers SQLErrD(1) - treated as Char(4); last 4 characters of
CPF or other escape message
SQLErrD(2) - treated as Char(4); 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 t-1 if unconnected,
0 if local and 1 if connection is remote
SQLErrD(6) - when SQLCode is 0, contains SQL
completion message id

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 29-30 .


Error Detection and Handling

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

SQLCODE Error Handling


SQLCODE (SQLCOD in RPG) 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 pgmrs also check SQLWN0


A few warning conditions do not return > 0 SQLCODE value
e.g., If SQLCOD > 0 or SQLWN0 <> *Blank

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 31-32 .


SQLCODE and Messages
Most SQLCODE values map to message IDs in QSQLMSG
message file
MSGID is SQxxxxx where xxxxx is derived with the following rules:
1. Calculate the absolute value of the SQLCODE value.
2. Zero-fill the result with leading zeros to construct a 5-digit number.
3. 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 to quickly find meanings of SQLCODE values

SQLCODE and SQLSTATE

SQLSTT or
SQLCOD or
Condition SQLSTATE Class
SQLCODE
(1st 2 positions)

Successful 0 '00'

Warning >0 '01'

End of Data
100 '02'
Row not found

Error <0 >='03'

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 33-34 .


SQLCODE vs. SQLSTATE
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
Use of deprecated functions is typically discouraged

DB2 UDB for iSeries plans to continue to support SQLCODE


for the forseeable future

Error Checking With SQLCOD

C/EXEC SQL
C+ SELECT name INTO :nam
C+ WHERE emp = :number
C/END-EXEC

C Select
C When SQLCod < 0
C ExSR SQLError
C When SQLCod = 100
C ExSR NoMoreRows
C When ( SQLCod > 0 Or SQLWn0 <> *Blank )
C ExSR SQLWarning
C Other
C ExSR ProcessRow
C EndSL

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 35-36 .


Error Checking With SQLSTT

C/EXEC SQL
C+ SELECT name INTO :nam
C+ WHERE emp = :number
C/END-EXEC

C Select
C When %Subst(SQLStt:1:2) >= '03'
C ExSR SQLError
C When %Subst(SQLStt:1:2) = '02'
C ExSR NoMoreRows
C When %Subst(SQLStt:1:2) = '01'
C ExSR SQLWarning
C Other
C ExSR ProcessRow
C EndSL

Embedded SQL Tips


Use SQL source member types
e.g., SQLRPG, SQLRPGLE, SQLCBL, SQLCBLLE
Prompting won't work without SQL member type

You can prompt SQL statements in SEU


You MUST key both /EXEC SQL and /END-EXEC statements first
Enter the C+ for the SQL statement
Then you can prompt (F4) for statements in between
Same prompter as interactive SQL

To help diagnose run-time or performance 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

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 37-38 .


Static vs. Dynamic SQL
Static SQL
SQL Statement structure known at compile time
Better Performance

Dynamic SQL
SQL Statements built during program execution
Greater Flexibility

A few charts in the appendix of this handout illustrate the


basics of using Dynamic SQL

Summary
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

Similar skills across many relational databases

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 39-40 .


What is Dynamic SQL?
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

Where to use Dynamic SQL


Report programs with user run time selection
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

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 41-42 .


Parameter Markers in Dynamic SQL
Dynamic SQL statements cannot contain host variables
e.g., :CUSTNO

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

C Eval SQLStmtFld = 'Delete From Customer Where -


C CUSTNO = ?'

Dynamic SQL - Example

C If DeleteCorp
C Eval Condition = 'Corp = ?'
C Else
C Eval Condition = 'CustNo = ?'
C EndIf
C Eval SQLStmtFld = 'Delete From Customer Where '
C + Condition
C/EXEC SQL
C+ PREPARE DynSQLStmt
C+ FROM :SQLStmtFld
C/END-EXEC
C If (SQLCod = 0) And (SQLWn0 = *Blank)
C/EXEC SQL
C+ EXECUTE DynSQLStmt
C+ Using :Cust
C/END-EXEC
C EndIf

©Copyright Partner400, 2003 - 2007. SQL in RPG - Page 43-44 .

Você também pode gostar