You are on page 1of 10

Embedded SQL in PL/I 10

1. PROGRAMMING IN PL/1..............................................................................................................................2
1.1 INTRODUCTION...............................................................................................................................................2
1.2 EMBEDDED SQL...........................................................................................................................................2
1.3 HOST VARIABLES...........................................................................................................................................2
1.4 THE CURSOR PRINCIPLE..............................................................................................................................4
1.5 TABLE DECLARATION......................................................................................................................................6
3.6 CHECK OF THE EXECUTION...............................................................................................................................8
1.7 NULL INDICATOR.........................................................................................................................................9
1.8 COMMIT-ROLLBACK.............................................................................................................................9

Kurt Van Diest / PFI 28218441.doc


Tel. (016) 30 23 02 V-20 July 2004
24 March 2000
Embedded SQL in PL/I 10

1. Programming in PL/1

1.1 Introduction

SQL can be used in different programming languages and environments. When


SQL is coded in a programming language, it is called embedded SQL. Here we
will specifically consider programming in PL/1 and an MVS environment.

First and foremost, we have to make a distinction between static and dynamic
embedded SQL:
- static embedded SQL: the statements to be executed are fully known at
the time of programming, e.g. SQL in PL/1 programs within the bank.
- dynamic embedded SQL: the statements to be executed are still not
known at the time of programming. The SQL statements will only be known upon
execution, e.g. SQL in QMF.

1.2 Embedded SQL

The structure of our program will remain the same.


To execute an SQL statement, we have to start with ‘EXEC SQL’ and end with a ‘;’
For example:

EXEC SQL SELECT *


INTO ....
FROM F3.TF30004
WHERE ..... ;

1.3 Host variables

We will use PLI variables in our SQL statements in order to use the result of our
SQL operations or to put variables in the WHERE clause. PLI variables are called
host variables.
Host variables are used to pass on values from SQL to PLI, (for example, the result
of a SELECT statement) or from PLI to SQL (for example in the WHERE clause, the
VALUES statement with INSERT, etc.).
Host variables are defined as ordinary PL/1 variables. When used in an SQL,
statement they are always preceded by a ‘:’. When used in PL/1 statements, this
colon is not needed.

Kurt Van Diest / PFI 28218441.doc


Tel. (016) 30 23 02 V-20 July 2004
24 March 2000
Embedded SQL in PL/I 10

However, it is important for these host variables to have a format that corresponds
to that of the DB2 columns:
DB2 format PL/1 format
SMALLINT BIN FIXED (15)
INTEGER BIN FIXED (31)
DECIMAL (P,Q) DEC FIXED (P,Q)
CHAR(N) CHAR(N)
VARCHAR(M) CHAR(M) VAR
LONG VARCHAR CHAR(X) VAR
DATE CHAR(10)
TIME CHAR(8)
TIMESTAMP CHAR(26)

A host variable can have a structure with two levels and can be used in all SQL
statements.
The use of host variables:
A) To save the result if the result is one row.

EXEC SQL SELECT CMUALF


INTO :W_CMUALF
FROM F3.TF30004
WHERE CLAALF = ‘FRA’;

We can proceed further in our program with this host variable.


For example:

IF W_CMUALF = ‘FRF’ THEN


W_CURRENCY = ‘FRENCH
FRANK’;
ELSE ...

B) We can also use a variable in the WHERE clause of SELECT, UPDATE or DELETE
statements.

EXEC SQL
SELECT COUNT(COCOMP)
INTO :W_SOM_COCOMP
FROM F3.TF30013
WHERE RCIFD = :W_RCIFD;

Kurt Van Diest / PFI 28218441.doc


Tel. (016) 30 23 02 V-20 July 2004
24 March 2000
Embedded SQL in PL/I 10

C) We can also use host variables to update a table.

W_NEW_BALANCE = W_OLD_BALANCE + W_ENTRY;


EXEC SQL UPDATE F4.TF42001
SET BEFFEC = :W_NEW_BALANCE
WHERE RCIFD = :W_RCIFD
AND RCIF = :W_RCIF
AND CACCT1 = :W_CACCT1
AND CMUALF =:W_CMUALF
AND RVOLG = :W_RVOLG;

D) With the INSERT statement.

EXEC SQL INSERT INTO F3.TF30004


VALUES (:W_CCOSYS,
:W_CTAAL,
:W_CLAALF,
:W_CREGIO ,
:W_CBCKUP);

1.4 The CURSOR principle

The method described above for retrieving information and putting it in host
variables cannot be used if the result of the query is more than one row. We will
use a cursor to process multiple rows one by one.

The cursor mechanism works in a similar way to an ordinary file:


- cursor declaration
- open
- read (to cursor end)
- close

1) Cursor declaration
For the declaration, we will put the SQL statement, together with any host
variables, into the WHERE clause, but not after the SELECT with INTO (see
above).
The host variables have to be declared before the cursor.

SYNTAX:

EXEC SQL DECLARE cursor name CURSOR {WITH HOLD} FOR


SELECT column,column,...
FROM table(s)
WHERE where clause ;

WITH HOLD: indicates that the cursor has to be opened with COMMIT or
ROLLBACK.

Kurt Van Diest / PFI 28218441.doc


Tel. (016) 30 23 02 V-20 July 2004
24 March 2000
Embedded SQL in PL/I 10

2) Open
By opening the cursor, the rows are selected and the SQL statement is
actually executed. A check after this statement will not determine whether
rows have been selected, only whether the SQL statement has been correctly
executed. This can only be established with the first FETCH (read).

SYNTAX:

EXEC SQL OPEN cursor


name ;

3) Fetch
Using the FETCH instruction, we will transfer one row from the result to the
host variables.
Syntax:

EXEC SQL FETCH cursor name


INTO :host variable1,:host variable2,... ;

With the first FETCH, we can see whether or not something has been selected.
Generally, fetch runs in a loop for as long as rows are found (SQLCODE = 0).
When the end of the cursor row is reached (SQLCODE = 100) or if there is an
error (SQLCODE < 0), we will leave the loop.

4) Close
After the processing, we will close the cursor again. If we have defined a
cursor without HOLD, the cursor will be implicitly closed with COMMIT or
ROLLBACK.

Syntax:

EXEC SQL CLOSE cursor name


;

Kurt Van Diest / PFI 28218441.doc


Tel. (016) 30 23 02 V-20 July 2004
24 March 2000
Embedded SQL in PL/I 10

1.5 Table declaration

To be able to use a table in our program, a description of this table will have to
be given. This description is used to check the syntax at precompilation (see
further).

Example:

EXEC SQL DECLARE F2.TF20020 TABLE

( DBGGLD DECIMAL(9,0) NOT NULL,


DEIGLD DECIMAL(9,0) NOT NULL,
CMUT CHAR(1) NOT NULL,
DMUT DECIMAL(9,0) NOT NULL,
DUMUT DECIMAL(7,0) NOT NULL,
CUSRID CHAR(8) NOT NULL,
DSCHRA DECIMAL(9,0) NOT NULL,
RUSEVW CHAR(8) NOT NULL,
CLOGBL CHAR(1) NOT NULL,
RVERS CHAR(2) NOT NULL,
CSTATU CHAR(1) NOT NULL,
CLAALF CHAR(3) NOT NULL,
CREGIO CHAR(5) NOT NULL,
CTAAL DECIMAL(3,0) NOT NULL,
NLAND CHAR(40) NOT NULL,
NLANDK CHAR(15) NOT NULL,
CVLREG CHAR(1) NOT NULL
) ;

Generally, we do not have to provide this table description ourselves. Whenever a


table is created or changed, a DCLGEN (=declaration generator) will be created.
This DCLGEN contains an SQL and PL/1 description of the table, and is located in
these two libraries: ‘PDP.DB2DCLPL.CCB00’ (for the development environments)
and ‘PDP.DB2DCLPL.CCM00’ (for production environments). The name of the
DCLGEN is the same as the table name: table F0.TF00008  dclgen TF00008.
To be able to use the DCLGEN in the program, we will have to include it.

EXEC SQL INCLUDE TF00008 ;

This command ensures that the DCLGEN is copied in for compilation.

Kurt Van Diest / PFI 28218441.doc


Tel. (016) 30 23 02 V-20 July 2004
24 March 2000
Embedded SQL in PL/I 10

This DCLGEN thus appears as follows:

/*********************************************************************/
/* DCLGEN TABLE(F0.TF00008) */
/* LIBRARY(PDT.DCLGEN.U32332.D170300.T103407.LIST(TF00008)) */
/* ACTION(REPLACE) */
/* LANGUAGE(PLI) */
/* STRUCTURE(TF00008) */
/* APOST */
/* LABEL(YES) */
/* ... IS THE DCLGEN COMMAND THAT MADE THE FOLLOWING STATEMENTS
*/
/*********************************************************************/
EXEC SQL DECLARE F0.TF00008 TABLE
( CCOSYS CHAR(2) NOT NULL,
CTAAL DECIMAL(3,0) NOT NULL,
CLAALF CHAR(3) NOT NULL,
CREGIO CHAR(5) NOT NULL,
CBCKUP CHAR(1) NOT NULL
) ;

/*********************************************************************/
/* PLI DECLARATION FOR TABLE F0.TF00008
*/
/*********************************************************************/
EXEC SQL BEGIN DECLARE SECTION;
DCL 1 TF00008,
5 CCOSYS CHAR(2),
5 CTAAL DEC FIXED(3,0),
5 CLAALF CHAR(3),
5 CREGIO CHAR(5),
5 CBCKUP
CHAR(1);
/*********************************************************************/
/* THE NUMBER OF COLUMNS DESCRIBED BY THIS DECLARATION IS 5
*/
/*********************************************************************/
EXEC SQL END DECLARE SECTION;

It is preferable to use these PL/1 variables since they are automatically copied in
together with the DB2 declaration.
Note that in this example, the PL/1 declaration is preceded by ‘EXEC SQL BEGIN
DECLARE SECTION’ and followed by ‘EXEC SQL END DECLARE SECTION’.
This is not needed when the program is only executed in MVS, but it is when the
program is also to be executed in a VM environment (as another DB system runs
there, i.e. SQL/DS).

Kurt Van Diest / PFI 28218441.doc


Tel. (016) 30 23 02 V-20 July 2004
24 March 2000
Embedded SQL in PL/I 10

3.6 Check of the execution

After an SQL operation has been executed, using the SQLCODE we have to check
whether an error has occurred, whether something has been found, etc. After
each SQL statement the SQLCODE has to be checked!
The SQLCODE can be divided into three major groups:

SQLCODE > 0 WARNING Exceptional but executed condition


(e.g. no row found (SQLCODE = 100))
SQLCODE = 0 OK
SQLCODE < 0 ERROR Error during execution of the SQL statement
(e.g. -803, a row has been added with a key
that already exists)

The most common SQLCODES for each statement are:

STATEMENT SQLCODE COMMENTS


SELECT 0 Requested information
found
+100 Row not found
INSERT 0 Addition successful
-803 Key for the added row
already exists
UPDATE 0 Change successful
+100 Row not found
DELETE 0 Row deleted
+100 Row not found
OPEN cursor 0 Select statement for cursor
correctly executed
FETCH 0 Row fetched
+100 No (further) row found
CLOSE cursor 0 Cursor correctly closed

The SQLCODE is a component of the SQL Communication Area (abbreviated to


SQLCA). In order to use the SQLCODE, we thus also have to include the SQLCA. The
method is the same as with DECLGEN, for ex.

EXEC SQL INCLUDE


SQLCA ;
DECLARE The declaration below is copied
1 SQLCA, into the program:
2 SQLCAID CHAR(8),
2 SQLCABC FIXED(31) BINARY,
2 SQLCODE FIXED(31) BINARY,
2 SQLERRM CHAR(70) VAR,
2 SQLERRP CHAR(8),
2 SQLERRD(6) FIXED(31) BINARY,
2 SQLWARN,
3 SQLWARN0 CHAR(1),
3 SQLWARN1 CHAR(1),
3 SQLWARN2 CHAR(1),
3 SQLWARN3 CHAR(1),
3 SQLWARN4 CHAR(1),
3 SQLWARN5 CHAR(1),
3 SQLWARN6 CHAR(1),
Kurt Van Diest / PFI3 SQLWARN7 CHAR(1), 28218441.doc
Tel. (016) 30 23 202SQLEXT, V-20 July 2004
3 SQLWARN8 CHAR(1), 24 March 2000
3 SQLWARN9 CHAR(1),
3 SQLWARNA CHAR(1),
3 SQLSTATE CHAR(5);
Embedded SQL in PL/I 10

1.7 NULL indicator

If a column can contain the NULL value or if we use a function that can return a
NULL value (e.g. MAX(column) when no row satisfies that criterion), we cannot
check it using the SQLCODE as it will contain the value 0.
Hence we will have to use an indicator field. When this indicator field is negative, it
means that the result of the query cannot be used for further processing. The host
variable does not contain any correct information. Note that the null indicator is
written directly against the host variable, thus without spaces or commas in
between!

Example:

DCL NULLVAR BIN FIXED(15);

EXEC SQL
SELECT MIN(COCOMP)
INTO :TF30013.COCOMP:NULLVAR
FROM F3.TF30013
WHERE RCIFD = :TF30013.RCIFD;

IF SELECT = 0 THEN
DO;
IF NULLVAR < 0 THEN
DO;
processing
END;
ELSE
DO;
processing
END;
END;
ELSE
Processing error

1.8 COMMIT-ROLLBACK

If the program changes data in the tables, this will only be temporary. It is only by
executing a COMMIT (implicit or explicit) that the changes are passed on. When
the program is executed correctly (i.e. without abend), a commit will be done
automatically on MVS. When a program is executed on VM we will have to write an
explicit commit. We can also pass on a commit explicitly.
Rollback will ensure that the changes up to the previous commit are undone. This
will be done implicitly with an abend.
We can also explicitly do a commit or a rollback:

EXEC SQL COMMIT WORK;

or

EXEC SQL ROLLBACK


Kurt Van Diest / PFI
WORK; 28218441.doc
Tel. (016) 30 23 02 V-20 July 2004
24 March 2000
Embedded SQL in PL/I 10

It is useful to do a commit now and again, certainly when a cursor is used. This is
so that if the program goes abend, not all changes will be undone.
A commit has to be done after a logical processing unit, i.e. if a number of tables
have been changed. You have to ensure that with an abend and restart, the data
in the various tables are still consistent.

Kurt Van Diest / PFI 28218441.doc


Tel. (016) 30 23 02 V-20 July 2004
24 March 2000

You might also like