Sunteți pe pagina 1din 149

Embedded SQL

Kevin Forsythe DMC Consulting


Kevin.forsythe@dmcconsulting.com

Why Embed SQL in your RPG?

Compile Time vs Run Time

New Source Type


Work with Members Using PDM File . . . . . . Library . . . . QRPGLESRC DMCSQLLIB DMC41 Position to . . . . . Type options, press Enter. 2=Edit 3=Copy 4=Delete 5=Display 8=Display description 9=Save 13=Change text Opt Member SQLPROC SQLTEST STOREDPRC1 STOREDPRC3 STOREDPRC4 STOREDPRC5 TSTRPGPRC TSTRPGPRC2 Type SQLRPGLE SQLRPGLE SQLRPGLE SQLRPGLE SQLRPGLE SQLRPGLE SQLRPGLE SQLRPGLE Text Test Test Test Test Test Test Test Test

6=Print 14=Compile

7=Rename 15=Create module...

program program program program program program program program

containing containing containing containing containing containing containing containing

SQL SQL SQL SQL SQL SQL SQL SQL

statements statements statements statements statements statements statements statements More...

Parameters or command ===> F3=Exit F4=Prompt F9=Retrieve F10=Command entry

F5=Refresh F23=More options

F6=Create F24=More keys

Before you can embed SQL into your RPGIV code you have to specify the source type as SQLRPGLE.

Syntax
C/EXEC SQL C+ your-sql-code-here C/END-EXEC C/EXEC SQL INCLUDE member-name C/END-EXEC ?

Syntax
Avoid creating fields that start with: 'SQ' 'SQL' 'RDI' 'DSN These may interfere with variable names used by the pre-compiler.

Host Variables :field-name


RPG IV variables you cant use as a HOST variable: Pointers Tables UDATE UDAY UMONTH UYEAR Look-ahead fields Named constants Definitions requiring the resolution of %SIZE or %ELEM

SQL Pre-Compiler CRTSQLxxx


The pre-compiler will do the following: Looks for SQL statements and for the definition of host variables.
Validates variable names and definitions used in the SQL statements. Any errors found will be included in a compile listing.

Verifies that each SQL statement is free of syntax errors. Validates the syntax of
each SQL statement. See the compile listing for errors.

Validates the SQL statements using the description in the database.


Validates table, view, and column names. If a specified table or view does not exist, or you are not authorized to the table or view, the validation will be done at run time. If the table or view does not exist at run time, an error occurs.

SQL Pre-Compiler
SQLAID SQLABC SQLCOD - SQLCODE SQLERL SQLERM SQLERP SQLERR SQLSTT - SQLSTATE SQLWRN - SQLWARN
The SQL pre-compiler adds a number of fields to your RPG IV programs. These fields are used primarily for error checking. These are covered in more detail later.

CRTSQLRPGI
When compiling an RPG program that includes embedded SQL statements, some new options are provided.

Commitment Control:
- Objects and updated records are locked until they are committed. Uncommitted changes from other programs can be seen.

*CHG *CS

- Objects and updated records are locked until they are committed. Uncommitted changes from other programs can not be seen, and selected records are locked until the next record is selected. - As *CS, but records selected are locked until a COMMIT is performed.

*ALL *RR

- As *ALL, but tables referenced by SELECT, UPDATE, INSERT, and DELETE are locked exclusively.

*NONE-

Commitment control is not used.

CRTSQLRPGI
Relational Database: *LOCAL - The SQL package information is embedded in the program. named - The SQL package will be created in the named relational database.

Listing Output: *PRINT - The pre-compile listing will be printed. *NONE - No pre-compile listing is produced.

CRTSQLRPGI
INCLUDE file: *SRCFILE - Source members referenced by SQL INCLUDES will be found in the same source file as the program source. named - Specify the file and library that source members referenced by SQL INCLUDES will be found in.

CRTSQLRPGI
Allow copy of data: *YES - A copy of selected data is only used when necessary. *OPTIMIZE- The system will determine whether to use a copy of the selected data, or read it directly from the table. *NO used. - A copy of the selected data is not If one is required, an error will occur.

CRTSQLRPGI
Close SQL Cursor: *ENDACTGRP - SQL cursors not explicitly closed in the program will be implicitly closed when the activation group the program is running in ends. *ENDMOD - SQL cursors not explicitly closed in the program will be implicitly closed when the module is exited.

CRTSQLRPGI
Allow Blocking: *READ - Read only data retrievals will be blocked. This improves performance for programs reading large numbers of records. *NONE - No blocking is allowed.

*ALLREAD - As read but if the commitment level is *CHG, then blocked reads may also be performed against updateable tables. However some SQL commands will not function correctly. See the help text for more information.

CRTSQLRPGI
Delay Prepare: *YES - Prepared SQL statements are validated when they are used in an OPEN, EXECUTE, or DESCRIBE statement. *NO - Prepared SQL statements are validated by the PREPARE statement. RDB Connect Method: *DUW - Your program can be connected to multiple databases simultaneously. *RUW - The CONNECT statement will cause previous connections to be disconnected.

CRTSQLRPGI
Package: *OBJ - The SQL package will be created with the same name as the program. named - Specify the SQL package name.

IBM SQL FLAGGING: *FLAG - SQL statements will be checked to see if they conform to IBMs SQL syntax. *NOFLAG - No checking will be done.

CRTSQLRPGI
ANS FLAGGING: *ANS - Statements are checked to see if they conform to ANSI X3.135-1992, ISO 9075-1992, and FIPS 127.2 standards. *NONE - No checking will be done. Debugging View: *NONE - Source statements will not be available during debug. *SOURCE - Source statements will be available during debug.

CRTSQLRPGI
User Profile: *NAMING - If the naming convention is SQL, the *OWNER will be used. If the naming convention is *SYS, *USER will be used. *USER - Authority is checked against the user profile of the user running the program. *OWNER - Authority is checked against the user profile of the user who owns the program. (Usually the programmer who compiled it. Also referred to as Adopted authority).

CRTSQLRPGI
Dynamic User Profile: *USER - Local Dynamic SQL statements are run under the users profile. *OWNER - Local Dynamic SQL statements are run under the profile of the programs owner.

ILE Review

RPG IV
Built in Functions Date & Time Support New Op Codes D Specs

ILE
Activation Groups Modules Serive Programs Sub Procedures

ILE Review
Service PGM X Module D Module E Module F (NOMAIN)
Sub Proc 1 Sub Proc 2 Sub Proc 3

Module B

Module C

Module A (Procedure Entry Point) Program Y

Embedding SELECT
Selecting ONE field from ONE record
DW_ITEM DW_DESC S S 9P 0 40

* Run the SQL select C 'ITEM?' C/Exec SQL C+ C+ C+ C/End-exec C C W_DESC DSPLY SELECT MDESC INTO :W_DESC FROM ITMMST WHERE MITEM = :W_ITEM DSPLY RETURN W_ITEM

Embedding SELECT
Selecting TWO fields from ONE record
DW_ITEM DW_PRICE DW_DESC S S S 9P 0 7P 2 40

* Run the SQL select C 'ITEM?' C/Exec SQL C+ C+ C+ C/End-exec C C C W_DESC W_PRICE DSPLY SELECT MDESC,MPRICE INTO :W_DESC, :W_PRICE FROM ITMMST WHERE MITEM = :W_ITEM DSPLY DSPLY RETURN W_ITEM

Embedding SELECT
Selecting MANY fields from ONE record
DW_DATA E DS EXTNAME(ITMMST)

* Run the SQL select C 'ITEM?' C/Exec SQL C+ C+ C+ C/End-exec C C C MDESC MPRICE DSPLY SELECT * INTO :W_DATA FROM ITMMST WHERE MITEM = :MITEM DSPLY DSPLY RETURN MITEM

Embedding INSERT
There are three types of embedded INSERTS:

INSERT VALUES: Adds one row to a table using the values specified. INSERT SELECT: Adds one or more rows using the results of a sub-select. INSERT n ROWS: Adds multiple rows at once using the values specified in a multiple occurrence data structure.

Embedding INSERT
* Run the SQL INSERT W/VALUES C/Exec SQL C+ C+ C+ C/End-exec INSERT INTO CUST VALUES(7, The Fruit Stand,,, Miami,FL,,)

* Run the SQL INSERT W/SUB-SELECT C/Exec SQL C+ C+ C/End-exec

INSERT INTO TESTLIB/CUST SELECT * FROM PRODLIB/CUST

Embedding INSERT
* Run the SQL INSERT W/n ROWS DW_FIELDS D W_ITEM D W_DESC D W_WGT D W_PRICE D W_CUST DS 9 40 4 9 or E DS 0 2 2 EXTNAME(CUST) OCCURS(10) OCCURS(10)

* Run the SQL select C/Exec SQL C+ C/End-exec INSERT INTO ITMMST 10 ROWS VALUES(:W_FIELDS)

Embedding UPDATE
* Run the SQL UPDATE C/Exec SQL C+ C+ C/End-exec UPDATE CUST SET CSTATE = FL WHERE CCITY = Miami

C/Exec SQL C+ UPDATE CUSTWORK SET ROW = (SELECT * FROM CUST WHERE C+ CUSTWORK.NAME = CUST.NAME) C/End-exec

Embedding DELETE
* Run the SQL DELETE C/Exec SQL C+ C/End-exec DELETE FROM CUST WHERE CNUMBER = :CUSTNBR

Using PREPARE
DW_SQL DW_SELECT DW_FROM DW_WHERE DW_FIELD DW_VALUE S C C C S S 1000 SELECT MITEM FROM ITMMST WHERE 10 30

Using PREPARE
C C C C C C FIELD?' VALUE?' DSPLY DSPLY EVAL W_FIELD W_VALUE W_SQL= W_SELECT + W_FROM + W_WHERE + W_FIELD + = + W_VALUE OR = + W_VALUE +

Using PREPARE
C/Exec SQL C+ PREPARE @S1 from :W_SQL C/End-exec C/Exec SQL C+ DECLARE @C1 CURSOR FOR @S1 C/End-exec C/Exec SQL C+ OPEN @C1 C/End-exec C DOU SQLCODE <> *zero C/Exec SQL C+ FETCH @C1 INTO :W_VALUE C/End-exec C C/Exec SQL C+ CLOSE @C1 C/End-exec ENDDO

Using PREPARE
An SQL statement can be entered into a character string variable. The prepare statement translates that into an executable statement. Prepare once, execute many times. The prepared statement cannot contain host variables.

PREPARE:

DECLARE: CURSOR:

If the SQL statement is a select statement, you must declare a cursor.

A cursor defines a result table and the current row within that table. It is read-only if data was selected from more than one table, the data was selected from a read-only table, or if the select statement used the DISTINCT keyword. (A number of other conditions could also cause the table to be read-only.)

OPEN:

To perform a prepared SELECT, you must open the cursor. The result table will be created and the cursor will be set to the beginning of the result table.

Use FETCH to read the next row from the result table. If you read past the end of the result table, the SQLCOD field will contain an error code of 100.

FETCH: CLOSE:
cursor.

After you have finished reading the rows from a result table, close the This will allow you to reopen it later, retrieving new results.

Using PREPARE
* DW_SQL DW_DELETE DW_FROM DW_WHERE DW_FIELD DW_VALUE C C C C C FIELD?' VALUE?' S C C C S S DSPLY DSPLY EVAL 1000 DELETE FROM ITMMST WHERE 10 30 W_FIELD W_VALUE W_SQL= W_DELETE + W_FROM + W_WHERE + W_FIELD + = + W_VALUE

C/Exec SQL C+ PREPARE @S1 from :W_SQL C/End-exec

Using EXECUTE

EXECUTE:
statement.

If the prepared statement is not a SELECT, use EXECUTE to perform the

EXECUTE IMMEDIATE:

If the character string contains no host variables or parameter markers, and is only going to be executed once, you can use EXECUTE IMMEDIATE to perform that statement.

Using EXECUTE
C/Exec SQL C+ C/End-exec C/Exec SQL C+ C/End-exec

EXECUTE @S1

EXECUTE IMMEDIATE :W_SQL

EXECUTE IMMEDIATE
in quotes.

has to use a string variable. You cannot use an expression You must first load the variable with the SQL statement.

Embedding SELECT Multiple Row Fetch


* Run the SQL SELECT for n ROWS DW_FIELDS D W_ITEM D W_DESC D W_WGT D W_PRICE DS 9 40 4 9 0 2 2 OCCURS(10)

C/EXEC SQL FETCH C1 FOR 10 ROWS C+ INTO :W_FIELDS C/END-EXEC

Embedding SELECT Multiple Row Fetch


It is possible to read more than one record at a time, loading a MODS with values for several records at once. This is more efficient than the standard one record at a time method.

Three variables will be updated in the SQLCA: SQLERRD(3) shows the number of rows retrieved. SQLERRD(4) shows the length of the row retrieved. SQLERRD(5) shows 100 if the last row was read.

Using Parameter Markers

* DW_SQL DW_SELECT DW_FROM DW_WHERE DW_VALUE C C C ITEM?'

S C C C S DSPLY EVAL

1000 SELECT MITEM FROM ITMMST WHERE MITEM = ? 30 W_VALUE W_SQL= W_SELECT + W_FROM + W_WHERE

Using Parameter Markers


C/Exec SQL C+ PREPARE @S1 from :W_SQL C/End-exec C/Exec SQL C+ DECLARE @C1 CURSOR FOR @S1 C/End-exec C/Exec SQL C+ OPEN @C1 USING :W_VALUE C/End-exec C DOU SQLCOD <> *zero C/Exec SQL C+ FETCH @C1 INTO :W_VALUE C/End-exec C C/Exec SQL C+ CLOSE @C1 C/End-exec ENDDO

Using Parameter Markers


DW_SQL DW_DELETE DW_FROM DW_WHERE DW_VALUE1 DW_VALUE2 S C C C S S 1000 DELETE FROM ITMMST WHERE MITEM IN (?, ?) 30 30

C C C C

ITEM?' ITEM?'

DSPLY DSPLY EVAL

W_VALUE1 W_VALUE2 W_SQL= W_DELETE + W_FROM + W_WHERE

C/Exec SQL C/End-exec C/Exec SQL C/End-exec

PREPARE @S1 from :W_SQL

EXECUTE @S1 USING :W_VALUE1, :W_VALUE2

Using Parameter Markers


DW_SQL DW_DELETE DW_FROM DW_WHERE DW_VALUE1 DW_COMP C C C C ITEM?' S C C C S S DSPLY EVAL EVAL 1000 DELETE FROM ITMMST WHERE MITEM LIKE ? 30 30 VARYING

W_VALUE1 W_COMP = %TRIM(W_VALUE1) W_SQL= W_DELETE + W_FROM + W_WHERE

Using Parameter Markers


C/Exec SQL C+ PREPARE @S1 from :W_SQL C/End-exec C/Exec SQL C+ EXECUTE @S1 USING :W_COMP C/End-exec

Be careful when using LIKE with host variables or parameter markers. The embedded blanks at the end of the field will cause the LIKE to fail. Use of a variable length field will eliminate this problem

Using Parameter Markers


Parameter markers cannot be used in all parts of an SQL statement. are some of the ways in which parameter markers CANNOT be used: In a select list - SELECT ? (except as a sub-query) In a Concatenation - ? || FRED As both parts of a comparison (WHERE ? = ?) To avoid this problem use the CAST function to specify the data type of the parameter. CAST(? AS CHAR) CAST(? AS NUMERIC) Here

SQL Error Handling - SQLCA

SQLCODE
0 Positive Negative - Success - Warning - Error

SQL Communications Area


D SQLCA D SQLAID D SQLABC D SQLCOD D SQLERL D SQLERM D SQLERP D SQLERRD D SQLERR D SQLER1 D SQLER2 D SQLER3 D SQLER4 D SQLER5 D SQLER6 DS 1 9 13 17 19 89 8A 12B 0 16B 0 18B 0 88A 96A

97 120B 0 DIM(6) 97 120A 97 100B 0 101 104B 0 105 108B 0 109 112B 0 113 116B 0 117 120B 0

SQL Communications Area


D SQLWRN D SQLWN0 D SQLWN1 D SQLWN2 D SQLWN3 D SQLWN4 D SQLWN5 D SQLWN6 D SQLWN7 D SQLWN8 D SQLWN9 D SQLWNA D SQLSTT 121 131A 121 121A 122 122A 123 123A 124 124A 125 125A 126 126A 127 127A 128 128A 129 129A 130 130A 131 131A 132 136A

SQL Communications Area


SQLERL - Contains the length of the text loaded into SQLERM. SQLERM - Contains Message text for the SQLCOD value.
SQLERP - Contains the name of the Product and Module returning an error. SQLERRD - Array containing 6 diagnostic codes. (1) - Last four digits of the CPF message if SQLCOD is negative. (2) - Last four digits of the CPD message if SQLCOD is negative. (3) - For INSERT, UPDATE, DELETE, and FETCH, the number of rows affected. For PREPARE, the estimated number of rows returned. (4) - For PREPARE, the estimated cost of execution. For CALL, the message key of the error which caused the call to fail. For trigger errors during a INSERT, UPDATE, or DELETE, the message key of the error. For FETCH, the length of the row. (5) - For DELETE, the number of rows affected by referential constraints. For PREPARE or EXECUTE IMMEDIATE, the position of a syntax error. For multi-row FETCH, +100 if the last record was read. For CONNECT and SET CONNECTION, -1 if not connected, 0 if local, 1 if remote. For PREPARE, the number of parameter markers. (6) - SQL completion code when SQLCOD is 0.

SQL Communications Area


SQLWRN - String of 11, 1 byte flags. (0) - Master flag, will contain a W if any flags contain a W or N. (1) - Contains a W if a string column was truncated while being loaded into host variable. (2) - Contains W if NULL values were eliminated from an argument of a function. (3) - Contains a W if the number of columns exceeds the number of host variables. (4) - Contains a W if UPDATE or DELETE do not contain a WHERE clause. (5) - Reserved. (6) - Contains a W if date arithmetic results in an end of month adjustment. (7) - Reserved. (8) - Contains a 'W' if the result of a character conversion contains a substitution character. (9) - Reserved. (10) - Reserved. SQLSTT - A return code for the most recent SQL statement. (For detail on the SQLSTATE (SQLSTT) values, see Appendix B in manual DB2 UDB for AS/400 SQL Programming.)

You can find more information on-line at: publib.boulder.ibm.com in the manual: DB2 for AS/400 SQL programming.

SQL Error Handling WHENEVER


In addition to the SQLCA, other error handling features are available. Use the SQL WHENEVER statement to set up error trapping before issuing other SQL statements. WHENEVER NOT FOUND WHENEVER SQLERROR WHENEVER SQLWARNING = IF SQLCODE = 100 = IF SQLCOD < *ZERO = IF SQCOD > *ZERO and SQLCOD <> 100

The WHENEVER statement will go into effect until a new WHENEVER statement of the same type is issued. This eliminates needing to test each SQL statement for an error. In general, this function is very similar to the global MONMSG function in CL. However the statements are processed by compile in the sequence they are written, not at run time in the order they are executed. Therefor their use is discouraged.

SQL Error Handling


* Run the SQL INSERT W/VALUES C/Exec SQL C+ WHENEVER SQLWARNING CONTINUE C/End-exec C/Exec SQL C+ WHENEVER NOT FOUND GOTO DONE C/End-exec C/Exec SQL C+ WHENEVER SQLERROR GOTO ERROR C/End-exec C C DONE ERROR TAG TAG

ADVANCED CURSORS

SCROLL

- Allows forward and back movement of the cursor.

DYNAMIC SCROLL - As Scroll but also allows update. WITH HOLD - Allows COMMIT to be performed without closing the cursor.

ADVANCED CURSORS
In the DECLARE CURSOR statement you can add additional clauses to provide more capability within the program. By default a FETCH will perform sequential reads against the data in the specified order. Specify SCROLL to allow more flexibility in moving the cursor. Specify DYNAMIC SCROLL to allow update. Specify WITH HOLD if you want to use commitment control with the updates.

ADVANCED CURSORS
FETCH NEXT PRIOR FIRST LAST BEFORE AFTER CURRENT - positions cursor ON next record. - positions cursor ON previous record. - positions cursor ON the first record in the result table. - positions cursor ON the last record in the result table. - positions cursor BEFORE the first record in the result table. - positions cursor AFTER the last record in the result table. - no change. A positive

RELATIVE - A negative number moves back x rows. value moves forward X rows.

ADVANCED CURSORS
C+ DECLARE @QC1 DYNAMIC SCROLL CURSOR WITH HOLD C+ FOR SQLSTMT @S1 C+ FETCH PRIOR FROM @QC1 INTO :W_DATA1 :W_IND1, C+ :W_DATA2 :W_IND2, :W_DATA3 :W_IND3 C+ FETCH RELATIVE -1 FROM @QC1 INTO :W_DATA1 :W_IND1, C+ :W_DATA2 :W_IND2, :W_DATA3:W_IND3 C+ FETCH BEFORE FROM @QC1 C+ DECLARE @C2 DYNAMIC SCROLL CURSOR WITH HOLD FOR C+ SELECT * FROM DATA FOR UPDATE OF LONGNAM2 C+ FETCH FIRST FROM @QC2 INTO :W_FIELDS C+ UPDATE DATA SET LONGNAM2 = FRED C+ WHERE CURRENT OF @C2

ADVANCED CURSORS
The FOR UPDATE OF clause in the SELECT statement indicates which columns in the table are valid for update. Specifying just FOR UPDATE will make all columns updateable. Updateable columns cannot be referenced in the ORDER BY clause.

SQL Commitment Control


Commit
UPDATE MASTER RECORD INSERT HISTORY RECORD DELETE TRANSACTION
COMMIT

UPDATE MASTER RECORD INSERT HISTORY RECORD DELETE TRANSACTION


COMMIT

SQL Commitment Control


Commitment control is used to group multiple file updates together, and treat them as a single transaction. Either they all succeed, or they all fail. This ensures data integrity even in the case of a program crash. All updates are considered tentative, until the commit is performed. The Commit command requires commitment control to be active. To determine if it is active, check each users Query Manager profile to determine their commitment control level. There are five different levels. Each level provides increasing levels of control.

SQL Commitment Control


1) NONE - Commitment control is not active. It is the default setting, and COMMIT and ROLLBACK cannot be used with this setting. 2) CHG - Rows that have been inserted, updated, or deleted will be locked until a COMMIT or ROLLBACK is performed. 3) CS - (Cursor Stability) As CHG, but in addition all rows selected in a WHERE clause are locked until you have scrolled past them. 4) ALL - All rows that were read, inserted, updated, or deleted are locked until a COMMIT or ROLLBACK is performed. 5) RR - (Repeatable Read) As ALL, but in addition all tables are locked.

SQL Commitment Control Rollback


The rollback command also requires commitment control to be active. Unlike COMMIT, ROLLBACK is rarely used in SQL. The system will automatically issue a roll back when a SQL job ends abnormally, and on exit from an interactive SQL session. Be sure to COMMIT all changes, before pressing F3 to exit. Also be aware that when using commitment control in an interactive SQL session you may be keeping records locked for extended periods of time. This may interfere with other users on the system.

COMMITMENT CONTROL
After reading a transaction record: 1) The master file will be updated 2) A record will be added to the history file 3) The transaction record will be deleted All of these transactions will be done as a group. Either they all succeed or they all fail. This will simplify restarting the program after an error.

COMMITMENT CONTROL

D W_FIELDS D W_SQL C C

E DS S EVAL 1000

EXTNAME(TRAN)

W_SQL = 'SELECT * + FROM TRAN FOR UPDATE'

C/EXEC SQL WHENEVER SQLERROR GOTO ERROR C/END-EXEC C/EXEC SQL PREPARE SQLSTMT FROM :W_SQL C/END-EXEC

COMMITMENT CONTROL

c* C/EXEC SQL C+ DECLARE @QC1 DYNAMIC SCROLL CURSOR WITH HOLD FOR SQLSTMT C/END-EXEC C/EXEC SQL C+ OPEN @QC1 C/END-EXEC C/EXEC SQL C+ FETCH NEXT FROM @QC1 INTO :W_FIELDS C/END-EXEC

COMMITMENT CONTROL
C DOW SQLCOD = *ZERO C/EXEC SQL C+ UPDATE MAST SET OHQTY = OHQTY + :TRQTY C+ WHERE MAST.PART = :PART C/END-EXEC C/EXEC SQL C+ INSERT INTO HIST VALUES(:W_FIELDS) C/END-EXEC C/EXEC SQL C+ DELETE FROM TRAN WHERE CURRENT OF @QC1 C/END-EXEC C COMMIT C/EXEC SQL C+ FETCH NEXT FROM @QC1 INTO :W_FIELDS C/END-EXEC C ENDDO

COMMITMENT CONTROL
C C C ERROR END TAG ROLBK TAG

C/EXEC SQL C+ WHENEVER SQLERROR CONTINUE C/END-EXEC * Close SQL cursor C/EXEC SQL C+ CLOSE @QC1 C/END-EXEC C RETURN

Null Values
C/EXEC SQL C+ UPDATE DATA SET LONGNAM2 = NULL WHERE NAME IS NOT NULL C/END-EXEC

C/EXEC SQL C+ SELECT * FROM DATA WHERE LONGNAM2 IS NULL C/END-EXEC

Null Values
NULL values are unknown values, not blank, not zero, not anything, simply unknown. You cannot reference the data in a field if it has a NULL value. Not all fields can contain NULL values. An even value in SQLTYPE denotes that the field can not contain NULL. An odd value denotes that NULL is allowed. SQL provides a mechanism for testing fields for NULL values. An associated indicator will be loaded with negative 1 if the field contains a NULL value, as seen on the next page.

Null Values

* Single Row FETCH testing for NULL values DW_NAME DW_LONGNAM1 DW_LONGNAM2 DW_IND1 DW_IND2 S S S S S 30 120 120 5I 0 5I 0

C/EXEC SQL C+ FETCH NEXT FROM @QC1 INTO :W_NAME :W_IND1, C+ :W_LONGNAM1, :W_LONGNAM2 :W_IND2 C/END-EXEC

Null Values
* Multi Row FETCH testing for NULL values DW_FIELDS D W_NAME D W_LONGNAM1 D W_LONGNAM2 DW_IND D W_IND1 D W_IND2 D W_IND3 DS 30 120 120 DS 5I 0 5I 0 5I 0 OCCURS(10) OCCURS(10)

C/EXEC SQL FETCH @QC1 FOR 10 ROWS C+ INTO :W_FIELDS :W_IND C/END-EXEC

Stored Procedures CREATE PROCEDURE RPGPROC(IN PARM1 CHAR (30)) LANGUAGE RPGLE NOT DETERMINISTIC CONTAINS SQL EXTERNAL NAME RPGPROC PARAMETER STYLE GENERAL

Stored Procedures CALL RPGPROC (DATA)

How to Embed RPG in your SQL?

Build Service Programs!

The Service Program is an extremely powerful tool for deploying applications. Essentially it allows you to extend both SQL and RPG to include new features that you need.

Build User Defined Functions!

User Defined Functions (UDFs) allow you to extend the capabilities of the SQL engine, and more tightly integrate it with your database. RPG ILE is often used to develop these functions.

Keep It Simple System

1) Have one binding directory for all tools i5Tools 2) Have one copy book for all prototypes i5Tools 3) Document Procedures in the Copy Book

Service Program Code


Create Binding Directory CRTBNDDIR i5Tools Add Service Programs to directory ADDBNDDIRE BNDDIR(I5TOOLS) OBJ((MsgBox)) ADDBNDDIRE BNDDIR(I5TOOLS) OBJ((Dates)) ADDBNDDIRE BNDDIR(I5TOOLS) OBJ((Fetch))

Service Program Examples

1)Message Box Utility


2) Get Text Descriptions of Dates 3) Perform SQL Fetch

MsgBox Code Part 1 of 4


H NOMAIN EXPROPTS(*RESDECPOS) H OPTION(*SRCSTMT:*NODEBUGIO) FMSGBOXDF CF E WORKSTN F USROPN
DMsgBox D Msg1 D Msg2 D D Msg3 D D Msg4 D PR 50A 50A 50A 50A VALUE OPTIONS(*NOPASS) VALUE OPTIONS(*NOPASS) VALUE OPTIONS(*NOPASS) VALUE

MsgBox Code Part 2 of 4


PMsgBox DMsgBox D Msg1 D Msg2 D D Msg3 D D Msg4 D B PI 50A 50A 50A 50A EXPORT VALUE OPTIONS(*NOPASS) VALUE OPTIONS(*NOPASS) VALUE OPTIONS(*NOPASS) VALUE

MsgBox Code Part 3 of 4

C C C C C

OPEN Clear Clear Clear Clear

MSGBOXDF Text1 Text2 Text3 Text4

MsgBox Code Part 4 of 4


C C C C C C C C C C C C C C C PMsgBox EVAL SELECT WHEN EVAL WHEN EVAL EVAL WHEN EVAL EVAL EVAL ENDSL EXFMT CLOSE Return E Text1 = Msg1 %PARMS = 2 Text2 = Msg2 %PARMS = 3 Text2 = Msg2 Text3 = Msg3 %PARMS = 4 Text2 = Msg2 Text3 = Msg3 Text4 = Msg4 Win1 MSGBOXDF

MsgBox DDS Part 1 of 2


A A A A A A A A A A R WIN1 WINDOW(10 10 8 60*NOMSGLIN) PUTOVR WDWBORDER( (*COLOR BLU)(*DSPATR RI)(*CHAR ' ')) 1 26'Message Box' DSPATR(HI)

MsgBox DDS Part 2 of 2

A A A A A A A A A

TEXT1 TEXT2 TEXT3 TEXT4

50 50 50 50

O O O O

3 4 5 6 8

6 6 6 6 2'F12 = Cancel' COLOR(BLU) ASSUME

R DUMMY 1 3' '

Service Program Code

Create Module CRTRPGMOD MODULE(MYLIB/MsgBox) SRCFILE(MYLIB/i5Tools) SRCMBR(MsgBox) Create Service Program CRTSRVPGM SRVPGM(MYFLIB/MsgBox) MODULE(MsgBox) EXPORT(*ALL)

Putting it to the test


H BNDDIR(I5TOOLS) /COPY i5Tools,i5Tools /FREE MsgBox(What a Cool Tool!); MsgBox(First one line: Then another!); *INLR = *ON; /END-FREE

Putting it to the test

Getting Date Names

Getting Date Names


02/14/2006
Order 123 scheduled to ship on Tuesday Month End Close for February is Complete Shipment due for Monday, February 14 2006

Service Program Code Part 1 of 4


H NOMAIN EXPROPT(*RESDECPOS) H OPTION(*SRCSTMT:*NODEBUGIO) H COPYRIGHT('DMC Consulting 2005') /COPY i5Tools,i5Tools
D GetDayNam PR 10 D InpDat D D GetMonNam PR 10 D InpDat D D GetDatNam PR 40 D InpDat D

Service Program Code Part 2 of 4


PGetDayNam DGetDayNam D Date D Daynam B PI S EXPORT 10 d 10

C/EXEC SQL C+ SET :DayNam = DAYNAME(:Date) C/END-EXEC C return DayNam P E

Service Program Code Part 3 of 4


PGetMonNam EXPORT DGetMonNam D Date D MonNam B PI S 10 d 10

C/EXEC SQL C+ SET :MonNam = MONTHNAME(:Date) C/END-EXEC C return MonNam P E

Service Program Code Part 4 of 4


PGetDatNam DGetDatNam D Date D Datnam B PI S EXPORT 40 d 40

C/EXEC SQL C+ SET :DatNam = DAYNAME(:Date) || ' ' || C+ MONTHNAME(:Date) || ' ' || C+ CHAR(DAYOFMONTH(:Date)) || ', ' C+ CHAR(YEAR(:Date)) C/END-EXEC C return DatNam P E

Service Program Code


Create Module CRTRPGMOD MODULE(KPFLIB/Dates) SRCFILE(KPFLIB/i5Tools) SRCMBR(Dates) Create Service Program CRTSRVPGM SRVPGM(KPFLIB/Dates) MODULE(Dates) EXPORT(*ALL)

Putting it to the test


H BNDDIR(I5TOOLS) /COPY i5Tools,i5Tools
/FREE Date = %DATE(); DayNam = GetDayNam(DATE); MsgBox(Order + Ordno + scheduled + to ship + DayNam); *INLR = *ON; /END-FREE

Getting Date Names

02/14/2006
Order 123 scheduled to ship on Tuesday

Putting it to Use
Put these two lines in every program H BNDDIR(I5TOOLS) /COPY i5Tools,i5Tools
/FREE Date = %DATE(); DayNam = GetDayNam(DATE); MsgBox(Order + Ordno + is due to + ship on + DayNam); *INLR = *ON; /END-FREE

User Defined Functions

1)Unpack Data 2)Running Totals

Getting Packed Data

ID ? ? ? ? ?

Customer General Motors Honda Toyota Ford Chrysler

SQL Syntax to Unpack


SELECT SUBSTR(CUSTFLAT,4,30), DECIMAL(SUBSTR(HEX(SUBSTR( CUSTFLAT,1,3)),1,5),5,0) * CASE WHEN SUBSTR(HEX(SUBSTR( CUSTFLAT,3,1)),2,1) ='F' THEN 1 ELSE -1 END FROM CUSTFLAT

RPG Syntax to Unpack Part 1 of 2

PUnPack DUnPack D Text D Start D Len D RawDS D Packed

B PI

15P 2 3000A Varying 5I 0 5I 0

DS 15P 0

RPG Syntax to Unpack part 2 of 2

*----------------------------------------------* Load Text Into Packed Field *----------------------------------------------C Clear Packed C EVALR %SUBST(RAWDS: C 9-Len:Len) = C %SUBST(Text:Start:Len) C Return Packed PUnPack E

RPG Syntax to Unpack


RawDS 00000000 0000000F

Text 001 00F

RawDS 00000001 0000000F

RPG Syntax to Unpack


Create Module CRTRPGMOD MODULE(KPFLIB/UnPack) SRCFILE(KPFLIB/i5Tools) SRCMBR(UnPack) Create Service Program CRTSRVPGM SRVPGM(KPFLIB/UNPACK) MODULE(UNPACK) EXPORT(*ALL)

RPG Syntax to Unpack


Register Function With SQL (SQL CMD)
CREATE FUNCTION MYLIB/UnPack (IN VARCHAR(2000), IN INTEGER, IN INTEGER) RETURNS DECIMAL(15,0) EXTERNAL NAME MYLIB/UNPACK(UNPACK)' LANGUAGE RPGLE PARAMETER STYLE GENERAL)

RPG Syntax to Unpack


Use the Function! Select Unpack(CUSTFLAT,1,3) from CUSTFLAT UNPACK 00001 00002 00003 00005

RPG Syntax to Unpack


Instead of this!
SELECT SUBSTR(CUSTFLAT,4,30), DECIMAL(SUBSTR(HEX(SUBSTR( CUSTFLAT,1,3)),1,5),5,0) * CASE WHEN SUBSTR(HEX(SUBSTR( CUSTFLAT,3,1)),2,1) ='F' THEN 1 ELSE -1 END FROM CUSTFLAT

Running Totals
Order 1001 1002 1003 1004 1005 Qty Total 10 10 12 7 15 11 22 29 44 55

Running Totals DB2SQL Parameter style


* D D D D D D D D D D D Prototype for RunSum(QTY) RunSum PR Parm1 QtyOut InNull1 OutNull SqlState FuncName SpecName MesgText Scratch Flag 8F 8F 5I 0 5I 0 5 517A VARYING 128A VARYING 70A VARYING 8F 10I 0

Running Totals
P D D D D D D D D D D D RunSum RunSum QtyIn QtyOut InNull1 OutNull SqlState FuncName SpecName MesgText Scratch Flag B PI EXPORT 8F 8F 5I 0 5I 0 5 517A VARYING 128A VARYING 70A VARYING 8F 10I 0

Running Totals
* C * * C C C * C C * C Trap for any error that occurs MONITOR If this is the first time its called for this select, set the balance to 0 IF FLAG = -1 Clear Scratch ENDIF Add the input quantity to the scratch quantity ADD QtyIn Scratch Z-ADD Scratch QtyOut Return the quantity RETURN

Running Totals

* If any error occurs return a zero C ON-ERROR *PROGRAM C C EVAL QtyOut = 0 C RETURN C ENDMON P E

Running Totals
Create Module CRTRPGMOD MODULE(KPFLIB/RunSum) SRCFILE(KPFLIB/i5Tools) SRCMBR(RunSum) Create Service Program CRTSRVPGM SRVPGM(KPFLIB/RunSum) MODULE(RunSum) EXPORT(*ALL)

Running Totals Register Function With SQL (SQL CMD)


CREATE FUNCTION your-schema/RunSum (INOUT DOUBLE) RETURNS DOUBLE EXTERNAL NAME 'your-schema/SQLFUNCS(RunSum)' LANGUAGE RPGLE PARAMETER STYLE DB2SQL NOT DETERMINISTIC SCRATCHPAD 8 FINAL CALL DISALLOW PARALLEL)

Running Totals
Use the Function! Select Order, Qty, Runsum(Qty) from ORDMAST
Order 1 1001 1002 1003 1004 Qty Total 10 10 12 7 15 11 22 29 44 55

Canned SQL
1)Fetch This!

Canned SQL
1)Easy Load all Subfile

RPG Syntax to Fetch

H EXPROPTS(*RESDECPOS) BNDDIR('I5TOOLS') H DFTACTGRP(*NO) ACTGRP(*NEW) H OPTION(*SRCSTMT:*NODEBUGIO) FSAMPSUBDF CF E WORKSTN PREFIX(S_) F SFILE(SUBFILE:SflRRN) *--------------------------------------------------------

RPG Syntax to Fetch


/COPY i5Tools,i5Tools D RefDS E DS D D D D D D D D PTR INDARRAY Exit SflDsp SflDspCtl SflEnd S DS 03 10 11 14 * 03N 10N 11N 14N

EXTNAME(Reffile) Prefix(Ref) Based(Ptr_Not_Used) INZ(%ADDR(*IN)) BASED(PTR)

RPG Syntax to Fetch


D Stmt D SflRRN D NumRows * D Cust D CNumber D CName S S S 512 4S 0 4S 0

DS

Qualified LIKE(RefCnumber) LIKE(RefCname)

RPG Syntax to Fetch


*-------------------------------------------------------* Load SQL Results into subfile *-------------------------------------------------------C CALLP Fetch('Select Cnumber,Cname + C from Cust': NumRows) C C C C C C C C DoW CALLP EVAL Eval Eval Eval Write Enddo SflRRN < NumRows Load(Cust) SflRRN = SflRRN + 1 S_CName = Cust.CName S_CNumber = Cust.CNumber S_Opt = *BLANK SUBFILE

RPG Syntax to Fetch


C C C C C C C C C C EVAL EVAL EVAL EVAL DoU Write Exfmt Enddo Eval Return SflDspCtl = *ON SflDsp = *ON SflEnd = *ON S_S@RRN = 1 Exit FKeys Control

*INLR = *ON

Dynamic SQL Syntax


C/Exec SQL C+ PREPARE stmt1 from :W_SQL C/End-exec C/EXEC SQL C+ DESCRIBE Stmnt1 INTO :SQLDA C/END-EXEC

Select Cnumber,Cname from Cust


SQLVAR Array Field Type Field Length Pointer to Data

Dynamic SQL Syntax


DSQLDA D SQLDAID D SQLDABC D SQLN D SQLD D SQLVAR D SQLTYPE D SQLLEN D SQLRES D SQLDATA D SQLIND D SQLNAMELEN D SQLNAME DS 8A 10I 5I 5I 80A 5I 5I 12A * * 5I 30A 0 0 0 DIM(120) 0 OVERLAY(SQLVAR:1) 0 OVERLAY(SQLVAR:3) OVERLAY(SQLVAR:5) OVERLAY(SQLVAR:17) OVERLAY(SQLVAR:33) 0 OVERLAY(SQLVAR:49) OVERLAY(SQLVAR:51)

Dynamic SQL Syntax


C C C * Small Integer C C * Large Integer C C EVAL DO SELECT WHEN EVAL WHEN EVAL SQLTYPE(X) = 500 W_Len = 2 SQLTYPE(X) = 496 W_Len = 4 RowLen = 0 SQLD

Dynamic SQL Syntax


* Zoned decimal format C WHEN C SQLLEN(X) DIV C EVAL C * Packed decimal format C WHEN C SQLLEN(X) DIV

SQLTYPE(X) = 488 256 W_LEN W_Len = %INT(%DEC( W_Len / 2:7:1) + 1) SQLTYPE(X) = 484 256 W_LEN

Dynamic SQL Syntax


C/EXEC SQL C+ FETCH @C1 USING DESCRIPTOR :SQLDA C/END-EXEC

Fetch 1 row of data into SQLVAR


SQLVAR(1) SQLVAR(2) SQLVAR(3)

Col 1

Col 2

Col 3

Dynamic SQL Syntax


Concatenate all columns

Col 1

Col 2

Col 3

Row Data

Dynamic SQL Syntax


Pointer to Data Pointer to Next Elem. Pointer to Data Pointer to Next Elem. Pointer to Data Pointer to Next Elem. Pointer to Data Pointer to Next Elem. Pointer to Data Pointer to Next Elem.

Dynamic SQL Syntax

CUST DS CNUMBER CNAME RsltData (1st address)

Why?

Simpler Applications
C C C C C C C C C C CALLP DoW CALLP EVAL Eval Eval Eval Write Enddo Fetch('Select Cnumber, + Cname from Cust': NumRows) SflRRN < NumRows Load(Cust) SflRRN = SflRRN + 1 S_CName = Cust.CName S_CNumber = Cust.CNumber S_Opt = *BLANK SUBFILE

Embedded SQL w/o Precompiler Avoid Record format Level checks Dynamic sort and selection options Just a starting point for your own tools

To the Web!
1)Fetch and Throw!

Canned SQL
1)Easy web display

RPG Syntax to Web


H EXPROPTS(*RESDECPOS) BNDDIR('I5TOOLS') H ACTGRP(*NEW) DFTACTGRP(*NO) /copy CGIDEV2/qrpglesrc,hspecs /copy CGIDEV2/qrpglesrc,hspecsbnd *================================================== * Includes to be used in CGIs *================================================== /copy CGIDEV2/qrpglesrc,prototypeb /copy CGIDEV2/qrpglesrc,usec /copy CGIDEV2/qrpglesrc,variables3 *================================================== /COPY i5Tools,i5Tools

RPG Syntax to Web


D RefDS D D Stmt D X D NumRows * D Customer D CNumber D CName E DS EXTNAME(Reffile) Prefix(Ref) 512 4S 0 4S 0

S S S

DS

Qualified LIKE(RefCnumber) LIKE(RefCname)

RPG Syntax to Web


* Main line *================================================== C CALLP DoCmd('ADDLIBLE KPFLIB') C CALLP DoCmd('ADDLIBLE + C CGIDEV2') /copy CGIDEV2/qrpglesrc,prolog3 * Load HTML C callp gethtml('HTMLSRC': C 'KPFLIB':'SAMPWEB2') * C callp wrtsection('top') * C CALLP Fetch('Select Cnumber, + C Cname from Cust: C NumRows)

RPG Syntax to Web


C C C C C C C C C C C C C DoW Add CALLP callp callp callp Enddo callp callp Eval Return X < NumRows 1 X Load(Customer) updhtmlvar('cnumber': %Char(Customer.Cnumber)) updhtmlvar('cname': Customer.CName) wrtsection('row')

wrtsection('bottom') wrtsection('*fini') *INLR = *ON

HTML Syntax
First Page
<HTML> <HEAD><title>Sample Web Page One</title> </HEAD> <BODY> <FORM NAME="SELECT" method="POST" action="/kpflib/sampweb.pgm"> <CENTER> <H2>Customer Data</H2> Display Customer Data <BR><BR> <INPUT type="submit" value=" List Customers </CENTER> </FORM> </body> </html>

">

HTML Syntax
Second Page (1 of 2)
/$top <html> <head><title>Customer List</title> </head> <body> <CENTER> <h2>Customer List</h2> <table> <tr> <th>Cus. Nbr</th> <th>Customer Name</th> </TR>

HTML Syntax
Second Page (2 of 2)
/$row <tr> <td>/%cnumber%/ </TD> <td>/%cname%/ </td> </tr> /$bottom </TR> </TABLE> </CENTER> </body> </html>

Canned SQL

Performance?
Indexes Creation Order Key Sequence Index Type Use EVI Optimizer Time Out Visual Debug Coding Techniques

Performance
There are often times many different ways to achieve the results you desire. Some will be more efficient than others. This example illustrates using a sub-select to generate the value of a single column. This is not a very efficient technique.

This more complex example shows how to join a file to a temporary sub-total file generated by a sub-select over the same file.

Performance
This additional example illustrates the WITH clause and a prelude to the SELECT statement. It predefines the sub-select as a temporary table object, and in many cases can greatly simplify the code in the rest of the select statement.

The second and third example are similar from a performance standpoint. But this last example is the better choice in general.

Performance
Another way to improve performance is by limiting the number of records selected. Add the FETCH FIRST x ROWS ONLY clause.

In Embedded SQL statements, if you will be processing the result set in groups of a certain number of records. You may wish to add the OPTIMIZE clasue.

SQE vs CQE
CQE - is an older less efficient version of the SQL engine it does however support some features which the newer SQE engine does not. SQE is the latest and most advanced SQL engine available for the iSeries. There are some features which it does not yet support though, and SQL commands utilizing such features will be rerouted to the CQE engine. By default the SQE engine will not process files with logical files which include Select/Omit statements. To instruct the SQE engine to ignore these logical files ensure that your copy of the QAQQINI file has the parameter: IGNORE_DERIVED_INDEX set to *YES. See more info at http://www-03.ibm.com/servers/eserver/iseries/db2/sqe.html

Additional Resources

IBM Database Homepage: http://www-03.ibm.com/servers/eserver/iseries/db2/ IBM SQE Documentation: http://www-03.ibm.com/servers/eserver/iseries/db2/sqe.html IBM Info Center: http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp SQL Book (Shameless self promotion): http://www.mc-store.com/5063.html Contact me for additional help or information on additional training options. You can reach me at: Kevin.forsythe@dmcconsulting.com, or call me at (419) 535-2900.

Why Embed SQL in your RPG?

COMPILE TIME Vs. RUN TIME

FS

pe cs

S-ar putea să vă placă și